- Add encrypt-secrets.sh / decrypt-secrets.sh: age-based secrets workflow replaces KeePassXC dependency; encrypted .env.age files committed to repo - Add bootstrap/secrets.enc/: all component secrets encrypted to age pubkey - Fix .gitignore: allow secrets.enc/**/*.age while blocking plaintext - Fix verify-t02.sh: update netpol names for Authelia+LLDAP+KeyCape stack - Fix verify-t03.sh: remove keycloak_db/role checks; fix ((PASS++)) set-e bug - Update postgresql/cluster.yaml: drop keycloak_db, bootstrap privacyidea_db only - Update postgresql/create-secrets.sh: remove keycloak secret - Fix netpol-databases.yaml: add port 8000 for CNPG instance manager HTTP API - T02 COMPLETE: namespaces, network policies, cert-manager issuers applied - T03 COMPLETE: CNPG operator installed, net-kingdom-pg cluster healthy Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase 0a — Pre-cluster Secret Bootstrap
This directory contains tooling for the KeePassXC bootstrap phase (T01 Phase 0a). No secrets are stored here — only scripts and documentation.
Why KeePassXC first?
The single-credential bootstrap principle (Decision D1): one master password unlocks the KeePassXC vault; all other credentials are generated inside it. KeePassXC is the pre-cluster source of truth. After the K3s cluster is running, secrets migrate into HashiCorp Vault (T01 Phase 0b) and KeePassXC becomes the break-glass / dev-local backup.
KeePassXC database structure
Create a new .kdbx database. Use a strong master password stored in your
personal password manager (Bitwarden, 1Password, etc.).
Recommended group structure:
net-kingdom/
├── privacyIDEA/
│ ├── pi-admin (username: pi-admin, password: PI_ADMIN_PASSWORD)
│ ├── database (username: privacyidea, password: PI_DB_PASSWORD)
│ ├── SECRET_KEY (password field only — PI_SECRET_KEY value)
│ ├── PI_PEPPER (password field only — PI_PEPPER value)
│ └── PI_ENCFILE (binary attachment: pi.enc — generate after deploy)
├── PostgreSQL/
│ ├── postgres root (username: postgres, password: PG_ROOT_PASSWORD)
│ ├── keycloak user (username: keycloak, password: PG_KEYCLOAK_PASSWORD)
│ └── privacyidea user (username: privacyidea — same password as PI_DB_PASSWORD)
├── Keycloak/
│ ├── admin (username: admin, password: KC_ADMIN_PASSWORD)
│ └── database (username: keycloak — same password as PG_KEYCLOAK_PASSWORD)
├── Break-glass/
│ ├── break-glass (username: break-glass, password: BREAKGLASS_PASSWORD)
│ └── recovery-otp (TOTP seed — enroll manually after Keycloak is up)
└── Vault/
└── (populated in Phase 0b after Vault is deployed)
Workflow
Step 1 — Generate secrets
chmod +x gen-secrets.sh
./gen-secrets.sh ./secrets
This writes .env files to ./secrets/ (gitignored). Inspect each file,
then copy each value into the appropriate KeePassXC entry.
Step 2 — Create the age encryption key (one-time)
age-keygen -o ~/net-kingdom-ops-bundle.key
The public key prints to stdout. The private key is in the .key file.
Store the .key file somewhere safe (NOT in this repo; NOT in the secrets/ dir).
Step 3 — Create the encrypted ops bundle
chmod +x pack-bundle.sh
./pack-bundle.sh ./secrets "age1..." ops-bundle.tar.age
Store ops-bundle.tar.age offsite (cloud storage, external drive, separate location).
Step 4 — Shred the generated files
find ./secrets -type f -exec shred -u {} \;
rm -rf ./secrets
Step 5 — PI_ENCFILE (after privacyIDEA container is running — T04)
# Generate the encryption key inside the running container:
kubectl exec -n mfa <pi-pod-name> -- pi-manage create_enckey
# Extract it:
kubectl cp -n mfa <pi-pod-name>:/etc/privacyidea/enckey ./pi.enc
# Store as a binary attachment in KeePassXC → net-kingdom/privacyIDEA/PI_ENCFILE
# Create the K8s Secret:
kubectl create secret generic privacyidea-enckey \
--from-file=PI_ENCFILE=./pi.enc \
--namespace mfa
# Shred the local copy:
shred -u ./pi.enc
Notes on secret reuse
Some secrets appear in multiple components — this is intentional to avoid drift. When adding to KeePassXC, note the cross-references rather than duplicating the value:
PI_DB_PASSWORD== PostgreSQLprivacyideauser passwordKC_DB_PASSWORD== PostgreSQLkeycloakuser password
Use KeePassXC references ({REF:P@T:UUID}) to avoid maintaining two copies.
Phase 0b — HashiCorp Vault (after T02, once K3s is running)
See ../vault/ (created in T01 Phase 0b) for:
- Vault Helm chart values
- ESO (External Secrets Operator) configuration
- Vault secret path layout
- Migration procedure: KeePassXC → Vault