Encrypting databases at rest: the basics
Why every managed database engine has its own version of the same finding
Every managed database on AWS stores its data on disk, and "at rest" encryption scrambles those bytes with an AWS KMS key so a stolen snapshot, a mis-shared backup or a compromised volume reveals ciphertext instead of customer records. Each engine expresses the same property in its own shape: RDS.3 and RDS.4 cover RDS instances and their snapshots, DocumentDB.1 covers DocumentDB clusters, Neptune.1 and Neptune.6 cover Neptune clusters and snapshots, Redshift.10 covers Redshift clusters, DynamoDB.3 covers DynamoDB tables that should use a customer-managed key, ElastiCache.4 covers replication-group storage, and Opensearch.1 and Opensearch.3 cover OpenSearch domain storage and node-to-node traffic. Different APIs, identical risk: a data store readable on disk.
AWS Security Hub turns each engine into its own control, so a single estate can fail ten or more at-rest encryption checks at once. They look like separate problems on the report, but they are one capability: prove that the bytes on disk for every database, and every snapshot derived from it, are encrypted under a key you can govern. The bytes themselves are protected with AES-256; the value is in the KMS key boundary, which lets you authorise, log and revoke access to the data without touching the database itself.
The trait that makes this capability sharp is that, for most of these engines, encryption is chosen at creation and cannot be toggled on afterwards. RDS, DocumentDB, Neptune and OpenSearch all bind encryption to the storage allocation, so there is no modify flag to flip. The supported path is to snapshot, copy the snapshot with a KMS key (the copy is where encryption is applied), restore a new encrypted cluster and cut over. Redshift is the exception that proves the rule: modify-cluster runs a background migration. Either way, the cost of fixing it only grows as the database accumulates data, which is the whole argument for catching it early.
In this lesson you will learn how AWS expresses encryption at rest across its database engines, why most of them make encryption immutable at creation time, the snapshot-copy-restore migration that is the only supported fix for the immutable engines (and the in-place migration that Redshift offers instead), and how to stop new unencrypted databases from ever appearing. The Controls this lesson covers section lists every Security Hub control in this capability, each linking to a deep page with the exact check and a copy-and-paste fix.
The setting you can never change your mind on
For most AWS database engines, at-rest encryption is one of the very few settings that is genuinely immutable for the life of the resource. You choose it at create time and that is it: there is no modify-db-instance flag for RDS storage encryption, no in-place enable for DocumentDB or Neptune, and no way to encrypt an existing OpenSearch domain. The architectural reason is that encryption is applied at the storage layer beneath the engine, so flipping it would mean rewriting every block in place, which the services simply do not offer. The only way across the boundary is to snapshot, copy the snapshot with the KMS key you want, and restore a brand-new resource from the encrypted copy. Redshift is the notable exception, where modify-cluster runs a background migration for you, but it is still a migration, not a toggle.
Finding unencrypted databases across an estate
Priya is the platform lead at a scale-up preparing for its first SOC 2 audit. Security Hub shows at-rest encryption failures spread across RDS, Redshift and OpenSearch in three accounts that pre-date the team's current encryption standard.
Rather than work the findings engine by engine, she starts by listing what is actually unencrypted across the database fleet, so she can separate the regulated-data stores that need migrating first from the throwaway ones that can simply be deleted.
Start with RDS, the most common and highest-impact failure. The StorageEncrypted field is exactly what RDS.3 evaluates.
Inventory first: prioritise the regulated-data stores, not the order the report lists them.
How AWS encrypts database storagedeep dive
Across these engines, encryption at rest is an AES-256 envelope scheme keyed by KMS, applied at the storage layer beneath the database. A per-resource data key encrypts the data blocks, and that data key is itself wrapped by a KMS key, either the AWS-managed key for the service (such as aws/rds or aws/es) or a customer-managed key you specify. Only the bottom keys ever touch the data; the upper tiers exist so that key rotation and access revocation happen without re-encrypting terabytes of blocks. Revoke access to the KMS key and the whole chain becomes unusable, which is the access-management property the controls are really about.
Snapshots inherit the encryption state of their source. An unencrypted RDS, Redshift or Neptune instance produces unencrypted snapshots, and those snapshots can be copied cross-region or shared cross-account, so plaintext copies propagate far from the original and persist long after the source is gone. Encrypting the source going forward does not retroactively encrypt snapshots already taken, which is why RDS.4, Neptune.6 and the snapshot-sharing controls are tracked separately: you have to find and re-encrypt or delete the legacy snapshots as their own step.
Security Hub evaluates these through AWS Config rules such as rds-storage-encrypted, redshift-cluster-kms-enabled and elasticsearch-encrypted-at-rest. Some are change-triggered (they clear shortly after a fixed resource registers) and some are periodic (they clear on the next scheduled evaluation, not instantly), which matters when you are gathering audit evidence against a deadline. Two engines deserve a note: DynamoDB is always encrypted, so DynamoDB.3 specifically wants a customer-managed key rather than the default; and Opensearch.3 covers node-to-node encryption, the in-cluster traffic between data nodes, which is distinct from on-disk storage but lives in the same hardening pass.
What is the impact of leaving a database unencrypted?
The direct impact is data exposure. An unencrypted database stores customer records, credentials, financial data and PII as plaintext on the underlying disks and in every backup and snapshot it produces. If any of those artefacts leaks (a snapshot shared to the wrong account, a backup copied to an unsecured bucket, a storage-layer compromise) the data is immediately readable. Encryption at rest is the control that turns that worst case from a reportable breach into a non-event, because the leaked copy is ciphertext without the KMS key.
The compliance impact is where these controls earn their weight. Encryption of data at rest is an explicit requirement in PCI DSS, a near-universal expectation in SOC 2 reports, and a control under HIPAA, ISO 27001 and most NIST-based regimes (SC-13 and SC-28). A single unencrypted production database holding regulated data is the kind of finding an auditor circles, that delays a certification, or that has to be disclosed in a vendor security questionnaire. The Medium severity that Security Hub assigns most of these controls understates the regulatory consequence.
The structural impact is the immutability constraint itself. Because most engines cannot toggle encryption on later, every unencrypted database is a standing liability that grows more painful to fix as it accumulates data and dependencies. A 20 GB database is a quick migration; a 4 TB cluster with tight uptime is a planned project. The cost of inaction is not a monthly dollar figure: it is the compounding difficulty of the eventual, unavoidable migration, plus every unencrypted snapshot that piles up in the meantime.
How do you encrypt the database estate safely?
Work the capability as one loop rather than chasing individual engine findings. The order matters: inventory and prioritise by data sensitivity, migrate the immutable engines via snapshot-copy-restore (or in place for Redshift), clean up legacy unencrypted snapshots, then enforce encryption by default so the gap cannot reopen.
1. Inventory every database and prioritise by data sensitivity
List every RDS, Aurora, DocumentDB, Neptune, Redshift, DynamoDB, ElastiCache and OpenSearch resource with its encryption flag, engine, size and the classification of what it holds. Do not treat all findings equally: an unencrypted throwaway dev database may simply be deleted, while a production database with customer records is the urgent one. Sort by data sensitivity and uptime sensitivity so the migration effort goes where the exposure actually is.
2. Migrate the immutable engines: snapshot, copy with a KMS key, restore
For RDS, DocumentDB, Neptune and OpenSearch there is no in-place toggle. Take a snapshot of the source (it is unencrypted), copy the snapshot passing a KMS key (the copy is where encryption is applied), then restore a new resource from the encrypted copy. Reapply the original parameter group, security groups and subnet group. For large databases, do the bulk restore ahead of time and schedule a short maintenance window for the final delta and the endpoint cutover. Only delete the old unencrypted resource after verifying the new one is healthy.
3. Use the in-place path where the engine offers one
Redshift is the exception: modify-cluster with --encrypted runs a background migration that provisions a new encrypted cluster and copies data across while the original stays readable, so plan it in a low-traffic window because write throughput dips. DynamoDB is always encrypted, so DynamoDB.3 is satisfied by updating the table to a customer-managed key, no migration needed. ElastiCache and the node-to-node OpenSearch control are configuration changes rather than data migrations. Match the path to the engine.
4. Clean up legacy snapshots and enforce encryption by default
Encrypting a cluster does not encrypt snapshots taken before the change, so find and delete or re-encrypt the legacy unencrypted snapshots before they are shared or copied. Then prevent recurrence: enable encryption-by-default where the engine supports it, and back it with a Service Control Policy or AWS Config rules (such as rds-storage-encrypted) that flag or deny creation of an unencrypted database. That converts these controls from a recurring cleanup chore into a one-time migration followed by a prevention guardrail.
# 1. Find unencrypted databases across engines (sample: RDS, Redshift, OpenSearch).
aws rds describe-db-instances \
--query 'DBInstances[?StorageEncrypted==`false`].DBInstanceIdentifier' --output text
aws redshift describe-clusters \
--query 'Clusters[?Encrypted==`false`].ClusterIdentifier' --output text
# 2. Immutable engine (RDS): snapshot, copy WITH a KMS key, restore the new instance.
SRC=prod-orders-db; KEY=alias/db-encryption
aws rds create-db-snapshot --db-instance-identifier $SRC --db-snapshot-identifier ${SRC}-snap
aws rds wait db-snapshot-completed --db-snapshot-identifier ${SRC}-snap
aws rds copy-db-snapshot \
--source-db-snapshot-identifier ${SRC}-snap \
--target-db-snapshot-identifier ${SRC}-snap-enc \
--kms-key-id $KEY
aws rds wait db-snapshot-completed --db-snapshot-identifier ${SRC}-snap-enc
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier ${SRC}-enc --db-snapshot-identifier ${SRC}-snap-enc
# 3. In-place engine (Redshift): background migration, run in a maintenance window.
aws redshift modify-cluster --cluster-identifier analytics-prod \
--encrypted --kms-key-id $KEY
# 4. Prevent recurrence: enforce encryption by default for new EBS-backed engines.
aws ec2 enable-ebs-encryption-by-default Quick quiz
Question 1 of 5Security Hub shows at-rest encryption failures across RDS, DocumentDB, Neptune and OpenSearch. What is the most efficient way to think about them?
You scored
0 / 5
Keep learning
Go deeper on how at-rest encryption works across the database engines in this capability.
- Encrypting Amazon RDS resources How RDS encryption at rest works, the immutability constraint, and the snapshot-copy-restore migration path.
- Amazon Redshift database encryption The KMS key hierarchy and the in-place migration that enabling encryption on an existing cluster runs.
- Encrypting Amazon DocumentDB data at rest Why DocumentDB encryption is set at creation, and how to satisfy DocumentDB.1 via the snapshot-copy path.
You can now treat database encryption at rest as one capability rather than a scatter of engine-specific findings: inventory every store, prioritise the regulated-data ones, migrate the immutable engines via snapshot-copy-restore (or modify in place for Redshift and DynamoDB), clean up legacy unencrypted snapshots, and enforce a default so the gap cannot reopen. The Controls this lesson covers section below links every control in this group to its deep page and fix.
Back to the library