scripts/cert-manager
Scripts for the M14-backend PKI (mTLS opt-in per source + internal
gRPC mTLS). These run before K8s is involved — the root CA
stays offline, the intermediate is what gets imported into
cert-manager.
Layout
| File |
Purpose |
When to run |
ca-init.sh |
Generate root + intermediate for a new env |
Once per env (dev, staging, prod) |
ca-rotate-intermediate.sh |
Rotate the intermediate (keep root) |
Annually, ~30d before expiry |
test-certs.sh |
Generate throwaway test certs for internal/auth/mtls_test.go |
Whenever tests need refreshing |
README.md |
This file |
— |
testdata/ |
Test cert fixtures (gitignored, regenerated) |
— |
Typical flow
1. Bootstrap a new environment
# On an air-gapped machine or encrypted USB
export BA_CA_PASSPHRASE='...' # use a password manager
scripts/cert-manager/ca-init.sh prod /secure/pki
# Move the root offline, keep the intermediate accessible
mv /secure/pki/prod/root-ca.key /offline-usb/
mv /secure/pki/prod/root-ca.crt /offline-usb/
# Import the intermediate into K8s (sealed-secrets or external-secrets)
# Apply the cert-manager ClusterIssuer manifest (deploy/cert-manager/...)
# Issue serving certs
2. Annual rotation (30 days before intermediate expires)
# On the air-gapped machine
export BA_CA_PASSPHRASE='...'
scripts/cert-manager/ca-rotate-intermediate.sh prod /offline-usb /tmp/new-pki
# Re-import the new intermediate into K8s
# Restart cert-manager controller
# Re-issue serving certs (delete+apply, or annotate)
# Verify with the smoke test
3. Test fixtures
scripts/cert-manager/test-certs.sh # generate
scripts/cert-manager/test-certs.sh clean # remove
Security notes
- Root key never touches the cluster. Generate it offline, store
it offline, only use it to sign the intermediate. If the root key
is compromised, the entire PKI is compromised (see
docs/runbooks/mtls-incident.md §"CA compromise").
- Passphrase management.
BA_CA_PASSPHRASE is the dev/CI path.
For prod, prefer interactive prompts or a hardware token. Never
store the passphrase in the same place as the cert.
- test-certs.sh is throwaway. The
testdata/ dir is gitignored
because it contains private keys. The real PKI is generated by
ca-init.sh, never committed.
Related docs
M14_SECURITY_PLAN.md — full milestone plan
docs/runbooks/mtls-incident.md — incident response
internal/auth/mtls.go — the verifier (companion to the test certs)
internal/auth/mtls_test.go — table-driven tests that use the test certs