Encrypting EBS Volumes of Amazon EC2 Instances Using Python
Introduction Ensuring compliance with stringent security requirements often leads to unexpected challenges - here’s one I recently tackled. The account in question has hundreds of EC2 instances with EBS volumes that are encrypted with the KMS AWS managed key aws/ebs. Due to more stringent security compliance requirements, the encryption key must be rotated every 90 days. The default one-year rotation period of the AWS managed key no longer suffices, thus all EC2 instance volumes must be re-encrypted with a custom managed key (CMK) that provides more control. With a looming deadline, it was simply not feasible to manually re-encrypt all EBS volumes. Thus I set out to find a tool or script that can automate this daunting task before resorting to developing my own (even if it’s AI-generated). Luckily I found a GitHub repository with a script that meets 90% of my needs, and made perfect after some enhancements. I’d like to share my experience and the resulting script in this blog post in case it benefits any fellow builders facing the same problem. Let’s first set the stage by examining the encryption workflow. The Encryption Workflow To encrypt or re-encrypt an EBS volume that is attached to an EC2 instance, it is unfortunately not as simple as setting a KMS key ID on the volume. The process is a bit roundabout and involves the following steps: Shut down the EC2 instance. Create a snapshot of the volume. Create a new volume from the previously created snapshot, while enabling encryption with the new KMS key. Ensure that you select the same availability zone as the original volume and apply any volume settings. Detach the original volume from the EC2 instance while making note of the device name to which the volume is attached. Attach the new volume to the EC2 instance with the same device name as above. Repeat step 2 to step 6 for any additional volumes that the EC2 instance has. Start the EC2 instance and verify that it is running properly. Delete the original volumes and the snapshots taken during this process as appropriate. There are other considerations and best practices for Amazon EBS encryption with auto scaling groups, spot instances, and snapshot sharing, however they are not relevant for the basic scenario for this blog post. As you can see, the workflow is quite involved and thus makes a great candidate for automation. Leveraging an Existing Script on GitHub The need to encrypt or re-encrypt EBS volumes is not uncommon, so I figure that someone would have developed tools and scripts for it. Indeed, a quick Google search yielded three possible options: dwbelliston/aws_volume_encryption - a Python-based script developed by Dustin Belliston that orchestrates encryption of EBS volumes of an EC2 instance. jbrt/ec2cryptomatic - a Go-based tool developed by Julien B. that is very similar to the Python solution above, but with a few more quality-of-life features. aws-samples/aws-system-manager-automation-unencrypted-to-encrypted-resources - an AWS solution that automatically remediates unencrypted EBS and RDS resources using AWS Config and SSM Automation. Given Boto3 and Python are part of my preferred toolset, I decided to leverage the aws_volume_encryption solution as my starting point. The repository has a well-written README file that provides usage instructions and detailed explanation on what each section of the code does. Be sure to check it out so you understand the general architecture and usage of the script. Enhancing the Existing Script Although developed years ago, the original script remains fully functional, proving its reliability. That said, I have identified a few small enhancements that could improve the usability of the script: Defer to Boto3’s default credential search mechanism instead of adding redundant options to the script. Create an encrypted volume directly from an encrypted snapshot. Add KMS key ID validation and skip encryption of volumes that are already encrypted with the provided KMS key. The KMS key ID can be any of the four supported formats by the AWS API. Add option to preserve the original volumes and add metadata tags (prefixed by VolumeEncryptionMetadata:) to them in case volume changes need to be reverted. Improve console logging with timestamps and more details. These enhancements allow me to test and benchmark the script more effectively, and they provide me an extra level of assurance when working on production workloads.
Introduction
Ensuring compliance with stringent security requirements often leads to unexpected challenges - here’s one I recently tackled. The account in question has hundreds of EC2 instances with EBS volumes that are encrypted with the KMS AWS managed key aws/ebs
. Due to more stringent security compliance requirements, the encryption key must be rotated every 90 days. The default one-year rotation period of the AWS managed key no longer suffices, thus all EC2 instance volumes must be re-encrypted with a custom managed key (CMK) that provides more control.
With a looming deadline, it was simply not feasible to manually re-encrypt all EBS volumes. Thus I set out to find a tool or script that can automate this daunting task before resorting to developing my own (even if it’s AI-generated). Luckily I found a GitHub repository with a script that meets 90% of my needs, and made perfect after some enhancements. I’d like to share my experience and the resulting script in this blog post in case it benefits any fellow builders facing the same problem. Let’s first set the stage by examining the encryption workflow.
The Encryption Workflow
To encrypt or re-encrypt an EBS volume that is attached to an EC2 instance, it is unfortunately not as simple as setting a KMS key ID on the volume. The process is a bit roundabout and involves the following steps:
Shut down the EC2 instance.
Create a snapshot of the volume.
Create a new volume from the previously created snapshot, while enabling encryption with the new KMS key. Ensure that you select the same availability zone as the original volume and apply any volume settings.
Detach the original volume from the EC2 instance while making note of the device name to which the volume is attached.
Attach the new volume to the EC2 instance with the same device name as above.
Repeat step 2 to step 6 for any additional volumes that the EC2 instance has.
Start the EC2 instance and verify that it is running properly.
Delete the original volumes and the snapshots taken during this process as appropriate.
There are other considerations and best practices for Amazon EBS encryption with auto scaling groups, spot instances, and snapshot sharing, however they are not relevant for the basic scenario for this blog post.
As you can see, the workflow is quite involved and thus makes a great candidate for automation.
Leveraging an Existing Script on GitHub
The need to encrypt or re-encrypt EBS volumes is not uncommon, so I figure that someone would have developed tools and scripts for it. Indeed, a quick Google search yielded three possible options:
dwbelliston/aws_volume_encryption - a Python-based script developed by Dustin Belliston that orchestrates encryption of EBS volumes of an EC2 instance.
jbrt/ec2cryptomatic - a Go-based tool developed by Julien B. that is very similar to the Python solution above, but with a few more quality-of-life features.
aws-samples/aws-system-manager-automation-unencrypted-to-encrypted-resources - an AWS solution that automatically remediates unencrypted EBS and RDS resources using AWS Config and SSM Automation.
Given Boto3 and Python are part of my preferred toolset, I decided to leverage the aws_volume_encryption solution as my starting point. The repository has a well-written README file that provides usage instructions and detailed explanation on what each section of the code does. Be sure to check it out so you understand the general architecture and usage of the script.
Enhancing the Existing Script
Although developed years ago, the original script remains fully functional, proving its reliability. That said, I have identified a few small enhancements that could improve the usability of the script:
Defer to Boto3’s default credential search mechanism instead of adding redundant options to the script.
Create an encrypted volume directly from an encrypted snapshot.
Add KMS key ID validation and skip encryption of volumes that are already encrypted with the provided KMS key. The KMS key ID can be any of the four supported formats by the AWS API.
Add option to preserve the original volumes and add metadata tags (prefixed by
VolumeEncryptionMetadata:
) to them in case volume changes need to be reverted.Improve console logging with timestamps and more details.
These enhancements allow me to test and benchmark the script more effectively, and they provide me an extra level of assurance when working on production workloads.