Seamlessly Re-Encrypt Your AWS EBS Volumes with a Shared KMS Key (CMK)

Seamlessly Re-Encrypt Your AWS EBS Volumes with a Shared KMS Key (CMK)

Publish Date: Mar 28
0 0

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
Enter fullscreen mode Exit fullscreen mode

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

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']
Enter fullscreen mode Exit fullscreen mode

To ensure data consistency, it waits for the snapshot to complete before proceeding.

waiter = ec2.get_waiter('snapshot_completed')
waiter.wait(SnapshotIds=[snapshot_id])
Enter fullscreen mode Exit fullscreen mode

Step 2: Copy the Snapshot with the Shared CMK

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']
Enter fullscreen mode Exit fullscreen mode

A wait process ensures the copied snapshot is ready for use.

Step 3: Create a New Volume from the Copied Snapshot

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']
Enter fullscreen mode Exit fullscreen mode

A waiter ensures the new volume is available before proceeding.

Step 4: Replace the Old Volume with the New Volume

Replace the Old Volume with the New Volume of the EC2

The script detaches the old volume from the EC2 instance:

ec2.detach_volume(VolumeId=volume_id)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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}")
Enter fullscreen mode Exit fullscreen mode

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>')

Enter fullscreen mode Exit fullscreen mode

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.

Comments 0 total

    Add comment