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 launchbecause the key policy doesn't allow theAWSServiceRoleForAutoScalingservice-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:CreateVolumewhenec2:Encryptedisfalse, 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-volumesandec2-ebs-encryption-by-defaulton, and review their findings monthly.