Deploy Keycloak IdP to cluster (Phase 5a) #34

Merged
forgejo_admin merged 6 commits from 32-deploy-keycloak-idp-to-cluster-phase-5a into main 2026-03-14 14:53:51 +00:00

Summary

  • Deploys Keycloak as a self-hosted identity provider on the cluster using the Bitnami Helm chart (v25.2.0) with built-in PostgreSQL
  • Exposes it via Tailscale funnel at keycloak.tail5b443a.ts.net
  • Infrastructure-only -- no realms, clients, or users configured (Phase 5b)

Changes

  • terraform/main.tf -- Added 3 new resources: kubernetes_namespace_v1.keycloak, helm_release.keycloak (Bitnami OCI chart v25.2.0), kubernetes_ingress_v1.keycloak_funnel with Tailscale funnel annotation and depends_on for tailscale_operator + ACL
  • terraform/variables.tf -- Added keycloak_admin_password variable (sensitive, type string, min 8 chars validation)
  • terraform/outputs.tf -- Added keycloak_url output

Test Plan

  • tofu fmt -check passes
  • tofu validate passes (Success! The configuration is valid.)
  • tofu plan with full secrets shows exactly 3 new resources (namespace, helm_release, ingress)
  • tofu apply -- Keycloak and PostgreSQL pods start in keycloak namespace
  • Visit https://keycloak.tail5b443a.ts.net -- admin console loads
  • Log in with admin credentials -- master realm accessible

Review Checklist

  • Passed automated review-fix loop
  • No secrets committed
  • No unnecessary file changes
  • Commit messages are descriptive
  • Closes #32
  • Plan: plan-2026-03-08-tryout-prep (Phase 5a)
## Summary - Deploys Keycloak as a self-hosted identity provider on the cluster using the Bitnami Helm chart (v25.2.0) with built-in PostgreSQL - Exposes it via Tailscale funnel at `keycloak.tail5b443a.ts.net` - Infrastructure-only -- no realms, clients, or users configured (Phase 5b) ## Changes - `terraform/main.tf` -- Added 3 new resources: `kubernetes_namespace_v1.keycloak`, `helm_release.keycloak` (Bitnami OCI chart v25.2.0), `kubernetes_ingress_v1.keycloak_funnel` with Tailscale funnel annotation and depends_on for tailscale_operator + ACL - `terraform/variables.tf` -- Added `keycloak_admin_password` variable (sensitive, type string, min 8 chars validation) - `terraform/outputs.tf` -- Added `keycloak_url` output ## Test Plan - [x] `tofu fmt -check` passes - [x] `tofu validate` passes (Success! The configuration is valid.) - [ ] `tofu plan` with full secrets shows exactly 3 new resources (namespace, helm_release, ingress) - [ ] `tofu apply` -- Keycloak and PostgreSQL pods start in `keycloak` namespace - [ ] Visit `https://keycloak.tail5b443a.ts.net` -- admin console loads - [ ] Log in with admin credentials -- master realm accessible ## Review Checklist - [x] Passed automated review-fix loop - [x] No secrets committed - [x] No unnecessary file changes - [x] Commit messages are descriptive ## Related - Closes #32 - Plan: `plan-2026-03-08-tryout-prep` (Phase 5a)
Add Bitnami Keycloak Helm chart (v25.2.0) with built-in PostgreSQL,
Tailscale funnel ingress, and sensitive admin password variable.
Three new resources: namespace, helm_release, ingress.

Closes #32

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

PR #34 Review

BLOCKERS

None. The code is correct and follows all established patterns in the codebase.

NITS

  1. Missing tofu plan output in PR body. The repo's own CLAUDE.md states: "Include tofu plan output for any Terraform changes." The .github/PULL_REQUEST_TEMPLATE.md has a dedicated section for this. The PR's Test Plan shows the tofu plan checkbox as unchecked. This is non-blocking since tofu fmt and tofu validate both passed, and the diff is straightforward (3 additive resources, 0 modifications), but the plan output should be included for completeness per repo conventions.

  2. PR body deviates from repo PR template. The PR uses ## Changes / ## Test Plan / ## Related sections instead of the repo template's ## Discovered Scope / ## Terraform Changes / ## README Impact sections. This is a minor structural mismatch. The content is all present and thorough -- just organized differently than the template prescribes.

  3. Built-in PostgreSQL vs. CNPG. The platform has an established pattern of using CNPG for Postgres (architectural consensus: "Apps own their postgres via CNPG Cluster CR"). The Bitnami subchart Postgres is reasonable for Phase 5a (infra-only), but Phase 5b or beyond should consider migrating to CNPG for consistency. This is a future consideration, not a blocker for this PR.

