Answers · Keeping it safe
How do I stop one service from reading another service's password?
In shortGive every service its own identity, grant only the credentials it uses, and test that it cannot read another service's password.
Give each service its own identity and grant that identity only the credentials it actually opens at run time. Then test the claim by presenting one service's identity and trying to read a password that belongs to another service: the read has to fail, and the refusal has to be recorded.
Scope the identity, not the location
The natural guess is that two services in the same namespace, the same virtual network or the same cluster can be trusted with each other's passwords. That guess fails because location is not authorisation. The secret store answers a request based on the identity presented, not on which subnet the request came from. If the image resizer and the payments worker present the same identity, they are the same principal to the store, and the image resizer can read the payment key, the signing key, the mail credentials and the database password. The image resizer is also the component most likely to be running somebody else's code, since it parses files uploaded by strangers. A shared identity makes every compromise as wide as the estate.
Put numbers on that product. If the estate has 12 identities and each can read 40 credentials, the grants in force are . If each identity is cut to the one credential its own code opens, the same 12 identities give grants. The reduction is grants. None of those 468 were doing useful work; they were reach. Scoping does not reduce the number of identities or the number of credentials. It reduces the second factor, and the product is what an attacker gets after one component falls.
- total grants in force
- identities in the estate
- credentials each identity may read
Grant the list the code opens
Do not build that list by asking the team what the service needs. The answer from memory names the obvious database and the obvious queue, and omits the metrics backend, the feature flag service, the internal search index and whatever a script added two years ago. Read the code instead: grep for every place a connection is opened and list the credentials those connections need. Then watch a full reporting cycle of what the component actually reads from the store, because the path that only runs during the quarterly job is the one that breaks. Grant exactly that list to a new identity, deploy it to one instance first, and leave the old grant in place until the reporting cycle has passed. Then remove the old grant.
The credential that is the same everywhere
There is one arrangement that defeats all of the above. Every service connects to the same database as the same database user. The secret store can have an identity per component and a careful grant for each, and it achieves nothing for that credential, because the value each component is permitted to read is the same value. If the payments worker and the report generator both read a password called app_rw, scoping who may read app_rw does not stop either one from using it. The fix is at the database end: give each component its own database account, its own password, and privileges matching what it does. Read-only where it only reads, no access to tables it never touches. Then the scoped credentials are different values, and the store-side scoping means something.
Where scoping stops
If two components genuinely need the same secret value, scoping the store cannot separate them. You have to separate the capability at the resource, as with per-component database accounts, or accept that the two components are one principal. The same limit applies to a credential baked into an image or copied into an environment variable that every process can read. Scoping the identity is not enough when the value is already present in the filesystem beside the code.
The test is the control. Present the image resizer's identity and attempt to read the payments worker's password. If the read succeeds, the scoping does not exist and the diagram is fiction. If it fails and nothing is recorded, the limit exists but you will never learn that anybody tried, which is half a control. If it fails and a line appears naming the identity, the target and the time, you have both the limit and the evidence. Do that before removing the old grant, because an untested scoping claim is usually wrong.
Worth keeping
- A shared identity makes every compromise as wide as the estate.
- Scoping the secret store does nothing if every service still uses the same database password.
- An untested scoping claim is usually wrong.
Where this goes next
This question is one step of Keeping a Secret in Production, a course that works through its subject from the beginning. The page that teaches this part of it is Deciding Who May Read It, and it reads the whole way through whether or not you have an account.
What an account changes is the practice: problems standing under every idea, marked with a reason rather than a tick, in a copy of the course that is yours.
Read that pageThe whole courseOther questions people ask about this
- Are environment variables safe for storing passwords?No: environment variables are convenient, but they are inherited by child processes, visible to process inspection and crash reports, and no record is kept when a password is read from them.
- Is a TLS certificate itself a secret?No. The certificate is public and is sent to every client that connects. The private key kept beside it is the secret, and it is one of the highest value credentials you hold.
- How does text I saved in a comment end up running as JavaScript in someone else's browser?The comment stayed text in storage; a page that later pasted it into its own markup made the browser read it as code.
- Why does escaping the quotes in user input not stop SQL injection?Escaping quotes only cleans one context; SQL injection stops only when query text and values travel separately, so the value is never parsed as code.
- Why isn't encrypting the password enough to keep it safe if the database leaks?Because encryption can be undone by your own login code, so the key that lets you check a password usually sits near the database, and anyone who copies both can read every password.
- Is it actually OK to look at a risk and decide not to fix it?Yes, if the decision not to fix it is written down with a reason, a named owner and a date or trigger for looking again; otherwise it is just an oversight.