Skip to content

aws-samples/sample-acm-export-cert-automation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

6 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

ACM Certificate Export and Renewal Automation

Note: This is a sample project for demonstration and learning purposes.

This project demonstrates how to automate the process of exporting Amazon Certificate Manager (ACM) certificates and installing them on EC2 instances and on-premises servers. It also showcases automated certificate renewal, creating a seamless, event-driven workflow that requires minimal manual intervention. The solution is designed to be flexible and customizable for different operating systems and application types.

🎯 Learning Objectives

  • Implement secure certificate management using AWS services
  • Build event-driven automation with Step Functions and EventBridge
  • Apply tag-based targeting for EC2 instance management
  • Implement attribute-based access control (ABAC) for security
  • Create a complete serverless workflow with proper error handling

βœ… Prerequisites

Before setting up this solution, ensure you have:

  • AWS CLI configured with appropriate permissions
  • An AWS account with access to:
    • ACM (Amazon Certificate Manager)
    • Lambda
    • Step Functions
    • DynamoDB
    • Systems Manager (SSM)
    • Secrets Manager
    • EventBridge
    • API Gateway
    • IAM
  • At least one ACM certificate that you want to export (must have "Exportable" flag set to true)
  • One or more EC2 instances with:
    • SSM Agent installed and running
    • Proper IAM instance profile attached
    • Network connectivity to AWS services
  • IAM permissions to create and manage:
    • CloudFormation stacks
    • Lambda functions
    • IAM roles and policies
    • DynamoDB tables
    • Step Functions state machines
    • EventBridge rules
    • API Gateway endpoints

πŸš€ Quickstart with CloudFormation

Deploy the solution quickly using the provided CloudFormation templates:

