skip to content

A deploy job must push a rotated database password into a secret store — why grant it write but not read?

level: middleimportance: should knowfreq 47%

answer

  1. write is not a weaker read
  2. the deploy identity is widely reachable
  3. no read back, confirm by use
  4. history read is a third right
  5. write becomes read once something pushes it

basics

~20 s

Write and read are separate rights over the same value. A deploy job generates the new password, so it never needs to learn an existing one; granting only write means a stolen deploy identity can disrupt but cannot collect what the store already holds.

solid answer

~40 s

The job generates the new value, so it already knows the only value it needs — reading tells it nothing it did not produce. That matters because a deploy identity is the least defensible long-lived identity most estates have: it runs on shared build infrastructure, it is triggered by a merge, it works unattended, and its output is captured. With `write` alone, a theft buys disruption; with read, it buys the estate's contents. The usual objection is verification, and the answer is that a blind writer confirms **by use**: the write returns a version, and the payments service starts, authenticates against the database and reports success. One honest limit: where a later step pushes whatever the store holds to the account, a write right becomes knowledge of a working credential.

code

yaml · 18 lines
yaml
# One stored value, three identities, no overlap of rights

- grantedTo: payments-deploy-job
  scope: payments-database-password
  rights: [write]
  note: pushes a new value, cannot read back what it wrote

- grantedTo: payments-service
  scope: payments-database-password
  rights: [read]
  note: reads at start-up, cannot change or destroy the value

- grantedTo: platform-operator
  scope: service
  rights: [restart, replicate, backup, upgrade]
  note: operates the store, holds nothing over any value

# deliberately absent: readHistory anywhere, and read for the deploy job

go deeper

for a junior

Recall that writing a value and reading a value are two different permissions, and that a job which generates a new password has no reason to be told the old one.

for a middle

Explain how a writer that cannot read still verifies: the write returns a version, and the consumer confirms by authenticating with the value rather than anyone comparing bytes.

for a senior

Show where the split thins out: a write right becomes a live credential when a later step pushes the stored value onto the account, and history reads granted beside write undo the whole arrangement.

for a principal

Own the flow direction across the estate: decide whether the identity that proposes a value may also be the one that makes it real, and what review sits between them.

## Write is not a weaker read Over a single stored value, a store expresses at least three distinct rights: **read** the current contents, **write** a new value, and — where the store keeps history — **read an earlier version**. They are separate rights, and a design that treats write as a junior form of read hands every writer the estate's contents. The deploy job that rotates the payments team's database password needs exactly one of them. It generates a new password, changes the database account, and puts the new value where the payments service will find it. At no point in that sequence does it need to know what the value was. ## Why this identity in particular A deploy identity is the least defensible long-lived identity most estates hold, not because the team is careless but because of where it lives: - it runs on shared build infrastructure that many people can reach; - it is triggered by whatever can start a deployment, which is usually a merge; - it is long-lived, because it has to work unattended at three in the morning; - its output is captured — job output, artefacts, diagnostics — and captured output is read later by people who were granted nothing. Give it read and you have created an identity that can enumerate and remove values, sitting on machines whose purpose is to run other people's code. Give it write alone and a theft yields the ability to disrupt, not the ability to collect. ## How a blind writer knows it worked The standing objection is that a writer which cannot read cannot verify. It can — just not by inspection: 1. The write returns a **version or receipt**: an increasing number, or an identifier for the value just stored. That is metadata about the value, not its contents. 2. The job records the version it expects consumers to move to. 3. The **consumer confirms by use**. The payments service starts, reads the value, authenticates against the database and reports success. A credential that authenticates has been verified in the only way that matters. 4. If the consumer fails, that failure is the signal, and the response is to write again or roll back — still without reading. Confirming by use is strictly stronger than confirming by reading. A read only tells you that the bytes in the store match the bytes you generated; it says nothing about whether the database account accepts them. ## Where write-only stops being harmless This is the honest limit of the control, and a thorough answer reaches it. A write right converts into knowledge of a **live** credential in any flow where what is written later becomes the value the downstream system accepts. If the design is "write the new password into the store, then let something push the store's value to the database account", an attacker holding the write right can put in a password of their choosing and wait for the estate to make it real. So the grant has to be read together with the direction of the flow: | Flow | What a stolen write right yields | |---|---| | The job changes the account first, then writes what the account now accepts | disruption: consumers get a value the account rejects | | Something reads the store and pushes that value onto the account | a working credential the attacker chose | | The job writes a proposal and a separate identity applies it after review | disruption only, and the review is the check | The middle row is why write over a credential is still a privileged right, and why the identity that applies a value to a downstream account is worth separating from the identity that proposed it. ## The shape of the grant - **Deploy identity: write**, on the one value it rotates. Not read, not history, not other teams' values. - **Payments service: read**, on the same value. Not write — a consumer that can overwrite its own credential can also destroy it, and a compromised service then poisons what it was merely supposed to use. - **Operator: neither.** They run the service. - **History is a third decision.** Where the store keeps previous versions, the right to read them is a read right with a delay. Granting it beside write quietly undoes the split, and it is the easiest one to grant by accident because it often travels with a management right rather than with read. Two failure modes worth naming out loud. The first is the read granted "just to verify" during an incident: a read right with a good story and no expiry. The second is believing that a write event in the store's record proves the right value landed — the record shows that a write happened and which identity made it, not what it contained or whether it works. Only the consumer's successful authentication shows that.

  • The deploy job cannot read the value back. How do you know the rotation reached the payments service?
    By use, not by inspection. The write returns a version; the job records it; the payments service starts, reads the value, authenticates against the database and reports success. That result proves more than a read-back would, because it exercises the database account rather than comparing bytes. A failure to authenticate is the signal to write again or roll back.
  • Is a write-only identity safe to leave long-lived and widely reachable?
    Safer, not safe. It cannot collect what the store holds, but it can overwrite a value and take consumers down, and where a later step pushes the stored value onto the account it can install a credential it knows. Treat it as privileged: narrow its scope to the values it rotates, record every write, and alert on writes outside a deployment.
  • Should the payments service hold write on its own credential as well as read?
    No. Read is what it needs to start. Adding write means a compromise of the service can overwrite or destroy the credential it depends on, turning a read-only foothold into an outage, and it collapses the distinction between the identity that proposes a value and the one that consumes it.

saying these in an interview costs you the question

  • Says a write-only identity is harmless because it cannot exfiltrate anything
  • Grants the deploy job read so it can verify what it just wrote
  • Forgets that a right to read previous versions is a read right
  • Believes a write event in the record proves the correct value landed
  • Gives the consuming service write as well as read on its own credential