建立生产密钥恢复合同(08-01-production-secret-recovery-env-externalization)

这个提交包含在:
2026-08-01 19:18:54 +08:00
父节点 07de198b51
当前提交 ca24479a44
共修改 11 个文件,包含 727 行新增和 8 行删除
@@ -1342,3 +1342,65 @@ REMOTE_DIR="$(docker inspect <server> --format '<working_dir-label>')" \
DEPLOY_SERVER=<approved-ssh-target> \
bash deploy/trialrun/deploy-existing.sh
```
## Scenario: Environment Recovery Classification And Secret Custody
### 1. Scope / Trigger
- Trigger: adding/removing a trialrun environment key, documenting host-loss recovery, or preparing an environment-file migration.
- Purpose: make environment loss recoverable without placing Secret values in Git, ordinary backup, logs or AI context.
### 2. Signatures
- Template contract: `deploy/trialrun/.env.example`.
- Recovery classification: `deploy/trialrun/env-recovery-classification.json`.
- Recovery card: the opening section of `deploy/trialrun/runbook.md`.
- Validator: `node deploy/trialrun/validate-env-contract.js`.
- Fixed categories: `template_rebuild`, `external_reissue`, `direct_rotate`, `downtime_reset`, `preserve_original`.
### 3. Contracts
- Every `.env.example` key appears in exactly one fixed recovery category; the classification file contains key names only, never values, defaults, hashes, accounts or platform addresses.
- `template_rebuild` comes from reviewed templates/runbooks; `external_reissue` comes from the owning platform; `direct_rotate` records the invalidation consequence; `downtime_reset` requires an isolated approved outage.
- `POSTGRES_PASSWORD` is a reset case. PostgreSQL stores a verifier in `pg_authid`, not recoverable plaintext. Any temporary authentication relaxation is local-socket only, never a trusted host rule, and the original authentication file must be restored byte-for-byte before reopening the application.
- `FIELD_ENCRYPTION_KEY` is `preserve_original` and the highest-risk class. Its current AES-256-GCM payload is `v1:<iv>:<tag>:<ciphertext>` without a key id; replacing a lost key does not recover existing bank, identity or notification-channel ciphertext.
- `preserve_original` custody must be available to both the system administrator and a company responsible person through a repository-external shared vault or encrypted sealed copy. Evidence records roles and status only.
- Original-key custody is a current recovery constraint, not a permanent rotation design. Key id, keyring, lazy/bulk re-encryption and old-key retirement require a separate approved security task.
- Database/attachment backups do not absorb plaintext environment files. Phase 1 recovery-contract work never reads production env or contacts production systems.
### 4. Validation & Error Matrix
- New `.env.example` key missing from classification -> validator fails.
- Key appears in two categories -> validator fails and names the duplicated key.
- Unknown category, extra key, illegal key name or value-like entry -> validator fails.
- `FIELD_ENCRYPTION_KEY` outside `preserve_original` -> validator fails.
- `POSTGRES_PASSWORD` outside `downtime_reset` -> validator fails.
- Original encryption key unavailable -> stop recovery and report ciphertext impact; never generate a replacement and claim success.
- Temporary database trust remains or a DB host port is published -> recovery fails and the external entry remains closed.
### 5. Good/Base/Bad Cases
- Good: a TTL is rebuilt from the template, a WeCom Secret is reissued by its platform owner, JWT is rotated with session invalidation, and the field-encryption key is restored from dual-access custody.
- Base: the production key set differs from the example contract; a separately approved read-only check explains key names/counts without reading values before migration.
- Bad: put `.env` into the paired data backup, print a secret hash as evidence, assume `pg_authid` reveals the old password, or replace `FIELD_ENCRYPTION_KEY` with a new random value.
### 6. Tests Required
- `node deploy/trialrun/validate-env-contract.js`.
- Focused unit tests must cover the complete contract plus missing, duplicate, extra, unknown-category, illegal/value-like, field-key and database-password misclassification cases.
- Run `node scripts/qa/check-sensitive-content.mjs`, Trellis governance, process contract, docs registry audit and `git diff --check` after classification/runbook changes.
- Production key-name comparison, shared-vault custody, env migration, systemd updates, restarts and old-copy deletion remain separately approved Phase 2 evidence.
### 7. Wrong vs Correct
#### Wrong
```json
{"direct_rotate":["FIELD_ENCRYPTION_KEY"]}
```
#### Correct
```json
{"preserve_original":["FIELD_ENCRYPTION_KEY"]}
```