Deployment Steps

  1. Deploy the CloudFormation stack to the central account where the solution will be installed:

    aws cloudformation deploy \
      --stack-name acm-cert-automation-crossaccount \
      --template-file infra/cloudformation/acm-cert-export-cross-account.yaml \
      --capabilities CAPABILITY_NAMED_IAM

    This template includes:

    • Enhanced DynamoDB table with composite key structure
    • Secure SSM document for certificate installation
    • Automatic certificate renewal via EventBridge
    • IAM roles with least privilege permissions
  2. Deploy the CloudFormation stack to the target account(s) where the EC2 instances reside:

    Option A: Single Account Deployment

    aws cloudformation deploy \
      --stack-name acm-cert-target-iam \
      --template-file infra/cloudformation/target-account-iam-simplified.yaml \
      --parameter-overrides CentralAccountId=123456789012 \
      --capabilities CAPABILITY_NAMED_IAM

    Option B: Multi-Account Deployment using StackSets

    # Create StackSet in the central account
    aws cloudformation create-stack-set \
      --stack-set-name acm-cert-target-iam-stackset \
      --template-body file://infra/cloudformation/target-account-iam-simplified.yaml \
      --parameters ParameterKey=CentralAccountId,ParameterValue=123456789012 \
      --capabilities CAPABILITY_NAMED_IAM \
      --permission-model SERVICE_MANAGED \
      --auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false
    
    # Deploy to multiple target accounts
    aws cloudformation create-stack-instances \
      --stack-set-name acm-cert-target-iam-stackset \
      --deployment-targets OrganizationalUnitIds=ou-xxxx-xxxxxxxx \
      --regions us-east-1

    Note: StackSets require AWS Organizations and appropriate permissions. For specific account targeting, replace OrganizationalUnitIds with Accounts=111111111111,222222222222

  3. Tag your target EC2 instances and their IAM instance profiles:

    Tag the EC2 instance:

    aws ec2 create-tags \
      --resources i-1234567890abcdef0 \
      --tags Key=<YOUR_TAG_KEY>,Value=<YOUR_TAG_VALUE>

    Tag the IAM role attached to the instance profile:

    aws iam tag-role \
      --role-name <YOUR_INSTANCE_PROFILE_ROLE_NAME> \
      --tags Key=<YOUR_TAG_KEY>,Value=<YOUR_TAG_VALUE>

    Important: Both the EC2 instance and its IAM role must have matching tags for ABAC to work properly. Replace <YOUR_TAG_KEY> and <YOUR_TAG_VALUE> with your chosen values (e.g., Key=env,Value=dev)

  4. Update instance profiles of the EC2 instances with the required IAM policy:

    Add the following ABAC policy to the IAM role attached to your EC2 instances:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowGetSecretWhenEnvMatches",
          "Effect": "Allow",
          "Action": [
            "secretsmanager:GetSecretValue",
            "secretsmanager:DescribeSecret"
          ],
          "Resource": "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:acm-passphrase/*",
          "Condition": {
            "StringEquals": {
              "secretsmanager:ResourceTag/<YOUR_TAG_KEY>": "${aws:PrincipalTag/<YOUR_TAG_KEY>}"
            }
          }
        }
      ]
    }

    Important: Replace <YOUR_TAG_KEY> with your chosen tag key (e.g., env, environment, team). Tag the instance profile IAM Role with the same tag key and value as used in your deployment (e.g., env=dev)

  5. Get the API Gateway endpoint URL from CloudFormation outputs:

    aws cloudformation describe-stacks \
      --stack-name acm-cert-automation-crossaccount \
      --query "Stacks[0].Outputs[?OutputKey=='APIEndpoint'].OutputValue" \
      --output text
  6. Prepare the payload for the API Gateway endpoint:

    Create or update templates/exportCertCrossAccount.json:

    {
      "CertificateArn": "arn:aws:acm:us-east-1:<ACCOUNT_ID>:certificate/<CERTIFICATE_ID>",
      "CertName": "demo_cert",
      "TargetTagKey": "env",
      "TargetTagValue": "dev",
      "TargetAccountId": "<TARGET_ACCOUNT_ID>"
    }
  7. Invoke the API to export and install the certificate:

    Using awscurl (requires AWS credentials):

    awscurl -X POST https://your-api-id.execute-api.us-east-1.amazonaws.com/prod/export-cert \
      -H "Content-Type: application/json" \
      -d @templates/exportCertCrossAccount.json

    Or using standard curl with AWS SigV4 signing:

    aws apigateway test-invoke-method \
      --rest-api-id your-api-id \
      --resource-id your-resource-id \
      --http-method POST \
      --body file://templates/exportCertCrossAccount.json
  8. Monitor the execution in the Step Functions console:

    Navigate to the AWS Step Functions console to see the certificate export and installation progress in real-time.

Verifying Successful Installation

After the Step Function completes, verify the certificate installation on your EC2 instances:

# SSH into your EC2 instance
ssh ec2-user@your-instance-ip

# Check certificate files
ls -la /etc/ssl/certs/ | grep your-cert-name
ls -la /etc/ssl/private/ | grep your-cert-name

# Verify certificate details
openssl x509 -in /etc/ssl/certs/your-cert-name.crt -text -noout

# Retrieve passphrase from Secrets Manager
PASSPHRASE=$(aws secretsmanager get-secret-value \
  --secret-id acm-passphrase/your-cert-name \
  --query SecretString \
  --output text | jq -r '.passphrase')

# Verify private key details using the passphrase
sudo openssl rsa -in /etc/ssl/private/your-cert-name.key \
  -passin pass:$PASSPHRASE -text -noout

# Verify the private key matches the certificate (both should output the same MD5 hash)
openssl x509 -noout -modulus -in /etc/ssl/certs/your-cert-name.crt | openssl md5
sudo openssl rsa -noout -modulus -in /etc/ssl/private/your-cert-name.key \
  -passin pass:$PASSPHRASE | openssl md5

Testing Automated Certificate Renewal

You can test the renewal process by manually triggering an EventBridge event using the AWS CLI:

Note: For testing purposes, update the EventBridge rule to use "Source": "custom.aws.acm" instead of "aws.acm". This is necessary because users typically don't have permissions to invoke actual ACM events and can only trigger custom events.

