mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 12:31:29 +00:00
476022ca59
Closes acquisition-diligence Bundle 6 findings on secret custody, config
encryption, and local artifact hygiene. Source IDs: S6, R4, SEC-M2,
RT-M1, RT-M2, RT-L1.
Surgical closures (artifact-only audit-framed memos stay out of the
public repo per the Bundle 5 lesson):
R4 / RT-L1 — local EC private key artifact
rm cmd/agent/mc-001.key (gitignored, never in git history, leftover
from a 2025-era agent dev run on the operator's workstation).
Added scripts/ci-guards/B6-no-private-keys-in-tree.sh that fails the
build if any TRACKED non-test file contains a PEM private-key block,
so the next attempt to commit similar material gets caught at CI.
Allowlist: *_test.go (hermetic-test PEMs), examples/*.md (sample
walkthroughs), internal/scep/intune/testdata/ (certificates, not
keys).
RT-M1 — landing-page HSM implication
certctl.io/index.html: 'their hardware' / 'your hardware' colloquial
comparisons rephrased to 'their custody' / 'your servers'. The phrase
'Your keys. Your hardware. Your data. Your terms.' becomes 'Your
keys. Your servers. Your data. Your terms.' to remove any inferred
HSM-backed key-storage claim. The technical disclosure now lives in
docs/operator/secret-custody.md (linked below); the landing page no
longer makes a claim it cannot back.
S6 + SEC-M2 + RT-M2 (composite documentation closure)
Added docs/operator/secret-custody.md — public operator reference
enumerating every secret material on the control plane and on
agents:
- Local CA private key (FileDriver, file-on-disk, heap-resident
with the L-014 carve-out documented in
internal/connector/issuer/local/local.go).
- Agent ECDSA P-256 keys (file on agent host, never transmitted).
- OIDC client secret (AES-256-GCM v3, PBKDF2 600k).
- Session signing key (same encryption regime).
- Break-glass credential (Argon2id, never encrypted).
- API-key bearer tokens (SHA-256 hash only; plaintext shown once).
- CSR private keys mid-issuance (agent memory only).
- Issuer-connector backend secrets (encrypted_config column,
fail-closed for source='database', plaintext-by-design for
source='env' with rationale).
The Env-seeded-vs-DB-seeded plaintext policy is explained in plain
text so a buyer review can independently verify the startup guard at
cmd/server/main.go:222-262 makes sense.
Added docs/operator/runbooks/config-encryption-upgrade.md — the
procedural arm: how to force v1/v2 -> v3 re-seal across the
database, plus the passphrase-rotation order. Documents the
AEAD-driven read fallback (v3 -> v2 -> v1) and the fact that
re-sealing happens passively on UPDATE. Open roadmap item: a
certctl admin reseal --all command (tracked in
WORKSPACE-ROADMAP.md).
Both docs wired into docs/README.md Operator + Runbooks tables.
Verification:
rg -n 'CONFIG_ENCRYPTION|encrypt|v1|private key|HSM|PKCS11|mc-001.key|\.key|Local CA' \
internal cmd docs .gitignore README.md # ambient (no NEW leaks)
find . -name '*.key' \
-not -path './.git/*' -not -path './web/node_modules/*' # empty
git ls-files | xargs grep -lE 'BEGIN .* PRIVATE KEY' \
| grep -vE '_test\.go$|^examples/|^internal/scep/intune/testdata/' # empty
bash scripts/ci-guards/B6-no-private-keys-in-tree.sh # PASS
bash scripts/ci-guards/G-3-env-docs-drift.sh # PASS
bash scripts/ci-guards/doc-rot-detector.sh # PASS
Residual roadmap (deliberately deferred):
- signer.PKCS11Driver (HSM-token-backed CA-key custody).
- signer.CloudKMSDriver (AWS/GCP/Azure KMS-backed CA-key custody).
- FIPS 140-3 mode for the whole control plane.
- HSM-backed session signing key.
- Built-in 'certctl admin reseal --all' command.
All five tracked in WORKSPACE-ROADMAP.md, not retracted.
62 lines
2.7 KiB
Bash
Executable File
62 lines
2.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# scripts/ci-guards/B6-no-private-keys-in-tree.sh
|
|
#
|
|
# Bundle 6 closure (R4 / RT-L1): a real EC P-256 private key
|
|
# (cmd/agent/mc-001.key) lived in the working tree as a leftover from a
|
|
# 2025-era agent dev run. `.gitignore` line 49 (`cmd/agent/*.key`)
|
|
# meant it never reached `git ls-files`, but the file was still on
|
|
# every operator's workstation and on every CI runner's checkout, so
|
|
# `find . -name '*.key'` and any future overzealous `git add` could
|
|
# have surfaced it.
|
|
#
|
|
# This guard catches the same class of mistake from the OTHER
|
|
# direction: it scans every TRACKED file (i.e. files already in git,
|
|
# what an external acquirer's clone sees) for PEM private-key blocks
|
|
# and fails the build if any of them contain real key material outside
|
|
# the known-good test-fixture set.
|
|
#
|
|
# Allowlist rationale:
|
|
# - *_test.go files generate ephemeral keys for hermetic tests. They
|
|
# never carry real production material — the keys are RSA/ECDSA pairs
|
|
# minted by the test setup at runtime, then embedded as PEM so test
|
|
# fixtures stay self-contained. Buyer review can confirm by grepping
|
|
# for `GenerateKey(` / `crypto/rand` nearby.
|
|
# - examples/*.md sample walkthroughs deliberately include throwaway
|
|
# keys so the operator can paste-and-run.
|
|
# - internal/scep/intune/testdata/*.pem are CERTIFICATES (no private
|
|
# key block) — verified at write time but excluded here as a belt-
|
|
# and-suspenders precaution.
|
|
#
|
|
# If a new file legitimately needs a sample PEM private key (e.g. a
|
|
# new connector's test fixture), add it to the allowlist below with a
|
|
# short rationale comment. Real production material — Local CA keys,
|
|
# agent keys, OIDC client secrets, session signing keys — NEVER
|
|
# appears in a checked-in file.
|
|
|
|
set -e
|
|
|
|
BAD=$(git ls-files -z \
|
|
| xargs -0 grep -lE 'BEGIN (RSA |EC |DSA |OPENSSH |)PRIVATE KEY' 2>/dev/null \
|
|
| grep -vE '_test\.go$' \
|
|
| grep -vE '^examples/' \
|
|
| grep -vE '^internal/scep/intune/testdata/' \
|
|
|| true)
|
|
|
|
if [ -n "$BAD" ]; then
|
|
echo "::error::B6 regression: PEM private-key block found in tracked non-test file(s):"
|
|
echo "$BAD"
|
|
echo ""
|
|
echo "Real private-key material MUST NOT be checked into the repo."
|
|
echo "If this is a legitimate sample fixture, add the path to the"
|
|
echo "allowlist in scripts/ci-guards/B6-no-private-keys-in-tree.sh"
|
|
echo "with a rationale comment, and verify the key is throwaway."
|
|
echo ""
|
|
echo "If this is leftover dev/demo material (the original Bundle 6"
|
|
echo "trigger was cmd/agent/mc-001.key from an agent test run),"
|
|
echo "delete the file and add the file pattern to .gitignore so it"
|
|
echo "stops landing in working trees."
|
|
exit 1
|
|
fi
|
|
|
|
echo "B6 guard OK: no PEM private-key blocks in tracked non-test files"
|