#!/bin/bash
#
# ssl_gen_crt
#
# Author        : Nohaj
# Contact       : johan@slashroot.fr
# Date          : 12/02/20
# Version       : 2.1 (13/12/22)
# Description   : Script qui permet de generer (ou renouveler) une clé et un certificat HTTPS en utilisant notre CA Sectigo via certbot et ACME
#               : Les clés et certificats sont stockés sur le montage NFS de l'équipe clusters et ajoutés dans vault (admins/kv/certificats) 
# Require       : Droits root pour certbot / accès au montage NFS / accès à vault 
#

#
# Changelog
#
# V1.X : on genere une clé et un csr qui permet de demander le certificat depuis l'interface Sectigo
#
# V1.1 : mise au propre de tout le script
#
# V1.2 : ajout de la possibilite de creer des certificats en multi-domain
#
# V2.0 : on genere directement la clé et le certificat avec certbot (validation via ACME avec le compte "Pole ISA" créé par Johan)
#      : la partie renouvellement du script n'a pas encore été testé car les certificats ne sont renouvelables qu'a partir de <30 jours
#      : probablement prévoir une v2.1 a ce moment la du coup ...
#
# V2.1 : pour le renouvellement on part sur une nouvelle clé 
#

#
# Usage
#
usage(){
    echo ""
    echo "Usage : ssl_gen_crt NAME.slashroot.{fr|net} [NAME2.slashroot.{fr|net}]"
    echo ""
    echo "EXEMPLE :"
    echo "   ssl_gen_crt hello.slashroot.fr"
    echo "   ssl_gen_crt coucou.slashroot.fr coucou-dmz.slashroot.fr"
    echo ""
    echo "NOTES :"
    echo "    Bien mettre le fqdn "principal" en premier lorsqu'on demande du multi-domain"
    echo ""
}

echo ""

#
# Variables et vérifications
#

if [[ -f /etc/profile.d/sectigo.sh ]] ; then
    source /etc/profile.d/sectigo.sh
    if [[ -z $SECTIGO_HMAC_KEY ]] || [[ -z $SECTIGO_KEY_ID ]] ; then
        echo "ERREUR - Les credentials Sectigo pour ACME ne semblent pas présents"
        exit 1
    fi
else
    echo "ERREUR - Le fichier de config (/etc/profile.d/sectigo.sh) est introuvable"
    exit 1
fi