aws events put-events --entries '[
  {
    "Source": "custom.aws.acm",
    "DetailType": "ACM Certificate Available",
    "Detail": "{\"Action\": \"RENEWAL\", \"CertificateType\": \"AMAZON_ISSUED\", \"CommonName\": \"example.cipherclouds.com\", \"DomainValidationMethod\": \"DNS\", \"CertificateCreatedDate\": \"2025-05-18T02:22:05Z\", \"CertificateExpirationDate\": \"2026-06-16T23:59:59Z\", \"DaysToExpiry\": 395, \"InUse\": false, \"Exported\": true}",
    "Resources": [
      "arn:aws:acm:us-east-1:1234567890123:certificate/0762eb4c-f9a8-4cf2-bfd6-7715ff743942"
    ],
    "EventBusName": "default"
  }
]' --region us-east-1

Prerequisites for testing:

  • The certificate ARN must exist in your DynamoDB table
  • The EventBridge rule must be configured to listen for custom.aws.acm events

πŸ—οΈ Solution Overview

The solution consists of two main parts:

  1. Export and Install: Triggered via API Gateway to export certificates from ACM and install them on EC2 or on-premises servers
  2. Certificate Renewal: Automatically handles certificate renewals via EventBridge events

On-Demand Certificate Deployment Flow

On-Demand Certificate Deployment Flow

  1. Initiate Certificate Issuance: The user triggers the certificate issuance process, ensuring that the certificate is in the "issued" state before proceeding.
  2. API Triggers Step Function: An API call triggers a Step Function to begin the certificate installation cycle.
  3. Invoke ACM Export Lambda: The Step Function calls the first step, invoking the acm-export Lambda, which generates a passphrase and securely stores it in AWS Secrets Manager.
  4. Export Certificate: The acm-export Lambda uses the generated passphrase to export the ACM certificate, completing the first step of the export process.
  5. Invoke SSM Run Lambda: The Step Function invokes the ssm-run Lambda, passing the secret name, passphrase, encrypted private key, and public key to the next step in the cycle, as provided by the acm-export Lambda.
  6. Update DynamoDB: The ssm-run Lambda updates the DynamoDB table with relevant details, including the certificate ARN, certificate name, tag values, issuance date, and expiration date.
  7. Execute SSM Automation Document: The ssm-run Lambda triggers an SSM automation document, running commands to install the certificate by passing the public key, encrypted private key, and the secret alias of the passphrase.
  8. Install Certificate on EC2 Instances: The SSM automation document executes the installation of the certificates and the private key on the EC2 instances, while also validating the passphrase. (Customer can enhance these steps as they use the sample)
  9. Wait for SSM Deployment Completion: The Lambda status check waits for SSM to complete the certificate deployment across all EC2 instances before concluding the Step Function.

Automated Certificate Renewal Flow

Automated Certificate Renewal Flow

  1. EventBridge Triggers Certificate Renewal: An EventBridge event is triggered, confirming that the certificate has been renewed.
  2. Invoke Renewal Lambda: The EventBridge event invokes the renew-acm Lambda function, which initiates the renewal process.
  3. Invoke ACM Export Lambda: The Step Function invokes the acm-export Lambda, which generates a passphrase and securely stores it in AWS Secrets Manager.
  4. Export Renewed Certificate: The acm-export Lambda uses the generated passphrase to export the renewed ACM certificate, completing the export process.
  5. Invoke SSM Run Lambda: The Step Function invokes the ssm-run Lambda, passing the secret name, passphrase, encrypted private key, and public key to the next step in the cycle, as provided by the acm-export Lambda.
  6. Update DynamoDB: The ssm-run Lambda updates the DynamoDB table with relevant details, including the certificate ARN, certificate name, tag values, issuance date, and expiration date for the renewed certificate.
  7. Execute SSM Automation Document: The ssm-run Lambda triggers an SSM automation document, running commands to install the renewed certificate by passing the public key, encrypted private key, and the secret alias of the passphrase.
  8. Install Certificate on EC2 Instances: The SSM automation document executes the installation of the renewed certificate and the private key on the EC2 instances, while also validating the passphrase.
  9. Wait for SSM Deployment Completion: The Lambda status check waits for SSM to complete the certificate deployment across all EC2 instances before concluding the Step Function.

