generated from coulomb/repo-seed
- 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>
171 lines
7.0 KiB
Bash
Executable File
171 lines
7.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# verify-t03.sh — verify NK-WP-0001-T03 done-criteria
|
|
#
|
|
# Checks:
|
|
# 1. CloudNativePG operator is installed and running
|
|
# 2. Cluster net-kingdom-pg is Ready
|
|
# 3. privacyidea_db database exists
|
|
# 4. privacyidea role exists
|
|
# 5. K8s Secrets are present in the databases namespace
|
|
# 6. (Optional) Scheduled backup CR is present when backup is configured
|
|
#
|
|
# Note: keycloak_db removed — Keycloak replaced by Authelia+LLDAP+KeyCape (T05).
|
|
#
|
|
# Usage:
|
|
# chmod +x verify-t03.sh
|
|
# ./verify-t03.sh
|
|
|
|
set -euo pipefail
|
|
|
|
PASS=0
|
|
FAIL=0
|
|
WARN=0
|
|
|
|
pass() { echo " [PASS] $1"; PASS=$((PASS + 1)); }
|
|
fail() { echo " [FAIL] $1"; FAIL=$((FAIL + 1)); }
|
|
warn() { echo " [WARN] $1"; WARN=$((WARN + 1)); }
|
|
|
|
section() { echo ""; echo "── $1 ──────────────────────────────────────"; }
|
|
|
|
# ── 1. CloudNativePG operator ─────────────────────────────────────────────────
|
|
section "1. CloudNativePG operator"
|
|
|
|
if kubectl get ns cnpg-system &>/dev/null; then
|
|
pass "cnpg-system namespace exists"
|
|
else
|
|
fail "cnpg-system namespace not found — install operator first (see postgresql/README.md)"
|
|
fi
|
|
|
|
if kubectl get crd clusters.postgresql.cnpg.io &>/dev/null; then
|
|
pass "clusters.postgresql.cnpg.io CRD registered"
|
|
else
|
|
fail "CloudNativePG CRD not found — operator not installed"
|
|
fi
|
|
|
|
CNPG_READY=$(kubectl get pods -n cnpg-system -l app.kubernetes.io/name=cloudnative-pg \
|
|
--field-selector=status.phase=Running --no-headers 2>/dev/null | wc -l || echo 0)
|
|
if [[ "$CNPG_READY" -ge 1 ]]; then
|
|
pass "CloudNativePG operator pod running ($CNPG_READY pod(s))"
|
|
else
|
|
fail "No running CloudNativePG operator pods in cnpg-system"
|
|
fi
|
|
|
|
# ── 2. Cluster readiness ──────────────────────────────────────────────────────
|
|
section "2. Cluster net-kingdom-pg"
|
|
|
|
CLUSTER_READY=$(kubectl get cluster net-kingdom-pg -n databases \
|
|
-o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null || echo "")
|
|
if [[ "$CLUSTER_READY" == "True" ]]; then
|
|
pass "Cluster net-kingdom-pg status: Ready"
|
|
else
|
|
CLUSTER_PHASE=$(kubectl get cluster net-kingdom-pg -n databases \
|
|
-o jsonpath='{.status.phase}' 2>/dev/null || echo "not found")
|
|
fail "Cluster net-kingdom-pg not Ready (phase: $CLUSTER_PHASE)"
|
|
fi
|
|
|
|
PRIMARY_POD=$(kubectl get pod -n databases \
|
|
-l "cnpg.io/cluster=net-kingdom-pg,role=primary" \
|
|
--field-selector=status.phase=Running \
|
|
-o name 2>/dev/null | head -1 || echo "")
|
|
if [[ -n "$PRIMARY_POD" ]]; then
|
|
pass "Primary pod running: $PRIMARY_POD"
|
|
else
|
|
fail "No running primary pod found for net-kingdom-pg"
|
|
fi
|
|
|
|
# ── 3. Databases ──────────────────────────────────────────────────────────────
|
|
section "3. Databases"
|
|
|
|
if [[ -n "$PRIMARY_POD" ]]; then
|
|
DB_LIST=$(kubectl exec -n databases "$PRIMARY_POD" -- \
|
|
psql -U postgres -tAc "SELECT datname FROM pg_database WHERE datname = 'privacyidea_db';" \
|
|
2>/dev/null || echo "")
|
|
|
|
if echo "$DB_LIST" | grep -q "privacyidea_db"; then
|
|
pass "privacyidea_db exists"
|
|
else
|
|
fail "privacyidea_db not found"
|
|
fi
|
|
else
|
|
warn "Skipping database checks — no primary pod available"
|
|
fi
|
|
|
|
# ── 4. Roles ──────────────────────────────────────────────────────────────────
|
|
section "4. Database roles"
|
|
|
|
if [[ -n "$PRIMARY_POD" ]]; then
|
|
ROLE_LIST=$(kubectl exec -n databases "$PRIMARY_POD" -- \
|
|
psql -U postgres -tAc "SELECT rolname FROM pg_roles WHERE rolname = 'privacyidea';" \
|
|
2>/dev/null || echo "")
|
|
|
|
if echo "$ROLE_LIST" | grep -q "privacyidea"; then
|
|
pass "role privacyidea exists"
|
|
else
|
|
fail "role privacyidea not found"
|
|
fi
|
|
else
|
|
warn "Skipping role checks — no primary pod available"
|
|
fi
|
|
|
|
# ── 5. K8s Secrets ────────────────────────────────────────────────────────────
|
|
section "5. K8s Secrets (databases namespace)"
|
|
|
|
for secret in net-kingdom-pg-privacyidea-app; do
|
|
if kubectl get secret "$secret" -n databases &>/dev/null; then
|
|
pass "Secret $secret exists"
|
|
else
|
|
fail "Secret $secret not found — run create-secrets.sh"
|
|
fi
|
|
done
|
|
|
|
# CNPG auto-creates these
|
|
for secret in net-kingdom-pg-superuser; do
|
|
if kubectl get secret "$secret" -n databases &>/dev/null; then
|
|
pass "Secret $secret exists (CNPG-managed)"
|
|
else
|
|
warn "Secret $secret not found (CNPG creates this; may appear after cluster init)"
|
|
fi
|
|
done
|
|
|
|
# ── 6. Backup configuration ───────────────────────────────────────────────────
|
|
section "6. Backup (optional until object storage is provisioned)"
|
|
|
|
if kubectl get scheduledbackup net-kingdom-pg-daily -n databases &>/dev/null; then
|
|
BACKUP_SUSPENDED=$(kubectl get scheduledbackup net-kingdom-pg-daily -n databases \
|
|
-o jsonpath='{.spec.suspend}' 2>/dev/null || echo "false")
|
|
if [[ "$BACKUP_SUSPENDED" == "true" ]]; then
|
|
warn "ScheduledBackup net-kingdom-pg-daily is suspended"
|
|
else
|
|
pass "ScheduledBackup net-kingdom-pg-daily present and active"
|
|
fi
|
|
|
|
LAST_BACKUP=$(kubectl get backup -n databases \
|
|
-l "cnpg.io/cluster=net-kingdom-pg" \
|
|
--sort-by='.metadata.creationTimestamp' \
|
|
-o name 2>/dev/null | tail -1 || echo "")
|
|
if [[ -n "$LAST_BACKUP" ]]; then
|
|
pass "At least one backup found: $LAST_BACKUP"
|
|
else
|
|
warn "No backups yet — trigger a manual backup or wait for schedule"
|
|
fi
|
|
else
|
|
warn "ScheduledBackup not deployed — configure object storage, then apply scheduled-backup.yaml"
|
|
fi
|
|
|
|
# ── Summary ───────────────────────────────────────────────────────────────────
|
|
echo ""
|
|
echo "════════════════════════════════════════════════"
|
|
echo " T03 verification: PASS=$PASS WARN=$WARN FAIL=$FAIL"
|
|
echo "════════════════════════════════════════════════"
|
|
|
|
if [[ "$FAIL" -gt 0 ]]; then
|
|
echo " Result: INCOMPLETE — resolve FAIL items before proceeding to T04"
|
|
exit 1
|
|
elif [[ "$WARN" -gt 0 ]]; then
|
|
echo " Result: PARTIAL — T03 core done; WARN items should be addressed before production"
|
|
exit 0
|
|
else
|
|
echo " Result: COMPLETE — T03 done-criteria met"
|
|
exit 0
|
|
fi
|