SOP COMPLIANCE

  • Branch named after issue (32-deploy-keycloak-idp-to-cluster-phase-5a)
  • PR body has Summary, Changes, Test Plan, Related sections
  • Related section references plan slug (plan-2026-03-08-tryout-prep) and Closes #32
  • No secrets, .env files, or credentials committed (.gitignore covers .tfvars, .env, secrets/)
  • No unnecessary file changes (3 files, all directly scoped to Keycloak deployment)
  • Commit messages are descriptive
  • set_sensitive with type = "string" used for password (matches platform convention)
  • Ingress pattern matches all other Tailscale funnels (annotation, class, depends_on)
  • Variable has sensitive = true and length validation (matches Harbor/MinIO pattern)
  • tofu plan output not included in PR body (repo convention)

VERDICT: APPROVED

## PR #34 Review ### BLOCKERS None. The code is correct and follows all established patterns in the codebase. ### NITS 1. **Missing `tofu plan` output in PR body.** The repo's own `CLAUDE.md` states: "Include `tofu plan` output for any Terraform changes." The `.github/PULL_REQUEST_TEMPLATE.md` has a dedicated section for this. The PR's Test Plan shows the `tofu plan` checkbox as unchecked. This is non-blocking since `tofu fmt` and `tofu validate` both passed, and the diff is straightforward (3 additive resources, 0 modifications), but the plan output should be included for completeness per repo conventions. 2. **PR body deviates from repo PR template.** The PR uses `## Changes` / `## Test Plan` / `## Related` sections instead of the repo template's `## Discovered Scope` / `## Terraform Changes` / `## README Impact` sections. This is a minor structural mismatch. The content is all present and thorough -- just organized differently than the template prescribes. 3. **Built-in PostgreSQL vs. CNPG.** The platform has an established pattern of using CNPG for Postgres (architectural consensus: "Apps own their postgres via CNPG Cluster CR"). The Bitnami subchart Postgres is reasonable for Phase 5a (infra-only), but Phase 5b or beyond should consider migrating to CNPG for consistency. This is a future consideration, not a blocker for this PR. ### SOP COMPLIANCE - [x] Branch named after issue (`32-deploy-keycloak-idp-to-cluster-phase-5a`) - [x] PR body has Summary, Changes, Test Plan, Related sections - [x] Related section references plan slug (`plan-2026-03-08-tryout-prep`) and `Closes #32` - [x] No secrets, .env files, or credentials committed (`.gitignore` covers `.tfvars`, `.env`, secrets/) - [x] No unnecessary file changes (3 files, all directly scoped to Keycloak deployment) - [x] Commit messages are descriptive - [x] `set_sensitive` with `type = "string"` used for password (matches platform convention) - [x] Ingress pattern matches all other Tailscale funnels (annotation, class, depends_on) - [x] Variable has `sensitive = true` and length validation (matches Harbor/MinIO pattern) - [ ] `tofu plan` output not included in PR body (repo convention) ### VERDICT: APPROVED
Bitnami removed all Docker Hub images (keycloak + postgresql tags
return 404). Switch to official quay.io/keycloak/keycloak:26.0.7
with raw k8s manifests (Deployment + Service + PVC + Secret).

Uses dev-file mode (H2 with file persistence on PVC) — appropriate
for <100 users. Tailscale handles TLS termination. PostgreSQL
backend is a future migration if scale demands it.

Resources: namespace, PVC (2Gi), secret, deployment, service, ingress.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
local-path provisioner uses WaitForFirstConsumer binding mode.
PVC stays Pending until a Pod mounts it. Terraform's default
behavior waits for Bound state, causing context deadline exceeded.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keycloak JVM needs ~1.5Gi during startup (schema init + class loading).
1Gi limit caused immediate OOMKilled (exit code 137). Bump to 2Gi limit
with 200m CPU request for headroom.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keycloak requires KC_HEALTH_ENABLED=true to expose /health/ready
and /health/live endpoints. Without it, probes get 404 and the
liveness probe keeps restarting the pod.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keycloak 26.x serves health endpoints on a separate management
port (9000), not the main application port (8080). Probes on 8080
return 404. Added startup probe with /health/started to prevent
liveness probe from killing the pod during JVM init.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
forgejo_admin deleted branch 32-deploy-keycloak-idp-to-cluster-phase-5a 2026-03-14 14:53:51 +00:00
Sign in to join this conversation.
No description provided.