Treat key recovery as part of data recovery: rewrap master keys safely, rotate data keys deliberately, and prove that backups can actually decrypt ciphertext.

Rotate Keys, Back Up Key Material, Test Recovery, and Prevent Encrypted Data from Becoming Unrecoverable

Encrypted data is only as recoverable as its key hierarchy. AtlasMart must be able to restore the key vault and Customer Master Key, distinguish CMK rewrapping from DEK rotation, and prove decryption after recovery instead of merely backing up ciphertext.

Advanced120–200 minutesKey rotation and recovery labMongoDB 8.3.8 · mongosh 2.10.0 · PyMongo 4.17.0Last reviewed: September 2026

Learning objectives

01

Distinguish Customer Master Key rotation/rewrapping from Data Encryption Key rotation and data re-encryption.

02

Back up key-vault material and CMK custody information together with encrypted data without co-locating them insecurely.

03

Explain the current CMK rewrapping invariant, then demonstrate a wrong-key recovery failure and successful restore with the original CMK.

04

Inject a recoverability failure with the wrong master key, then restore the correct key and verify decryption.

05

Design operational key deletion, rotation, escrow/recovery, and disaster tests so ciphertext never becomes permanently unreadable by accident.

Reproducible lab baseline

This lesson pins MongoDB Community Server 8.3.8 with mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim, mongosh 2.10.0, and PyMongo 4.17.0 where driver behavior is used. Topology: one disposable Community standalone named atlasmart-ch23-l5. The lab uses explicit CSFLE because it lets recovery mechanics be demonstrated without paid KMS infrastructure. The local master key and backup are disposable and must never be treated as a production storage pattern. Host publication is loopback-only on port 27185. Authentication/TLS state is stated next to the experiment. Default read/write concern and primary read preference are used unless noted. FCV is observed and never changed. The local KMS examples generate disposable 96-byte master keys at runtime and never embed a real cloud/KMIP credential. Atlas, Enterprise Advanced, AWS KMS, Azure Key Vault, GCP KMS, KMIP, and HSMs are optional production paths. Product runtime labs were not executed in the generation environment; ciphertext values, key identifiers, timings, storage amplification, and recovery results must be measured locally rather than copied as invented output.

1. Two “rotations” change different things

CMK rotation / DEK rewrapping changes the master key that protects existing DEKs. The DEK itself can remain the same, so encrypted application data does not need to be rewritten merely because the wrapping key changed. DEK rotation creates a new data key for future ciphertext; existing ciphertext encrypted under the old DEK must remain decryptable until it is explicitly re-encrypted or retired through a deliberate migration. Conflating these procedures can either cause unnecessary data rewrites or destroy access to historical ciphertext.

Operation What changes What should remain readable
CMK rotation + rewrapManyDataKey wrapped keyMaterial/masterKey metadata existing ciphertext using same DEK
new DEK for future data new key-vault document / key id old ciphertext via old DEK until migrated
data re-encryption ciphertext and referenced DEK new and old during controlled migration/rollback
key destruction / crypto-shredding ability to unwrap DEK intentionally becomes unreadable; requires governance proof

2. Create encrypted evidence and export recovery artifacts

prepare disposable MongoDB, Python encryption dependency, and two local CMKs
docker rm -f atlasmart-ch23-l5 2>/dev/null || truedocker volume rm atlasmart-ch23-l5-db 2>/dev/null || truedocker run -d --name atlasmart-ch23-l5 \  -p 127.0.0.1:27185:27017 \  -v atlasmart-ch23-l5-db:/data/db \  mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim \  --bind_ip_all --port 27017until mongosh "mongodb://127.0.0.1:27185/admin" --quiet --eval 'db.runCommand({ping:1}).ok' 2>/dev/null | grep -q 1; do sleep 1; donemongosh "mongodb://127.0.0.1:27185/admin" --quiet --eval '  printjson(db.adminCommand({buildInfo:1}));  printjson(db.adminCommand({getParameter:1,featureCompatibilityVersion:1}));' python -m venv /tmp/atlasmart-ch23-recovery-venv. /tmp/atlasmart-ch23-recovery-venv/bin/activatepython -m pip install --disable-pip-version-check "pymongo[encryption]==4.17.0"python - <<'PY'from pathlib import Pathimport osfor name in ('cmk-v1.bin','cmk-v2.bin'):    p=Path('/tmp')/name; p.write_bytes(os.urandom(96)); os.chmod(p,0o600)print('generated two independent 96-byte local test CMKs')PY
create a DEK, encrypt data, and export key-vault evidence
from pathlib import Pathfrom bson.codec_options import CodecOptionsfrom bson import BSONfrom pymongo import MongoClientfrom pymongo.encryption import ClientEncryptionclient=MongoClient("mongodb://127.0.0.1:27185")kv=client.encryption.__keyVaultkv.create_index("keyAltNames", unique=True, partialFilterExpression={"keyAltNames":{"$exists":True}})kms1={"local":{"key":Path('/tmp/cmk-v1.bin').read_bytes()}}ce1=ClientEncryption(kms1,"encryption.__keyVault",client,CodecOptions())key_id=ce1.create_data_key("local",key_alt_names=["atlasmart-recovery-key"])ct=ce1.encrypt("recover-me-2305","AEAD_AES_256_CBC_HMAC_SHA_512-Random",key_id=key_id)client.atlasmart.recovery_demo.replace_one({"_id":"demo"},{"_id":"demo","secret":ct},upsert=True)Path('/tmp/key-vault-backup.bson').write_bytes(BSON.encode(kv.find_one({"_id":key_id})))print('key_id=',key_id)print('ciphertext_type=',type(ct).__name__)print('decrypt_before=',ce1.decrypt(ct))

