Introduction
Amazon Elastic Block Store (EBS) allows encryption using AWS-managed or customer-managed keys. However, modifying the encryption key of an existing EBS volume is not straightforward. This blog post walks through a Python script utilizing Boto3 to re-encrypt an EBS volume with a shared AWS Customer Managed key (CMK), ensuring data security compliance. In this scenario the CMK is shared from a different account. We will go through the steps to change the encryption key of the volume from AWS default key to shared CMK.
Required Libraries
The script makes use of the boto3 library, which is the official AWS SDK for Python. It allows programmatic access to AWS services, including EC2, which manages EBS volumes.
To install Boto3, run:
pip install boto3
The script uses the following components from boto3:
- boto3.client('ec2'): Creates an EC2 client to interact with AWS EC2 services.
- create_snapshot(): Creates a backup snapshot of an EBS volume.
- get_waiter('snapshot_completed'): Waits until the snapshot is fully created.
- copy_snapshot(): Copies the snapshot with a new encryption key.
- get_waiter('snapshot_completed'): Ensures the copied snapshot is ready.
- create_volume(): Creates a new EBS volume from the copied snapshot.
- get_waiter('volume_available'): Ensures the new volume is available.
- detach_volume(): Detaches the old volume from the EC2 instance.
- attach_volume(): Attaches the new volume to the EC2 instance.
- describe_volumes(): Retrieves details of the newly attached volume.
Understanding the Script
The provided Python script automates the process of changing an EBS volume’s encryption key in five key steps:
Step 1: Create a Snapshot of the Existing Volume
The script begins by creating a snapshot of the existing EBS volume, serving as a backup before re-encryption.
snapshot = ec2.create_snapshot(VolumeId=volume_id, Description="Snapshot before changing encryption key")
snapshot_id = snapshot['SnapshotId']
To ensure data consistency, it waits for the snapshot to complete before proceeding.
waiter = ec2.get_waiter('snapshot_completed')
waiter.wait(SnapshotIds=[snapshot_id])
Step 2: Copy the Snapshot with the Shared CMK
The script then copies the snapshot, applying the new KMS key for encryption.
copied_snapshot = ec2.copy_snapshot(
SourceRegion=region,
SourceSnapshotId=snapshot_id,
DestinationRegion=region,
KmsKeyId=kms_key_arn,
Encrypted=True,
Description="Snapshot with customer-managed KMS key"
)
copied_snapshot_id = copied_snapshot['SnapshotId']
A wait process ensures the copied snapshot is ready for use.
Step 3: Create a New Volume from the Copied Snapshot
The copied snapshot is then used to create a new volume that is encrypted with the new KMS key.
new_volume = ec2.create_volume(
SnapshotId=copied_snapshot_id,
AvailabilityZone=availability_zone,
Encrypted=True,
KmsKeyId=kms_key_arn
)
new_volume_id = new_volume['VolumeId']
A waiter ensures the new volume is available before proceeding.
Step 4: Replace the Old Volume with the New Volume
The script detaches the old volume from the EC2 instance:
ec2.detach_volume(VolumeId=volume_id)
After confirming the old volume is detached, the new volume is attached in its place.
ec2.attach_volume(VolumeId=new_volume_id, InstanceId=instance_id, Device=device_name)
Step 5: Verify the New Volume
Finally, the script retrieves and prints the details of the newly attached volume to verify the encryption change.
volume_info = ec2.describe_volumes(VolumeIds=[new_volume_id])
print(f"New volume details: {volume_info}")
Script
Below is the full python code to change the encryption key of the EBS volume.
import boto3
def convert_ebs_encryption(volume_id, kms_key_arn, region, availability_zone, instance_id, device_name):
ec2 = boto3.client('ec2', region_name=region)
# Step 1: Create a snapshot of the existing volume
snapshot = ec2.create_snapshot(VolumeId=volume_id, Description="Snapshot before changing encryption key")
snapshot_id = snapshot['SnapshotId']
print(f"Snapshot created: {snapshot_id}")
# Wait for the snapshot to complete
waiter = ec2.get_waiter('snapshot_completed')
waiter.wait(SnapshotIds=[snapshot_id])
# Step 2: Copy the snapshot with the new KMS key
copied_snapshot = ec2.copy_snapshot(
SourceRegion=region,
SourceSnapshotId=snapshot_id,
DestinationRegion=region,
KmsKeyId=kms_key_arn,
Encrypted=True,
Description="Snapshot with customer-managed KMS key"
)
copied_snapshot_id = copied_snapshot['SnapshotId']
print(f"Copied snapshot created: {copied_snapshot_id}")
# Wait for the copied snapshot to complete
waiter.wait(
SnapshotIds=[copied_snapshot_id],
WaiterConfig={
'Delay': 60, # Wait 60 seconds between each attempt
'MaxAttempts': 60 # Maximum of 60 attempts
}
)
# Step 3: Create a new volume from the copied snapshot
new_volume = ec2.create_volume(
SnapshotId=copied_snapshot_id,
AvailabilityZone=availability_zone,
Encrypted=True,
KmsKeyId=kms_key_arn
)
new_volume_id = new_volume['VolumeId']
print(f"New volume created: {new_volume_id}")
# Wait for the new volume to become available
waiter = ec2.get_waiter('volume_available')
waiter.wait(VolumeIds=[new_volume_id])
print(f"New Volume is available")
## Step 4: Detach the old volume and attach the new volume
#ec2.detach_volume(VolumeId=volume_id)
#ec2.attach_volume(VolumeId=new_volume_id, InstanceId=instance_id, Device=device_name)
#print(f"New volume {new_volume_id} attached to instance {instance_id} as {device_name}")
# Step 4: Detach the old volume
ec2.detach_volume(VolumeId=volume_id)
# Wait for the old volume to be fully detached
detach_waiter = ec2.get_waiter('volume_available')
detach_waiter.wait(VolumeIds=[volume_id])
print(f"Old volume {volume_id} detached successfully")
# Attach the new volume
ec2.attach_volume(VolumeId=new_volume_id, InstanceId=instance_id, Device=device_name)
print(f"New volume {new_volume_id} attached to instance {instance_id} as {device_name}")
# Step 5: Verify the new volume
volume_info = ec2.describe_volumes(VolumeIds=[new_volume_id])
print(f"New volume details: {volume_info}")
# Example usage
#convert_ebs_encryption('<EBS_VOLUME_ID>', '<CUSTOMER_KMS_KEY_ID>', '<REGION>', '<AVAILABILITY_ZONE>', '<INSTANCE_ID>', '<DEVICE_NAME>')
Conclusion
This automated approach enables AWS users to change the encryption key of an EBS volume without downtime for all non root volumes. It ensures compliance with security policies while maintaining data integrity. By leveraging Boto3 and AWS KMS, organizations can efficiently manage encrypted EBS volumes at scale.