Skip to main content

AWS ACM Certificate Sync Tool

A robust tool to sync AWS ACM certificates to local files for web servers (nginx, apache, haproxy, etc.). Designed for containerized environments and automation workflows.

⚡ Now Possible with ACM Export Feature
As of June 2025, AWS Certificate Manager allows exporting public certificates for use anywhere, making it possible to sync ACM-managed certificates to your own infrastructure while maintaining centralized certificate management and automatic renewals.

Why This Tool?

While AWS ACM provides excellent certificate management within AWS services (ALB, CloudFront, etc.), many scenarios require certificates on your own servers:

  • Hybrid deployments: On-premises servers that need AWS-managed certificates
  • Custom applications: Services running on EC2 that don't integrate directly with ACM
  • Multi-cloud setups: Consistent certificate management across cloud providers
  • Legacy systems: Existing infrastructure that needs modern certificate automation
  • Development environments: Local testing with production-like certificates

This tool bridges that gap by automatically exporting ACM certificates and deploying them to your servers with proper formatting for different web servers.

Features

  • 🔍 Multiple certificate sources: Find certificates by ARN or AWS tags
  • 🎯 Smart certificate selection: When multiple certificates match tags, automatically selects:
    • Valid certificates over expired ones
    • Among valid certificates, the one with longest remaining validity
  • 📦 Multiple output formats: Support for nginx, apache, haproxy certificate formats
  • 🎯 Multiple targets: Deploy the same certificate to different servers/locations
  • ⚡ Smart updates: Only downloads certificates when needed (expiry check, content changes)
  • 🔐 Secure handling: Uses temporary passphrase for ACM export then stores unencrypted/encrypted as needed
  • ⏰ Flexible scheduling: Run once or as daemon with configurable schedule
  • 🐳 Container-ready: Designed for sidecar deployment patterns

Installation

From PyPI

pip install aws_cert_syncer

From Source

git clone https://github.com/koenvo/aws_cert_syncer.git
cd aws_cert_syncer
uv sync

Quick Start

  1. Create configuration file (config.yaml):
aws:
  region: us-east-1

certificates:
  - name: my-web-cert
    arn: "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
    targets:
      - base_dir: "/etc/ssl"
        server_type: "nginx"
        reload_command: "systemctl reload nginx"
  1. Run the tool:
# Install from PyPI
aws_cert_syncer --config config.yaml

# Or run from source
python cert_sync.py --config config.yaml

Configuration

Complete Example

aws:
  region: us-east-1

certificates:
  # Method 1: Certificate by ARN
  - name: my-domain-cert
    arn: "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
    
    targets:
      # Deploy to nginx
      - base_dir: "/etc/ssl"
        server_type: "nginx"
        passphrase: ""
        reload_command: "systemctl reload nginx"
      
      # Deploy to haproxy (same cert, different format)
      - base_dir: "/opt/haproxy/ssl"
        server_type: "haproxy"
        reload_command: "systemctl reload haproxy"

  # Method 2: Certificate by tags (with smart selection)
  - name: api-cert
    tags:
      Domain: "api.example.com"
      Environment: "production"
    
    targets:
      - base_dir: "/etc/ssl"
        server_type: "apache"
        passphrase: "my-secure-password"
        reload_command: "systemctl reload apache2"

  # Method 3: Custom file paths
  - name: legacy-app
    tags:
      Name: "legacy.company.com"
    
    targets:
      - base_dir: "/opt/app/ssl"
        server_type: "nginx"
        cert_path: "/opt/app/ssl/custom-cert.pem"
        key_path: "/opt/app/ssl/custom-key.pem"
        reload_command: "docker restart legacy-app"

Certificate Selection Logic

When using tags and multiple certificates match:

  1. Valid certificates (ISSUED status + not expired) are preferred over invalid/expired ones
  2. Among valid certificates, the one with the longest remaining validity is selected
  3. Detailed logging shows all matches and selection reasoning

Example scenario:

  • Certificate A: Expires in 30 days ✅ Valid
  • Certificate B: Expires in 90 days ✅ Valid
  • Certificate C: Expired ❌ Invalid

Result: Certificate B is selected (longest validity)

Usage

Command Line Options

aws_cert_syncer [options]

Options:
  --config, -c    Path to configuration file (default: /config.yaml)
  --daemon, -d    Run as daemon with scheduling
  --dry-run       Show what would be done without making changes
  --help          Show help message

Standalone Usage

# Run once
aws_cert_syncer --config config.yaml

# Run as daemon (uses SCHEDULE environment variable)
aws_cert_syncer --config config.yaml --daemon

# Dry run (see what would happen)
aws_cert_syncer --config config.yaml --dry-run

Docker Usage

# Pull from registry (when published)
docker pull your-registry/aws_cert_syncer

# Build locally
docker build -t aws_cert_syncer .

# Run once
docker run --rm \
  -v $(pwd)/config.yaml:/config/config.yaml \
  -v ~/.aws:/home/certsync/.aws \
  -v /etc/ssl:/etc/ssl \
  aws_cert_syncer

# Run as daemon
docker run -d \
  -v $(pwd)/config.yaml:/config/config.yaml \
  -v ~/.aws:/home/certsync/.aws \
  -v /etc/ssl:/etc/ssl \
  -e SCHEDULE=02:00 \
  -e DAYS_BEFORE_EXPIRY=30 \
  aws_cert_syncer --daemon

