Elmiva Vault

Security / Architecture

Per-Secret Encryption Keys with Google Cloud KMS

One global encryption key is easy to explain in a diagram and painful to defend in an incident. The more honest design treats every secret as its own cryptographic unit, with its own blast radius and its own key story.

May 10, 2026 8 min read Security / Architecture

The Global Key Looks Elegant Until It Leaks

A single application-wide AES key is the kind of architecture that feels disciplined at the beginning. One environment variable. One rotation procedure. One place to monitor. Then the uncomfortable questions arrive. What happens if the key is exposed? Which ciphertexts are in scope? How do you rotate it without turning every secret into one large migration?

The answer is usually "all of them." That blast radius is too large for a system whose whole purpose is to hold unrelated credentials for different workspaces, integrations, contractors, and operational procedures. A database dump should not turn into one uniform cryptographic problem.

Vault uses envelope encryption because operational boundaries should survive cryptographic failures. Each secret receives its own encryption key material rather than sharing one global application key. That keeps the blast radius smaller and makes rotation and incident analysis easier to reason about later.

KMS Wrapping and Context Binding

Envelope encryption can still be sloppy if wrapped keys are treated as interchangeable blobs. Vault binds encryption operations to the identity of the secret itself, so the key material belongs to one object rather than to the database in general.

If cryptographic material is copied into the wrong context, it should fail safely instead of silently decrypting under the wrong object. That context binding matters because operational mistakes are often more realistic than clean textbook attacks.

The goal is not cryptographic novelty. The goal is preserving clear operational boundaries. A secret has its own key material, its own KMS binding, and its own rotation story.

The Short DEK Cache

Pure designs become dangerous when they ignore operational reality. Calling KMS for every secret reveal would reduce local key exposure, but it would also make the product fragile during latency spikes or transient infrastructure issues.

Vault keeps decrypted key material in a deliberately short-lived in-memory cache. The cache exists to smooth normal operational use without turning local process memory into a permanent key store. Rotation invalidates the old entry, and a replacement secret receives new key material.

That tradeoff is intentionally narrow. The cache is there for brief bursts of legitimate use, not for long-lived local decryption authority. Security systems become dangerous when failure behavior is vague; here, failure should be sharp enough for operators to notice.

What Never Gets Logged

Encryption protects storage, but logs are where many systems accidentally leak. Debug streams, request bodies, exception context, analytics events, and audit metadata are all tempting places to put "just enough information" to understand what happened. For a secrets product, that instinct has to be resisted.

Plaintext secret values and key material do not belong in logs. Secret reads are audited as structured events about action, actor, resource, workspace, intent, method, IP, user agent, and correlation id. The log should answer "who revealed this secret and why?" without becoming another database of sensitive payloads.

Why Encryption and Rotation Are Connected

Immutable rotation becomes much cleaner when each secret already has its own independent cryptographic identity. A replacement secret is not just a new plaintext value under the same object. It becomes a new encrypted object with its own history, references, and audit trail.

That distinction matters during incident response because the system can explain what changed instead of merely overwriting the past. If a value leaked, the replacement has a separate boundary while the old object remains part of the historical chain.

The Tradeoff Is Operational, Not Academic

Per-secret keys add complexity. The application has to treat encryption, KMS wrapping, cache lifetime, and rotation as part of one operational model. A single global key would make some of that disappear.

But the simpler design pushes complexity into the worst possible moment: breach analysis and key rotation. Per-secret envelope encryption pays a little complexity on every write so the incident story is smaller later. That is usually the right trade for a system built around operational secrets.

The architectural opinion is straightforward: secrets should not share fate just because they share a database. Each secret deserves its own cryptographic boundary, its own replacement chain, and its own audit story.