Назад | Перейти на главную страницу

Сравните локальный и удаленный SSL-сертификат, чтобы определить, совпадают ли они

Я работаю над развертыванием наших SSL-сертификатов LetsEncrypt. У меня есть задания cron, которые выполняются ежедневно, и при необходимости я обновляю сертификат с помощью certbot. У меня также есть сценарий, который развернет сертификат в балансировщике нагрузки.

Certbot имеет обратный вызов развертывания при обновлении сертификата. Certbot вызовет мой скрипт сразу после обновления сертификата. Кажется, это нормально работает - в основном. Однако, если развертывание не удастся по какой-либо причине, я хотел бы повторить попытку на следующий день. Не похоже, что в certbot есть какие-либо функции для этого.

Как реализовать сценарий со следующей логикой:

if [ /etc/letsencrypt/live/example.com/cert.pem != certfrom https://example.com/ ]
then
    example.com-cert-deploy.sh
fi

Вы можете использовать что-то вроде:

$ openssl s_client -showcerts -servername example.com -connect example.com:443 </dev/null

... который, помимо прочего, выведет сертификат сервера. Вы можете проанализировать это, сохранить, а затем сравнить с другим сертификатом на диске.

Достаточно сравнить «отпечаток пальца» локального сертификата с действующим сертификатом.

Два отпечатка пальца можно получить с помощью следующих двух команд:

  • openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -fingerprint -noout
  • echo | openssl s_client -showcerts -connect example.com:443 -servername example.com 2>&1 | openssl x509 -fingerprint -noout

Чтобы упростить сравнение, я поместил их в скрипт с проверкой ошибок. Он принимает доменное имя в качестве аргумента и завершает работу со статусом сбоя, если они отличаются. Его можно использовать как:

if ! ./lets-encrypt-installed-test.sh --quiet example.com
then
    ./example.com-cert-deploy.sh
fi

Вот полное содержание скрипта:

#!/bin/sh

set -e 

quiet=0

for var in "$@"
do
    case "$var" in
        -q)
            quiet=1
            ;;
        --quiet)
            quiet=1
            ;;
        -*)
            echo "Unexpected argument $var" >&2
            exit 1
            ;;
        *.*)
            domain="$var"
            ;;
        *)
            echo "Expected argument $var" >&2
            exit 1
            ;;
    esac
done

if [ "z$domain" == "z" ]
then
    echo "Expected domain as parameter to $0" >&2
    exit 1
fi

lefile="/etc/letsencrypt/live/$domain/cert.pem"

if [ ! -e $lefile ]
then    
    echo "Lets Encrypt file does not exist: $lefile" >&2
    exit 1
fi

leprint=`openssl x509 -in $lefile -fingerprint -noout`

case "$leprint" in
    *Fingerprint*)
        ;;
    *)
        echo "No fingerprint from $lefile" >&2
        exit 1
        ;;
esac

liveprint=`echo | openssl s_client -showcerts -connect "$domain":443 -servername "$domain" 2>&1 | openssl x509 -fingerprint | grep -i fingerprint`

case "$liveprint" in
    *Fingerprint*)
        ;;
    *)
        echo "No fingerprint from SSL cert of https://$domain/" >&2
        exit 1
        ;;
esac

if [ "$leprint" != "$liveprint" ]
then
    if [ "$quiet" == "0" ]
    then
        echo "Fingerprints for local and remote SSL certificates differ:" >&2
        echo "$lefile: $leprint" >&2
        echo "https://$domain/: $liveprint" >&2
    fi
    exit 1
fi 

exit 0