What ?
A simple guide of the steps to follow for updating an SSL/TLS certificate PROGRAMMATICALLY using AWS CLI.
Why ?
Because the official documentation about it is a whole mess when is something rather easy and I'd like to share with others and possibly save some time.
How ?
Once you generate your custom certificate using, for example, Let's Encrypt, you may run these AWS CLI commands to update it using bash:
# Use any name but prefer to use one based on a timestamp since they cannot be repeated on every update
AWS_MY_CERT_NAME=my-cert-$(date +%Y%m%d)
# Set the CloudFront distribution we want to update (found at AWS console)
MY_CLOUDFRONT_ID=EV40L17AXPTKC
# Upload the custom certificate to IAM (using ACM does not work)
aws iam upload-server-certificate --server-certificate-name $AWS_MY_CERT_NAME --certificate-body file://my-cert.pem --private-key file://my-cert-privkey.pem --certificate-chain file://my-cert-chain.pem --path /cloudfront/
# Get certificate ID for the update
AWS_MY_CERT_ID=$(aws iam get-server-certificate --server-certificate-name $AWS_MY_CERT_NAME --query "ServerCertificate.ServerCertificateMetadata.ServerCertificateId" --output text)
# Here the trick: load the current configuration to patch it on the fly (AWS has no other option currently)
aws cloudfront get-distribution-config --id $MY_CLOUDFRONT_ID --query DistributionConfig > config.json
sed -i.bak "s/.*\"IAMCertificateId\".*/\"IAMCertificateId\": \"$AWS_MY_CERT_ID\",/g" config.json
sed -i.bak "s/.*\"Certificate\".*/\"Certificate\": \"$AWS_MY_CERT_ID\",/g" config.json
aws cloudfront update-distribution --id $MY_CLOUDFRONT_ID --distribution-config file://config.json
NOTE: using the /cloudfront/
path is important for making the certificate available for CloudFront usage.
When ?
You can add these commands to a bash script file to run it using cron configuration every month (or sooner depending on the frequency of your updates)
Who ?
These commands are based on these blogs and references:
https://docs.aws.amazon.com/cli/latest/reference/cloudfront/index.html
https://docs.aws.amazon.com/cli/latest/reference/cloudfront/update-distribution.html
https://www.reddit.com/r/aws/comments/5jm7wd/why_is_my_custom_ssl_cert_not_available_when/
https://aws.amazon.com/premiumsupport/knowledge-center/install-ssl-cloudfront/
https://intellipaat.com/community/2745/unable-to-select-custom-ssl-certificate-stored-in-aws-iam
https://aws.amazon.com/premiumsupport/knowledge-center/custom-ssl-certificate-cloudfront/
https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-output.html#cli-usage-output-filter
https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-output.html#cli-usage-output-format
https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-shorthand.html
https://docs.aws.amazon.com/cli/latest/reference/cloudfront/get-distribution-config.html
Top comments (4)
Hi! I am getting this error:
"The If-Match version is missing or not valid for the resource"
EDIT: I found out!
It is missing these steps:
I got it working by using jq instead of sed, thanks for the great guide! Here's an example on how to use jq to manipulate the json for anyone else stuck on the tricky regex of sed
One issue is that it's tricky to get environment variables in jq so I just hardcoded everything I need to update in the cloudfront distro.
I keep getting this error first of all.
sed -i.bak "s/.\"ViewerCertificate\"./\"ACMCertificateArn\": \"$AWS_MY_CERT_ID\",/g" config.json
sed: 1: "s/.*"ViewerCertificate" ...": bad flag in substitute command: 'f'
sed -i.bak '' "s/.\"ViewerCertificate\"./\"ACMCertificateArn\": \"$AWS_MY_CERT_ID\",/g" config.json
sed: s/."ViewerCertificate"./"ACMCertificateArn": "arn:aws:acm:us-east-1:316897671968:certificate/9f337eae-09ef-4f4b-8d50-3c7e05bedc75",/g: No such file or directory
➜ owner-webapp git:(SF-727-qa) ✗
Can I use this method to update acm certificate credentials if the certificate is already created?