From 17aa3655abc0d7b7cdd86e9bf525d162a605cef7 Mon Sep 17 00:00:00 2001 From: Massimiliano Adamo <maxadamo@gmail.com> Date: Wed, 22 Sep 2021 21:24:54 +0200 Subject: [PATCH] add version number --- .gitignore | 3 +- .gitlab-ci-psnc.yml | 20 ++- acme-downloader-artifactory.sh | 296 +++++++++++++++++++++++++++++++++ acme-downloader.sh | 13 +- build-bash.sh | 20 +++ build.sh => build-go.sh | 0 6 files changed, 336 insertions(+), 16 deletions(-) create mode 100755 acme-downloader-artifactory.sh create mode 100755 build-bash.sh rename build.sh => build-go.sh (100%) diff --git a/.gitignore b/.gitignore index 0420207..f95f979 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .*.sw[op] .DS_Store acme-downloader -acme-downloader.exe \ No newline at end of file +acme-downloader.exe +acme-downloader-afactory.sh \ No newline at end of file diff --git a/.gitlab-ci-psnc.yml b/.gitlab-ci-psnc.yml index 03b71cf..708fea6 100644 --- a/.gitlab-ci-psnc.yml +++ b/.gitlab-ci-psnc.yml @@ -6,8 +6,8 @@ stages: - upload_windows_amd64_binary variables: - ARTIFACTORY_BASE_URL: https://artifactory.software.geant.org/artifactory/acme-downloader - ARTIFACTORY_METADATA_URL: https://artifactory.software.geant.org/artifactory/api/storage/acme-downloader + AFACTORY_BASE_URL: https://artifactory.software.geant.org/artifactory/acme-downloader + AFACTORY_METADATA_URL: https://artifactory.software.geant.org/artifactory/api/storage/acme-downloader ARTIFACT_NAME: acme-downloader sonarqube: @@ -27,7 +27,9 @@ upload_linux_shell: only: - tags script: - - 'curl -sSf -H "X-JFrog-Art-Api:${ARTIFACTORY_TOKEN}" -X PUT -T ./${ARTIFACT_NAME}.sh ${ARTIFACTORY_BASE_URL}/${ARTIFACT_NAME}.sh' + - ./build-bash.sh ${CI_COMMIT_TAG:1} + - 'curl -sSf -H "X-JFrog-Art-Api:${AFACTORY_TOKEN}" -X PUT -T ./${ARTIFACT_NAME}-afactory.sh ${AFACTORY_BASE_URL}/${ARTIFACT_NAME}.sh' + - 'curl -sSf -H "X-JFrog-Art-Api:${AFACTORY_TOKEN}" -X PUT "${AFACTORY_BASE_URL}/${ARTIFACT_NAME}.sh?properties=version=${CI_COMMIT_TAG:1}' tags: - acme @@ -36,9 +38,9 @@ upload_linux_amd64_binary: only: - tags script: - - ./build.sh --os=linux --arch=amd64 --version=$CI_COMMIT_TAG --upx - - 'curl -sSf -H "X-JFrog-Art-Api:${ARTIFACTORY_TOKEN}" -X PUT -T ./$ARTIFACT_NAME ${ARTIFACTORY_BASE_URL}/${ARTIFACT_NAME}_linux_amd64' - - 'curl -sSf -H "X-JFrog-Art-Api:${ARTIFACTORY_TOKEN}" -X PUT "${ARTIFACTORY_METADATA_URL}/${ARTIFACT_NAME}_linux_amd64?properties=version=${CI_COMMIT_TAG:1}"' + - ./build-go.sh --os=linux --arch=amd64 --version=$CI_COMMIT_TAG --upx + - 'curl -sSf -H "X-JFrog-Art-Api:${AFACTORY_TOKEN}" -X PUT -T ./$ARTIFACT_NAME ${AFACTORY_BASE_URL}/${ARTIFACT_NAME}_linux_amd64' + - 'curl -sSf -H "X-JFrog-Art-Api:${AFACTORY_TOKEN}" -X PUT "${AFACTORY_METADATA_URL}/${ARTIFACT_NAME}_linux_amd64?properties=version=${CI_COMMIT_TAG:1}"' tags: - acme @@ -47,8 +49,8 @@ upload_windows_amd64_binary: only: - tags script: - - ./build.sh --os=windows --arch=amd64 --version=$CI_COMMIT_TAG --upx - - 'curl -sSf -H "X-JFrog-Art-Api:${ARTIFACTORY_TOKEN}" -X PUT -T ./${ARTIFACT_NAME}.exe ${ARTIFACTORY_BASE_URL}/${ARTIFACT_NAME}_windows_amd64.exe' - - 'curl -sSf -H "X-JFrog-Art-Api:${ARTIFACTORY_TOKEN}" -X PUT "${ARTIFACTORY_METADATA_URL}/${ARTIFACT_NAME}_windows_amd64.exe?properties=version=${CI_COMMIT_TAG:1}"' + - ./build-go.sh --os=windows --arch=amd64 --version=$CI_COMMIT_TAG --upx + - 'curl -sSf -H "X-JFrog-Art-Api:${AFACTORY_TOKEN}" -X PUT -T ./${ARTIFACT_NAME}.exe ${AFACTORY_BASE_URL}/${ARTIFACT_NAME}_windows_amd64.exe' + - 'curl -sSf -H "X-JFrog-Art-Api:${AFACTORY_TOKEN}" -X PUT "${AFACTORY_METADATA_URL}/${ARTIFACT_NAME}_windows_amd64.exe?properties=version=${CI_COMMIT_TAG:1}"' tags: - acme diff --git a/acme-downloader-artifactory.sh b/acme-downloader-artifactory.sh new file mode 100755 index 0000000..851535b --- /dev/null +++ b/acme-downloader-artifactory.sh @@ -0,0 +1,296 @@ +#!/bin/bash +# +# exit 0: the certificate still looks good and it won't be replaced +# exit 64: a new certificate was installed and we need to reload our service +# anything else: 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 +# +VERSION="1.0.9" +BUILDTIME="2021-09-22_19:04:16" +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 + if [ "$#" -eq 1 ]; then + exit $1 + fi + exit +} +trap 'clean_up' SIGINT + +if [ $(id -u) -ne 0 ]; then + echo -e "plase run this script as root\ngiving up..." + clean_up 2 +elif ! which jq &>/dev/null; then + echo -e "please install jq\ngiving up..." + clean_up 2 +elif ! which curl &>/dev/null; then + echo -e "please install curl\ngiving up..." + clean_up 2 +fi + +check_version() { + # check upstrem version + SCRIPT_URL="https://artifactory.software.geant.org/artifactory/acme-downloader/acme-downloader.sh" + METADATA_URL="https://artifactory.software.geant.org/artifactory/api/storage/acme-downloader/acme-downloader.sh?properties=version" + REMOTE_VERSION=$(curl -s $METADATA_URL | jq -j .properties.version[0]) + if [[ $VERSION != $REMOTE_VERSION ]]; then + echo "" + echo "you are running version $(basename $0) ${VERSION}" + echo "version $REMOTE_VERSION is available" + echo "in order to fetch and install the new version you can use the option: --update" + echo "" + else + if [[ -n $CHECK ]]; then + echo "you are running the latest version" + fi + fi + if [[ -n $CHECK ]]; then + exit 0 + 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 2 +elif [[ "$ID" == "ubuntu" ]] || [[ "$ID" == "debian" ]] || [[ "$ID" == "arch"* ]]; 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 2 +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, nmaas...)" + 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 " --check-version [OPTIONAL check difference with upstream exit]" + echo " --update [OPTIONAL self-updates the script and exit]" + echo " --version [OPTIONAL print version number and creation date]" + echo "" + clean_up 2 +} + +OPTS=$(getopt -o "h" --longoptions "help,redis-token:,vault-token:,cert-name:,team-name:,days:,type:,cert-destination:,fullchain-destination:,key-destination:,ca-destination:,check-version,update,version,wildcard" -- "$@") +eval set -- "$OPTS" + +while true; do + case "$1" in + -h | --help) + usage + ;; + --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' + ;; + --update) + UPDATE='UPDATE' + ;; + --check-version) + CHECK='CHECK' + ;; + --version) + SCRIPT_VERSION='SCRIPT_VERSION' + ;; + --) + shift + break + ;; + esac + shift +done + +if [[ -n $SCRIPT_VERSION ]]; then + echo "$(basename $0) version: $VERSION built on $BUILDTIME" + clean_up 0 +fi + +TYPE=$(echo $TYPE | tr '[:lower:]' '[:upper:]') + +check_version $0 + +if [[ -n $UPDATE ]]; then + curl $SCRIPT_URL -o $0 + UPDATE_STATUS=$? + if [ $UPDATE_STATUS == 0 ]; then + echo -e "\n$0 updated successfully\n" + else + echo -e "\nfailed to update $0" + echo -e "Please download the script manually from this URL: ${SCRIPT_URL}\n" + fi + clean_up $UPDATE_STATUS +fi + +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 +if [[ -z $WILDCARD ]]; then + MODIFIED_CERT_NAME=$CERT_NAME +else + MODIFIED_CERT_NAME="wildcard_${CERT_NAME}" +fi +[[ -z $DAYS ]] && DAYS=30 +[[ -z $CERT_DESTINATION ]] && CERT_DESTINATION="${CERT_BASE}/${MODIFIED_CERT_NAME}.crt" +[[ -z $FULLCHAIN_DESTINATION ]] && FULLCHAIN_DESTINATION="${CERT_BASE}/${MODIFIED_CERT_NAME}_fullchain.crt" +[[ -z $KEY_DESTINATION ]] && KEY_DESTINATION="${KEY_BASE}/${MODIFIED_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 + echo "the certificate $FULLCHAIN_DESTINATION is still valid" + 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 + if [[ "$TEAM_NAME" == "puppet" ]]; then + 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 + else + curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:${CERT_NAME}:redis_sectigo_ov_${UNDERSCORED_CERT_NAME}_pem.txt >$TMP_CERT + curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:${CERT_NAME}:redis_sectigo_ov_${UNDERSCORED_CERT_NAME}_fullchain_pem.txt >$TMP_FULLCHAIN + curl -s -u redis:$REDIS_TOKEN ${REDIS_URL}/${TEAM_NAME}:${CERT_NAME}:redis_sectigo_ov_${UNDERSCORED_CERT_NAME}_chain_pem.txt >$TMP_CA + curl -s -H "X-Vault-Token: ${VAULT_TOKEN}" ${VAULT_URL}/${TEAM_NAME}/${CERT_NAME}/vault_sectigo_ov_wildcard_${UNDERSCORED_CERT_NAME}_key | jq -j .data.value >$TMP_KEY + echo "curl -s -H "X-Vault-Token: ${VAULT_TOKEN}" ${VAULT_URL}/${CERT_NAME}/${TEAM_NAME}/vault_sectigo_ov_wildcard_${UNDERSCORED_CERT_NAME}_key" + fi +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 2 +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 2 +fi +if ! openssl x509 -in $TMP_CA -text -noout &>/dev/null; then + echo "the CA is malformed. Giving up" + clean_up 2 +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 2 +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 2 +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 2 +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 64: if we are here we need to reload our service +exit 64 diff --git a/acme-downloader.sh b/acme-downloader.sh index 575c3c9..3f96024 100755 --- a/acme-downloader.sh +++ b/acme-downloader.sh @@ -7,6 +7,8 @@ # the certificate will be checked, if it is valid, if the key matches # and if it contains at least the cert-name # +VERSION="VERSION_SET_BY_CI" +BUILDTIME="BUILDTIME_SET_BY_CI" REDIS_URL="https://redis.geant.org/GET" VAULT_URL="https://vault.geant.org/v1" TMP_CERT=$(mktemp) @@ -39,14 +41,13 @@ fi check_version() { # check upstrem version - LOCAL_MD5=$(md5sum $1 | awk '{print $1}') SCRIPT_URL="https://artifactory.software.geant.org/artifactory/acme-downloader/acme-downloader.sh" - METADATA_URL="https://artifactory.software.geant.org/artifactory/api/storage/acme-downloader/acme-downloader.sh" - REMOTE_MD5=$(curl -s $METADATA_URL | jq -j .checksums.md5) - if [[ $LOCAL_MD5 != $REMOTE_MD5 ]]; then + METADATA_URL="https://artifactory.software.geant.org/artifactory/api/storage/acme-downloader/acme-downloader.sh?properties=version" + REMOTE_VERSION=$(curl -s $METADATA_URL | jq -j .properties.version[0]) + if [[ $VERSION != $REMOTE_VERSION ]]; then echo "" - echo "$1 differs from $SCRIPT_URL" - echo "suggesting that you are running an older version" + echo "you are running version ${VERSION}" + echo "version $REMOTE_VERSION is available" echo "in order to fetch and install the new version you can use the option: --update" echo "" else diff --git a/build-bash.sh b/build-bash.sh new file mode 100755 index 0000000..41985e8 --- /dev/null +++ b/build-bash.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# +# upload a copy of the script with version number and buildtime +# +if [ "$#" -gt 0 ]; then + VERSION=$1 +else + VERSION=$(git describe --tags $(git rev-list --tags --max-count=1) | tr -d v) +fi +BUILDTIME=$(date -u '+%Y-%m-%d_%H:%M:%S') +REPO_DIR=$(dirname $0) +if [[ "$REPO_DIR" = '.' ]]; then + REPO_DIR=$(pwd) +fi + +test -f acme-downloader-afactory.sh && rm -f acme-downloader-afactory.sh +cp acme-downloader.sh acme-downloader-afactory.sh + +sed -i s/VERSION_SET_BY_CI/$VERSION/ acme-downloader-afactory.sh +sed -i s/BUILDTIME_SET_BY_CI/$BUILDTIME/ acme-downloader-afactory.sh diff --git a/build.sh b/build-go.sh similarity index 100% rename from build.sh rename to build-go.sh -- GitLab