if [[ $# -eq 0 ]] ; then
    usage
    exit 1
fi

# Le script prend X arguments qui doivent etre un FQDN qui fini par slashroot.fr ou slashroot.net
if [[ $# -eq 1 ]] ; then
    CERT_TYPE="standard"
    DOMAIN_LIST=$1
    if [[ ! $1 =~ .slashroot.fr$ ]] && [[ ! $1 =~ .slashroot.net$ ]] ; then
        echo "ERREUR - Le FQDN n'est pas correct (seuls slashroot.fr et slashroot.net sont acceptés)"
        exit 1
    fi
else
    CERT_TYPE="multi-domain"
    DOMAIN_LIST=$@
    for fqdn in $@ ; do
        if [[ ! $fqdn =~ .slashroot.fr$ ]] && [[ ! $fqdn =~ .slashroot.net$ ]] ; then
            usage
            exit 1
        fi
    done
fi

USER=$(whoami)
NAME=$1

if [[ $USER == "root" ]] ; then
    CERTBOT_CMD="/usr/bin/certbot"
else
    CERTBOT_CMD="sudo /usr/bin/certbot"
    if ( ! $CERTBOT_CMD --version &> /dev/null ) ; then
        echo "ERREUR - Vous n'avez pas les droits sudo sur la commande certbot, on abandonne"
        exit 1
    fi
fi

# On vérifie l'accès à vault
if ( ! vault token lookup &> /dev/null ) ; then
    echo "ERREUR - Vous n'avez pas l'air d'être connecté à vault, on abandonne (essayez peut-être la commande vault_init_and_renew)"
    exit 1
fi

# On vérifie l'accès aux données
if ( ! ls /etc/letsencrypt/ &> /dev/null ) ; then
    echo "ERREUR - Vous n'avez pas l'air d'avoir accès au dossier letsencrypt, on abandonne"
    exit 1
fi

#
# Au boulot
#

if [[ -d /etc/letsencrypt/archive/$NAME ]] ; then
    ACTION="renew"
else
    ACTION="generate"
fi
  
if [[ $ACTION == "generate" ]] ; then
    
    echo -n "On genere key et crt pour $DOMAIN_LIST ? [o/N] : " ; read reponse
    echo ""
    
    if [[ $reponse == "o" ]] || [[ $reponse == "O" ]] ; then
    
        echo "Génération en cours ...."
        echo ""
        if [[ $CERT_TYPE == "standard" ]] ; then
            if ( $CERTBOT_CMD certonly --standalone --non-interactive --agree-tos --email DSI.Infra.Clusters@slashroot.fr --server $SECTIGO_ACME_OV_SERVER --eab-kid $SECTIGO_KEY_ID --eab-hmac-key $SECTIGO_HMAC_KEY --domain $DOMAIN_LIST &> /dev/null ) ; then
                echo "OK - Génération et validation terminée"
                echo ""
            else
                echo "ERREUR - Quelque chose s'est mal passé, merci d'investiguer"
                exit 1
            fi
        fi
    
        if [[ $CERT_TYPE == "multi-domain" ]] ; then
            for DOMAIN in $DOMAIN_LIST ; do
                DOMAINS="$DOMAINS --domain $DOMAIN"
            done
            if ( $CERTBOT_CMD certonly --standalone --non-interactive --agree-tos --email DSI.Infra.Clusters@slashroot.fr --server $SECTIGO_ACME_OV_SERVER --eab-kid $SECTIGO_KEY_ID --eab-hmac-key $SECTIGO_HMAC_KEY $DOMAINS &> /dev/null ) ; then
                echo "OK - Génération et validation terminée"
                echo ""
            else
                echo "ERREUR - Quelque chose s'est mal passé, merci d'investiguer"
                exit 1
            fi
        fi
    
        # On met tout le bazar dans vault
        echo "Mise en place de la clé et des certificats dans vault"
        echo ""
        cat /etc/letsencrypt/archive/$NAME/privkey1.pem | vault kv put admins/kv/certificats/$NAME key=- &> /dev/null
        cat /etc/letsencrypt/archive/$NAME/cert1.pem | vault kv patch admins/kv/certificats/$NAME cert=- &> /dev/null
        cat /etc/letsencrypt/archive/$NAME/fullchain1.pem | vault kv patch admins/kv/certificats/$NAME cert_chained=- &> /dev/null
    
        if ( ! vault kv get -field=key /admins/kv/certificats/$NAME &> /dev/null ) || ( ! vault kv get -field=cert /admins/kv/certificats/$NAME &> /dev/null ) || ( ! vault kv get -field=cert_chained /admins/kv/certificats/$NAME &> /dev/null ) ; then 
            echo "ERREUR - Quelque chose s'est mal passé, merci d'investiguer"
            exit 1
        else
            echo "OK - La clé et les certificats ont été ajoutés dans vault (https://vault.slashroot.fr/ui/vault/secrets/siege%2Fdsi%2Finfra%2Fclusters%2Fkv/show/certificats/$NAME)"
            echo ""
            exit 0
        fi
    else
        echo "Abandon..."
        exit 1
    fi
fi

if [[ $ACTION == "renew" ]] ; then
    
    echo -n "On renouvelle le certificat $NAME ? [o/N] : " ; read reponse
    echo ""

    if [[ $reponse == "o" ]] || [[ $reponse == "O" ]] ; then

        days_remaining=$(sudo certbot certificates -d $NAME | grep "Expiry Date" -m 1 | awk '{print $6}')
        if [[ $days_remaining -ge 30 ]] ; then
            echo "Le certificat $NAME expire dans 30 jours ou plus ($days_remaining jours restants)"
            echo "Impossible de renouveler le certificat, on abandonne"
            exit 1
        fi

        echo "Renouvellement en cours ...."
        echo ""
        if [[ $CERT_TYPE == "standard" ]] ; then
            if ( $CERTBOT_CMD certonly --standalone --non-interactive --agree-tos --email DSI.Infra.Clusters@slashroot.fr --server $SECTIGO_ACME_OV_SERVER --eab-kid $SECTIGO_KEY_ID --eab-hmac-key $SECTIGO_HMAC_KEY --domain $DOMAIN_LIST &> /dev/null ) ; then
                echo "OK - Renouvellement terminé"
                echo ""
            else
                echo "ERREUR - Quelque chose s'est mal passé, merci d'investiguer"
                exit 1
            fi
        fi

        if [[ $CERT_TYPE == "multi-domain" ]] ; then
            for DOMAIN in $DOMAIN_LIST ; do
                DOMAINS="$DOMAINS --domain $DOMAIN"
            done
            if ( $CERTBOT_CMD certonly --standalone --non-interactive --agree-tos --email DSI.Infra.Clusters@slashroot.fr --server $SECTIGO_ACME_OV_SERVER --eab-kid $SECTIGO_KEY_ID --eab-hmac-key $SECTIGO_HMAC_KEY $DOMAINS &> /dev/null ) ; then
                echo "OK - Renouvellement terminé"
                echo ""
            else
                echo "ERREUR - Quelque chose s'est mal passé, merci d'investiguer"
                exit 1
            fi
        fi

        # On met les nouveaux certificats dans vault
        echo "Mise à jour des certificats dans vault (best effort)"
        echo ""
        lastprivkey=$(ls -t /etc/letsencrypt/archive/$NAME/privkey* | head -n 1 | rev | cut -d'/' -f 1 )
        i=${lastprivkey:4:1}
        cat /etc/letsencrypt/archive/$NAME/privkey${i}.pem | vault kv patch admins/kv/certificats/$NAME key=- &> /dev/null
        cat /etc/letsencrypt/archive/$NAME/cert${i}.pem | vault kv patch admins/kv/certificats/$NAME cert=- &> /dev/null
        cat /etc/letsencrypt/archive/$NAME/fullchain${i}.pem | vault kv patch admins/kv/certificats/$NAME cert_chained=- &> /dev/null
        if ( ! vault kv get -field=key /admins/kv/certificats/$NAME &> /dev/null ) || ( ! vault kv get -field=cert /admins/kv/certificats/$NAME &> /dev/null ) || ( ! vault kv get -field=cert_chained /admins/kv/certificats/$NAME &> /dev/null ) ; then
            echo "ERREUR - Quelque chose s'est mal passé, merci d'investiguer"
            exit 1
        else
            echo "OK - La clé et les certificats ont été mise à jour dans vault (https://vault.slashroot.fr/ui/vault/secrets/siege%2Fdsi%2Finfra%2Fclusters%2Fkv/show/certificats/$NAME)"
            echo ""
            exit 0
        fi
    else
        echo "Abandon..."
        exit 1
    fi
fi
