# Credential creation-point inventory -- 2026-07-25

Read-only research capture for the D-137 credential-matrix design. No credential file
was opened; every row below is a file:line reference to CODE or RUNBOOK PROSE that
mints, materializes, or uploads credential material.

Classification used: **MINT** (new secret material comes into existence),
**MATERIALIZE** (an existing secret is fetched/copied/written somewhere new),
**UPLOAD** (public key registered -- no secret created). Only MINT rows are creation
points; the other two classes were checked and excluded deliberately.

Operator-ruled scope for the matrix (this session): the **materialization test** --
in-matrix if a credential is ever written to a file, presented by a human, or consumed
out-of-band, regardless of who generated it.

## Counts

| Class | Count | Where |
|---|---|---|
| Scripted MINT (repo code generates the secret) | 25 rows | `scripts/` |
| Runbook/prose MINT (operator runs by hand, no script owns it) | 30 rows | `runbooks/`, `clientdocs/` |
| **Declared secrets with NO creation point anywhere in the repo** | **12** | see below |
| Charm/platform-minted at bundle apply | summarised | `bundle.yaml` deploy |
| MATERIALIZE / UPLOAD (excluded, verified non-creating) | 20+ | see source agent record |

## FINDING 1 -- twelve declared secrets have NO mint command anywhere

This is the most consequential result and it **qualifies the "creation points are already
known" premise**: for twelve standing credentials, they are not.

`grep -rnI "ssh-keygen" .` returns **ZERO hits repo-wide** (searched everything except
`.git`/`.terraform`/tfstate/tfplan, including `tests/`, `docs/archive/`, `clientdocs/`,
`.claude/`). There is likewise no `mkpasswd`, `htpasswd`, `password_hash`, `pwgen`,
`uuidgen`, nor any Terraform `random_password` / `tls_private_key`. Yet the manifests
declare:

| Credential | Declared at | Only provenance record |
|---|---|---|
| `office1_svc_ed25519{,.pub}` | `vr1-office1.manifest:30-31` | `vr1-office1-as-built.md:126` (SEC-007) |
| `vr1-dc0_svc_ed25519{,.pub}` | `vr1-dc0.manifest:16-17` | a manifest COMMENT (`:10-12`) |
| `vr1-dc1_svc_ed25519{,.pub}` | `vr1-dc1.manifest:16-17` | a manifest COMMENT (`:10-12`) |
| `vr1-dc0-edge_ed25519{,.pub}` | `vr1-dc0.manifest:22-23` | manifest comment (backfilled 2026-07-25) |
| `vr1-dc1-edge_ed25519{,.pub}` | `vr1-dc1.manifest:21-22` | manifest comment (`:18-20`) |
| `vr1-dc1-maas-power_ed25519{,.pub}` | `vr1-dc1.manifest:29-30` | manifest comment (`:26-28`, SEC-016) |
| `opnsense-root-password` | `vr1-office1.manifest:34` | `vr1-office1-as-built.md:128`, SEC-007 -- **HUMAN GUI login** |
| `opnsense-root-hash` | `vr1-office1.manifest:33` | same (bcrypt of the above, for `config.xml`) |
| `tailscale-authkey.txt` | `vr1-office1.manifest:36` | SEC-008 -- operator-supplied, third-party control server (correctly has no repo mint) |
| `vr1-netbox.env` | `vr1-office1.manifest:37` | minted on the upstream apex; SEC-006 (BURNED) |
| `vr1-office1.env` / `vr1-stage1.env` | `.manifest:39-40` | `vr1-office1-as-built.md:132-133` |

Six SSH keypairs and the OPNsense root password/hash are pure operator-terminal mints
whose only record is a manifest comment. **Consequence: they are not reproducible.** If
the jumphost is rebuilt, no repo artifact states how to recreate them -- which is a
Roosevelt-transfer defect, not merely a hygiene one. The tailscale key is genuinely
third-party and correctly has no repo mint.