🧩 Cross-Account Implementation

Cross-Account Certificate Export Flow

The cross-account architecture separates certificate management (central account) from certificate deployment (target account) for enhanced security and isolation.

Central Account (Certificate Management):

  • Hosts ACM certificates
  • Runs Lambda functions to export certificates
  • Manages Step Functions orchestration
  • Stores DynamoDB table with certificate metadata

Target Account (Certificate Deployment):

  • Contains EC2 instances that receive certificates
  • Stores certificate passphrases in Secrets Manager
  • Executes SSM automation documents
  • Accesses secrets via ABAC-controlled IAM roles

Cross-Account Flow

  1. Central Account Lambda exports certificate: acm-Export-CrossAccount generates passphrase and exports certificate from ACM
  2. Target Account receives secret: Passphrase is stored in target account's Secrets Manager with matching tags
  3. Central Account triggers SSM: updtDBstrtSSMAutomation-CrossAccount invokes SSM automation in target account
  4. Target Account EC2 retrieves secret: EC2 instance's IAM role (with matching tags) retrieves passphrase from target account's Secrets Manager
  5. Certificate installed locally: SSM automation installs certificate on EC2 instance using the retrieved passphrase

🧩 Architecture Components

  • API Gateway - Accepts requests to export and install certificates
  • ACM (Amazon Certificate Manager) - Source of certificates and renewal events
  • Amazon EventBridge - Listens for certificate renewal events
  • Lambda Functions:
    • renewACMCert-CrossAccount - Handles renewal events and starts the Step Function
    • acm-Export-CrossAccount - Exports certificates from ACM
    • updtDBstrtSSMAutomation-CrossAccount - Updates DynamoDB and triggers SSM automation
    • checkAutomationStatus-CrossAccount - Monitors SSM automation execution
  • Step Function - Orchestrates the export and installation process
  • DynamoDB (CertTagMapping) - Stores certificate metadata and target information using a composite key structure:
    • TagKeyValue (Partition Key) - Combination of tag key and value for efficient querying by tag
    • CertificateArn#CertName (Sort Key) - Enables range queries on certificate ARNs
  • Secrets Manager - Securely stores certificate passphrases
  • SSM - Runs the enhanced Install-ACMCertificate document to securely install certificates on targets

DynamoDB Table Schema

The CertTagMapping table uses the following structure:

Attribute Type Description
TagKeyValue String (PK) Format: {TagKey}:{TagValue} (e.g., env:dev)
CertificateArn#CertName String (SK) Format: {CertificateArn}#{CertName}
CertificateArn String Full ARN of the ACM certificate
CertName String Friendly name for the certificate
IssuedDate String ISO 8601 timestamp of certificate issuance
ExpirationDate String ISO 8601 timestamp of certificate expiration
TargetAccountId String AWS account ID where targets reside

πŸ’° Cost Considerations

This solution uses the following AWS services that may incur costs:

  • Lambda: Charged per invocation and execution duration
  • Step Functions: Charged per state transition
  • DynamoDB: On-demand or provisioned capacity pricing
  • Secrets Manager: Charged per secret per month and per API call
  • API Gateway: Charged per million API calls
  • SSM: No additional charge for SSM Agent or Run Command
  • EventBridge: Charged per custom event published

Estimated monthly cost for moderate usage (100 certificate operations): $5-15 USD

Step Function Flow

Start
 └──► ExportCertOnly (acm-Export-CrossAccount)
       ↓
    CheckAndUpdateMappingAndSendSSM (updtDBstrtSSMAutomation-CrossAccount)
       ↓
       WaitForStatus (Wait 15s)
       ↓
    CheckAutomationStatus (checkAutomationStatus-CrossAccount)
       ↓
 β”Œβ”€β”€β”€β”€β”€β–Ί IsCommandComplete? (Choice)
 β”‚            β”œβ”€β”€β–Ί SuccessState (Succeed)
 β”‚            └──► FailureState (Fail)
 └─────────────► WaitForStatus (loop back if still InProgress)

