Home / AWS

AWSHow-toBeginner

Turn on EBS encryption by default and encrypt existing unencrypted volumes

Enable EBS encryption by default in every region, choose the KMS key, find unencrypted volumes and snapshots, and swap an existing volume for an encrypted copy.

Deepak Bhardwaj5 min read

Applies toAmazon EBS, Amazon EC2, AWS KMS, AWS Config, AWS CLI v2

Goal: every new EBS volume is encrypted without anyone having to remember, and the unencrypted volumes you already have are replaced with encrypted ones. EBS has an account setting for the first part. The second part needs a snapshot, a new volume and a short stop of the instance.

What "encryption by default" does and doesn't do

It does It doesn't
Encrypt every new volume created in that account and region Change existing volumes or snapshots
Encrypt volumes created from unencrypted snapshots and AMIs Apply to other regions; it's set per region
Use the default key you choose (aws/ebs unless you change it) Let you turn encryption off for a single volume while it's on

1. Check and enable it in every region

for r in $(aws ec2 describe-regions --query "Regions[].RegionName" --output text); do
  printf "%-16s %s\n" "$r" "$(aws ec2 get-ebs-encryption-by-default --region $r \
    --query EbsEncryptionByDefault --output text)"
done

Enable it where it shows False:

aws ec2 enable-ebs-encryption-by-default --region eu-west-1

Loop over the regions you use, or all of them, so that a volume created in a region nobody watches is encrypted too. The setting is per account. In AWS Organizations you have to apply it in every member account (for example with StackSets, or with a script that assumes a role in each account).

2. Choose the default KMS key

aws ec2 get-ebs-default-kms-key-id --region eu-west-1

The AWS managed key alias/aws/ebs works without any setup, but you can't edit its key policy. That means you can't share snapshots or AMIs encrypted with it with other accounts. If you copy AMIs or share snapshots across accounts (DR accounts, AMI factories), use a customer managed key:

aws ec2 modify-ebs-default-kms-key-id --region eu-west-1 \
  --kms-key-id arn:aws:kms:eu-west-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab

# go back to aws/ebs
aws ec2 reset-ebs-default-kms-key-id --region eu-west-1

Warning

With a customer managed key, the key policy must allow every service that launches instances for you. The common failure: Auto Scaling launches fail with Client.InternalError: Client error on launch because the key policy doesn't allow the AWSServiceRoleForAutoScaling service-linked role to use the key and create grants. Add that role to the key policy (kms:Encrypt, kms:Decrypt, kms:ReEncrypt*, kms:GenerateDataKey*, kms:DescribeKey, kms:CreateGrant) before you change the default key.

Caution

If you disable the default key or schedule it for deletion, every volume encrypted with it becomes unusable, and new launches fail. Protect the key with a key policy that limits who can disable it or schedule its deletion.

3. Find what is still unencrypted

aws ec2 describe-volumes --filters Name=encrypted,Values=false \
  --query "Volumes[].{id:VolumeId,state:State,size:Size,instance:Attachments[0].InstanceId,device:Attachments[0].Device}" \
  --output table

aws ec2 describe-snapshots --owner-ids self --filters Name=encrypted,Values=false \
  --query "Snapshots[].[SnapshotId,VolumeId,StartTime,VolumeSize]" --output table

For ongoing reporting across accounts, turn on the AWS Config managed rules encrypted-volumes and ec2-ebs-encryption-by-default.

4. Encrypt an existing data volume

You can't encrypt a volume in place. Create an encrypted copy and swap it in. Plan a short stop of the application (or of the instance, for a root volume).

VOL=vol-0abc1234567890def
INST=$(aws ec2 describe-volumes --volume-ids $VOL --query "Volumes[0].Attachments[0].InstanceId" --output text)
DEV=$(aws ec2 describe-volumes --volume-ids $VOL --query "Volumes[0].Attachments[0].Device" --output text)
AZ=$(aws ec2 describe-volumes --volume-ids $VOL --query "Volumes[0].AvailabilityZone" --output text)
TYPE=$(aws ec2 describe-volumes --volume-ids $VOL --query "Volumes[0].VolumeType" --output text)
echo "$INST $DEV $AZ $TYPE"

Stop writes (stop the service and unmount the volume, or stop the instance), then snapshot:

SNAP=$(aws ec2 create-snapshot --volume-id $VOL --description "pre-encrypt $VOL" \
  --query SnapshotId --output text)
aws ec2 wait snapshot-completed --snapshot-ids $SNAP

Create the encrypted volume straight from the unencrypted snapshot. You don't need a separate copy-snapshot step for a volume in the same region:

NEWVOL=$(aws ec2 create-volume --snapshot-id $SNAP --availability-zone $AZ \
  --volume-type $TYPE --encrypted \
  --kms-key-id alias/ebs-default-cmk \
  --tag-specifications "ResourceType=volume,Tags=[{Key=Name,Value=encrypted-$VOL}]" \
  --query VolumeId --output text)
aws ec2 wait volume-available --volume-ids $NEWVOL

For gp3, io1 and io2, pass --iops (and --throughput for gp3) to match the old volume. Otherwise the new volume gets the defaults.

Swap them:

aws ec2 detach-volume --volume-id $VOL
aws ec2 wait volume-available --volume-ids $VOL
aws ec2 attach-volume --volume-id $NEWVOL --instance-id $INST --device $DEV

Mount it and start the service. If /etc/fstab uses UUID=, it still matches, because the filesystem was copied block for block.

5. Encrypt a root volume

The process is the same, except that the instance must be stopped and the new volume must be attached under the instance's root device name:

ROOTDEV=$(aws ec2 describe-instances --instance-ids $INST \
  --query "Reservations[0].Instances[0].RootDeviceName" --output text)
aws ec2 stop-instances --instance-ids $INST
aws ec2 wait instance-stopped --instance-ids $INST
# snapshot, create-volume --encrypted, detach old root as above, then:
aws ec2 attach-volume --volume-id $NEWVOL --instance-id $INST --device $ROOTDEV
aws ec2 start-instances --instance-ids $INST

Tip

For instances in an Auto Scaling group, don't swap volumes. With encryption by default on, the next instance refresh launches encrypted volumes from the same AMI. To get an encrypted AMI, run aws ec2 copy-image --encrypted --kms-key-id ... and point the launch template at it.

6. Clean up

Keep the old volume for a day or two in case you need to roll back, then delete it and the unencrypted snapshot:

aws ec2 delete-volume --volume-id $VOL
aws ec2 delete-snapshot --snapshot-id $SNAP

For old unencrypted snapshots that you have to keep, create encrypted copies with aws ec2 copy-snapshot --source-snapshot-id snap-... --source-region eu-west-1 --encrypted --kms-key-id ... and then delete the originals.

Prevent it next time

  • Enable encryption by default in every region, in every account, as part of account vending.
  • Add an SCP that denies ec2:CreateVolume when ec2:Encrypted is false, as a backstop for accounts where someone turns the setting off.
  • Use a customer managed key if snapshots or AMIs ever leave the account, and grant the Auto Scaling service-linked role on day one.
  • Keep the Config rules encrypted-volumes and ec2-ebs-encryption-by-default on, and review their findings monthly.