Two reachable clusters each carry a CNPG Cluster named apps-pg in a namespace named databases. KUBECONFIG is an environment variable, so the Makefile ?= default never applied, and RAILIANCE01_KUBECONFIG pointed at config-hosteurope - a different cluster. Had the environment pointed at the other reachable cluster instead of an unauthorized one, make apps-pg-deploy would have applied RPF-WP-0019 connection limits, role timeouts and backup config to the wrong cluster and reported success. The Unauthorized error was the only thing that prevented it. Filename selection cannot protect against this: both kubeconfigs resolve to a 127.0.0.1 tunnel port and the environment wins either way. railiance01-guard pins identity instead, comparing the live kube-system namespace UID against RAILIANCE01_CLUSTER_UID, and fails closed on mismatch or unreachability. It gates apps-pg deploy, backup-deploy, overflow-dry-run, status and shell. Verified refusing on the wrong cluster, refusing when unreachable, and passing on railiance01. Not global: db-status legitimately targets the other cluster for gitea-db. RPF-WP-0019 blocker note corrected - the cluster was never unreachable, our wiring was wrong. RPF-WP-0020 seeded for the pre-existing CCR test failure, which is two unrelated problems: CCR-2026-0010 is an active lane missing its whole openbao.auth block, and CCR-2026-0011 is an honest in-flight draft the suite has no way to express. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
463 lines
25 KiB
Makefile
463 lines
25 KiB
Makefile
SHELL := /usr/bin/env bash
|
|
.DEFAULT_GOAL := help
|
|
|
|
KUBECONFIG ?= $(firstword $(wildcard $(HOME)/.kube/config-railiance01) $(wildcard $(HOME)/.kube/config))
|
|
KUBECTL_BIN ?= $(firstword $(shell command -v kubectl 2>/dev/null) $(wildcard $(HOME)/.local/bin/kubectl) kubectl)
|
|
KUBECTL := $(KUBECTL_BIN) --kubeconfig=$(KUBECONFIG)
|
|
|
|
# Cluster identity pin (RPF-WP-0019).
|
|
#
|
|
# Two reachable clusters each carry a CNPG Cluster named `apps-pg` in a
|
|
# namespace named `databases`. Selecting by kubeconfig FILENAME does not
|
|
# protect against applying to the wrong one: KUBECONFIG is an environment
|
|
# variable, `?=` does not override it, and both files resolve to a
|
|
# 127.0.0.1 tunnel port. So the guard pins cluster IDENTITY instead —
|
|
# the kube-system namespace UID, which is unique per cluster and stable
|
|
# for its lifetime.
|
|
#
|
|
# railiance01 (k3s v1.35.1) carries platform-pg, forgejo-db and both
|
|
# apps-pg consumers. The other cluster carries gitea-db and only one
|
|
# apps-pg consumer; `db-status` legitimately targets it, which is why the
|
|
# guard is applied per-target rather than globally.
|
|
RAILIANCE01_CLUSTER_UID ?= a553c742-0115-43d4-99a4-a5ca56fe0786
|
|
HELM := helm --kubeconfig=$(KUBECONFIG)
|
|
NAMESPACE := platform
|
|
|
|
PG_CHART_VERSION ?= 16.2.2
|
|
VALKEY_CHART_VERSION ?= 2.x
|
|
OPENBAO_CHART_VERSION ?= 0.28.2
|
|
OPENBAO_NAMESPACE ?= openbao
|
|
OPENBAO_RELEASE ?= openbao
|
|
OPENBAO_VALUES ?= helm/openbao-values.yaml
|
|
OPENBAO_MIDDLEWARE ?= helm/openbao-middleware.yaml
|
|
OPENBAO_UI_OVERLAY_DIR ?= helm/openbao-ui-overlay
|
|
OPENBAO_UI_OVERLAY_K8S ?= helm/openbao-ui-overlay-k8s.yaml
|
|
OPENBAO_VERIFY_AUTH_ARGS ?=
|
|
OPENBAO_RESTORE_EVIDENCE ?= /tmp/netkingdom-openbao-restore-drill/evidence.json
|
|
OPENBAO_EMERGENCY_EVIDENCE ?= /tmp/netkingdom-openbao-emergency-drill/evidence.json
|
|
EXTERNAL_SECRETS_NAMESPACE ?= external-secrets
|
|
ARGOCD_NAMESPACE ?= argocd
|
|
ARGOCD_BOOTSTRAP_DIR ?= argocd/bootstrap
|
|
ARGOCD_REPOSITORY_SECRET ?=
|
|
CREDENTIAL_GRANTS ?= credential-grants/catalog.yaml
|
|
CREDENTIAL_CHANGE ?= CCR-2026-0001
|
|
CREDENTIAL_CHANGE_EVIDENCE_ARGS ?=
|
|
CREDENTIAL_CHANGE_LIFECYCLE_ACTION ?= deactivate
|
|
CREDENTIAL_CHANGE_LIFECYCLE_ARGS ?=
|
|
CREDENTIAL_CHANGE_IMPORT_ARGS ?=
|
|
STATE_HUB_URL ?= http://127.0.0.1:8000
|
|
OPENBAO_TOKEN_GRANT_ARGS ?=
|
|
OPENBAO_CREDENTIAL_CHANGE_APPLIER_ARGS ?=
|
|
OPENBAO_WORKLOAD_KV_ARGS ?=
|
|
CREDENTIAL_HELPER_GLOBAL_ARGS ?=
|
|
CREDENTIAL_HELPER_ARGS ?=
|
|
CREDENTIAL_HELPER_CHILD_ENV ?=
|
|
CREDENTIAL_HELPER_PURPOSE ?= flex-auth-openbao-smoke
|
|
|
|
##@ CloudNative PG (cnpg) — primary database operator
|
|
|
|
db-deploy: ## Apply Gitea cnpg Cluster (creates gitea-db in databases namespace)
|
|
$(KUBECTL) apply -f helm/gitea-db-cluster.yaml
|
|
|
|
db-status: ## Show cnpg cluster health
|
|
$(KUBECTL) cnpg status gitea-db -n databases 2>/dev/null || \
|
|
$(KUBECTL) get cluster gitea-db -n databases -o wide
|
|
|
|
db-shell: ## Open psql shell on gitea-db primary
|
|
$(KUBECTL) cnpg psql gitea-db -n databases -- -U gitea gitea
|
|
|
|
db-logs: ## Tail gitea-db primary logs
|
|
$(KUBECTL) logs -n databases -l cnpg.io/cluster=gitea-db -f --tail=50
|
|
|
|
##@ Forgejo database (railiance01 production forge)
|
|
|
|
forgejo-db-deploy: ## Apply forgejo-db cnpg Cluster + NetworkPolicies on railiance01
|
|
$(KUBECTL) apply -f helm/forgejo-db-cluster.yaml
|
|
$(KUBECTL) apply -f helm/forgejo-db-networkpolicies.yaml
|
|
|
|
forgejo-db-status: ## Show forgejo-db cnpg cluster health
|
|
$(KUBECTL) cnpg status forgejo-db -n databases 2>/dev/null || \
|
|
$(KUBECTL) get cluster forgejo-db -n databases -o wide
|
|
|
|
forgejo-db-shell: ## Open psql shell on forgejo-db primary
|
|
$(KUBECTL) cnpg psql forgejo-db -n databases -- -U forgejo forgejo
|
|
|
|
CONSUMING_ENTITY ?=
|
|
ESTIMATE_EUR ?=
|
|
CONSUMPTION_CLASS ?= new-order
|
|
CONSUMPTION_MODE_FILE ?= data/consumption-mode/current.json
|
|
|
|
##@ Consumption mode (RAILIANCE-WP-0017)
|
|
|
|
consumption-preflight: ## Refuse a new order that exceeds a restricted entity's allowance
|
|
@test -n "$(CONSUMING_ENTITY)" || { echo 'set CONSUMING_ENTITY=entity:<slug>' >&2; exit 2; }
|
|
CONSUMPTION_MODE_FILE='$(CONSUMPTION_MODE_FILE)' python3 scripts/consumption_mode.py check \
|
|
--entity '$(CONSUMING_ENTITY)' \
|
|
--class '$(CONSUMPTION_CLASS)' \
|
|
$(if $(ESTIMATE_EUR),--estimate-eur '$(ESTIMATE_EUR)')
|
|
|
|
##@ Shared apps-pg (S5 application databases)
|
|
|
|
cluster-id: ## Print the kube-system UID of the cluster KUBECONFIG currently selects
|
|
@echo "kubeconfig: $(KUBECONFIG)"
|
|
@echo "cluster-uid: $$($(KUBECTL) get ns kube-system -o jsonpath='{.metadata.uid}' 2>/dev/null || echo UNREACHABLE)"
|
|
|
|
railiance01-guard: ## Fail closed unless KUBECONFIG selects railiance01
|
|
@uid=$$($(KUBECTL) get ns kube-system -o jsonpath='{.metadata.uid}' 2>/dev/null); \
|
|
if [ -z "$$uid" ]; then \
|
|
echo "railiance01-guard: cluster unreachable via $(KUBECONFIG)" >&2; \
|
|
echo " hint: unset KUBECONFIG, or set it to ~/.kube/config-railiance01" >&2; \
|
|
exit 2; \
|
|
fi; \
|
|
if [ "$$uid" != "$(RAILIANCE01_CLUSTER_UID)" ]; then \
|
|
echo "railiance01-guard: REFUSING - wrong cluster" >&2; \
|
|
echo " kubeconfig: $(KUBECONFIG)" >&2; \
|
|
echo " expected: $(RAILIANCE01_CLUSTER_UID)" >&2; \
|
|
echo " found: $$uid" >&2; \
|
|
echo " both clusters carry apps-pg in namespace databases; applying here would hit the wrong one." >&2; \
|
|
exit 2; \
|
|
fi; \
|
|
echo "railiance01-guard: ok ($$uid)"
|
|
|
|
apps-pg-verify-capacity: ## Verify cell ceiling, role limits and distinct backup prefixes
|
|
python3 tools/verify_apps_pg_capacity.py helm/apps-pg-cluster.yaml helm/apps-pg-2-cluster.yaml
|
|
|
|
apps-pg-deploy: railiance01-guard apps-pg-verify-capacity ## Apply shared apps-pg cnpg Cluster + NetworkPolicies
|
|
@if [ -n "$(CONSUMING_ENTITY)" ]; then \
|
|
$(MAKE) consumption-preflight CONSUMING_ENTITY='$(CONSUMING_ENTITY)' \
|
|
ESTIMATE_EUR='$(ESTIMATE_EUR)' CONSUMPTION_CLASS=new-order; \
|
|
fi
|
|
$(KUBECTL) apply -f helm/apps-pg-cluster.yaml
|
|
$(KUBECTL) apply -f helm/apps-pg-networkpolicies.yaml
|
|
|
|
apps-pg-backup-deploy: railiance01-guard ## Apply the daily backup after the governed S3 Secret exists
|
|
@$(KUBECTL) get secret platform-pg-backup-s3 -n databases >/dev/null || { echo 'missing governed platform-pg-backup-s3 secret' >&2; exit 2; }
|
|
$(KUBECTL) apply -f helm/apps-pg-backup.yaml
|
|
|
|
apps-pg-overflow-dry-run: railiance01-guard apps-pg-verify-capacity ## Server-validate the unapplied overflow cell
|
|
@$(KUBECTL) get secret apps-pg-2-credentials -n databases >/dev/null || { echo 'missing distinct apps-pg-2-credentials secret' >&2; exit 2; }
|
|
$(KUBECTL) apply --dry-run=server -f helm/apps-pg-2-cluster.yaml
|
|
$(KUBECTL) apply --dry-run=server -f helm/apps-pg-2-networkpolicies.yaml
|
|
$(KUBECTL) apply --dry-run=server -f helm/apps-pg-2-backup.yaml
|
|
|
|
apps-pg-overflow-deploy: apps-pg-overflow-dry-run ## Provision only for an approved fourth consumer
|
|
$(KUBECTL) apply -f helm/apps-pg-2-cluster.yaml
|
|
$(KUBECTL) apply -f helm/apps-pg-2-networkpolicies.yaml
|
|
$(KUBECTL) apply -f helm/apps-pg-2-backup.yaml
|
|
|
|
apps-pg-status: railiance01-guard ## Show apps-pg cnpg cluster health
|
|
$(KUBECTL) cnpg status apps-pg -n databases 2>/dev/null || \
|
|
$(KUBECTL) get cluster apps-pg -n databases -o wide
|
|
|
|
apps-pg-shell: railiance01-guard ## Open psql shell on apps-pg primary as apps_admin / apps_meta
|
|
$(KUBECTL) cnpg psql apps-pg -n databases -- -U apps_admin apps_meta 2>/dev/null || \
|
|
$(KUBECTL) exec -it -n databases apps-pg-1 -- psql -U apps_admin apps_meta
|
|
|
|
apps-pg-logs: ## Tail apps-pg primary logs
|
|
$(KUBECTL) logs -n databases -l cnpg.io/cluster=apps-pg -f --tail=50
|
|
|
|
net-kingdom-pg-inter-hub-networkpolicy-deploy: ## Allow inter-hub to reach net-kingdom-pg
|
|
$(KUBECTL) apply -f helm/net-kingdom-pg-inter-hub-networkpolicy.yaml
|
|
|
|
##@ PostgreSQL HA (retired — CNPG superseded this)
|
|
|
|
pg-deploy: ## Retired: refuse to deploy Bitnami postgresql-ha
|
|
@echo 'pg-deploy is retired (RAILIANCE-WP-0016 item 14). Use apps-pg / forgejo-db / rapp-postgres.' >&2; exit 2
|
|
|
|
pg-status: ## Confirm Bitnami postgresql-ha is absent
|
|
@if $(KUBECTL) get ns $(NAMESPACE) >/dev/null 2>&1; then \
|
|
$(KUBECTL) get pods -n $(NAMESPACE) -l app.kubernetes.io/name=postgresql-ha; \
|
|
else \
|
|
echo 'postgresql-ha retired: namespace $(NAMESPACE) is absent'; \
|
|
fi
|
|
|
|
pg-pgpool-check: ## Retired: no pgpool secret to check
|
|
@echo 'pg-pgpool-check is retired with postgresql-ha (RAILIANCE-WP-0016 item 14).' >&2; exit 2
|
|
|
|
##@ Valkey (cache) — declared, not deployed
|
|
|
|
valkey-deploy: ## Gated: do not deploy Valkey until a consumer rapp exists
|
|
@echo 'valkey-deploy is gated (RAILIANCE-WP-0016 item 14): no live consumer, nothing to extract from S2.' >&2; exit 2
|
|
|
|
valkey-status: ## Confirm Valkey is absent
|
|
@if $(KUBECTL) get ns $(NAMESPACE) >/dev/null 2>&1; then \
|
|
$(KUBECTL) get pods -n $(NAMESPACE) -l app.kubernetes.io/name=valkey; \
|
|
else \
|
|
echo 'valkey undeployed: namespace $(NAMESPACE) is absent'; \
|
|
fi
|
|
|
|
##@ OpenBao (secrets)
|
|
|
|
openbao-repo: ## Add / update the official OpenBao Helm repository
|
|
$(HELM) repo add openbao https://openbao.github.io/openbao-helm --force-update
|
|
$(HELM) repo update openbao
|
|
|
|
openbao-dry-run: openbao-repo ## Render the OpenBao Helm release without applying it
|
|
$(HELM) upgrade --install $(OPENBAO_RELEASE) openbao/openbao \
|
|
--version $(OPENBAO_CHART_VERSION) \
|
|
--namespace $(OPENBAO_NAMESPACE) \
|
|
--create-namespace \
|
|
-f $(OPENBAO_VALUES) \
|
|
--dry-run
|
|
|
|
openbao-overlay-apply: ## Apply KeyCape login overlay gateway and assets
|
|
OPENBAO_UI_OVERLAY_DIR=$(OPENBAO_UI_OVERLAY_DIR) \
|
|
OPENBAO_UI_OVERLAY_K8S=$(OPENBAO_UI_OVERLAY_K8S) \
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
scripts/openbao-ui-overlay-apply.sh
|
|
|
|
openbao-verify-login-overlay: ## Verify public KeyCape login overlay is active
|
|
OPENBAO_UI_OVERLAY_DIR=$(OPENBAO_UI_OVERLAY_DIR) \
|
|
scripts/openbao-verify-login-overlay.sh $(OPENBAO_VERIFY_LOGIN_OVERLAY_ARGS)
|
|
|
|
openbao-deploy: openbao-repo ## Deploy / upgrade OpenBao to the openbao namespace
|
|
$(KUBECTL) create namespace $(OPENBAO_NAMESPACE) --dry-run=client -o yaml | $(KUBECTL) apply -f -
|
|
$(KUBECTL) apply -f $(OPENBAO_MIDDLEWARE)
|
|
$(HELM) upgrade --install $(OPENBAO_RELEASE) openbao/openbao \
|
|
--version $(OPENBAO_CHART_VERSION) \
|
|
--namespace $(OPENBAO_NAMESPACE) \
|
|
-f $(OPENBAO_VALUES) \
|
|
--wait --timeout 5m
|
|
$(MAKE) openbao-overlay-apply
|
|
|
|
openbao-status: ## Show OpenBao pods, services, PVCs, and seal/init status
|
|
$(KUBECTL) get pods,svc,pvc -n $(OPENBAO_NAMESPACE) \
|
|
-l app.kubernetes.io/instance=$(OPENBAO_RELEASE) -o wide
|
|
-$(KUBECTL) exec -n $(OPENBAO_NAMESPACE) $(OPENBAO_RELEASE)-0 -- bao status
|
|
|
|
openbao-verify: ## Run non-secret OpenBao deployment checks
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-verify.sh basic
|
|
|
|
openbao-verify-post-unseal: ## Run post-unseal OpenBao filesystem checks
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-verify.sh post-unseal
|
|
|
|
openbao-configure-initial: ## Apply first post-unseal audit, auth, mounts, and policies
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-apply-initial-config.sh
|
|
|
|
openbao-configure-ssh: ## Enable SSH secrets engine, roles, and warden-sign policy
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-apply-ssh-engine.sh
|
|
|
|
openbao-verify-ssh: ## Verify SSH engine mount, roles, and warden-sign policy
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-verify-ssh-engine.sh
|
|
|
|
openbao-verify-authenticated: ## Run authenticated non-mutating OpenBao audit/auth/mount checks
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) scripts/openbao-verify-authenticated.sh $(OPENBAO_VERIFY_AUTH_ARGS)
|
|
|
|
openbao-configure-external-secrets-issue-core: ## Configure OpenBao policy/role for issue-core ESO pilot
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) ESO_NAMESPACE=$(EXTERNAL_SECRETS_NAMESPACE) \
|
|
scripts/openbao-apply-external-secrets-issue-core.sh
|
|
|
|
openbao-configure-external-secrets-activity-core: ## Configure OpenBao policy/role for activity-core ESO lane
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) OPENBAO_RELEASE=$(OPENBAO_RELEASE) ESO_NAMESPACE=$(EXTERNAL_SECRETS_NAMESPACE) OPENBAO_ESO_ROLE=external-secrets-activity-core OPENBAO_ESO_POLICY=external-secrets-activity-core POLICY_FILE='$(CURDIR)/openbao/policies/external-secrets-activity-core.hcl' OPENBAO_ESO_NEXT_PATH=platform/workloads/issue-core/issue-core/issue-core-runtime OPENBAO_ESO_NEXT_FIELDS=ISSUE_CORE_API_KEY OPENBAO_ESO_NEXT_TARGET=ExternalSecret/activity-core/actcore-issue-core-runtime scripts/openbao-apply-external-secrets-issue-core.sh
|
|
|
|
openbao-configure-external-secrets-forgejo: ## Configure OpenBao policy/role for Forgejo mailer ESO lane
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) ESO_NAMESPACE=$(EXTERNAL_SECRETS_NAMESPACE) \
|
|
OPENBAO_ESO_ROLE=external-secrets-forgejo \
|
|
OPENBAO_ESO_POLICY=external-secrets-forgejo \
|
|
POLICY_FILE='$(CURDIR)/openbao/policies/external-secrets-forgejo.hcl' \
|
|
OPENBAO_ESO_NEXT_PATH=platform/workloads/forgejo/forgejo-mailer \
|
|
OPENBAO_ESO_NEXT_FIELDS=MAILER_PASSWD \
|
|
OPENBAO_ESO_NEXT_TARGET=ExternalSecret/forgejo/forgejo-mailer \
|
|
scripts/openbao-apply-external-secrets-issue-core.sh
|
|
|
|
openbao-workload-kv-lanes-dry-run: ## Dry-run OpenBao workload KV read-lane policy apply
|
|
scripts/openbao-apply-workload-kv-lanes.sh --dry-run $(OPENBAO_WORKLOAD_KV_ARGS)
|
|
|
|
openbao-configure-workload-kv-lanes: ## Configure OpenBao workload KV read-lane policies
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/openbao-apply-workload-kv-lanes.sh $(OPENBAO_WORKLOAD_KV_ARGS)
|
|
|
|
openbao-validate-restore-evidence: ## Validate non-secret OpenBao restore-drill evidence JSON
|
|
OPENBAO_RESTORE_EVIDENCE='$(OPENBAO_RESTORE_EVIDENCE)' \
|
|
scripts/openbao-validate-restore-evidence.sh
|
|
|
|
openbao-validate-emergency-evidence: ## Validate non-secret OpenBao emergency seal/unseal drill evidence JSON
|
|
OPENBAO_EMERGENCY_EVIDENCE='$(OPENBAO_EMERGENCY_EVIDENCE)' \
|
|
scripts/openbao-validate-emergency-drill-evidence.sh
|
|
|
|
##@ Credential broker
|
|
|
|
credential-grants-validate: ## Validate non-secret credential grant catalog
|
|
scripts/credential-grants-validate.py $(CREDENTIAL_GRANTS)
|
|
|
|
credential-change-validate: ## Validate non-secret credential change requests
|
|
scripts/credential-change.py validate
|
|
|
|
credential-change-render: ## Render a credential change request review summary
|
|
scripts/credential-change.py render $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-plan: ## Render a credential change request apply plan for review
|
|
scripts/credential-change.py plan $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-decision-templates: ## Render CCR approve/deny/needs-changes templates
|
|
scripts/credential-change.py decision-templates $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-status: ## Render credential change request readiness status
|
|
scripts/credential-change.py status $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-status-json: ## Render credential change request readiness status as JSON
|
|
scripts/credential-change.py status --json $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-sync-decision: ## Sync resolved State Hub decision back into a CCR
|
|
scripts/credential-change.py sync-decision $(CREDENTIAL_CHANGE) --state-hub-url $(STATE_HUB_URL)
|
|
|
|
credential-change-apply-plan: ## Render approved-only operator apply plan
|
|
scripts/credential-change.py apply-plan $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-operator-commands: ## Render approved-only non-secret OpenBao operator commands
|
|
scripts/credential-change.py operator-commands $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-applier-dry-run: ## Validate delegated OpenBao metadata mutations for a CCR
|
|
scripts/credential-change.py applier-dry-run $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-applier-apply-plan: ## Render delegated OpenBao metadata apply plan
|
|
scripts/credential-change.py applier-apply $(CREDENTIAL_CHANGE) --plan-only
|
|
|
|
credential-change-applier-apply: ## Apply delegated metadata; pass confirmation/actor args via CREDENTIAL_CHANGE_EVIDENCE_ARGS
|
|
scripts/credential-change.py applier-apply $(CREDENTIAL_CHANGE) $(CREDENTIAL_CHANGE_EVIDENCE_ARGS)
|
|
|
|
credential-change-runbook: ## Render the attended CCR apply/verify runbook
|
|
scripts/credential-change.py runbook $(CREDENTIAL_CHANGE)
|
|
|
|
credential-change-record-evidence: ## Record non-secret CCR evidence; pass CREDENTIAL_CHANGE_EVIDENCE_ARGS
|
|
scripts/credential-change.py record-evidence $(CREDENTIAL_CHANGE) $(CREDENTIAL_CHANGE_EVIDENCE_ARGS)
|
|
|
|
credential-change-lifecycle-plan: ## Render deactivation/rotation/compromise lifecycle guidance
|
|
scripts/credential-change.py lifecycle-plan $(CREDENTIAL_CHANGE) --action $(CREDENTIAL_CHANGE_LIFECYCLE_ACTION)
|
|
|
|
credential-change-lifecycle-event: ## Record lifecycle event; pass CREDENTIAL_CHANGE_LIFECYCLE_ARGS
|
|
scripts/credential-change.py lifecycle-event $(CREDENTIAL_CHANGE) --action $(CREDENTIAL_CHANGE_LIFECYCLE_ACTION) $(CREDENTIAL_CHANGE_LIFECYCLE_ARGS)
|
|
|
|
credential-change-import-inventory: ## Import existing lane as non-secret CCR; pass CREDENTIAL_CHANGE_IMPORT_ARGS
|
|
scripts/credential-change.py import-inventory $(CREDENTIAL_CHANGE_IMPORT_ARGS)
|
|
|
|
openbao-credential-change-appliers-dry-run: ## Dry-run credential-change applier policies/token roles
|
|
scripts/openbao-apply-credential-change-appliers.py --dry-run $(OPENBAO_CREDENTIAL_CHANGE_APPLIER_ARGS)
|
|
|
|
openbao-configure-credential-change-appliers: ## Apply credential-change applier policies/token roles
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/openbao-apply-credential-change-appliers.py $(OPENBAO_CREDENTIAL_CHANGE_APPLIER_ARGS)
|
|
|
|
openbao-token-grants-dry-run: ## Dry-run OpenBao token roles and issuer policies for credential grants
|
|
scripts/openbao-apply-token-grants.py --dry-run $(OPENBAO_TOKEN_GRANT_ARGS)
|
|
|
|
openbao-configure-token-grants: ## Apply OpenBao token roles and issuer policies for credential grants
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/openbao-apply-token-grants.py $(OPENBAO_TOKEN_GRANT_ARGS)
|
|
|
|
openbao-verify-token-grants-dry-run: ## Dry-run OpenBao token grant verification
|
|
scripts/openbao-verify-token-grants.py --dry-run $(OPENBAO_TOKEN_GRANT_ARGS)
|
|
|
|
openbao-verify-token-grants: ## Verify OpenBao token roles and issuer policies for credential grants
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/openbao-verify-token-grants.py $(OPENBAO_TOKEN_GRANT_ARGS)
|
|
|
|
openbao-verify-token-grants-smoke: ## Mint/revoke a child token and prove bounded warden-sign capabilities
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/openbao-verify-token-grants.py --issue-smoke-token $(OPENBAO_TOKEN_GRANT_ARGS)
|
|
|
|
credential-helper-dry-run: ## Dry-run credential request, exec, status, and revoke helper flows
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) request --dry-run \
|
|
--grant ops-warden/warden-sign --purpose $(CREDENTIAL_HELPER_PURPOSE) \
|
|
$(CREDENTIAL_HELPER_ARGS)
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) request --dry-run \
|
|
--grant ops-warden/warden-sign --purpose $(CREDENTIAL_HELPER_PURPOSE) \
|
|
--delivery kubernetes-auth $(CREDENTIAL_HELPER_ARGS)
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) exec --dry-run \
|
|
--grant ops-warden/warden-sign --purpose $(CREDENTIAL_HELPER_PURPOSE) \
|
|
$(CREDENTIAL_HELPER_ARGS) -- SMOKE_VAULT=1 /bin/true
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) status --dry-run example-accessor
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) revoke --dry-run example-accessor
|
|
|
|
credential-tests: ## Run offline credential broker unit tests
|
|
python3 -m unittest discover -s tests -p 'test_credential*.py'
|
|
|
|
credential-change-tests: ## Run credential change request unit tests
|
|
python3 -m unittest discover -s tests -p 'test_credential_change.py'
|
|
|
|
credential-exec-ops-warden-smoke: ## Run ops-warden smoke with an exec-injected warden-sign token
|
|
KUBECTL='$(KUBECTL)' OPENBAO_NAMESPACE=$(OPENBAO_NAMESPACE) \
|
|
OPENBAO_RELEASE=$(OPENBAO_RELEASE) \
|
|
scripts/credential.py $(CREDENTIAL_HELPER_GLOBAL_ARGS) exec \
|
|
--grant ops-warden/warden-sign --purpose ops-warden-production-sign-smoke \
|
|
$(CREDENTIAL_HELPER_ARGS) -- \
|
|
$(CREDENTIAL_HELPER_CHILD_ENV) \
|
|
SMOKE_VAULT=1 /home/worsch/ops-warden/scripts/policy_gate_production_smoke.sh
|
|
|
|
##@ ArgoCD GitOps bootstrap
|
|
|
|
argocd-bootstrap-dry-run: ## Server-side dry-run ArgoCD AppProjects and root Application
|
|
$(KUBECTL) apply --dry-run=server -k $(ARGOCD_BOOTSTRAP_DIR)
|
|
|
|
argocd-bootstrap-deploy: ## Apply ArgoCD AppProjects and root Application
|
|
$(KUBECTL) apply -k $(ARGOCD_BOOTSTRAP_DIR)
|
|
|
|
argocd-repo-apply: ## Apply a SOPS-encrypted ArgoCD repository Secret (set ARGOCD_REPOSITORY_SECRET)
|
|
@test -n "$(ARGOCD_REPOSITORY_SECRET)" || \
|
|
(echo "ERROR: set ARGOCD_REPOSITORY_SECRET=argocd/repositories/<repo>.repository.sops.yaml"; exit 1)
|
|
sops -d $(ARGOCD_REPOSITORY_SECRET) | $(KUBECTL) apply -f -
|
|
|
|
argocd-status: ## Show Railiance ArgoCD projects, root app, and registered repos
|
|
$(KUBECTL) get appprojects.argoproj.io -n $(ARGOCD_NAMESPACE) \
|
|
railiance-bootstrap railiance-tenants railiance-platform-addons
|
|
$(KUBECTL) get applications.argoproj.io -n $(ARGOCD_NAMESPACE) \
|
|
railiance-apps-root external-secrets openbao-secretstore issue-core
|
|
$(KUBECTL) get secrets -n $(ARGOCD_NAMESPACE) \
|
|
-l argocd.argoproj.io/secret-type=repository
|
|
|
|
##@ Backup
|
|
|
|
RAILIANCE01_KUBECONFIG ?= $(HOME)/.kube/config-railiance01
|
|
|
|
backup: ## Backup platform services (PostgreSQL logical dump) — age-encrypted to Nextcloud
|
|
@test -x tools/cmd/railiance-backup || { echo "tools/cmd/railiance-backup not installed; use forgejo-backup for Forgejo." >&2; exit 1; }
|
|
sudo tools/cmd/railiance-backup
|
|
|
|
forgejo-backup: ## Forgejo dump + forgejo-db pg_dump → age → Nextcloud (T04/T09 Option A)
|
|
KUBECONFIG="$(RAILIANCE01_KUBECONFIG)" tools/cmd/forgejo-backup
|
|
|
|
forgejo-backup-dry-run: ## Forgejo backup without Nextcloud upload
|
|
KUBECONFIG="$(RAILIANCE01_KUBECONFIG)" RAILIANCE_BACKUP_DRY_RUN=1 tools/cmd/forgejo-backup
|
|
|
|
forgejo-backup-status: ## Show last Forgejo backup success and 7-day gate
|
|
@STAMP="$(HOME)/.cache/railiance/backups/forgejo/success-log"; \
|
|
if [[ ! -f "$$STAMP" ]]; then echo "No forgejo backups recorded yet."; exit 1; fi; \
|
|
echo "Last success: $$(tail -1 "$$STAMP")"; \
|
|
echo "Recent successes:"; tail -7 "$$STAMP"; \
|
|
echo "7-day gate: $$(tail -7 "$$STAMP" | wc -l)/7 consecutive days logged (verify cron separately)"
|
|
|
|
forgejo-package-prune-dry-run: ## List Forgejo package versions beyond retention depth (no deletes)
|
|
tools/cmd/forgejo-package-prune
|
|
|
|
forgejo-package-prune: ## Prune Forgejo packages — keep newest 3 versions per package
|
|
tools/cmd/forgejo-package-prune --apply
|
|
|
|
##@ Family declarations
|
|
|
|
reef-deployables: ## Capture live reef-railiance deployables for the family validator
|
|
python3 scripts/capture-reef-deployables.py -o docs/evidence/reef-railiance-deployables.json
|
|
|
|
apps-pg-evidence: ## Capture non-secret apps-pg capacity evidence for resource-control
|
|
python3 scripts/capture-apps-pg-evidence.py -o docs/evidence/RAILIANCE-WP-0016-apps-pg-observation.json
|
|
|
|
##@ Help
|
|
|
|
help: ## Show this help
|
|
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} \
|
|
/^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-22s\033[0m %s\n", $$1, $$2 } \
|
|
/^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) }' $(MAKEFILE_LIST)
|
|
|
|
.PHONY: db-deploy db-status db-shell db-logs forgejo-db-deploy forgejo-db-status forgejo-db-shell apps-pg-deploy apps-pg-status apps-pg-shell apps-pg-logs net-kingdom-pg-inter-hub-networkpolicy-deploy pg-deploy pg-status pg-pgpool-check valkey-deploy valkey-status openbao-repo openbao-dry-run openbao-overlay-apply openbao-verify-login-overlay openbao-deploy openbao-status openbao-verify openbao-verify-post-unseal openbao-configure-initial openbao-configure-ssh openbao-verify-ssh openbao-verify-authenticated openbao-configure-external-secrets-issue-core openbao-configure-external-secrets-activity-core openbao-configure-external-secrets-forgejo openbao-validate-restore-evidence openbao-validate-emergency-evidence credential-grants-validate credential-change-applier-dry-run credential-change-applier-apply-plan credential-change-applier-apply credential-change-runbook credential-change-record-evidence credential-change-lifecycle-plan credential-change-lifecycle-event credential-change-import-inventory openbao-credential-change-appliers-dry-run openbao-configure-credential-change-appliers openbao-token-grants-dry-run openbao-configure-token-grants openbao-verify-token-grants-dry-run openbao-verify-token-grants openbao-verify-token-grants-smoke credential-helper-dry-run credential-tests credential-exec-ops-warden-smoke argocd-bootstrap-dry-run argocd-bootstrap-deploy argocd-repo-apply argocd-status backup forgejo-backup forgejo-backup-dry-run forgejo-backup-status forgejo-package-prune forgejo-package-prune-dry-run reef-deployables apps-pg-evidence consumption-preflight help
|