How I automated Certificate expiration alerts with AWS

Tetiana Mostova - Jan 12 - - Dev Community

As a Software engineer, I recently faced a challenge with certificate rotation at work. While solving it, I discovered a neat way to automate SSL certificates rotation alerts using AWS services. Here's how you can set up your own automated notification system!

Prerequisites

  • AWS Account
  • Basic understanding of AWS services
  • AWS CLI configured (optional)

The Problem

Manual tracking of secret expiration dates is:

  • Error-prone
  • Easy to forget
  • Time-consuming
  • Stressful (nobody wants expired certificates in production!)

The Solution

I created a simple automation using three AWS services:

  • EventBridge for scheduling
  • Lambda for checking expiration
  • SNS for notifications

How It Works

  1. Lambda checks secrets periodically
  2. When a secret is nearing expiration, EventBridge triggers notifications
  3. SNS sends alerts to the team

Here's the Lambda function that does the magic:

import json
import boto3
from datetime import datetime
import OpenSSL.crypto

def lambda_handler(event, context):
    secretsmanager = boto3.client('secretsmanager')
    sns = boto3.client('sns')

    try:
        # Get list of secrets
        secrets = secretsmanager.list_secrets()

        for secret in secrets['SecretList']:
            # Get the secret value
            secret_value = secretsmanager.get_secret_value(SecretId=secret['Name'])
            secret_dict = json.loads(secret_value['SecretString'])

            # Look for certificate entries (ending in .cert)
            for key, value in secret_dict.items():
                if key.endswith('.cert'):
                    # Parse the certificate
                    cert_data = value.replace('\\n', '\n')
                    cert = OpenSSL.crypto.load_certificate(
                        OpenSSL.crypto.FILETYPE_PEM, 
                        cert_data
                    )

                    # Get expiration date
                    expiry = datetime.strptime(
                        cert.get_notAfter().decode('ascii'),
                        '%Y%m%d%H%M%SZ'
                    )

                    # Calculate days until expiration
                    days_until_expiry = (expiry - datetime.utcnow()).days

                    # Alert if expiring within 60 days
                    if days_until_expiry <= 60:
                        sns.publish(
                            TopicArn='arn:aws:sns:REGION:ACCOUNT_ID:secret-rotation-alerts',
                            Subject=f'Certificate Expiration Alert - {key}',
                            Message=f'''
                            Certificate {key} in secret {secret["Name"]} is expiring soon!

                            Expiration Date: {expiry.date()}
                            Days until expiration: {days_until_expiry}

                            Please rotate this certificate soon.
                            '''
                        )

        return {
            'statusCode': 200,
            'body': 'Certificate check completed successfully'
        }

    except Exception as e:
        print(f"Error: {str(e)}")
        return {
            'statusCode': 500,
            'body': f'Error checking certificates: {str(e)}'
        }
Enter fullscreen mode Exit fullscreen mode

Setting It Up

Step 1: Create an IAM Role for Lambda

  1. Go to IAM Console
  2. Click "Roles" → "Create role"
  3. Select "AWS Service" and choose "Lambda"
  4. Add following permissions (Create new policy):
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "secretsmanager:ListSecrets",
                "secretsmanager:DescribeSecret"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "sns:Publish"
            ],
            "Resource": "arn:aws:sns:REGION:ACCOUNT_ID:secret-rotation-alerts"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode
  1. Name the role secret-rotation-checker-role

Step 2 Create SNS Topic:

   aws sns create-topic --name secret-rotation-alerts
   aws sns subscribe --topic-arn <your-topic-arn> --protocol email --notification-endpoint your@email.com
Enter fullscreen mode Exit fullscreen mode

Next, confirm subscription via email.

Step 3: Create Lambda Function

  1. Go to Lambda Console
  2. Click "Create function"
  3. Settings:

    • Author from scratch
    • Function name: secret-rotation-checker
    • Runtime: Python 3.9
    • Architecture: x86_64
    • Permissions: Use existing role that we’ve created in previous stepssecret-rotation-checker-role
  4. Paste the Lambda code above and remember to replace REGION and ACCOUNT_ID with your values then click "Deploy".

Step 4: Create EventBridge Rule

  1. Go to EventBridge Console
  2. Click "Rules" → "Create rule"

Image description

  1. Settings:
    • Name: quarterly-secret-check
    • Description: "Check secrets every quarter for rotation"
    • Rule type: Schedule
    • Occurrence: Recurring schedule
    • Schedule type: Cron-based schedule
    • Cron: 0 9 1 1,4,7,10 ? * (Runs quarterly)

Image description

  1. Select target:
    • Target type: AWS Service
    • Templated targets: Lambda Invoke
    • Function: secret-rotation-checker

Image description

Why every 3 months?

  • Most secrets/certificates are valid for 1 year
  • Quarterly checks provide enough time to act
  • Reduces unnecessary Lambda executions
  • Still catches any missed rotations

Step 5: Test the Setup

  1. Go back to Lambda console
  2. Select your function
  3. Click "Test" tab
  4. Create new test event (empty {} is fine)
  5. Click "Test"
  6. Check CloudWatch logs for execution results
  7. Check your email for any alerts

That's it! Now you'll get email alerts when secrets need rotation.

Customization Options

The Lambda function can be customized in several way. You can modify the code to check specific secrets by filtering them using tags, which is useful for managing different types of secrets separately. If you need earlier notifications, you can adjust the alert threshold from the current 330 days to any number that suits your rotation schedule. The notification system can be expanded beyond email by adding more SNS subscription types like Slack or Microsoft Teams. For more detailed tracking, you can enhance the alerts by including additional secret metadata and details in the notifications.

Cost Considerations

This automation solution is designed to be extremely cost-effective. Since the Lambda function only executes quarterly (4 times per year), the Lambda costs are minimal. SNS notifications are only triggered when secrets actually need rotation, making the messaging costs negligible. CloudWatch logs are kept minimal, only storing essential execution information, which keeps logging costs low. Overall, the entire setup typically costs less than a dollar per month, making it a cost-effective solution for maintaining security compliance.

Taking It Further

Want to automate the actual rotation? AWS Secrets Manager has a built-in rotation feature for some secret types. For custom secrets, you can write another Lambda function that:

  1. Generates new secrets
  2. Updates applications
  3. Verifies everything works
  4. Archives old secrets

But that's a topic for another post! 😉

Key Takeaways

Implementing this automation has taught me several valuable lessons. First and foremost, automating secret rotation tracking is significantly more reliable than manual tracking methods, eliminating human error and reducing operational overhead. The seamless integration between AWS services (Lambda, EventBridge, and SNS) demonstrates how powerful cloud services can be when used together. While the code implementation is relatively simple, it saves countless hours that would otherwise be spent on manual checks and tracking. Most importantly, this automation provides peace of mind – you can rest easier knowing that your secrets rotation schedule is being monitored automatically, and you'll receive timely notifications when action is needed.

Hope this helps someone else automate their secret management! Let me know if you have questions or suggestions for improvements.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .