For systems using nginx, haproxy, or similar software that needs a local certificate, automating certificate management for your dns provider is crucial. Let’s take a look at how to set up Certbot with AWS’s Route53 for handling domain validation and certificate renewal.
Prerequisites
First, make sure you have the required tools installed:
wget https://bootstrap.pypa.io/get-pip.py
sudo python3 get-pip.py
pip3 install -U pyopenssl cryptography # (there is a bug in old pyopenssl and cryptography so these need to be up to date)
apt install certbot
pip3 install certbot-dns-route53
certbot plugins # Check to make sure the plugin is loaded
Note: Up-to-date versions of pyopenssl and cryptography are required due to a known bug in older versions.
Route53 Authentication
To allow Certbot to interact with Route53, we need to create a credential file with AWS access keys. Replace the placeholders with your actual keys:
mkdir /root/.aws
cat << EOF > /root/.aws/credentials
[default]
aws_access_key_id=KEYID_PLACEHOLDER
aws_secret_access_key=ACCESSKEY_PLACEHOLDER
EOF
Also, you need to create an IAM policy for the user, replacing Z064682SAMPLEYS04I0D with your actual hosted zone ID:
{
"Version": "2012-10-17",
"Id": "letsencrypt-policy",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:GetChange",
"route53:ListHostedZones",
"route53:ListHostedZonesByName"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets",
"route53:ListResourceRecordSets"
],
"Resource": "arn:aws:route53:::hostedzone/Z064682SAMPLEYS04I0D",
"Condition": {
"ForAllValues:StringLike": {
"route53:ChangeResourceRecordSetsNormalizedRecordNames": [
"_acme-challenge.*"
],
"route53:ChangeResourceRecordSetsRecordTypes": [
"TXT"
],
"route53:ChangeResourceRecordSetsActions": [
"UPSERT",
"DELETE"
]
}
}
}
]
}
- Record Name Restriction: Only allows modifications to
_acme-challenge.*records, protecting your main domain records - Record Type Limitation: Restricts operations to TXT records only (used for DNS challenges)
- Action Limitation: Only permits UPSERT and DELETE operations, blocking other potentially dangerous actions
- Principle of Least Privilege: Grants only the minimum permissions needed for certificate validation
If your AWS credentials are compromised, an attacker cannot modify your main domain records, create malicious redirects, or disrupt other services - they can only manage the temporary challenge records needed for certificate validation.
Certificate Management
Initial Certificate Creation
Run the following command to initially create the certificate for your domain:
certbot certonly -d some.domain.com -d *.some.domain.com --dns-route53 --logs-dir /var/log/letsencrypt/log/ --config-dir /etc/letsencrypt/config/ --work-dir /etc/letsencrypt/work/ -m [email protected] --agree-tos --non-interactive --server https://acme-v02.api.letsencrypt.org/directory
Important: For testing, use the staging server first to avoid hitting rate limits:
# Use staging server for testing
certbot certonly -d some.domain.com -d *.some.domain.com --dns-route53 --logs-dir /var/log/letsencrypt/log/ --config-dir /etc/letsencrypt/config/ --work-dir /etc/letsencrypt/work/ -m [email protected] --agree-tos --non-interactive --server https://acme-staging-v02.api.letsencrypt.org/directory
Renewing Certificates
Use the following command to renew certificates when needed:
certbot renew --dns-route53 --logs-dir /var/log/letsencrypt/log/ --config-dir /etc/letsencrypt/config/ --work-dir /etc/letsencrypt/work/ -m [email protected] --agree-tos --non-interactive --server https://acme-v02.api.letsencrypt.org/directory --post-hook "sudo service nginx reload"
Automating Renewals with Crontab
You can set up a cron job to automatically renew the certificates. Here’s how to create the renewal script and set up a cron job:
mkdir /root/.aws
cat << EOF > /root/renew-letsencrypt-certificates.sh
#!/bin/bash
certbot renew --dns-route53 \
--logs-dir /var/log/letsencrypt/log/ \
--config-dir /etc/letsencrypt/config/ \
--work-dir /etc/letsencrypt/work/ \
-m [email protected] \
--agree-tos --non-interactive \
--server https://acme-v02.api.letsencrypt.org/directory \
--post-hook "sudo service nginx reload"
EOF
# Crontab
0 0 */89 * * /bin/bash -c "/root/renew-letsencrypt-certificates.sh
And there you go!
Buy Me a Coffee