0

I'm working on the deployment of our LetsEncrypt SSL certificates. I have cron jobs that run daily and renew the certificatse if needed using certbot. I also have a script that will deploy the certificate to the load balancer.

Certbot has a deploy callback when a cert is renewed. Certbot will call my script immediately after renewing a certificate. That seems to work fine -- mostly. However, if the deployment fails for any reason, I'd like it to try again the next day. It doesn't look like there is any functionality built into certbot for this.

How do I implement a script that has the following logic:

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

You can use something like:

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

...which among other things will output the server certificate. You can parse that out, save it, and then diff with the other on-disk cert.

  • When I run that: unknown option -serverame – Stephen Ostermiller Jun 19 '17 at 13:21
  • Typo...try again :) – EEAA Jun 19 '17 at 13:21
  • That shows good info, but it looks nothing like the contents of cert.pem – Stephen Ostermiller Jun 19 '17 at 13:22
  • 1
    Your certificate is surely not private - by definition the certificate must be public for it to be of any use. The contents of your server certificate is in the output of the above command. – EEAA Jun 19 '17 at 13:26
  • 1
    Yes, comparing the fingerprints should be sufficient for your purposes. – EEAA Jun 19 '17 at 13:42
0

It is enough to compare the "fingerprint" of the local certificate against the live certificate.

The two fingerprints can be obtained by the following two commands:

  • 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

To make the comparison easier, I put them into a script with error checking. It accepts a domain name as an argument and exits with a failure status if the two differ. It can be used like:

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

Here is the full contents of the script:

#!/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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.