> ## Documentation Index
> Fetch the complete documentation index at: https://docs.jacobpevans.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets that expire

> Why passwords and API keys here are issued on demand and die shortly after, instead of being stored in a file someone has to remember to rotate.

> A password stored in a file is a password you're still finding in five years, in places you forgot you put it.

Automation needs credentials. A backup job needs the storage password, a deployment needs an API token. The obvious approach is to put them in a config file and lock it down.

That approach fails in a specific, predictable way, and it is not usually a dramatic breach. It is entropy.

## How stored credentials rot

They spread. A credential in a file gets copied into a second file for a second job. Then it lands
in someone's notes to debug something at 1 AM, and later in a CI variable. Nobody tracks the copies
because each copy seemed reasonable at the time.

They outlive their purpose. The token issued for a one-off migration two years ago still works, still has full access, and nobody remembers it exists.

And rotation becomes frightening. Changing a credential means finding every copy, and since nobody
knows where they all are, the rational choice is to leave it alone. So credentials get older and
more widely spread, permanently.

## Issue on demand instead

Flip the model. Instead of storing credentials, store the *authority to create them*, and mint one when needed.

<Steps>
  <Step title="Something needs access">
    A job starts and needs to read from storage.
  </Step>

  <Step title="It proves what it is">
    Not with the target credential, but with its own identity: one that says what role it plays, not what it may read.
  </Step>

  <Step title="A fresh credential is created">
    The secrets manager generates a brand-new one, valid for this job and scoped to exactly what this role may do. It's set to expire in an hour.
  </Step>

  <Step title="It expires">
    The job finishes. Shortly after, the credential stops working whether or not anyone remembered to clean it up.
  </Step>
</Steps>

```mermaid theme={null}
%%{init:
  {'theme':'base','look':'handDrawn','themeVariables':{'fontFamily':'Geist','fontSize':'14px','primaryColor':'#102937','primaryTextColor':'#F4EFE6','primaryBorderColor':'#4FB3A9','lineColor':'#4FB3A9','secondaryColor':'#0B1D2A','tertiaryColor':'#1A2A38','clusterBkg':'rgba(79,179,169,0.08)','clusterBorder':'#4FB3A9'}}}%%
  flowchart LR
  Job([Automation job])
  Check{Allowed?}
  Store[(Secrets manager)]
  Cred([Short-lived credential])
  Gone((Expires))

  Job --> Check
  Check --> Store
  Store --> Cred
  Cred --> Gone

  classDef host fill:#102937,stroke:#4FB3A9,stroke-width:2px,color:#F4EFE6;
  classDef gate fill:#102937,stroke:#E06B4A,stroke-width:2.5px,color:#F4EFE6;
  classDef sink fill:#102937,stroke:#F4EFE6,stroke-width:2.5px,color:#F4EFE6;
  classDef external fill:#102937,stroke:#E6B35A,stroke-width:2px,color:#F4EFE6;

  class Job,Cred host
  class Check gate
  class Store sink
  class Gone external
```

## What this buys

**Leaks have a deadline.** A credential found in a log tomorrow expired an hour after it was issued. This does not make a leak fine. It makes it survivable.

**Rotation stops being an event.** Every credential is new. There is no rotation project because there is nothing old to rotate.

**Access becomes visible.** Every issue is logged: which identity, which path, when. "Who read this?" becomes a query rather than an investigation.

**Revocation is real.** Remove a role's permission and the next request fails. You are not hunting copies, because there are no copies to hunt.

## Where it bottoms out

Something has to be trusted first. The job needs *some* credential to prove its identity, and that
one cannot itself be issued on demand. This is the bootstrapping problem, and it does not fully
disappear.

What it does is shrink. Instead of dozens of long-lived secrets spread across dozens of files, there
is one small starting credential, and everything else derives from it. One thing to protect
carefully is a much better position than fifty.

<Note>
  The property worth insisting on is that a helper which cannot obtain a credential must **fail
  loudly**. A script that exits successfully having quietly exported nothing produces a confusing
  failure much later. It surfaces in a different system, with no connection to the real cause.
  Silence is the expensive outcome, not the error.
</Note>

## Where to go next

<CardGroup cols={2}>
  <Card title="One login for everything" icon="key" href="/explainers/one-login-for-everything">
    The human-facing half of the same problem.
  </Card>

  <Card title="Security overview" icon="shield-halved" href="/security/overview">
    The concrete tooling this describes in the abstract.
  </Card>
</CardGroup>
