#!/bin/bash # # exit 0: the certificate still looks good and it won't be replaced # exit 1: a new certificate was installed and we need to reload our service # exit 2: uh, oh something went wrong # # the certificate will be checked, if it is valid, if the key matches # and if it contains at least the cert-name # LOCAL_MD5=$(md5sum $0 | awk '{print $1}') REMOTE_MD5=$(curl -s https://repositories.geant.org/pub/acme/acme-downloader.sh | md5sum | awk '{print $1}') if [[ $LOCAL_MD5 != $REMOTE_MD5 ]]; then echo "$0 differs from https://repositories.geant.org/pub/acme/acme-downloader.sh" echo "suggesting that you are running an older version" echo "" fi REDIS_URL="https://redis.geant.org/GET" VAULT_URL="https://vault.geant.org/v1" TMP_CERT=$(mktemp) TMP_FULLCHAIN=$(mktemp) TMP_CA=$(mktemp) TMP_KEY=$(mktemp) stty -echoctl # hide ^C # function called by trap clean_up() { rm -f $TMP_CERT $TMP_FULLCHAIN $TMP_CA $TMP_KEY exit 2 } trap 'clean_up' SIGINT if [ $(id -u) -ne 0 ]; then echo -e "plase run this script as root\ngiving up..." clean_up elif ! which curl jq &>/dev/null; then echo -e "please install curl and jq\ngiving up..." clean_up fi # lsb_release is not always installed if ! source /etc/os-release &>/dev/null; then echo "no idea what to do with this OS: I was not able to access /etc/os-release" echo "" clean_up elif [[ "$ID" == "ubuntu" ]] || [[ "$ID" == "debian" ]]; then CERT_BASE="/etc/ssl/certs" KEY_BASE="/etc/ssl/private" GROUPNAME="ssl-cert" elif [[ "$ID" == "centos" ]] || [[ "$ID" == "rhel" ]]; then CERT_BASE="/etc/pki/tls/certs" KEY_BASE="/etc/pki/tls/private" GROUPNAME="root" else echo "no idea what to do with OS: $ID" echo "please amend the script accordingly" echo "" clean_up fi usage() { echo "Usage: $(basename $0)" echo " -h | --help [Print this help and exit]" echo " --redis-token (Redis access token)" echo " --vault-token (Vault access token)" echo " --cert-name (Certificate name)" echo " --team-name (Team name: swd, dream_team, it, ne, ti...)" echo " --days [OPTIONAL check days before expiration. Default: 30)" echo " --type [OPTIONAL. OV or EV. Default: EV]" echo " --cert-destination [OPTIONAL Default: ${CERT_BASE}/<cert-name>.crt]" echo " --fullchain-destination [OPTIONAL Default: ${CERT_BASE}/<cert-name>_fullchain.crt]" echo " --key-destination [OPTIONAL Default: ${KEY_BASE}/<cert-name>.key]" echo " --ca-destination [OPTIONAL Default: ${CERT_BASE}/COMODO_<type>.crt]" echo " --wildcard [OPTIONAL if the certificate is wildcard]" echo "" clean_up } OPTS=$(getopt -o "h" --longoptions "help,redis-token:,vault-token:,cert-name:,team-name:,days:,type:,cert-destination:,fullchain-destination:,key-destination:,ca-destination:,wildcard" -- "$@") eval set -- "$OPTS" while true; do case "$1" in -h | --help) usage clean_up ;; --redis-token) shift REDIS_TOKEN="${1}" ;; --vault-token) shift VAULT_TOKEN="${1}" ;; --cert-name) shift CERT_NAME="${1}" ;; --team-name) shift TEAM_NAME="${1}" ;; --days) shift DAYS="${1}" ;; --type) shift TYPE="${1}" ;; --cert-destination) shift CERT_DESTINATION="${1}" ;; --fullchain-destination) shift FULLCHAIN_DESTINATION="${1}" ;; --key-destination) shift KEY_DESTINATION="${1}" ;; --ca-destination) shift CA_DESTINATION="${1}" ;; --wildcard) WILDCARD='WILDCARD' ;; --) shift break ;; esac shift done TYPE=$(echo $TYPE | tr '[:lower:]' '[:upper:]') if [[ -z $REDIS_TOKEN ]] || [[ -z $VAULT_TOKEN ]] || [[ -z $CERT_NAME ]] || [[ -z $TEAM_NAME ]]; then echo -e "\n--redis-token, --vault-token, --cert-name and --team-name are mandatory\n" usage fi [[ -z $TYPE ]] && TYPE="EV" # let's default to EV type if [[ $TYPE != "EV" ]] && [[ $TYPE != "OV" ]]; then echo "type must be either EV, ev, OV, ov" usage fi [[ -z $DAYS ]] && DAYS=30 [[ -z $CERT_DESTINATION ]] && CERT_DESTINATION="${CERT_BASE}/${CERT_NAME}.crt" [[ -z $FULLCHAIN_DESTINATION ]] && FULLCHAIN_DESTINATION="${CERT_BASE}/${CERT_NAME}_fullchain.crt" [[ -z $KEY_DESTINATION ]] && KEY_DESTINATION="${KEY_BASE}/${CERT_NAME}.key" [[ -z $CA_DESTINATION ]] && CA_DESTINATION="${CERT_BASE}/COMODO_${TYPE}.crt" UNDERSCORED_CERT_NAME=$(echo $CERT_NAME | sed -e 's,\.,_,g') MINUTES=$((${DAYS} * 86400)) # give up if the certificate expiration is still within a proper range if openssl x509 -checkend $MINUTES -noout -in $FULLCHAIN_DESTINATION &>/dev/null; then rm -f $TMP_CERT $TMP_FULLCHAIN $TMP_CA $TMP_KEY exit 0 fi # download certificates and delete the last empty line if it exists and remove the first line from Webdis if [[ -z $WILDCARD ]]; then curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:${CERT_NAME}:redis_${UNDERSCORED_CERT_NAME}_pem.txt >$TMP_CERT curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:${CERT_NAME}:redis_${UNDERSCORED_CERT_NAME}_fullchain_pem.txt >$TMP_FULLCHAIN curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:${CERT_NAME}:redis_${UNDERSCORED_CERT_NAME}_chain_pem.txt >$TMP_CA curl -s -H "X-Vault-Token: ${VAULT_TOKEN}" ${VAULT_URL}/${TEAM_NAME}/${CERT_NAME}/vault_${UNDERSCORED_CERT_NAME}_key | jq -j .data.value >$TMP_KEY else curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:common:redis_sectigo_ov_${UNDERSCORED_CERT_NAME}_pem.txt >$TMP_CERT curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:common:redis_sectigo_ov_${UNDERSCORED_CERT_NAME}_fullchain_pem.txt >$TMP_FULLCHAIN curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:common:redis_sectigo_ov_${UNDERSCORED_CERT_NAME}_chain_pem.txt >$TMP_CA curl -s -H "X-Vault-Token: ${VAULT_TOKEN}" ${VAULT_URL}/${TEAM_NAME}/common/vault_sectigo_ov_wildcard_${UNDERSCORED_CERT_NAME}_key | jq -j .data.value >$TMP_KEY fi # Before installing any certificate we need to check the validity of # Certificate, Full Chain, CA and Key that we downloaded # checking if certificates are valid if ! openssl x509 -checkend $MINUTES -noout -in $TMP_CERT &>/dev/null; then echo "the Certificate is malformed or is expiring. Giving up" clean_up fi if ! openssl x509 -checkend $MINUTES -noout -in $TMP_FULLCHAIN &>/dev/null; then echo "the Full Chain is malformed or is expiring. Giving up" clean_up fi if ! openssl x509 -in $TMP_CA -text -noout &>/dev/null; then echo "the CA is malformed. Giving up" clean_up fi # checking if key matches the certificate and the full-chain KEY_MD5=$(openssl rsa -noout -modulus -in $TMP_KEY | openssl md5 | awk '{print $NF}') FULLCHAIN_MD5=$(openssl x509 -noout -modulus -in $TMP_FULLCHAIN | openssl md5 | awk '{print $NF}') CRT_MD5=$(openssl x509 -noout -modulus -in $TMP_CERT | openssl md5 | awk '{print $NF}') if [[ $KEY_MD5 != $CRT_MD5 ]] || [[ $KEY_MD5 != $FULLCHAIN_MD5 ]]; then echo "the Key $TMP_KEY is either malformed or it does not match the certificate. Giving up" clean_up fi # checking if the certificate contains at least our cert_name if ! openssl x509 -noout -text -in $TMP_CERT | grep -qw $CERT_NAME; then echo "the certificate does not match your CN $CERT_NAME" clean_up fi if ! openssl x509 -noout -text -in $TMP_FULLCHAIN | grep -qw $CERT_NAME; then echo "the full chain certificate does not match your CN $CERT_NAME" clean_up fi # let's install the certificates install --owner=root --group=root --mode=0755 --directory $CERT_BASE install --owner=root --group=$GROUPNAME --mode=0750 --directory $KEY_BASE install --owner=root --group=root --mode=0644 -T ${TMP_CERT} ${CERT_DESTINATION} install --owner=root --group=root --mode=0644 -T ${TMP_FULLCHAIN} ${FULLCHAIN_DESTINATION} install --owner=root --group=root --mode=0644 -T ${TMP_CA} ${CA_DESTINATION} install --owner=root --group=$GROUPNAME --mode=0640 -T ${TMP_KEY} ${KEY_DESTINATION} rm -f $TMP_CERT $TMP_FULLCHAIN $TMP_CA $TMP_KEY echo "installed: ${CERT_DESTINATION}" echo "installed: ${FULLCHAIN_DESTINATION}" echo "installed: ${CA_DESTINATION}" echo "installed: ${KEY_DESTINATION}" # exiting 1: if we are here we need to reload our service exit 1