## FINDING 2 -- credential directories OUTSIDE the `*-creds/` convention

SEC-009 says all site secrets live in `~/<site>-creds/`. The inventory shows at least
three other jumphost directories holding credential material, none of which
`creds-audit` covers (it checks `~/<site>-creds/` folders plus a loose-FILE sprawl glob
in `$HOME` -- it never inspects these DIRECTORIES):

- `~/vault-init/init.txt` -- Vault **5 unseal shares + root token**, the cloud's entire
  root of trust (`runbooks/phase-02-vault-bringup.md:71`, irreversible one-shot).
- `~/octavia-pki/` -- **8 artifacts**: 2 CA passphrases, 2 CA private keys, 2 CA certs,
  the controller key, the signed bundle (`runbooks/phase-01-bundle-deploy.md:299-410`).
- `~/tenant-<client>/` -- per-tenant domain-admin / cluster / svc passwords, an
  application credential, and a Nova private key (`scripts/tenant-onboard.sh:70-71,
  94-95, 141, 167`).

All three are named in CLAUDE.md as secret locations, so they are KNOWN -- they are
simply outside the control. This materially extends SEC-023.

Related: `runbooks/phase-01-bundle-deploy.md:391-410` writes
`overlays/octavia-pki.yaml` containing base64 CA key blobs **plus the issuing-CA
passphrase in plaintext, inside the repo clone** (gitignored). Given SEC-004 (repo
currently PUBLIC), that gitignore is the only thing standing between a CA private key
and publication.

## FINDING 3 -- highest-concentration mint sites (matrix seeding order)

1. `scripts/site-headend-install.sh` -- **7 mints** (`:418` primitive, `:430` DB pass,
   `:445` rack-enrollment secret, `:450`/`:452` admin password, `:453` API key, `:485`
   LXD trust). Every Office1/DC-region MAAS + LXD secret originates here.
2. `scripts/tenant-onboard.sh` -- 7 mints, the entire tenant identity set.
3. `runbooks/phase-01-bundle-deploy.md:299-410` -- 8 Octavia PKI artifacts.
4. `runbooks/tenant-onboarding-v2-DRAFT.md:162-320` -- 6 mints DUPLICATING #2 (two
   creation locations, one credential set -- do not double-count).
5. `runbooks/phase-02-vault-bringup.md:71-144` -- 4 mints incl. the root of trust.
6. `runbooks/dc-dc-phase4-juju-bundle-per-dc.md:119-151` -- 4 mints PER DC.

## FINDING 4 -- corroborations of already-recorded defects

- `dc-dc-phase4-juju-bundle-per-dc.md:128` mints `juju-<dc>` via `maas createadmin`
  with **no** `--password`, so MAAS prompts and the value is stored nowhere --
  independently confirming the SEC-020 finding about those two superusers.
- `site-headend-install.sh:452` uses `--password` in **argv**, the exposure SEC-020
  flagged and which this session's `operator` mint avoided via stdin.
- `scripts/phase-03-admin-openrc.sh:46-52` is classified MATERIALIZE (charm-generated,
  operator-materialized) -- exactly the case the ruled materialization test captures and
  a generation-based test would have missed (SEC-023).

## What this means for the matrix

The matrix must carry a `mint-ref` column that can hold **three** provenance kinds, not
one: `script:line`, `runbook:step`, and `operator-terminal` (undocumented). Finding 1
means a meaningful fraction of today's estate is the third kind, so a checker that
requires every row to name executable code would fail 12 rows on day one. Those rows
are the backlog the matrix exists to surface -- they should be admitted as
`operator-terminal` and tracked as a debt to convert, not treated as parse errors.

Source: three read-only Explore agents, 2026-07-25. Full per-row tables (55 MINT rows
with file:line, host, destination, stage, and human/service classification) are in the
session transcript; the structural findings and all counts are reproduced above.
