System design interview
Design a secrets manager
Envelope encryption, workload identity, path policies, audit and safe rotation.
Press Play to follow a request through the design, or step through it.
- Client and edge
- Service
- Data store
- A new service instance asks the platform to vouch for it, and receives a signed token that is valid for 10 minutes.
- It asks the secrets API for the payments database password, and presents the token.
- The API checks the token's signature, and checks the path policy, which allows this workload to read this path. It then loads the current version.
- The record holds ciphertext and a wrapped data key. The API asks the key service to unwrap the key, using a master key that never leaves it.
- The data key comes back. It is used once in memory and then dropped.
- The API appends the record: who, which path and version, allowed, and when. It waits for the write to be safe.
- The API decrypts the secret and returns it over TLS. The workload caches it for 5 minutes.
- Workload
- Identity service: signs tokens
- Secrets API: identity, policy
- Key service: master key, HSM
- Secret store: ciphertext only
- Audit log: append-only
- Rotation job: new, then revoke
- Target system: database, cloud
On this page
In 2 minutes
I would build the service around envelope encryption and short-lived identity. Each secret version is encrypted with its own data key using an authenticated cipher. The data key is wrapped by a master key that never leaves a key service backed by a hardware module, so a stolen copy of the secret store reveals nothing. Replacing the master key means re-wrapping about 500,000 small keys, around 17 minutes at a rate-limited pace so reads keep priority, and never touching the values.
Workloads carry no long-lived password. The platform signs a token that is valid for 10 minutes, and the API checks it, evaluates a deny-by-default path policy on every read, and appends a record to a hash-chained audit log before it returns the value. If the audit write fails, the read is denied. Clients cache secrets for 5 minutes, which keeps reads near 333 a second, so the store is tiny and the load is light.
Rotation is a sequence. Create the new credential in the target system, test it, publish a new version, wait longer than the cache, then revoke the old one, with progress saved so a crash can resume. If the service is down, clients keep their cached value for up to an hour and alert. The trade-off is a window with two valid credentials and a hard dependency on the audit log.
Step 1 of 6: Clarify the scope
Interviewer asks
Design a secrets manager. Services use it to fetch database passwords, API keys and certificates at startup and while they run. Every read must be authorised and recorded, a stolen copy of the database must reveal nothing, and secrets must be replaceable without an outage.
Questions to ask first
Ask these before you draw anything. Under each one is why its answer changes the design.
- Who reads secrets: running services, people, or both?
Services need automatic proof of identity with no human step. People need approvals and a loud break-glass path.
- How many secrets and readers, and how often does a reader come back?
The count is small, but the read rate depends on whether clients cache, which sets how hard the service is hit.
- Which secrets must be rotated, and how fast after a leak?
Rotation speed sets whether we need overlap windows and automation, or if a manual change is enough.
- What must the audit trail prove, and for how long do we keep it?
Auditors ask who read which secret and when. The answer decides whether the log must be tamper-evident and how much it stores.
- If the secrets service is down, may services keep running?
A service that cannot start without a secret turns this system into a single point of failure for everything.
Requirements
Functional
- Store secrets by path, with versions, and read the current or an earlier version.
- Let a workload prove its identity without holding any long-lived password.
- Allow or deny each read by a path policy, and record every decision.
- Rotate a secret by creating the new credential in the target system, with a safe overlap.
Non-functional
- A read of a secret: p99 under 50 ms. Writes can take up to a second.
- A stolen copy of the secret store reveals no secret value.
- Every read is in the audit log before the value is returned, and the log cannot be edited.
- 99.99% availability for reads, and running services survive an outage of up to 1 hour.
- The master key never leaves the key service, and is replaced at least once a year.
Step 2 of 6: Size it
The data is tiny and the read rate is modest, because clients cache. The effort goes into trust: who may read, a log that proves it, and rotation that never breaks a running service.
Assumed for the exercise, not facts about a real system:
- 20,000 workload instances, each using 5 secrets. Clients cache a secret for 5 minutes.
- 100,000 secrets with 5 retained versions each. A stored version is about 2 KB, with its wrapped key.
- Every read produces one audit record of about 300 bytes. Peak reads are 3 times the average.
- The key service can do about 2,000 wrap or unwrap operations a second.
- Reads per second
- 20,000 instances × 5 secrets ÷ 300 s cache time
- ≈ 333/s, about 1,000/s at the peak
- Reads without a client cache
- 20,000 instances × 200 calls/s each that need a password, against 333/s with a cache
- 4,000,000/s, about 12,000 times more
- Secret store size
- 100,000 secrets × 5 versions × 2 KB
- ≈ 1 GB, tiny, and it fits on one replicated database
- Audit log growth
- 333 reads/s × 86,400 s = 28.8M a day; × 300 B = 8.6 GB a day; × 365
- ≈ 3.1 TB a year
- Re-wrapping every key after a master key change
- 500,000 versions × 2 operations (unwrap, wrap) = 1M operations; at 1,000/s, leaving room for peak reads
- 1,000 s, about 17 minutes, run off-peak
Step 3 of 6: Sketch the path of one request
Step through the diagram at the top of the page to watch a request move through these parts.
A Workload first proves who it is to the Identity service, which is run by the platform and signs a short-lived token naming the workload. The workload then calls the Secrets API with that token. The API checks the token's signature and expiry, finds the policy for the path, and decides. A read that is denied is logged and refused.
The Secret store holds only ciphertext. Each secret version is encrypted with its own data key, and that key is wrapped by a master key that lives in the Key service. To read, the API fetches the record, asks the key service to unwrap the data key, decrypts in memory, and writes an entry to the Audit log before returning the value.
A Rotation job replaces credentials on a schedule. It creates the new credential in the Target system first, stores it as a new version, waits, and only then revokes the old one. It also drives re-wrapping when the master key changes.
Other paths through the system
Rotate a password
- The job creates a new password for the application's database user. The old password still works.
- The database accepts the new one. The job logs in with it to prove that it works.
- The job asks the key service for a fresh data key, and for its wrapped copy.
- The keys come back, and the job encrypts the new password with the data key.
- It writes version 8 as the current version. Version 7 stays readable as the previous one.
- After a grace period longer than the client cache, the job revokes the old password in the database.
Replace the master key
- A new master key version exists. The job reads wrapped data keys in batches of 1,000.
- It sends each batch to the key service to be re-wrapped under the new master key.
- The key service unwraps and wraps inside its own boundary, and returns only the newly wrapped keys.
- The job saves the new wrapped keys. The ciphertext is not touched, and no secret value is ever seen.
Step 4 of 6: Go deep on the hard part
Envelope encryption
Interviewer asks
How do you store secrets so that a copy of the database alone reveals nothing?
Use two layers of keys.
Read moreShow less: Envelope encryption
Each secret version gets its own random data key, and the value is encrypted with it using an authenticated cipher such as AES-GCM. The path and version are bound in as extra authenticated data, so a ciphertext cannot be copied into another record unnoticed. The data key is then wrapped, which means encrypted, by a master key held in the key service, ideally inside a hardware security module. We store the ciphertext, the wrapped key, and the id of the master key version that wrapped it.
Why a stolen database is useless. An attacker gets ciphertext and wrapped keys. Unwrapping needs the master key, and the master key never leaves the key service. The key service only does the operation for an authorised caller and logs it. So the attacker must break into the key service as well, which is a separate system with separate access.
Why not encrypt every secret directly with the master key. It would work, but envelope encryption wins in three ways. First, the master key touches only tiny data keys, so bulk data never passes through the module. Second, replacing the master key means re-wrapping 500,000 small keys, about 17 minutes at 1,000 operations a second, rate-limited so reads keep priority, and not re-encrypting every value. Third, a leaked data key exposes one version of one secret and nothing else.
Master key changes. Create a new master key version. New writes use it at once. The job re-wraps old records in the background. Old master versions stay enabled until the last record is re-wrapped, and are then disabled, not deleted, for a retention period so an old backup can still be read if needed. Deleting a master key on purpose makes every copy of data under it unreadable, which is a deliberate way to destroy data.
Starting the key service. It needs to reach its master key after a restart. With a hardware module, it authenticates to the module. Without one, the key is split into shares, and a quorum of operators, say 3 of 5, must provide them to unseal it. Either way, no single person or file holds the whole key.
Identity, policy and audit
Interviewer asks
How does a service prove who it is without a password, and how do you decide and record every read?
The first secret problem. If a service needs a password to get its passwords, we have only moved the problem.
Read moreShow less: Identity, policy and audit
So the workload holds no long-lived credential. The platform that runs it, such as the orchestrator or the cloud provider, vouches for it by signing a short-lived token that names the workload: its service account, environment and namespace. The token lives for about 10 minutes. The secrets API checks the signature with the platform's public keys, which it caches, and checks the expiry and that the token was meant for this service. A stolen token is useful for minutes, and it can also be tied to the workload's mutual TLS certificate.
Policies. Deny by default. A policy says that an identity pattern may do certain actions on a path prefix. For example, the payments service in production may read anything under the payments path, and nothing else. Actions are separate: read, write, list and rotate. An explicit deny beats any allow. The person who writes a secret should not be the identity that reads it. Evaluate on every read. Nodes may hold policies in memory, but they are updated by a push with a version number, and an old policy is never used for more than about a minute.
Humans. People get access through approval, with a short time limit, and the approval itself is logged. A break-glass path exists for emergencies. It works at once but pages the security team and is reviewed afterwards.
The audit log. Each read adds a record: time, caller identity, path, version, action, decision, request id and source address. Never the value. Write it before returning the secret, and if the write fails, deny the read, because a read nobody can see is the thing the log exists to prevent. Make it tamper-evident: each record includes a hash of the one before, and a signed checkpoint is copied every few minutes to a separate account that the secrets admins cannot write to. At 300 bytes a record, a year is about 3.1 TB, which cold storage handles easily. Alert on new readers of a sensitive path, and on a sudden jump in volume.
Rotation and failing safe
Interviewer asks
How do you replace a secret that dozens of services are using without breaking any of them?
Versions. A write never overwrites.
Read moreShow less: Rotation and failing safe
It creates version n+1 and moves the current pointer. The previous version stays readable for a while. A caller can ask for current or for a specific version.
The overlap. Clients cache a secret for about 5 minutes, and a rolling deploy can last longer. If the old password stopped working the moment the new one appeared, every instance with a cached copy would fail. So rotation is a sequence, and the target system accepts both credentials in the middle of it:
- Create first. The job creates the new credential in the target system. The old one remains valid.
- Test. It uses the new credential to log in. If this fails, stop. Nothing has changed.
- Publish. It stores the new value as the current version and keeps the old one as the previous version.
- Wait. Hold for a grace period longer than the client cache and a deploy, such as an hour.
- Revoke. It disables the old credential in the target and marks the old version retired.
The job records its progress in the store after each step, so a crash resumes at the right step and every step can be repeated safely. For databases, two users used in turns work well: rotate the idle one, switch the current pointer, and leave the other valid until the next cycle.
Clients. The client library caches the secret with a TTL plus random jitter, and refreshes before it expires. If the target rejects the credential, the library fetches again at once, one time. That repairs a missed rotation without a human.
Failing safe. If the secrets service cannot be reached, the client keeps using its cached value, even past its TTL, for up to an hour, and raises an alert. An instance starting with no cache and no service stops and retries, because starting with a blank password helps nobody. Run the API and the key service in three zones, so reads stay up when a zone is lost.
Step 5 of 6: Name the trade-offs
How values are encrypted
A data key per version, wrapped by a master key over Encrypt each value directly with the master key
Rotating the master key re-wraps small keys, and one leaked key exposes one version. The cost is an extra key to store and manage with every record.
How a workload proves who it is
A 10-minute token signed by the platform over A static token stored in each service's config
Nothing long-lived can be stolen from a file or a log. The cost is a dependency on the platform's identity service at startup and each refresh.
If the audit write fails
Deny the read over Return the secret and retry the log write
No read ever goes unrecorded. The cost is that a log outage becomes a read outage, so the log needs its own high availability.
Replacing a credential
Create the new one, overlap, then revoke the old one over Swap the credential in one step
Cached copies and rolling deploys keep working. The cost is a window where two credentials are valid, and a longer rotation.
Step 6 of 6: Say what breaks next
Questions an interviewer asks once the design is on the board. Answer each one out loud first.
- What are dynamic secrets, and when would you use them?
The service creates a fresh credential for each requester on demand, for example a database user that lives for one hour, and deletes it afterwards. There is nothing to rotate and each reader is traceable. The cost is that the target system must handle a burst of new accounts.
- What happens if the key service is down?
New reads fail, because no key can be unwrapped. Running services keep going on their cached values for up to an hour, which is why the client cache matters. Run the key service in three zones, and practise losing one.
- How do you stop secrets from leaking into logs and config files?
Pass secrets to the process in memory, not on a command line or in environment dumps. Mark secret fields so logging code masks them, and scan code and logs for known secret formats. A secret found in a log is treated as leaked and rotated.
- How would you handle a secret that is leaked right now?
Trigger an immediate rotation, with a short grace period, and revoke the old credential. Use the audit log to see who read the old version and when. Deny the leaked workload's identity until it is cleaned up.