mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 12:03:59 +00:00
Completes the Phase 2 OIDC laptop dev path. Source for the OIDC surface
(discovery, authorize, token, userinfo, JWKS controllers + signing /
session services) landed on `main` via the merge that brought
claude/crazy-bose-fec256 back. This commit makes Phase 2 actually
exercisable in the k3d dev loop without any GKE deploy.
What's new:
authority/src/main/resources/application-k3d.yml
Spring profile activated by `-Dspring-boot.run.profiles=k3d`.
Enables OIDC (knoe.oidc.enabled=true), points the issuer at
`http://localhost:8080`, sets Kerberos realm to KNOE.LOCAL, and
aligns the datasource with the port-forwarded localhost:5432 DB.
etc/gen_oidc_signing_key.sh (executable)
Idempotent RS256 PKCS#8 keypair generator. Outputs:
etc/secrets/knoe-auth-oidc-key.pem (PEM)
etc/secrets/knoe-auth-oidc-key.b64 (single-line base64 of DER —
directly consumable as KNOE_AUTH_OIDC_SIGNING_KEY by
OidcTokenService.init())
`etc/secrets/` is already gitignored. Set FORCE=1 to rotate.
What's wired:
scripts/k3d-knoe-up.sh
New §7 calls etc/gen_oidc_signing_key.sh after schema seed. Keypair
persists across `make k3d-knoe-down && make k3d-knoe-up` cycles.
scripts/k3d-knoe-pf.sh
Output now includes the KNOE_AUTH_OIDC_SIGNING_KEY export line, the
full `mvn spring-boot:run` invocation with -Dspring-boot.run.profiles=k3d,
and the three OIDC endpoints to curl-test.
What's documented:
docs/local-dev-knoe-auth.md
"Daily loop" Terminal B: now exports KNOE_AUTH_OIDC_SIGNING_KEY,
runs with `-Dspring-boot.run.profiles=k3d`, and the verify section
includes /jwks.json. IntelliJ run config: adds Active Profiles: k3d
and a note about pasting the b64 directly (no shell expansion in
the env-var field).
docs/knoe-system.md
Phase 2 status row split: "k3d setup" → Shipped, "GKE deploy" →
Pending. The "Open work items" Phase 2 entry rewritten to flag
that the GKE deploy is the remaining thread (gated on queue #3 for
the image rebuild as `knoe-auth:latest`).
docs/TODO.md
Promoted "Phase 2 OIDC provider — GKE deploy" into §In progress
(replacing the empty "(none)" placeholder). Done section updated
with two entries: the k3d Phase 1 dev loop (Junie's c3...) and
this Phase 2 OIDC k3d sandbox.
End-to-end loop the engineer can run:
make k3d-knoe-up # one-time, ~5 min
make k3d-knoe-pf & # port-forwards
export KRB5_CONFIG=$PWD/etc/krb5.local.conf
export KNOE_AUTH_OIDC_SIGNING_KEY=$(cat etc/secrets/knoe-auth-oidc-key.b64)
mvn -pl authority spring-boot:run \
-Dspring-boot.run.jvmArguments="-Djava.security.krb5.conf=$PWD/etc/krb5.local.conf" \
-Dspring-boot.run.profiles=k3d
# then:
curl -s http://localhost:8080/.well-known/openid-configuration | jq .issuer
# → "http://localhost:8080"
curl -s http://localhost:8080/jwks.json | jq '.keys[0].kty'
# → "RSA"
Verified locally: keypair generator round-trips through openssl pkey -inform DER
(produces valid 2048-bit RSA keys); idempotent (existing key kept by default,
FORCE=1 rotates); bash -n clean on all 5 touched scripts.
Out of scope (TODO §In progress captures it):
- GKE deploy of Phase 2 (image rebuild + K8s Secret + deployment env vars)
- SPNEGO E2E from host browsers (k3d-mirror Phase 2)
- knoe-auth-as-pod in k3d (k3d-mirror Phase 3)
- OidcCodeService DB persistence (separate track)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
168 lines
6.5 KiB
Bash
Executable File
168 lines
6.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# scripts/k3d-knoe-up.sh
|
|
# Bring up the k3d-knoe local dev cluster: CNPG operator + single-replica DB + KDC + schema.
|
|
#
|
|
# Usage:
|
|
# ./scripts/k3d-knoe-up.sh
|
|
#
|
|
# Prerequisites:
|
|
# k3d, kubectl, docker (running)
|
|
#
|
|
# What it does:
|
|
# 1. Creates k3d cluster "k3d-knoe" (if not present)
|
|
# 2. Installs CNPG operator (v1.29.0)
|
|
# 3. Applies knoe-db CNPG Cluster (single-replica, local-path storage)
|
|
# 4. Waits for CNPG cluster to be healthy
|
|
# 5. Applies KDC manifests (configmap, pvc, deployment, service)
|
|
# 6. Runs etc/init_knoe_auth.sh schema --mode k3d to seed knoe.* tables
|
|
# 7. Generates a persistent RS256 keypair for Phase 2 OIDC signing
|
|
# (etc/gen_oidc_signing_key.sh — idempotent; keeps existing key if present)
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
K8S_KNOE="$REPO_ROOT/k8s/knoe"
|
|
|
|
CLUSTER_NAME="${K3D_CLUSTER_NAME:-k3d-knoe}"
|
|
CTX="k3d-${CLUSTER_NAME}"
|
|
DB_NS="knoe-db-0"
|
|
SYS_NS="knoe-system"
|
|
CNPG_VERSION="${CNPG_OPERATOR_VERSION:-1.29.0}"
|
|
CNPG_NS="cnpg-system"
|
|
|
|
log() { echo "[k3d-knoe-up] $*"; }
|
|
die() { echo "[k3d-knoe-up] ERROR: $*" >&2; exit 1; }
|
|
|
|
kube() { kubectl --context="$CTX" "$@"; }
|
|
|
|
# ── 1. Cluster ────────────────────────────────────────────────────────────────
|
|
|
|
if k3d cluster list 2>/dev/null | awk '{print $1}' | grep -qx "${CLUSTER_NAME#k3d-}"; then
|
|
log "k3d cluster '${CLUSTER_NAME#k3d-}' already exists — skipping create."
|
|
else
|
|
log "Creating k3d cluster '${CLUSTER_NAME#k3d-}'..."
|
|
k3d cluster create "${CLUSTER_NAME#k3d-}" \
|
|
--agents 0 \
|
|
--k3s-arg "--disable=traefik@server:0" \
|
|
--wait
|
|
log "Cluster created."
|
|
fi
|
|
|
|
# Ensure kubeconfig is merged
|
|
k3d kubeconfig merge "${CLUSTER_NAME#k3d-}" --kubeconfig-merge-default >/dev/null 2>&1 || true
|
|
|
|
# ── 2. CNPG operator ──────────────────────────────────────────────────────────
|
|
|
|
log "Installing CNPG operator v${CNPG_VERSION}..."
|
|
kube apply --server-side -f \
|
|
"https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-${CNPG_VERSION%.*}/releases/cnpg-${CNPG_VERSION}.yaml" \
|
|
2>/dev/null || \
|
|
kube apply -f \
|
|
"https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-${CNPG_VERSION%.*}/releases/cnpg-${CNPG_VERSION}.yaml"
|
|
|
|
log "Waiting for CNPG operator to be ready..."
|
|
kube -n "$CNPG_NS" rollout status deployment/cnpg-controller-manager --timeout=120s
|
|
|
|
# ── 3. knoe-db namespace + secret + cluster ───────────────────────────────────
|
|
|
|
kube get namespace "$DB_NS" >/dev/null 2>&1 || kube create namespace "$DB_NS"
|
|
|
|
# Create the knoe-db-user secret (CNPG bootstrap owner secret)
|
|
if ! kube -n "$DB_NS" get secret knoe-db-user >/dev/null 2>&1; then
|
|
log "Creating knoe-db-user secret..."
|
|
kube -n "$DB_NS" create secret generic knoe-db-user \
|
|
--from-literal=username=knoe \
|
|
--from-literal=password=knoe-dev-password
|
|
fi
|
|
|
|
# Render the knoe-db manifest for k3d:
|
|
# - instances: 1 (single-replica)
|
|
# - remove synology-iscsi storageClassName + selector blocks
|
|
# - remove affinity with kubernetes.io/hostname topology
|
|
# - remove plugins block (no barman in k3d)
|
|
# - remove certificates block (no pre-issued TLS secrets in k3d)
|
|
# - remove env block referencing AWS/Garage (not needed locally)
|
|
# - substitute image registry placeholder with a public postgres image
|
|
log "Rendering knoe-db manifest for k3d..."
|
|
RENDERED=$(python3 - <<'PYEOF'
|
|
import re, sys
|
|
|
|
with open("k8s/knoe/knoe-db.yaml") as f:
|
|
text = f.read()
|
|
|
|
# instances: 3 -> 1
|
|
text = re.sub(r'(\binstances:\s*)3\b', r'\g<1>1', text)
|
|
|
|
# Remove plugins block (barman)
|
|
text = re.sub(r'\n plugins:\n( - .*\n( .*\n)*)+', '\n', text)
|
|
|
|
# Remove certificates block
|
|
text = re.sub(r'\n certificates:\n( .*\n)+', '\n', text)
|
|
|
|
# Remove env block (AWS/Garage refs)
|
|
text = re.sub(r'\n env:\n( - .*\n( .*\n)*)+', '\n', text)
|
|
|
|
# Remove walStorage block (not needed for single-replica dev)
|
|
text = re.sub(r'\n walStorage:\n( .*\n)+', '\n', text)
|
|
|
|
# Replace synology-iscsi storageClassName
|
|
text = re.sub(r'storageClassName: synology-iscsi', '', text)
|
|
|
|
# Remove selector block with synology.storage labels
|
|
text = re.sub(r'\n selector:\n matchLabels:\n synology\.storage/role: \w+\n', '\n', text)
|
|
|
|
# Remove affinity block (contains kubernetes.io/hostname)
|
|
text = re.sub(r'\n affinity:\n( .*\n)+', '\n', text)
|
|
|
|
# Replace image placeholder with standard postgres (CNPG uses its own image)
|
|
text = re.sub(
|
|
r'imageName: \$\{KNOE_IMAGE_REGISTRY\}/knoe-db:\$\{KNOE_DB_IMAGE_TAG\}',
|
|
'imageName: ghcr.io/cloudnative-pg/postgresql:17',
|
|
text
|
|
)
|
|
|
|
# Remove maxSyncReplicas (irrelevant for single instance)
|
|
text = re.sub(r'\n maxSyncReplicas: \d+\n', '\n', text)
|
|
|
|
print(text)
|
|
PYEOF
|
|
)
|
|
|
|
echo "$RENDERED" | kube apply -f -
|
|
|
|
log "Waiting for CNPG cluster 'knoe-db' to be healthy (up to 5 min)..."
|
|
for i in $(seq 1 60); do
|
|
phase=$(kube -n "$DB_NS" get cluster knoe-db \
|
|
-o jsonpath='{.status.phase}' 2>/dev/null || echo "")
|
|
if [[ "$phase" == "Cluster in healthy state" ]]; then
|
|
log "CNPG cluster is healthy."
|
|
break
|
|
fi
|
|
if [[ $i -eq 60 ]]; then
|
|
die "CNPG cluster did not become healthy in time. Phase: $phase"
|
|
fi
|
|
echo " [$i/60] phase='$phase' — waiting 5s..."
|
|
sleep 5
|
|
done
|
|
|
|
# ── 4. KDC ────────────────────────────────────────────────────────────────────
|
|
|
|
kube get namespace "$SYS_NS" >/dev/null 2>&1 || kube create namespace "$SYS_NS"
|
|
|
|
log "Provisioning KDC (realm KNOE.LOCAL)..."
|
|
KNOE_MODE=k3d APP_CLUSTER_KUBECONTEXT="$CTX" \
|
|
"$REPO_ROOT/etc/init_knoe_auth.sh" initialize --mode k3d --context "$CTX"
|
|
|
|
# ── 7. Phase 2 OIDC signing key (laptop-side) ────────────────────────────────
|
|
log "Generating RS256 signing key for OIDC (idempotent) ..."
|
|
bash "$REPO_ROOT/etc/gen_oidc_signing_key.sh" || die "OIDC keypair generation failed"
|
|
|
|
log ""
|
|
log "=== k3d-knoe is up ==="
|
|
log " CNPG cluster: kubectl --context=$CTX -n $DB_NS get cluster knoe-db"
|
|
log " KDC: kubectl --context=$CTX -n $SYS_NS get deploy knoe-kdc"
|
|
log ""
|
|
log "Next: make k3d-knoe-pf (opens port-forwards + prints env vars to export)"
|
|
log "Then: see docs/local-dev-knoe-auth.md for the daily loop"
|