AWS Route 53
Route 53 uses an IAM access key + secret scoped to a single hosted zone. The IAM policy below is the minimum needed for DNS-01 validation — nothing more.
Prerequisites
- An AWS account with the hosted zone you want to validate.
- Permission to create IAM users (or delegate to an existing programmatic user).
Minimum IAM policy
Attach this to the IAM user (or role) whose access key you'll hand to CertAutoPilot. Replace ZONEID with your actual Route 53 zone ID.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "route53:GetChange",
"Resource": "arn:aws:route53:::change/*"
},
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets",
"route53:ListResourceRecordSets"
],
"Resource": "arn:aws:route53:::hostedzone/ZONEID"
},
{
"Effect": "Allow",
"Action": "route53:ListHostedZonesByName",
"Resource": "*"
}
]
}
The ListHostedZonesByName statement has to be *-scoped (AWS limitation) but it only returns names — no data exposure.
Create the access key
- IAM console → Users → Create user → programmatic-access only (no console).
- Attach the policy above.
- Generate an access key. Copy the Access key ID and Secret access key — the secret is shown once.
Add the credential
- Settings → DNS Credentials → New → AWS Route 53.
- Name:
route53-example-prod. - Access key ID, Secret access key: paste.
- Optional: Region — defaults to the lego provider's internal default (
us-east-1endpoint, global service). Leave blank unless you have a reason. - Optional: Hosted zone ID — if set, the backend skips the zone-lookup step and goes straight to that zone. Useful when the IAM policy restricts lookups, or when multiple zones share the same apex name.
- Test connectivity → Save.
Config fields
| Field | Required | Purpose |
|---|---|---|
access_key_id | yes | IAM access key ID. |
secret_access_key | yes | IAM secret. |
region | no | AWS region for endpoint routing. Default: SDK default. |
hosted_zone_id | no | Pin to a specific zone. Required when multiple zones share an apex name. |
Cross-account delegation
If your Route 53 zones live in a different AWS account than your IAM identity, you can use an STS AssumeRole flow by creating an IAM user in the owning account with the policy above, then rotating long-lived keys on a schedule. Native AssumeRole (role ARN + session tokens) is not currently wired through the credential form; request if you need it.
Propagation
Route 53 is fast — typically under 5 seconds before the TXT record is resolvable from external resolvers. The default propagation settings work without tuning.
Troubleshooting
"AccessDenied" on ChangeResourceRecordSets
The IAM policy is scoped to the wrong hosted zone ID, or the user-zone resource-level permission is missing. Double-check the zone ID matches aws route53 list-hosted-zones.
"Throttling: Rate exceeded"
Route 53 has a 5 req/s per-zone quota. Very high fan-out issuance can hit this — CertAutoPilot retries with backoff. If persistent, stagger the issuance (bulk actions with a smaller batch size).
"Multiple hosted zones match"
Route 53 supports public + private zones with the same name. Set hosted_zone_id explicitly.