3. CMK rotation rewraps the DEK; it does not magically rotate data encryption

Current key-management APIs provide rewrapManyDataKey so existing DEKs can be decrypted under the old CMK and re-encrypted under a new CMK. The DEK identifier remains stable. The exact driver method signature differs by language; use the current driver API and KMS provider options. In a production cloud/KMIP flow, rotating the provider CMK and then rewrapping DEKs requires both old-key access during transition and new-key access afterward.

PyMongo-shaped CMK rewrap workflow — verify against installed API
# Continue from the previous script.from pymongo.encryption import ClientEncryptionkms_both={    "local:old":{"key":Path('/tmp/cmk-v1.bin').read_bytes()},    "local:new":{"key":Path('/tmp/cmk-v2.bin').read_bytes()},}# Named providers / rewrap parameters are provider- and driver-version sensitive.# In production, use the exact current ClientEncryption.rewrap_many_data_key API# for AWS/Azure/GCP/KMIP and verify the returned bulk write result.# The invariant to verify is: key_id is unchanged, master-key wrapping changes,# and ciphertext still decrypts with the newly configured CMK path.
Why this block is intentionally not presented as a copy/paste rewrap command

Local-provider naming and rewrap option signatures are driver-version sensitive. The lesson teaches the invariant and requires the learner to use the installed PyMongo 4.17 API documentation rather than freezing a guessed signature. The executable recovery failure below remains deterministic and edition-neutral.

4. Prove the catastrophic case safely: wrong CMK means no plaintext

attempt decrypt with the wrong local master key, then restore the right one
from pathlib import Pathfrom bson.codec_options import CodecOptionsfrom pymongo import MongoClientfrom pymongo.encryption import ClientEncryptionclient=MongoClient("mongodb://127.0.0.1:27185")ct=client.atlasmart.recovery_demo.find_one({"_id":"demo"})["secret"]wrong={"local":{"key":Path('/tmp/cmk-v2.bin').read_bytes()}}try:    ce_wrong=ClientEncryption(wrong,"encryption.__keyVault",client,CodecOptions())    print(ce_wrong.decrypt(ct))except Exception as exc:    print('expected_wrong_key_failure=',type(exc).__name__)correct={"local":{"key":Path('/tmp/cmk-v1.bin').read_bytes()}}ce_ok=ClientEncryption(correct,"encryption.__keyVault",client,CodecOptions())print('restored_plaintext=',ce_ok.decrypt(ct))

5. Backup design: encrypted data, key vault, and CMK recovery are one restore contract

Backing up only encrypted database files is incomplete if the key vault or CMK cannot be recovered. Backing up the CMK next to the database under the same access policy defeats separation. A recovery plan needs independent protected copies, restore ordering, KMS identity/permissions, integrity checks, and a periodic decrypt test using synthetic ciphertext. For cloud KMS providers, key ARN/resource IDs, regions, tenant/project ownership, IAM policy, deletion-protection windows, and network reachability all become part of recovery.

  • Back up the key-vault namespace with the same rigor as application data; retain its unique index requirements.
  • Protect CMK recovery material independently from database backups and test access from the disaster-recovery environment.
  • Record which DEKs protect which fields/collections and which key alternate names applications resolve.
  • Before destroying an old DEK, prove all required ciphertext was migrated or intentionally crypto-shredded under approved retention policy.
  • After every CMK rotation, run a decrypt smoke test against old and new representative ciphertext before removing old-key access.

6. Production judgment

Encryption creates a new failure mode: perfectly intact ciphertext can become permanently useless. Treat key loss as data loss. CMK rotation should be rehearsed, DEK rotation should have migration/rollback telemetry, key vault backups should be restored in drills, and intentionally destructive crypto-shredding should be governed like a destructive database operation. The next chapter moves below the logical encryption layer into WiredTiger pages, journaling, checkpoints, compression, and cache—mechanisms whose files may themselves be protected by Enterprise/Atlas storage encryption but whose durability behavior must still be understood independently.

Check your understanding

  1. Does CMK rotation necessarily require rewriting every encrypted application field?
  2. Does creating a new DEK automatically migrate old ciphertext?
  3. What two recovery artifacts are required in addition to ciphertext?
  4. Why is restoring a backup without decrypt testing insufficient?
  5. When is key destruction appropriate?
Review the answers

1. No. Rewrapping existing DEKs under a new CMK can preserve the DEK and existing ciphertext.

2. No. Existing ciphertext remains tied to the old key until explicitly re-encrypted or intentionally retired.

3. The key-vault data needed to locate wrapped DEKs and the CMK/KMS access needed to unwrap them.

4. The files can restore successfully while keys, KMS permissions, key-vault state, or application configuration are wrong, leaving ciphertext unreadable.

5. Only as an intentional, governed crypto-shredding action after retention/legal requirements and irreversibility have been explicitly accepted.

Authoritative references

Version-, edition-, driver-, topology-, and preview-sensitive encryption behavior was checked against current MongoDB documentation at generation time. Re-check these sources before applying the procedure to a later release.

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.