Tim's Tech Thoughts

Data Encryption at Rest: Preparing for EBS Volumes Remediation

2024-08-26 AWS Timothy Patterson

Taking the First Steps Toward Secure Data at Rest

In the previous post , I discussed the importance of encrypting data at rest and introduced the powerful combination of AWS tools and the Prowler open-source framework. After running Prowler’s security assessment, you may have identified some unencrypted resources, particularly EBS volumes attached to EC2 instances.

Remediating unencrypted EBS volumes is critical for ensuring that sensitive data is protected, but it requires a careful, planned approach.

Before diving into remediation, the first step is to collect detailed information on the unencrypted volumes and the EC2 instances they are attached to.

Collecting Detailed EC2 and EBS Information

To prepare for remediation, I’ve created a Python script (ebs-vols-report.py) that generates a report of all your EC2 instances, the EBS volumes attached to them, and their encryption status. Running this script gives you a clear snapshot of which EBS volumes are unencrypted and provides detailed information that will guide you through the remediation process.

What Does the Script Do?

The script uses the AWS SDK for Python (boto3) to interact with your AWS environment. Here’s a breakdown of how it works:

Get Instance and Volume Information:

  • The script connects to your AWS account using the boto3 session with the provided AWS profile and region. It then retrieves all EC2 instances in the region using the ec2_resource object.
  • For each EC2 instance, it collects the instance ID, instance name (using the Name tag), and its current state (powered on or off).
  • It loops through each instance’s block device mappings to gather the attached EBS volume IDs.
  • The script calls the describe_volumes function to get more detailed information about each volume, including its encryption status.

Write the Data to a CSV File:

  • The script writes the collected data (instance ID, name, state, volume ID, and encryption status) to a CSV file (ec2_instance_data.csv), providing a structured report of which instances have unencrypted volumes attached.
  • This report serves as the baseline for your remediation process. You will use it to identify which instances require encryption updates, and later, you can run the report again to validate that your remediation was successful.

How to Run the Script

python ebs-vols-report.py --region us-west-2 --profile your-aws-profile

The script takes two arguments:

  • --region: The AWS region where your instances are running (e.g., us-west-2).
  • --profile: The AWS profile you’ve set up locally to authenticate and connect to your AWS account.

The output will look something like this:

Instance ID Instance Name State Volume ID Encrypted
i-1234567890 WebServer running vol-0abcdef False
i-0987654321 DBServer stopped vol-1ghijkl True

Once you have this detailed information in hand, you can move on to the actual remediation process.

The Full Python Script

import boto3
import csv
import argparse

# Function to get the instance's 'Name' tag
def get_instance_name(instance):
    for tag in instance.tags or []:
        if tag['Key'] == 'Name':
            return tag['Value']
    return 'N/A'  # If no 'Name' tag is found, return 'N/A'

# Function to get instance state and volume encryption status
def get_instance_data(ec2_resource, ec2_client):
    instance_data = []

    # Loop through all EC2 instances
    for instance in ec2_resource.instances.all():
        instance_id = instance.instance_id
        instance_name = get_instance_name(instance)
        state = instance.state['Name']  # powered on/off state

        # Get the block device mappings (EBS volumes attached to the instance)
        for device in instance.block_device_mappings:
            if 'Ebs' in device:
                volume_id = device['Ebs']['VolumeId']

                # Get the volume details, including the encryption status
                volume = ec2_client.describe_volumes(VolumeIds=[volume_id])['Volumes'][0]
                encrypted = volume['Encrypted']

                instance_data.append({
                    'Instance ID': instance_id,
                    'Instance Name': instance_name,
                    'State': state,
                    'Volume ID': volume_id,
                    'Encrypted': encrypted
                })

    return instance_data

# Function to write the instance data to a CSV file
def write_to_csv(data, filename='ec2_instance_data.csv'):
    with open(filename, mode='w', newline='') as file:
        writer = csv.DictWriter(file, fieldnames=['Instance ID', 'Instance Name', 'State', 'Volume ID', 'Encrypted'])
        writer.writeheader()
        writer.writerows(data)

    print(f"Data written to {filename}")

def main():
    # Create an argument parser for region and profile
    parser = argparse.ArgumentParser(description="Script to list EC2 instances and EBS volumes with encryption status")
    parser.add_argument('--region', required=True, help="The AWS region to use")
    parser.add_argument('--profile', required=True, help="The AWS profile to use")

    args = parser.parse_args()

    # Create a session using the provided profile and region
    session = boto3.Session(profile_name=args.profile, region_name=args.region)

    # Create an EC2 resource and EC2 client
    ec2_resource = session.resource('ec2')
    ec2_client = session.client('ec2')

    # Get instance data and write to CSV
    instance_data = get_instance_data(ec2_resource, ec2_client)
    write_to_csv(instance_data)

if __name__ == "__main__":
    main()

Beginning the Remediation Process

Now that you know which EC2 instances have unencrypted EBS volumes, it’s time to make sure you fully understand the remediation process for getting them encrypted. Here’s the step-by-step process for securing the unencrypted volumes:

Determine KMS Key to Use: It is very important to have your destination in mind. For example, if your goal is simplicity, you may use the built-in AWS KMS provided default key for encrypting your volumes. However, if you are going to be using something like the AWS Backup service to copy recovery points containing these volumes across AWS accounts or AWS regions, you will need to pivot your KMS key strategy accordingly. I highly recommend you create a new multi-region KMS key for this exclusive purpose.

Power Down the EC2 Instance: For safety and to ensure data integrity, stop the EC2 instance. This prevents any changes to the volume during the encryption process. It is super important to understand that there is no way to perform a live re-encryption operation in place. You must plan for downtime accordingly. The amount of downtime for each instance depends on a number of factors, such as number of EBS volumes attached to the instance, the EBS volume type, EBS volume size, and how much of the volume is in active use (in terms of blocks written).

Detach the EBS Volumes: Using the AWS Management Console or AWS CLI, detach the unencrypted EBS volumes from the instance.

Create an Unencrypted Snapshot: Before making any modifications, create a snapshot of the unencrypted volume. This acts as a backup and ensures that no data is lost during the process.

Copy the Snapshot with Encryption: Create a new encrypted snapshot from the unencrypted one. This step uses your KMS key to encrypt the data.

Create a New EBS Volume: Once you have the encrypted snapshot, create a new EBS volume from it.

Reattach the Encrypted EBS Volume: Attach the newly encrypted EBS volume to your EC2 instance.

Power the EC2 Instance Back On: Finally, restart the instance, and it will now have encrypted EBS volumes attached.

Validating the Remediation

After completing the remediation process, you can run the ebs-vols-report.py script again. This will allow you to verify that all previously unencrypted EBS volumes are now encrypted. The new report should show True under the “Encrypted” column for all the volumes you remediated.

Next Steps: Automating the Remediation

Remediation is a crucial part of securing your AWS environment, and the preparation phase is just as important. By using this Python script, you’ve taken the first step in gathering the data needed to begin remediation. In the next post, we’ll cover a Python script to fully automate the encryption process, streamlining the work even further!

Stay tuned as we continue to secure your AWS resources, one encrypted volume at a time!

Disclaimer: The opinions expressed herein are my own personal thoughts and do not represent the views of any present or past employer in any way.