This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is an AWS Lambda function that runs Certbot to obtain and renew SSL/TLS certificates from Let's Encrypt. It supports wildcard certificates using DNS-01 challenges and uploads the resulting certificates to S3. The Lambda is triggered by CloudWatch scheduled events for automated certificate renewal.
The Lambda handler follows this sequence:
lambda_handler()- Entry point that wraps execution with cleanupguarded_handler()- Main logic that:- Reads DNS plugin from
DNS_PLUGINenvironment variable - Reads certificate parameters from CloudWatch event payload (emails, domains, S3 bucket/prefix/region)
- Calls
obtain_certs()to run Certbot with DNS-01 challenge - Calls
upload_certs()to upload resulting certificates to S3
- Reads DNS plugin from
rm_tmp_dir()- Cleanup called before and after execution to clear/tmp/certbot
- Uses
/tmp/certbotas working directory (Lambda's writable temp space) - Runs in non-interactive mode with DNS-01 challenge
- Certificate structure in
/tmp/certbot/live/[domain]/:- cert.pem, chain.pem, fullchain.pem, privkey.pem, README
- Creates Lambda function with IAM role
- Provisions Route53 permissions for DNS challenge (if
create_aws_route53_iam_role=true) - Provisions S3 upload permissions (if
create_aws_s3_iam_role=true) - Creates CloudWatch Event Rules for each certificate in
certificatesvariable - Each event rule triggers Lambda with specific certificate parameters
The certificates variable is a map where each entry defines:
- Scheduling (cron/rate expression)
- Certificate parameters (emails, domains, S3 destination)
./package.shThis creates certbot/certbot-lambda.zip containing:
- Python 3.13 virtualenv with all requirements.txt dependencies
- main.py Lambda handler Uses Amazon Linux 2023 Python 3.13 (matching Lambda runtime)
- Create/activate virtualenv:
python3.13 -m venv certbot/venv
source certbot/venv/bin/activate- Install desired versions:
pip3 install certbot==<VERSION> certbot-dns-route53==<VERSION> [other-plugins]- Generate new requirements.txt:
pip freeze | grep -v "pkg-resources" > requirements.txtNote: Ensure dependency versions are compatible with Python 3.13 (e.g., cffi>=2.0.0)
cd terraform
terraform init
terraform plan
terraform applyDNS_PLUGIN- Certbot DNS plugin name (default: "dns-route53")CERTBOT_URL- Let's Encrypt ACME endpoint (default: production v02 API)- Custom variables in
lambda_custom_environment(e.g., for non-AWS DNS providers like Tencent Cloud)
emails- Comma-separated email addresses for Let's Encrypt registrationdomains- Comma-separated domain list (supports wildcards like *.example.com)s3_bucket- Destination S3 bucket names3_prefix- Key prefix for uploaded certificatess3_region- AWS region of S3 bucket
The codebase supports multiple DNS providers through Certbot plugins:
- Route53 (default): Built-in AWS support, uses IAM role permissions
- Other providers: Specify plugin in
certbot_dns_pluginvariable and provide credentials vialambda_custom_environment
Example for Tencent Cloud:
certbot_dns_plugin = "dns-tencentcloud"
lambda_custom_environment = {
TENCENTCLOUD_SECRET_ID = "..."
TENCENTCLOUD_SECRET_KEY = "..."
}GitHub Actions workflow (.github/workflows/release.yml):
- Triggers on version tags (v*)
- Builds in Amazon Linux 2023 container
- Runs
package.shto create Lambda zip - Creates GitHub release with
certbot-lambda.zipartifact
- Lambda runtime uses Python 3.13 on Amazon Linux 2023
- Build environment must match: use
amazonlinux:latest(AL2023) orpublic.ecr.aws/lambda/python:3.13 - The Lambda requires sufficient timeout (default 300s) for DNS propagation and ACME challenge
- IAM permissions needed: Route53 (ListHostedZones, GetChange, ChangeResourceRecordSets) and S3 (ListBucket, PutObject)
- Certificates are organized by domain name in S3:
{prefix}/{domain}/cert.pem, etc. - ACME account state is tied to email address - using the same email across different Lambda functions may cause "No such authorization" errors if previous runs left stale state