|
#!/bin/bash |
|
# |
|
# [1] "If you're using a CA other than AWS Certificate Manager and if you want to |
|
# use the same certificate both for CloudFront and for other AWS services, |
|
# you must upload the certificate twice: once for CloudFront and once for the |
|
# other services." (http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/SecureConnections.html#CNAMEsAndHTTPS) |
|
# |
|
# If using your cert on cloudfront, make sure your cloudfront distribution has |
|
# a behavior for .well-known/acme-challenge/* that lets requests through to |
|
# the origin. You will probably need to forward the 'host' header in this behavior. |
|
# |
|
# References: |
|
# http://marketing.intracto.com/renew-https-certificate-on-amazon-cloudfront |
|
# https://vincent.composieux.fr/article/install-configure-and-automatically-renew-let-s-encrypt-ssl-certificate |
|
# https://github.com/alex/letsencrypt-aws |
|
|
|
CONFIG_FILE='letsencrypt.ini' |
|
# Use RAM disk to avoid saving private key to disk: |
|
LE_WORKDIR='/dev/shm/LE-work-dir' |
|
LE_CONFIGDIR='/dev/shm/LE-config-dir' |
|
LE_CMD="./certbot-auto --work-dir=$LE_WORKDIR --config-dir=$LE_CONFIGDIR --debug" |
|
LOAD_BALANCER_NAME='...' |
|
INSTANCE_PROTO=HTTP |
|
INSTANCE_PORT=80 |
|
EXP_LIMIT=30 # renew if cert will expire in this many days or fewer |
|
export AWS_DEFAULT_REGION=us-east-1 |
|
|
|
set -e |
|
#set -o pipefail |
|
|
|
if [ ! -f $CONFIG_FILE ]; then |
|
echo "[ERROR] config file does not exist: $CONFIG_FILE" |
|
exit 1; |
|
fi |
|
|
|
echo "Making sure dependencies are present..." |
|
|
|
if [ ! -f certbot-auto ]; then |
|
wget https://dl.eff.org/certbot-auto |
|
chmod a+x certbot-auto |
|
fi |
|
|
|
sudo `which pip` install -U pip virtualenv |
|
|
|
DOMAIN=`grep "^\s*domains" $CONFIG_FILE | sed "s/^\s*domains\s*=\s*//" | sed 's/(\s*)\|,.*$//'` |
|
|
|
echo "Checking expiration date for $DOMAIN..." |
|
|
|
DATE_NOW=$(date -d "now" +%s) |
|
EXP_DATE=$(date -d "`echo | openssl s_client -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -enddate | cut -d"=" -f2-`" +%s) |
|
EXP_DAYS=$(echo \( $EXP_DATE - $DATE_NOW \) / 86400 |bc) |
|
ISSUER=$(echo | openssl s_client -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -issuer | cut -d"=" -f2-) |
|
|
|
if [ "$EXP_DAYS" -gt "$EXP_LIMIT" ] && [[ $ISSUER == *"Let's Encrypt"* ]] && [ "$1" != "--force" ] ; then |
|
echo "The certificate is up to date and uses Let's Encrypt, no need for renewal ($EXP_DAYS days left)." |
|
exit 0; |
|
else |
|
echo "The certificate for $DOMAIN is about to expire soon or is not using Let's Encrypt:" |
|
echo "Days remaining: $EXP_DAYS" |
|
echo "Issuer: $ISSUER" |
|
echo "Starting webroot renewal script..." |
|
$LE_CMD certonly --agree-tos --renew-by-default --config $CONFIG_FILE |
|
CERT_NAME="letsencrypt_cert_`date +%m-%d-%y_%H-%M-%S`" |
|
echo "Uploading $CERT_NAME to IAM" |
|
# path needs to be this to work for cloudfront (will work with elb too) |
|
CERT_RES=$(sudo aws iam upload-server-certificate \ |
|
--server-certificate-name $CERT_NAME \ |
|
--certificate-body file://$LE_CONFIGDIR/live/$DOMAIN/cert.pem \ |
|
--private-key file://$LE_CONFIGDIR/live/$DOMAIN/privkey.pem \ |
|
--certificate-chain file://$LE_CONFIGDIR/live/$DOMAIN/chain.pem \ |
|
--output json |
|
) |
|
echo "CERT_RES: $CERT_RES" |
|
NEW_CERT_ARN=$(echo $CERT_RES | python -c 'import json,sys;print(json.load(sys.stdin)["ServerCertificateMetadata"]["Arn"])') |
|
echo "NEW_CERT_ARN: $NEW_CERT_ARN" |
|
ELB_DESC=$(aws elb describe-load-balancers \ |
|
--load-balancer-name $LOAD_BALANCER_NAME \ |
|
--output json |
|
) |
|
echo "ELB_DESC: $ELB_DESC" |
|
OLD_CERT_NAMES=$(echo $ELB_DESC | python -c 'import json,sys;print(" ".join(l["Listener"]["SSLCertificateId"].split("/")[-1] for l in json.load(sys.stdin)["LoadBalancerDescriptions"][0]["ListenerDescriptions"] if "SSLCertificateId" in l["Listener"] and l["Listener"]["LoadBalancerPort"] == 443))') |
|
echo "OLD_CERT_NAMES: $OLD_CERT_NAMES" |
|
echo "Waiting for cert to become active..." |
|
sleep 20 |
|
if [ "x$OLD_CERT_NAMES" != "x" ]; then |
|
echo "Updating ELB IAM cert to $NEW_CERT_ARN..." |
|
aws elb set-load-balancer-listener-ssl-certificate \ |
|
--load-balancer-name $LOAD_BALANCER_NAME \ |
|
--load-balancer-port 443 \ |
|
--ssl-certificate-id $NEW_CERT_ARN |
|
echo "Waiting 10 minutes, then deleting old certs: $OLD_CERT_NAMES" |
|
sleep 600 |
|
echo $OLD_CERT_NAMES | xargs -n 1 aws iam delete-server-certificate --server-certificate-name |
|
else |
|
echo "No listener for port 443 found; creating new HTTPS listener..." |
|
aws elb create-load-balancer-listeners \ |
|
--load-balancer-name $LOAD_BALANCER_NAME \ |
|
--listeners Protocol=HTTPS,LoadBalancerPort=443,InstanceProtocol=$INSTANCE_PROTO,InstancePort=$INSTANCE_PORT,SSLCertificateId=$NEW_CERT_ARN |
|
fi |
|
echo "Renewal process finished for domain $DOMAIN, cleaning up..." |
|
sudo rm -rf "$LE_CONFIGDIR" |
|
exit 0; |
|
fi |