Docker Compose (Sidecar Pattern)

See examples/docker-compose.yml.example for a complete setup with nginx and haproxy.

# Start all services
docker-compose up -d

# View logs
docker-compose logs cert-sync

# Force certificate sync
docker-compose exec cert-sync aws_cert_syncer --config /config/config.yaml

Environment Variables

Variable Description Default
LOG_LEVEL Logging level (DEBUG, INFO, WARNING, ERROR) INFO
DAYS_BEFORE_EXPIRY Days before expiry to trigger renewal 30
SCHEDULE Daemon schedule (see formats below) 02:00

Schedule Formats

  • Time format: 02:00 (daily at 2 AM), 14:30 (daily at 2:30 PM)
  • Interval format: 6h (every 6 hours), 30m (every 30 minutes), 1h (hourly)

Server Types & File Formats

Nginx

  • Files: Separate {name}.crt, {name}.key, {name}-chain.crt
  • Location: /etc/ssl/certs/ and /etc/ssl/private/
  • Key format: Unencrypted (ignores passphrase for automatic startup)
  • Permissions: 644 (cert), 600 (key)

Apache

  • Files: Separate {name}.crt, {name}.key, {name}-chain.crt
  • Location: /etc/ssl/certs/ and /etc/ssl/private/
  • Key format: Supports encrypted keys with passphrase
  • Permissions: 644 (cert), 600 (key)

HAProxy

  • Files: Single combined {name}.pem (cert + key + chain)
  • Location: /etc/ssl/haproxy/
  • Key format: Unencrypted (ignores passphrase)
  • Permissions: 600 (combined file)

AWS Setup

IAM Permissions

Create an IAM policy with these permissions:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "acm:ListCertificates",
                "acm:DescribeCertificate", 
                "acm:ExportCertificate",
                "acm:ListTagsForCertificate"
            ],
            "Resource": "*"
        }
    ]
}

AWS Credentials

The tool uses standard AWS credential chain:

  1. Environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
  2. AWS credentials file: ~/.aws/credentials
  3. IAM instance profile (recommended for EC2/ECS)
  4. IAM roles for service accounts (recommended for Kubernetes)

Development

Setup

git clone https://github.com/koenvo/aws_cert_syncer.git
cd aws_cert_syncer
uv sync

Testing

# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=cert_sync

# Run specific test
uv run pytest tests/test_cert_sync.py::TestCertificateRetriever::test_find_certificate_by_tags_multiple_matches_prefers_valid

Code Quality

# Format code
uv run ruff format .

# Lint code  
uv run ruff check .

# Fix auto-fixable issues
uv run ruff check . --fix

Examples

Complete configuration examples are available in the examples/ directory:

Troubleshooting

Common Issues

Certificate not found:

  • Verify ARN is correct and certificate exists in the specified region
  • Check that tags match exactly (case-sensitive)
  • Ensure AWS credentials have acm:ListCertificates permission

Permission denied writing files:

  • Check that target directories are writable by the user running the tool
  • Verify parent directories exist
  • In containers, ensure proper volume mounts

Reload command fails:

  • Test reload commands manually first
  • Check that the service is installed and running
  • Verify the user has permission to run the reload command
  • Consider using sudo in reload commands if needed

Multiple certificates found:

  • This is normal - the tool automatically selects the best one
  • Check logs to see which certificate was selected and why
  • Use more specific tags if you want to target a specific certificate

Debug Mode

# Enable debug logging
LOG_LEVEL=DEBUG aws_cert_syncer --config config.yaml

# Dry run to see what would happen
aws_cert_syncer --config config.yaml --dry-run

Monitoring

The tool logs all operations with structured messages:

  • Certificate selection decisions
  • File operations and permissions
  • Reload command execution
  • Error details with context

Integrate with your logging infrastructure to monitor certificate sync operations.

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass
  6. Submit a pull request

License

MIT License - see LICENSE file for details.

Security

  • Report security vulnerabilities via GitHub security advisories
  • Private keys are handled securely and never logged
  • Temporary files are cleaned up automatically
  • File permissions are set restrictively by default

Metadata

Release files for aws-cert-syncer 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aws-cert-syncer 0.1.0
File Size Uploaded
aws_cert_syncer-0.1.0.tar.gz 15.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aws-cert-syncer 0.1.0
File Interpreter ABI Platform
aws_cert_syncer-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.8 kB

Release files / aws_cert_syncer-0.1.0.tar.gz

Download URL aws_cert_syncer-0.1.0.tar.gz
Size 15.3 kB
Tags Source
SHA-256 checksum
How to use checksums
eebb1fc7940805ec326fd94cd6bffdeee050b9356c18d18222ebd4f559777558
BLAKE2b-256 checksum
How to use checksums
ead48c1b2afc32d6e625c875bc20b65571121ae88444a5fd4bee28450acba4a4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 18, 2025.

Transparency log

Release files / aws_cert_syncer-0.1.0-py3-none-any.whl

Download URL aws_cert_syncer-0.1.0-py3-none-any.whl
Size 12.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0d06e17fc70affe794edf567ca022a5388462b9192d9c15ba143758b2f8144d0
BLAKE2b-256 checksum
How to use checksums
c04e99eab19f69a7a9625b869a4b90a26500648f0447bd2e7e3160f88b8349b2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 18, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page