|
#!/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='/usr/local/etc/le-exampledomain-webroot.ini' |
|
LE_PATH='/opt/letsencrypt' |
|
LOAD_BALANCER_NAME='exampleloadbalancer' |
|
export AWS_DEFAULT_PROFILE='ExampleProfile' |
|
export AWS_DEFAULT_REGION='us-west-2' |
|
|
|
EXP_LIMIT=30 |
|
UPDATE_CLOUDFRONT=true |
|
# deletes the old certs |
|
DELETE_OLD=false |
|
|
|
|
|
if [ ! -f $CONFIG_FILE ]; then |
|
echo "[ERROR] config file does not exist: $CONFIG_FILE" |
|
exit 1; |
|
fi |
|
|
|
DOMAIN=`grep "^\s*domains" $CONFIG_FILE | sed "s/^\s*domains\s*=\s*//" | sed 's/(\s*)\|,.*$//'` |
|
CERT_FILE="/etc/letsencrypt/live/$DOMAIN/fullchain.pem" |
|
|
|
if [ ! -f $CERT_FILE ]; then |
|
echo "[ERROR] certificate file not found for domain $DOMAIN." |
|
fi |
|
|
|
DATE_NOW=$(date -d "now" +%s) |
|
EXP_DATE=$(date -d "`openssl x509 -in $CERT_FILE -text -noout | grep "Not After" | cut -c 25-`" +%s) |
|
EXP_DAYS=$(echo \( $EXP_DATE - $DATE_NOW \) / 86400 |bc) |
|
|
|
echo "Checking expiration date for $DOMAIN..." |
|
|
|
if [ "$EXP_DAYS" -gt "$EXP_LIMIT" ] && [ "$1" != "--force" ] ; then |
|
echo "The certificate is up to date, no need for renewal ($EXP_DAYS days left)." |
|
exit 0; |
|
else |
|
echo "The certificate for $DOMAIN is about to expire soon. Starting webroot renewal script..." |
|
$LE_PATH/letsencrypt-auto certonly --agree-tos --renew-by-default --config $CONFIG_FILE |
|
CERT_NAME="auto_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=$(aws iam upload-server-certificate \ |
|
--server-certificate-name $CERT_NAME \ |
|
--certificate-body file:///etc/letsencrypt/live/$DOMAIN/cert.pem \ |
|
--private-key file:///etc/letsencrypt/live/$DOMAIN/privkey.pem \ |
|
--certificate-chain file:///etc/letsencrypt/live/$DOMAIN/chain.pem \ |
|
--path /cloudfront/production/ \ |
|
--output json |
|
) |
|
echo $CERT_RES |
|
NEW_CERT_ARN=$(echo $CERT_RES | python -c 'import json,sys;obj=json.load(sys.stdin);print(obj["ServerCertificateMetadata"]["Arn"])') |
|
echo $NEW_CERT_ARN |
|
echo "Updating ELB IAM cert..." |
|
sleep 20 |
|
aws elb set-load-balancer-listener-ssl-certificate \ |
|
--load-balancer-name $LOAD_BALANCER_NAME \ |
|
--load-balancer-port 443 \ |
|
--ssl-certificate-id $NEW_CERT_ARN |
|
if [ UPDATE_CLOUDFRONT = true ] ; then |
|
echo "Updating cloudfront distribution..." |
|
aws configure set preview.cloudfront true |
|
DISTRIBUTION=$(aws cloudfront list-distributions --query \ |
|
"DistributionList.Items[0].{DistributionId: Id}" --output text) |
|
OLD_CERT_ARN=$(aws cloudfront list-distributions --query "DistributionList.Items[0].ViewerCertificate.Certificate" --output text) |
|
aws cloudfront get-distribution-config --id $DISTRIBUTION --query 'DistributionConfig' --output json > /tmp/dist_config.json |
|
sed -i "s/$OLD_CERT_ARN/$NEW_CERT_ARN/" /tmp/dist_config.json |
|
aws cloudfront update-distribution \ |
|
--id $DISTRIBUTION \ |
|
--distribution-config file:///tmp/dist_config.json |
|
echo "Done updating cloudfront" |
|
fi |
|
echo "Renewal process finished for domain $DOMAIN" |
|
|
|
# TODO: test! |
|
if [ DELETE_OLD = true ] ; then |
|
echo "Deleting ALL old certs in 10 minutes..." |
|
sleep 600 |
|
aws iam list-server-certificates --query \ |
|
"ServerCertificateMetadataList[?ServerCertificateName != '$CERT_NAME'].ServerCertificateName" \ |
|
--output text | xargs -n 1 aws iam \ |
|
delete-server-certificate \ |
|
--server-certificate-name |
|
echo "Deleted old certificates" |
|
fi |
|
exit 0; |
|
fi |
Warning - reading that last awscli | xargs command - if you use the 'DELETE_OLD' option here, it will delete ALL your IAM server certs, not just the 'old ones that match the domains of the newly-generated one'. This option should definitely never be used unless you definitely use only a single cert and will never use more than one.
You can check how many you have with
aws iam list-server-certificates --query "ServerCertificateMetadataList[].ServerCertificateName"