---
name: credential-inventory-audit
description: "Audit which credentials are configured where: scan process env, .env files, keychains, vaults, and password managers into a configured-vs-missing table, flag drift and expiry, and run a remediation workflow. Triggers when someone needs a secrets inventory, is onboarding, suspects credential sprawl, or must prove to an auditor that every secret has one home."
---

# Credential Inventory Audit

## Purpose

Answer one question with evidence: for every credential the system needs, where does it actually live, and is that the right place? The audit produces a configured-vs-missing table across stores, a drift report (same credential in multiple places, or the same value hiding under two names), an expiry/rotation report, and a remediation workflow that brings everything to one store per environment. It is read-only by default: it reports where credentials are, never their values.

## Workflow

1. **Declare what should exist.** Build the expected-credential registry first: every credential name the project needs, its canonical store per environment, its owner, and its rotation cadence. Use the template in `references/inventory-method.md`. Without this, an audit only finds sprawl, never gaps.
2. **Scan each store, read-only.** For each environment (dev, staging, prod), enumerate credential *names* (never values) in: process env and dotenv files, the canonical secret store (Vault, 1Password, AWS/GCP/Azure secret manager, Doppler), and anywhere else credentials tend to hide (CI env stores, Docker secrets, macOS keychain entries, CI job logs are checked via scanners, not by reading). `bin/cred-inventory.py` automates the local half; store-side listing uses each store's list command. This never writes, updates, or rotates anything.
3. **Build the configured-vs-missing table.** Rows are expected credentials, columns are environments and stores. Mark each cell: configured (name present), missing (expected but absent), or unexpected (present but not in the registry). Missing cells are gaps; unexpected cells are sprawl. The drift section lists: the same fingerprint under different names (one credential duplicated), the same name in two stores (double-booked), and values that appear verbatim in both a local file and a vault (rotation bypass).
4. **Check expiry and rotation health.** For each credential, record last-rotated date and compare against cadence. Starting defaults: third-party API keys 90 days, database passwords 30-60 days, TLS certificates automated via ACME rather than scheduled. Anything past cadence, or with an unknown rotation date, goes on the rotation list. The audit does not rotate: it schedules rotations in the remediation plan.
5. **Remediate in order.** Triage verified-active exposure first, then by blast radius (production over dev over test), then by exposure window (public repo over private). The remediation workflow covers: rotate-before-rewrite when a secret touched git history, one store per environment consolidation, and the proof-of-clean re-scan. Detail in `references/inventory-method.md`.

## Output Contract

The audit delivers a report (markdown, plus CSV of the inventory table) containing:

- **Configured-vs-missing table**: credential, expected store, status per environment, owner, last rotated, cadence, status flag.
- **Drift report**: duplicate values, double-booked names, file-vs-vault overlaps, unexpected credentials, each with a proposed canonical home.
- **Rotation report**: credentials past cadence or with unknown rotation date, with a scheduled rotation plan (who rotates, order, verification step).
- **Remediation plan**: ordered action list (rotate first, consolidate, re-scan), each action with an owner and a done-check. No action executes during the audit itself; this plan is the handoff.

## Operating Rules

1. Read-only during the audit. Never print, log, copy, or export a credential value. The tooling reports names, presence, and truncated value fingerprints only, so the report itself is safe to share and store.
2. Never rotate during discovery. Rotating first destroys the evidence of what was duplicated where. Rotation happens only in the remediation phase, with the duplicate map in hand.
3. One store per environment is the target state. The audit does not invent new stores; if the project has two candidates (for example Doppler and Vault), the remediation plan picks one per environment and migrates the other, it does not bless both.
4. When a leaked credential is confirmed (for example a scanner or the drift report shows a value in git history): rotate that credential FIRST, then rewrite history, then re-scan. History rewriting alone is not remediation, the value is already compromised.
5. Every finding gets a done-check in the remediation plan. "Consolidate Stripe key into Vault" is not done until the re-scan shows the name absent from the old store and present in the new one.
6. Secrets of the person running the audit (their Vault token, their 1Password session) are access tools, not audit targets. They never appear in the inventory.