πŸ“Š Successful Execution Flow

Successful step function execution flow

Benefits

Feature Benefit
Tag-based targeting Works with both EC2 and on-premises servers
Central certificate management All certificate metadata stored in DynamoDB
Fully automated renewals No manual intervention needed for renewals
SSM automation Consistent installation across environments
Step Function orchestration Reliable execution with visibility and logging

πŸ“ Important Notes

  • Target EC2 instances must be running Linux and have SSM Agent installed
  • Certificates are installed in /etc/ssl/certs/ and /etc/ssl/private/ folders
  • The API Gateway is secured with IAM authentication
  • Each certificate requires a one-to-one mapping with EC2 instance tags
  • You can customize the installation paths by modifying the SSM document
  • Certificate passphrases are automatically generated and stored securely in Secrets Manager
  • The solution uses ABAC (Attribute-Based Access Control) for enhanced security

πŸ”§ Customization Options

The solution can be extended to support different operating systems and application types. Here's how:

1. Customizable SSM Documents

Modify the Lambda function to use different SSM documents based on the target environment:

# Example: Select SSM document based on OS type
ssm_document = {
    'linux': 'Install-ACMCertificate-Linux',
    'windows': 'Install-ACMCertificate-Windows'
}.get(os_type, 'Install-ACMCertificate-Linux')

2. OS-Specific Installation

Support various operating systems by adding an OSType parameter to your payload:

{
  "CertificateArn": "arn:aws:acm:...",
  "OSType": "windows",
  "InstallPath": "C:\\Certificates"
}

3. Application-Specific Configuration

Adapt certificate installation for different application types:

{
  "CertificateArn": "arn:aws:acm:...",
  "ApplicationType": "nginx",
  "PostInstallAction": "restart-nginx"
}

4. Custom Installation Paths

Specify custom certificate installation paths:

{
  "CertificateArn": "arn:aws:acm:...",
  "CertPath": "/opt/app/certs",
  "KeyPath": "/opt/app/private"
}

5. Post-Installation Actions

Enable application-specific actions after certificate installation:

# Example SSM document step
- name: RestartService
  action: aws:runShellScript
  inputs:
    runCommand:
      - systemctl restart {{ ApplicationService }}

πŸ”’ EC2 IAM Policy Requirements

EC2 instances that receive certificates must have an IAM role with the following policy to enable Attribute-Based Access Control (ABAC) for accessing certificate passphrases:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowGetSecretWhenEnvMatches",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue",
                "secretsmanager:DescribeSecret"
            ],
            "Resource": "arn:aws:secretsmanager:[REGION]:[ACCOUNT_ID]:secret:acm-passphrase/*",
            "Condition": {
                "StringEquals": {
                    "secretsmanager:ResourceTag/env": "${aws:PrincipalTag/env}"
                }
            }
        }
    ]
}

Important: The IAM role assigned to the EC2 instance (not the EC2 instance itself) must have the same tags as the secret for ABAC to work properly. In the policy above, ${aws:PrincipalTag/env} refers to the tag on the IAM role, not the EC2 instance. During execution, the system validates that the role's tag matches the secret's tag to allow access.

This ABAC policy ensures that:

  • EC2 instances can only access secrets when their IAM role has matching environment tags
  • The SSM automation can retrieve the passphrase to decrypt the private key during installation
  • Security is maintained through role-based tag access control

πŸ” Troubleshooting

Common Issues and Solutions

Certificate Export Fails

Symptom: Step Function fails at the ExportCertOnly step

Possible Causes:

  • Certificate is not in "ISSUED" state
  • Certificate doesn't have "Exportable" flag set to true
  • Insufficient IAM permissions

Solution:

# Check certificate status
aws acm describe-certificate --certificate-arn your-cert-arn

