generated from coulomb/repo-seed
311 lines
17 KiB
Makefile
311 lines
17 KiB
Makefile
SHELL := /usr/bin/env bash
|
|
.DEFAULT_GOAL := help
|
|
|
|
# Operator age public key — used as bundle encryption recipient
|
|
OPERATOR_AGE_PUBKEY := $(shell cat keys/age.pub 2>/dev/null | tr -d '[:space:]')
|
|
SECURITY_BOOTSTRAP_METADATA ?= $(if $(METADATA),$(METADATA),.local/security-bootstrap.json)
|
|
SECURITY_BOOTSTRAP_HOST ?= $(if $(HOST),$(HOST),127.0.0.1)
|
|
SECURITY_BOOTSTRAP_PORT ?= $(if $(PORT),$(PORT),8876)
|
|
OPENBAO_RESTORE_EVIDENCE ?= /tmp/netkingdom-openbao-restore-drill/evidence.json
|
|
OPENBAO_EMERGENCY_EVIDENCE ?= /tmp/netkingdom-openbao-emergency-drill/evidence.json
|
|
BOOTSTRAP_CLEANUP_EVIDENCE ?= /tmp/netkingdom-bootstrap-cleanup/evidence.json
|
|
LIFECYCLE_FLOW_EVIDENCE ?= /tmp/netkingdom-lifecycle-flow/evidence.json
|
|
ONBOARDING_DRY_RUN_EVIDENCE ?= /tmp/netkingdom-onboarding-dry-run/evidence.json
|
|
RAILIANCE_PLATFORM_PATH ?= ../railiance-platform
|
|
CUSTODY_ROSTER ?= .local/custody-roster.json
|
|
CUSTODY_ROSTER_SIGNATURE ?= .local/custody-roster.json.sig
|
|
CUSTODY_ROSTER_ALLOWED_SIGNERS ?= .local/custody-roster.allowed_signers
|
|
CUSTODY_ROSTER_SIGNING_KEY ?= $(HOME)/.ssh/id_custodian_agent
|
|
CUSTODY_ROSTER_SIGNING_PRINCIPAL ?= platform-custodian
|
|
|
|
# ── Help ──────────────────────────────────────────────────────────────────────
|
|
help: ## Show this help
|
|
@echo "net-kingdom — available targets"
|
|
@echo ""
|
|
@grep -E '^[a-zA-Z0-9_-]+:.*?## ' $(MAKEFILE_LIST) \
|
|
| sort \
|
|
| awk 'BEGIN {FS = ":.*?## "}; {printf " %-28s %s\n", $$1, $$2}'
|
|
|
|
# ── Git hooks ─────────────────────────────────────────────────────────────────
|
|
hooks: ## Configure git to use repo-local hooks (.githooks)
|
|
@mkdir -p .githooks
|
|
git config core.hooksPath .githooks
|
|
@test -f .githooks/pre-commit \
|
|
|| (echo "ERROR: .githooks/pre-commit not found"; exit 1)
|
|
chmod +x .githooks/pre-commit
|
|
@echo "✔ git hooks enabled (.githooks/pre-commit is active)"
|
|
|
|
hooks-test: ## Test that the pre-commit hook blocks plaintext secrets
|
|
@mkdir -p sso-mfa/bootstrap/secrets/_hooktest
|
|
@echo 'PI_SECRET_KEY=deadbeef' > sso-mfa/bootstrap/secrets/_hooktest/test.env
|
|
@git add sso-mfa/bootstrap/secrets/_hooktest/test.env 2>/dev/null || true
|
|
@if git commit -m "TEST: hook must block this" 2>/dev/null; then \
|
|
echo "FAIL: hook did NOT block plaintext commit"; \
|
|
git reset --soft HEAD~1 2>/dev/null || true; \
|
|
else \
|
|
echo "✔ Hook blocked plaintext as expected"; \
|
|
fi
|
|
@git restore --staged sso-mfa/bootstrap/secrets/_hooktest/test.env 2>/dev/null || true
|
|
@rm -rf sso-mfa/bootstrap/secrets/_hooktest
|
|
|
|
# ── SOPS / age ────────────────────────────────────────────────────────────────
|
|
sops-setup: ## Copy age key to SOPS default path (~/.config/sops/age/keys.txt)
|
|
@mkdir -p ~/.config/sops/age
|
|
@if [[ -f ~/.config/age/key.txt ]]; then \
|
|
cp -n ~/.config/age/key.txt ~/.config/sops/age/keys.txt || true; \
|
|
chmod 600 ~/.config/sops/age/keys.txt; \
|
|
echo "✔ SOPS key ready at ~/.config/sops/age/keys.txt"; \
|
|
elif [[ -f ~/.config/sops/age/keys.txt ]]; then \
|
|
echo "✔ SOPS key already present at ~/.config/sops/age/keys.txt"; \
|
|
else \
|
|
echo "ERROR: age key not found at ~/.config/age/key.txt"; \
|
|
echo " Generate one with: age-keygen -o ~/.config/age/key.txt"; \
|
|
exit 1; \
|
|
fi
|
|
|
|
sops-edit: ## Edit an encrypted file with SOPS: make sops-edit FILE=secrets/foo.yaml
|
|
@[[ -n "$(FILE)" ]] || (echo "Usage: make sops-edit FILE=secrets/path/to/file.yaml"; exit 1)
|
|
sops $(FILE)
|
|
|
|
sops-encrypt: ## Encrypt a file in place: make sops-encrypt FILE=secrets/foo.yaml
|
|
@[[ -n "$(FILE)" ]] || (echo "Usage: make sops-encrypt FILE=secrets/path/to/file.yaml"; exit 1)
|
|
sops --encrypt --in-place $(FILE)
|
|
@echo "✔ Encrypted $(FILE)"
|
|
|
|
sops-decrypt: ## Decrypt a file to stdout (never writes plaintext to disk): make sops-decrypt FILE=secrets/foo.yaml
|
|
@[[ -n "$(FILE)" ]] || (echo "Usage: make sops-decrypt FILE=secrets/path/to/file.yaml"; exit 1)
|
|
sops -d $(FILE)
|
|
|
|
sops-rotate: ## Rotate SOPS recipients after updating .sops.yaml: make sops-rotate FILE=secrets/foo.yaml
|
|
@[[ -n "$(FILE)" ]] || (echo "Usage: make sops-rotate FILE=secrets/path/to/file.yaml"; exit 1)
|
|
sops --rotate --in-place $(FILE)
|
|
@echo "✔ Recipients rotated for $(FILE)"
|
|
|
|
check-secrets: ## Fail if any file under secrets/ is not SOPS-encrypted
|
|
@echo "Checking for unencrypted files under secrets/..."
|
|
@bad=0; \
|
|
while IFS= read -r f; do \
|
|
[[ -z "$$f" ]] && continue; \
|
|
if grep -qE '^[[:space:]]*sops:[[:space:]]*$$|"sops"[[:space:]]*:' "$$f" 2>/dev/null; then \
|
|
continue; \
|
|
fi; \
|
|
case "$$f" in *.age|*.gpg) continue ;; esac; \
|
|
echo " UNENCRYPTED: $$f"; bad=1; \
|
|
done < <(git ls-files --others --cached 'secrets' 2>/dev/null | grep -v '/$'); \
|
|
if [[ "$$bad" -ne 0 ]]; then \
|
|
echo ""; \
|
|
echo "ERROR: Unencrypted secret(s) detected. Encrypt with: sops --encrypt --in-place <file>"; \
|
|
exit 1; \
|
|
fi; \
|
|
echo "✔ All secrets/ files appear SOPS-encrypted"
|
|
|
|
# ── Credential lifecycle ──────────────────────────────────────────────────────
|
|
creds-init: sops-setup hooks ## One-time setup: verify prerequisites, configure SOPS and git hooks
|
|
@echo "=== creds-init: checking prerequisites ==="
|
|
@command -v age >/dev/null 2>&1 || (echo "ERROR: age not installed (apt install age)"; exit 1)
|
|
@command -v sops >/dev/null 2>&1 || (echo "ERROR: sops not installed (see https://github.com/getsops/sops/releases)"; exit 1)
|
|
@command -v kubectl >/dev/null 2>&1 \
|
|
&& echo "✔ kubectl found" \
|
|
|| echo "WARN: kubectl not found (required for creds-apply/verify)"
|
|
@test -f ~/.config/sops/age/keys.txt \
|
|
|| (echo "ERROR: age key not found — run 'make sops-setup' after placing your key at ~/.config/age/key.txt"; exit 1)
|
|
@echo ""
|
|
@echo "✔ creds-init complete. Next: make creds-generate"
|
|
|
|
creds-generate: ## Generate all service secrets and print KeePassXC entry guide
|
|
@command -v openssl >/dev/null 2>&1 || (echo "ERROR: openssl not found"; exit 1)
|
|
cd sso-mfa/bootstrap && bash gen-secrets.sh
|
|
@sed -i "s|^generated_at: .*|generated_at: $$(date -Iseconds)|" sso-mfa/bootstrap/creds-state.yaml
|
|
@echo ""
|
|
@echo "State: generated_at updated in sso-mfa/bootstrap/creds-state.yaml"
|
|
@echo "Next : enter values into KeePassXC, then set keepass_confirmed: true"
|
|
@echo " Run 'make creds-bundle' to create an encrypted offsite backup."
|
|
|
|
creds-bundle: ## Age-encrypt the ops bundle for offsite storage
|
|
@[[ -n "$(OPERATOR_AGE_PUBKEY)" ]] \
|
|
|| (echo "ERROR: keys/age.pub not found — cannot determine encryption recipient"; exit 1)
|
|
@[[ -d sso-mfa/bootstrap/secrets ]] \
|
|
|| (echo "ERROR: sso-mfa/bootstrap/secrets/ not found — run 'make creds-generate' first"; exit 1)
|
|
cd sso-mfa/bootstrap && bash pack-bundle.sh secrets "$(OPERATOR_AGE_PUBKEY)"
|
|
@sed -i "s|^bundle_at: .*|bundle_at: $$(date -Iseconds)|" sso-mfa/bootstrap/creds-state.yaml
|
|
@echo ""
|
|
@echo "State: bundle_at updated in sso-mfa/bootstrap/creds-state.yaml"
|
|
@echo "Store the .tar.age bundle offsite (external drive, encrypted cloud, second location)."
|
|
|
|
creds-apply: ## Apply all create-secrets.sh scripts to the cluster in dependency order
|
|
bash sso-mfa/bootstrap/creds-apply.sh
|
|
|
|
creds-verify: ## Check all expected K8s secrets exist and update creds-state.yaml
|
|
bash sso-mfa/bootstrap/creds-verify.sh
|
|
|
|
creds-status: ## Print human-readable credential state from creds-state.yaml
|
|
bash sso-mfa/bootstrap/creds-status.sh
|
|
|
|
creds-rotate: ## Guided rotation for one secret: make creds-rotate SECRET=<name>
|
|
@[[ -n "$(SECRET)" ]] \
|
|
|| (echo "Usage: make creds-rotate SECRET=<name>"; \
|
|
echo ""; \
|
|
echo "Known secrets:"; \
|
|
echo " PI_SECRET_KEY PI_PEPPER PI_DB_PASSWORD LLDAP_JWT_SECRET"; \
|
|
echo " LLDAP_LDAP_USER_PASS AUTHELIA_SESSION_SECRET"; \
|
|
echo " AUTHELIA_KEYCAPE_CLIENT_SECRET KEYCAPE_RSA_KEY"; \
|
|
echo " BREAKGLASS_PASSWORD"; \
|
|
exit 1)
|
|
SECRET=$(SECRET) bash sso-mfa/bootstrap/creds-rotate.sh
|
|
|
|
## ── Agent-driven credential lifecycle (NK-WP-0005) ──────────────────────────
|
|
|
|
creds-agent-init: ## Fully automated credential bootstrap — generates, encrypts, injects, delivers emergency bundle
|
|
@bash sso-mfa/bootstrap/creds-bootstrap-agent.sh
|
|
|
|
creds-agent-status: ## Show current v2 bootstrap state (agent mode)
|
|
@bash sso-mfa/bootstrap/creds-status.sh --v2
|
|
|
|
creds-emergency-reprint: ## Re-deliver emergency bundle (if lost/stolen — reprints, rotates nothing)
|
|
@bash sso-mfa/bootstrap/emergency-bundle.sh --reprint
|
|
|
|
iam-profile-conformance-test: ## Run IAM Profile v0.2 conformance fixture tests
|
|
python3 -m pytest tools/iam-profile-conformance/tests
|
|
|
|
playbook-contract-test: ## Run Playbook Capability Contract fixture tests
|
|
python3 -m pytest tools/playbook-capability-contract/tests
|
|
|
|
security-bootstrap-console: security-bootstrap-metadata-init ## Show guided security bootstrap status and safe actions
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
|
--metadata "$(SECURITY_BOOTSTRAP_METADATA)" \
|
|
status
|
|
|
|
security-bootstrap-king-kit: ## Print the king credential kit checklist
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py king-kit
|
|
|
|
security-bootstrap-validate-kit: ## Validate non-secret king credential metadata
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
|
--metadata "$(SECURITY_BOOTSTRAP_METADATA)" \
|
|
validate-king-kit
|
|
|
|
security-bootstrap-validate-t02: ## Validate NET-WP-0017-T02 OpenBao audit/recovery gates
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
|
--metadata "$(SECURITY_BOOTSTRAP_METADATA)" \
|
|
validate-t02 \
|
|
--railiance-path "$(RAILIANCE_PLATFORM_PATH)" \
|
|
--restore-evidence "$(OPENBAO_RESTORE_EVIDENCE)" \
|
|
--emergency-evidence "$(OPENBAO_EMERGENCY_EVIDENCE)" \
|
|
--custody-roster "$(CUSTODY_ROSTER)" \
|
|
--custody-roster-signature "$(CUSTODY_ROSTER_SIGNATURE)" \
|
|
--custody-roster-allowed-signers "$(CUSTODY_ROSTER_ALLOWED_SIGNERS)"
|
|
|
|
security-bootstrap-validate-cleanup: ## Validate NET-WP-0017-T03/T04 cleanup and taint evidence
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
|
--metadata "$(SECURITY_BOOTSTRAP_METADATA)" \
|
|
validate-cleanup \
|
|
--evidence "$(BOOTSTRAP_CLEANUP_EVIDENCE)"
|
|
|
|
security-bootstrap-validate-lifecycle-flow: ## Validate NET-WP-0017-T05 lifecycle operator-flow evidence
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
|
validate-lifecycle-flow \
|
|
--evidence "$(LIFECYCLE_FLOW_EVIDENCE)"
|
|
|
|
security-bootstrap-validate-onboarding-dry-run: ## Validate NET-WP-0017-T06 non-root onboarding dry-run evidence
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
|
validate-onboarding-dry-run \
|
|
--evidence "$(ONBOARDING_DRY_RUN_EVIDENCE)"
|
|
|
|
security-bootstrap-custody-roster-template: ## Print a non-secret two-of-three custody roster template
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py custody-roster-template
|
|
|
|
security-bootstrap-cleanup-evidence-template: ## Print non-secret NET-WP-0017-T03/T04 cleanup and taint evidence JSON template
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py cleanup-evidence-template
|
|
|
|
security-bootstrap-lifecycle-flow-template: ## Print non-secret NET-WP-0017-T05 lifecycle operator-flow evidence JSON template
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py lifecycle-flow-template
|
|
|
|
security-bootstrap-lifecycle-guide: ## Print the practical T05 operator flow guide (onboard/lock/offboard/review/fabric-admin with previews + commands)
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py lifecycle-guide
|
|
|
|
security-bootstrap-onboarding-dry-run-template: ## Print non-secret NET-WP-0017-T06 onboarding dry-run evidence JSON template (use to start T06 evidence after running the lifecycle flow)
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py onboarding-dry-run-template
|
|
|
|
security-bootstrap-onboarding-dry-run: ## Run the T06 non-root dry-run orchestrator (see sso-mfa/k8s/lldap/dry-run-nonroot-user.sh and NET-WP-0019). Usage: make ... SUBJECT=foo EMAIL=foo@ex.com DISPLAY="Foo"
|
|
@cd sso-mfa/k8s/lldap && \
|
|
./dry-run-nonroot-user.sh $(or $(SUBJECT),t06-dryrun) $(or $(EMAIL),t06-dryrun@coulomb.social) "$(or $(DISPLAY),T06 Dry Run User)" --actor user --scope none
|
|
|
|
security-bootstrap-lifecycle-cleanup-dryrun-users: ## Clean up dry-run/test users by pattern (NET-WP-0019 T04). Usage: make ... PATTERN=t06-*
|
|
@cd sso-mfa/k8s/lldap && \
|
|
./dry-run-nonroot-user.sh --cleanup-only "$(or $(PATTERN),t06-*)"
|
|
|
|
security-bootstrap-validate-custody-roster: ## Validate and verify the signed local custody roster
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
|
validate-custody-roster \
|
|
--roster "$(CUSTODY_ROSTER)" \
|
|
--signature "$(CUSTODY_ROSTER_SIGNATURE)" \
|
|
--allowed-signers "$(CUSTODY_ROSTER_ALLOWED_SIGNERS)"
|
|
|
|
security-bootstrap-sign-custody-roster: ## Sign the ignored local custody roster with an SSH signing key
|
|
@mkdir -p "$$(dirname "$(CUSTODY_ROSTER_ALLOWED_SIGNERS)")"
|
|
@printf '%s ' "$(CUSTODY_ROSTER_SIGNING_PRINCIPAL)" > "$(CUSTODY_ROSTER_ALLOWED_SIGNERS)"
|
|
@cat "$(CUSTODY_ROSTER_SIGNING_KEY).pub" >> "$(CUSTODY_ROSTER_ALLOWED_SIGNERS)"
|
|
ssh-keygen -Y sign \
|
|
-f "$(CUSTODY_ROSTER_SIGNING_KEY)" \
|
|
-n netkingdom-custody-roster \
|
|
"$(CUSTODY_ROSTER)"
|
|
@if [[ "$(CUSTODY_ROSTER_SIGNATURE)" != "$(CUSTODY_ROSTER).sig" ]]; then \
|
|
cp "$(CUSTODY_ROSTER).sig" "$(CUSTODY_ROSTER_SIGNATURE)"; \
|
|
fi
|
|
|
|
security-bootstrap-approve-custody: ## Approve custody mode metadata: make security-bootstrap-approve-custody ARGS="--mfa-enrolled-confirmed --mfa-enrollment-source identity-provider --recovery-confirmed --custody-packet-prepared --no-secret-capture-confirmed"
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
|
--metadata "$(SECURITY_BOOTSTRAP_METADATA)" \
|
|
approve-custody-mode \
|
|
--mode "$(if $(MODE),$(MODE),temporary-single-king)" \
|
|
$(ARGS)
|
|
|
|
security-bootstrap-custody-packet: ## Print a blank offline custody packet template
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py custody-packet
|
|
|
|
security-bootstrap-openbao-preflight: ## Show safe OpenBao preflight commands
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py openbao-preflight \
|
|
--railiance-path ../railiance-platform
|
|
|
|
security-bootstrap-metadata-init: ## Create durable local non-secret bootstrap metadata if missing
|
|
@mkdir -p "$$(dirname "$(SECURITY_BOOTSTRAP_METADATA)")"
|
|
@if [[ -f "$(SECURITY_BOOTSTRAP_METADATA)" ]]; then \
|
|
echo "✔ Metadata already exists: $(SECURITY_BOOTSTRAP_METADATA)"; \
|
|
elif [[ -f /tmp/net-kingdom-security-bootstrap.json ]]; then \
|
|
cp /tmp/net-kingdom-security-bootstrap.json "$(SECURITY_BOOTSTRAP_METADATA)"; \
|
|
echo "✔ Imported previous /tmp bootstrap metadata to $(SECURITY_BOOTSTRAP_METADATA)"; \
|
|
else \
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py metadata-template \
|
|
> "$(SECURITY_BOOTSTRAP_METADATA)"; \
|
|
echo "✔ Created metadata: $(SECURITY_BOOTSTRAP_METADATA)"; \
|
|
fi
|
|
|
|
security-bootstrap-ui: security-bootstrap-metadata-init ## Serve local custody approval UI on localhost:8876: make security-bootstrap-ui
|
|
python3 tools/security-bootstrap-console/security_bootstrap_console.py \
|
|
--metadata "$(SECURITY_BOOTSTRAP_METADATA)" \
|
|
web-ui \
|
|
--host "$(SECURITY_BOOTSTRAP_HOST)" \
|
|
--port "$(SECURITY_BOOTSTRAP_PORT)"
|
|
|
|
.PHONY: help hooks hooks-test sops-setup sops-edit sops-encrypt sops-decrypt sops-rotate \
|
|
check-secrets creds-init creds-generate creds-bundle creds-apply creds-verify \
|
|
creds-status creds-rotate \
|
|
creds-agent-init creds-agent-status creds-emergency-reprint \
|
|
iam-profile-conformance-test playbook-contract-test \
|
|
security-bootstrap-console security-bootstrap-king-kit \
|
|
security-bootstrap-validate-kit security-bootstrap-validate-t02 \
|
|
security-bootstrap-validate-cleanup \
|
|
security-bootstrap-validate-lifecycle-flow \
|
|
security-bootstrap-validate-onboarding-dry-run \
|
|
security-bootstrap-custody-roster-template \
|
|
security-bootstrap-cleanup-evidence-template \
|
|
security-bootstrap-lifecycle-flow-template \
|
|
security-bootstrap-lifecycle-guide \
|
|
security-bootstrap-onboarding-dry-run-template \
|
|
security-bootstrap-onboarding-dry-run \
|
|
security-bootstrap-lifecycle-cleanup-dryrun-users \
|
|
security-bootstrap-validate-custody-roster \
|
|
security-bootstrap-sign-custody-roster \
|
|
security-bootstrap-approve-custody \
|
|
security-bootstrap-custody-packet security-bootstrap-openbao-preflight \
|
|
security-bootstrap-metadata-init security-bootstrap-ui
|