You checked your EC2 console, opened the Volumes view, and noticed it: the Encrypted column on your root volume says No. You probably launched that instance from a community AMI a year or two ago, before AWS started defaulting to encrypted EBS in most regions. Everything since then — your OS, your app code, your customer data, your secrets — has been sitting on an unencrypted block device. Snapshots inherit that state, AMIs you shared with another account inherited it, and any future restore continues to inherit it until you do something about it.
This guide walks through how to fix that without rebuilding the box from scratch. The path is well-known to anyone who has done it before, and full of small AWS-specific traps if you haven’t. The summary: you cannot encrypt an existing EBS volume in place. You snapshot it, copy the snapshot with encryption enabled, create a new volume from the copy, and swap the root. That’s it — but every step has at least one way to get wrong on the first try.
It pairs naturally with the Ubuntu/Debian EC2 hardening checklist and the AWS IMDSv2 migration guide — same broader topic: tightening cloud posture on workloads that were launched before you cared about any of this.
Why this matters
The standard pushback on “we should encrypt EBS” is: the disk never leaves AWS’s data center, so what are we protecting against? That argument misses where the risk actually lives.
- Snapshots and AMIs are portable. An unencrypted snapshot can be shared to another AWS account or made public with a single API call. An encrypted snapshot can’t — sharing requires KMS grants. The encryption flag is a hard guard against accidental cross-account data leakage, including the classic “I made this AMI public to debug something” mistake.
- KMS gives you a second access-control layer. With unencrypted EBS, anyone with
ec2:CreateVolumeandec2:AttachVolumeon the snapshot can mount it on a new instance and read everything. With KMS, they also needkms:Decryptand (often)kms:CreateGranton the key. That separation is the single biggest practical reason to encrypt — it forces a deliberate second permission for “I want to actually read this data”. - Compliance, even the informal kind. SOC 2, ISO 27001, PCI, HIPAA, most state privacy laws, and most enterprise customer security questionnaires ask whether data at rest is encrypted. The honest answer for an unencrypted EBS volume is “no”. Encrypted-with-KMS gets you a clean “yes” with zero application changes.
- Future-proofing. AWS now enables “Always encrypt new EBS volumes” by default in most regions for new accounts. Older accounts keep their old default. New volumes you create going forward will be encrypted; the old one keeps being the outlier. Migrating now eliminates the special case before it becomes the only special case left.
None of this changes how your app behaves. EBS encryption is transparent. The OS doesn’t know. The application doesn’t know. There is no measurable performance hit on current-generation instance types. The reason most people haven’t done it is that the migration is fiddly, not that the destination is.
What “enable default encryption” does and doesn’t fix
In EC2 → Account attributes → EBS encryption, there’s a setting called Always encrypt new EBS volumes. Turning it on is good and you should do it. But understand what it does:
- ✅ New volumes you create from scratch are encrypted.
- ✅ New snapshots you take of already-encrypted volumes stay encrypted.
- ✅ Volumes restored from encrypted snapshots stay encrypted.
- ❌ Existing unencrypted volumes are not retroactively encrypted.
- ❌ Snapshots of existing unencrypted volumes are not encrypted by default — they inherit the source’s state.
That last point trips people up. Once “default encryption” is on, you might assume taking a fresh snapshot of an old volume gives you an encrypted snapshot. It does not. Snapshots match the source volume’s encryption state. You have to make the encrypted copy explicit, which is exactly what the migration path below does.
So step zero is: flip on default encryption for the region (EC2 → Account attributes → EBS encryption → Always encrypt new EBS volumes), pick a default KMS key (aws/ebs is fine to start, or a CMK you control), and then deal with the old volume.
The two migration paths
You have two viable options for the root volume itself. Pick based on how much downtime you can take and whether you want to swap instance types or AMIs at the same time.
Path A — Swap the root volume on the same instance (downtime path)
Same instance ID, same Elastic IP, same security groups, same instance profile, same launch template. You take a planned outage (typically 5-15 minutes), encrypt the volume, swap it back in, boot, verify.
Use Path A when: - The instance has external state (Elastic IP attached directly, hard-coded references to the instance ID, attached IAM role, manually-created security group memberships) you don’t want to redo. - You’re fine with a single short maintenance window. - You haven’t already planned an OS or AMI refresh.
Path B — Build a new instance from an encrypted AMI (rebuild path)
Snapshot → copy with encryption → create AMI → launch a fresh instance from the encrypted AMI → swap the Elastic IP (or DNS) → terminate the old box.
Use Path B when: - You also want to refresh the OS or instance type. - You can run two instances side-by-side briefly and cut over with a CNAME or EIP move. - You’d rather not stop a production box, even briefly. - The instance has accumulated hand-applied config you’d like to leave behind anyway.
Path B is more cleanup work but lower risk because the old volume stays untouched until you’re confident the new instance is healthy. Path A is faster and surgical.
The rest of this guide focuses on Path A, because that’s what most solo operators on a single-box deployment actually want. The same KMS copy step is the core of Path B; the difference is what you do with the resulting AMI afterwards.
Mid-article CTA: Want a read-only audit that tells you which EBS volumes in your account are still unencrypted — plus open security groups, IMDSv1 stragglers, exposed IAM users, and a few other “you’d rather know” items? That’s exactly what QuickCheck is built for. One run, plain-English report, no install on your account.
Path A: Step-by-step
1. Inventory and prepare
First, capture the things you’ll need to put back.
INSTANCE_ID=i-0123456789abcdef0
REGION=us-east-1
aws ec2 describe-instances \
--instance-ids "$INSTANCE_ID" \
--region "$REGION" \
--query 'Reservations[0].Instances[0].{
AZ:Placement.AvailabilityZone,
Root:RootDeviceName,
RootVol:BlockDeviceMappings[?DeviceName==`/dev/xvda` || DeviceName==`/dev/sda1`].Ebs.VolumeId | [0],
Type:InstanceType,
AMI:ImageId
}'
Write down AZ, Root (will be /dev/xvda or /dev/sda1 — the difference matters in step 5), and RootVol (the source volume ID).
Pick the KMS key you’ll encrypt with. The default AWS-managed alias/aws/ebs is fine for most setups; use a customer-managed key (CMK) if you want explicit grant control or cross-account isolation later.
KMS_KEY_ID="alias/aws/ebs" # or arn:aws:kms:us-east-1:<acct>:key/<uuid>
Confirm your caller can actually use that key for encrypt-decrypt — the migration fails late if it can’t:
aws kms describe-key --key-id "$KMS_KEY_ID" --region "$REGION" \
--query 'KeyMetadata.{KeyState:KeyState,KeyUsage:KeyUsage,Arn:Arn}'
KeyState must be Enabled and KeyUsage must be ENCRYPT_DECRYPT.
2. Stop the instance
EBS root volumes can only be detached when the instance is stopped. There is no online path for the root. Plan a maintenance window now.
aws ec2 stop-instances --instance-ids "$INSTANCE_ID" --region "$REGION"
aws ec2 wait instance-stopped --instance-ids "$INSTANCE_ID" --region "$REGION"
This is the start of your downtime clock. From here, the only thing protecting you is that the original volume still exists and is unmodified.
3. Snapshot the unencrypted volume
SRC_VOL=vol-0aaaabbbbccccdddd0 # from step 1
SNAP_ID=$(aws ec2 create-snapshot \
--volume-id "$SRC_VOL" \
--description "pre-encryption snapshot of $SRC_VOL" \
--region "$REGION" \
--query 'SnapshotId' --output text)
aws ec2 wait snapshot-completed --snapshot-ids "$SNAP_ID" --region "$REGION"
echo "Source snapshot: $SNAP_ID"
This snapshot is unencrypted (inherits source state). It’s also your rollback insurance for the rest of the migration — do not delete it until you’re done and verified.
4. Copy the snapshot with KMS encryption
This is the only step in the whole process where encryption actually happens. It’s a same-region copy with --encrypted and a key ID.
ENC_SNAP_ID=$(aws ec2 copy-snapshot \
--source-region "$REGION" \
--region "$REGION" \
--source-snapshot-id "$SNAP_ID" \
--description "encrypted copy of $SNAP_ID" \
--encrypted \
--kms-key-id "$KMS_KEY_ID" \
--query 'SnapshotId' --output text)
aws ec2 wait snapshot-completed --snapshot-ids "$ENC_SNAP_ID" --region "$REGION"
echo "Encrypted snapshot: $ENC_SNAP_ID"
Confirm it’s actually encrypted:
aws ec2 describe-snapshots --snapshot-ids "$ENC_SNAP_ID" --region "$REGION" \
--query 'Snapshots[0].{Encrypted:Encrypted,KmsKeyId:KmsKeyId}'
You want "Encrypted": true and a KmsKeyId ARN that matches the key you used.
5. Create the new encrypted volume in the right AZ
This is the single most common place to lose 20 minutes. The new volume must be in the same Availability Zone as the instance. EBS volumes are AZ-scoped; you can’t attach a us-east-1a volume to a us-east-1b instance.
AZ=us-east-1b # from step 1
NEW_VOL=$(aws ec2 create-volume \
--snapshot-id "$ENC_SNAP_ID" \
--availability-zone "$AZ" \
--volume-type gp3 \
--encrypted \
--kms-key-id "$KMS_KEY_ID" \
--region "$REGION" \
--query 'VolumeId' --output text)
aws ec2 wait volume-available --volume-ids "$NEW_VOL" --region "$REGION"
echo "New encrypted root: $NEW_VOL"
Notes:
- gp3 is the modern default. If your old volume was gp2 or io1, this is a fine moment to upgrade. gp3 is cheaper than gp2 at equivalent performance.
- If you need a specific size (larger than the snapshot), add --size N in GiB. You can grow but not shrink.
6. Detach the old root, attach the new one
aws ec2 detach-volume --volume-id "$SRC_VOL" --region "$REGION"
aws ec2 wait volume-available --volume-ids "$SRC_VOL" --region "$REGION"
# Use the ROOT device name from step 1 — /dev/xvda for Nitro Ubuntu/Amazon Linux 2+
# Use /dev/sda1 for older Xen-virt instance types
ROOT_DEV=/dev/xvda
aws ec2 attach-volume \
--instance-id "$INSTANCE_ID" \
--volume-id "$NEW_VOL" \
--device "$ROOT_DEV" \
--region "$REGION"
aws ec2 wait volume-in-use --volume-ids "$NEW_VOL" --region "$REGION"
Get the root device name wrong and the instance will refuse to boot — it can’t find the kernel because EC2 looks at RootDeviceName to know what to chain-load. Check Root from step 1, not your assumptions.
7. Start the instance and verify
aws ec2 start-instances --instance-ids "$INSTANCE_ID" --region "$REGION"
aws ec2 wait instance-running --instance-ids "$INSTANCE_ID" --region "$REGION"
SSH in and confirm:
lsblk -f
# nvme0n1p1 (or xvda1) should be your root /, mounted, ext4/xfs, same UUID as before
mount | grep ' on / '
# Should show your root device
aws ec2 describe-volumes --volume-ids "$NEW_VOL" \
--query 'Volumes[0].{Encrypted:Encrypted,KmsKeyId:KmsKeyId}'
# Encrypted: true, KmsKeyId: matches your key
Run your app’s health check. If it had systemd services, systemctl --failed should be empty. Check that any external monitoring is green.
8. Clean up
Once you’re confident — wait a day or two on stateful boxes — delete the old unencrypted volume and the unencrypted snapshot.
aws ec2 delete-volume --volume-id "$SRC_VOL" --region "$REGION"
aws ec2 delete-snapshot --snapshot-id "$SNAP_ID" --region "$REGION"
# Keep $ENC_SNAP_ID — it's your encrypted baseline going forward.
Pitfalls to know up front
A few traps that have caused real outages:
- AZ mismatch on create-volume. Already covered, worth repeating. The error message reads
InvalidParameterValue: The Availability Zone is not the same. Recreate the volume in the right AZ; cost is just the create/delete time. - Root device name
/dev/xvdavs/dev/sda1vs/dev/nvme0n1. The AWS API root device name is/dev/xvdaor/dev/sda1. The kernel may surface the volume as/dev/nvme0n1. Use the API name forattach-volume --device; the kernel name is irrelevant at attach time. - KMS permission gaps. If you’re using a CMK in a different account, or restricting your IAM role tightly, you need
kms:Decrypt,kms:GenerateDataKeyWithoutPlaintext,kms:ReEncrypt*,kms:CreateGrant, andkms:DescribeKeysomewhere in the chain. The error isOptInRequiredorInvalidKmsKey. Don’t grantkms:*on the key to make it go away — grant exactly those five. - Forgetting the instance profile. Detaching and reattaching volumes does not touch the IAM role on the instance. But if you were using IMDSv1 and your migration coincides with an AMI change, double-check the role survived. Pair this work with the IMDSv2 migration and you only do the maintenance window once.
- Application state outside the root volume. If your app keeps data on a secondary EBS volume, encrypt that one too with the same process. Root encryption alone leaves your real data unencrypted on disk, which is the worst possible posture: you get the operational cost of the migration with none of the actual data protection.
- Backups inherit, but old backups don’t migrate. Once the volume is encrypted, AWS Backup / DLM snapshots inherit the encryption. Old snapshots from before today are still unencrypted. Either re-snapshot via the same copy-with-encryption trick or expire them through retention policy.
Rollback plan
You should write this down before you start, not figure it out at 11 p.m.
If the new volume won’t boot:
# 1. Stop the instance again
aws ec2 stop-instances --instance-ids "$INSTANCE_ID" --region "$REGION"
aws ec2 wait instance-stopped --instance-ids "$INSTANCE_ID" --region "$REGION"
# 2. Detach the new (broken) volume
aws ec2 detach-volume --volume-id "$NEW_VOL" --region "$REGION"
aws ec2 wait volume-available --volume-ids "$NEW_VOL" --region "$REGION"
# 3. Reattach the original unencrypted volume as the root
aws ec2 attach-volume \
--instance-id "$INSTANCE_ID" \
--volume-id "$SRC_VOL" \
--device "$ROOT_DEV" \
--region "$REGION"
# 4. Start the instance
aws ec2 start-instances --instance-ids "$INSTANCE_ID" --region "$REGION"
You are now back where you started, with the encrypted copy intact for forensic investigation of why the boot failed. Typical causes: wrong root device name, the volume was created in the wrong AZ and silently attached as a non-root device, or the source volume had a corrupt boot record that the snapshot faithfully preserved.
Do not delete $SRC_VOL or $SNAP_ID until rollback is no longer a concern — typically 24-72 hours of successful operation.
What this is not
To set expectations clearly:
- This is not full-disk encryption against a local-machine threat model. KMS-encrypted EBS protects data at rest as managed by AWS. It does not stop a process running on the live instance from reading its own filesystem. For that, you need LUKS or filesystem-level encryption on top, with key management of your own — a separate project.
- This is not a compliance attestation. Migrating to encrypted EBS is a posture improvement, not a certification. Your SOC 2 / ISO / HIPAA auditor will still want to see your key management policy, KMS key rotation status, and the inventory query that proves all volumes are encrypted, not just the one you remembered.
- This is not a guarantee. EBS encryption closes a specific cross-account data leakage path and gives you a KMS-grant access boundary. It does not address misconfigured security groups, leaked long-lived IAM keys, S3 buckets without encryption, or application vulnerabilities. Treat it as one item on the list.
Encrypt EBS because it is cheap, well-understood, and removes a real foot-gun in your snapshot and sharing surface. Then keep going on the rest of the list.
QuickCheck CTA
If you’d rather not write the inventory queries to find every unencrypted volume across every account and region — and then chase down the missing KMS grants, the public AMIs, and the other quiet posture issues that pile up over time — QuickCheck runs a read-only, one-shot review of your AWS posture and produces a plain-English report. Unencrypted EBS volumes are one of the dozen items it surfaces, alongside open security groups, IMDSv1 stragglers, missing MFA on root, untagged keys, and a few other “you’d rather know” things. See an example in the sample report. Not magic, not a replacement for proper cloud security tooling, but a fast way to know where you stand.
About Tuck Sentinel
Tuck Sentinel is the security-focused side of an indie operator workshop by Rich Gibbs. It builds small, sharp tools — like QuickCheck — for founders and small teams who want a competent read of their cloud posture without an enterprise platform. The bias: fast, honest, read-only assessments and migrations you can actually finish.
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Encrypting Your EBS Root Volume Without Rebuilding the Server (AWS 2026)",
"description": "A practical, indie-founder guide to migrating an unencrypted EC2 root volume to KMS-encrypted EBS — without rebuilding the instance, losing data, or fighting AZ mismatch and root device name traps.",
"author": {
"@type": "Organization",
"name": "Tuck Sentinel"
},
"publisher": {
"@type": "Organization",
"name": "Tuck Sentinel",
"url": "https://richgibbs.dev/"
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://blog.richgibbs.dev/encrypting-ebs-root-volume-without-rebuilding/"
},
"image": "https://blog.richgibbs.dev/static/og-default.png",
"articleSection": "Cloud Security",
"keywords": "AWS, EC2, EBS, KMS, encryption, cloud security, snapshot, migration",
"about": [
{ "@type": "Thing", "name": "AWS EBS encryption" },
{ "@type": "Thing", "name": "AWS KMS" },
{ "@type": "Thing", "name": "Cloud Security Posture" }
]
}