# Verify the certificate is exportable
aws acm get-certificate --certificate-arn your-cert-arn

SSM Command Fails on EC2 Instances

Symptom: SSM automation document execution fails

Possible Causes:

  • SSM Agent not running on EC2 instance
  • IAM instance profile missing required permissions
  • Network connectivity issues

Solution:

# Check SSM Agent status
sudo systemctl status amazon-ssm-agent

# Verify instance is managed by SSM
aws ssm describe-instance-information --filters "Key=InstanceIds,Values=i-xxxxx"

# Check IAM instance profile
aws ec2 describe-instances --instance-ids i-xxxxx \
  --query 'Reservations[0].Instances[0].IamInstanceProfile'

ABAC Policy Denies Access

Symptom: EC2 instance cannot retrieve passphrase from Secrets Manager

Possible Causes:

  • IAM role tags don't match secret tags
  • IAM role missing Secrets Manager permissions

Solution:

# Check IAM role tags
aws iam list-role-tags --role-name your-instance-role

# Check secret tags
aws secretsmanager describe-secret --secret-id acm-passphrase/your-secret

# Ensure tags match (e.g., env=dev on both)

EventBridge Rule Not Triggering

Symptom: Certificate renewals don't trigger automatically

Possible Causes:

  • EventBridge rule is disabled
  • Event pattern doesn't match ACM events
  • Lambda function has insufficient permissions

Solution:

# Check EventBridge rule status
aws events describe-rule --name your-rule-name

# Enable the rule if disabled
aws events enable-rule --name your-rule-name

# Test with a custom event (see Testing section)

DynamoDB Query Returns No Results

Symptom: Certificate metadata not found in DynamoDB

Possible Causes:

  • Certificate hasn't been processed yet
  • Incorrect tag key/value format
  • DynamoDB table permissions issue

Solution:

# Query DynamoDB table
aws dynamodb query \
  --table-name CertTagMapping \
  --key-condition-expression "TagKeyValue = :tkv" \
  --expression-attribute-values '{":tkv":{"S":"env:dev"}}'

🧹 Cleanup

To remove all resources created by this solution:

  1. Delete the CloudFormation stacks:

    # Delete target account stack
    aws cloudformation delete-stack --stack-name acm-cert-target-iam
    
    # Delete central account stack
    aws cloudformation delete-stack --stack-name acm-cert-automation-crossaccount
  2. Remove secrets from Secrets Manager (if not automatically deleted):

    # List all ACM passphrases
    aws secretsmanager list-secrets \
      --filters Key=name,Values=acm-passphrase/
    
    # Delete specific secrets
    aws secretsmanager delete-secret \
      --secret-id acm-passphrase/your-secret \
      --force-delete-without-recovery
  3. Remove certificates from EC2 instances (optional):

    # SSH into each instance and remove certificate files
    sudo rm /etc/ssl/certs/your-cert-name.crt
    sudo rm /etc/ssl/private/your-cert-name.key
  4. Verify all resources are deleted:

    # Check CloudFormation stacks
    aws cloudformation list-stacks --stack-status-filter DELETE_COMPLETE
    
    # Check for remaining Lambda functions
    aws lambda list-functions --query 'Functions[?contains(FunctionName, `acm`)]'

⚠️ Limitations and Considerations

This sample project has the following limitations to be aware of:

  • Only works with ACM certificates that have the "Exportable" flag set to true
  • Requires EC2 instances to have SSM Agent installed and proper IAM permissions
  • Certificate private keys are temporarily stored in memory during the export process
  • The solution is region-specific; cross-region deployments require additional configuration
  • Error handling is basic and may require enhancement for production use
  • No built-in monitoring dashboard (relies on CloudWatch Logs and Metrics)
  • Currently supports Linux-based EC2 instances only (Windows support requires custom SSM document)
  • One-to-one mapping between certificates and tag combinations (one cert per tag pair)

πŸ“š Further Reading

To learn more about the technologies used in this sample project:


Questions or Issues? Please open an issue in the repository or refer to the Troubleshooting section above.

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages