Build, Encrypt, and Manage AMIs with Python, Boto3, and GitHub Actions
Creating custom Amazon Machine Images (AMIs) is essential for scalable, repeatable, and secure infrastructure in the AWS cloud. This guide will teach us how to build, encrypt, and manage AMIs programmatically using Python, Boto3, and GitHub Actions for automation.
Why Custom AMIs Matter
Custom AMIs allow you to:
Pre-configure your operating system, software, and configurations
Ensure security compliance and baseline hardening.
Reduce deployment time across environments.
Manage updates consistently
Combining automation with GitHub Actions ensures every AMI you create is reproducible and version-controlled.
Prerequisites
Before you begin:
An AWS account with EC2 permissions
Python 3.8+ installed
boto3 and botocore libraries
GitHub repository with GitHub Actions enabled
Install required Python packages:
pip install boto3 botocore
Step 1: Create and Encrypt AMIs Using Python and Boto3
Below is a sample script to create an AMI from an existing EC2 instance and encrypt it.
Python Script to Create and Encrypt an AMI
import boto3
from datetime import datetime
ec2 = boto3.client('ec2', region_name='us-east-1')
def create_encrypted_ami(instance_id, kms_key_id):
timestamp = datetime.utcnow().strftime('%Y%m%d-%H%M%S')
image_name = f'custom-ami-{timestamp}'
# Create Image
response = ec2.create_image(
InstanceId=instance_id,
Name=image_name,
Description='Encrypted custom AMI',
NoReboot=True
)
image_id = response['ImageId']
print(f"Created AMI: {image_id}, waiting for it to become available...")
waiter = ec2.get_waiter('image_available')
waiter.wait(ImageIds=[image_id])
# Copy and encrypt the AMI
encrypted_response = ec2.copy_image(
SourceImageId=image_id,
SourceRegion='us-east-1',
Name=f'{image_name}-encrypted',
Encrypted=True,
KmsKeyId=kms_key_id
)
print(f"Encrypted AMI Created: {encrypted_response['ImageId']}")
return encrypted_response['ImageId']
Step 2: Automate AMI Creation with GitHub Actions
Add the following to .github/workflows/create-ami.yml in your repository.
GitHub Actions Workflow
name: Build and Encrypt AMI
on:
workflow_dispatch:
jobs:
create-ami:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install dependencies
run: pip install boto3
- name: Create Encrypted AMI
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: us-east-1
INSTANCE_ID: ${{ secrets.INSTANCE_ID }}
KMS_KEY_ID: ${{ secrets.KMS_KEY_ID }}
run: |
python3 create_encrypted_ami.py
Store INSTANCE_ID, KMS_KEY_ID, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY as encrypted GitHub secrets.
Step 3: Manage and Clean Up AMIs
It's best practice to remove older AMIs to manage cost and clutter.
def delete_old_amis(tag_key, tag_value, keep_latest=3):
images = ec2.describe_images(Owners=['self'])['Images']
filtered = [img for img in images if any(
tag['Key'] == tag_key and tag['Value'] == tag_value for tag in img.get('Tags', []))]
# Sort by creation date descending
sorted_images = sorted(filtered, key=lambda x: x['CreationDate'], reverse=True)
for img in sorted_images[keep_latest:]:
ec2.deregister_image(ImageId=img['ImageId'])
print(f"Deregistered AMI: {img['ImageId']}")
Best Practices
Tag AMIs with metadata (Environment, App, BuildVersion) for easier tracking.
Use KMS keys with tight access controls for encryption.
Integrate Slack or email notifications in GitHub Actions for feedback.
Combine with Packer if you require more extensive provisioning.

Comments
Post a Comment