feat: manage Keycloak realm config via Terraform provider #142
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/pal-e-platform#142
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type
Feature
Lineage
plan-pal-e-platform→ Platform Hardening → discovered scope from Keycloak theme deployment (PR #130)Repo
forgejo_admin/pal-e-platformUser Story
As a platform operator
I want Keycloak realm settings (login theme, clients, etc.) managed declaratively in Terraform
So that
tofu applyconfigures everything — no manual Admin API calls or console clicksLabels:
story:keycloak-iac,arch:keycloak,type:featureContext
PR #130 deployed a custom Keycloak login theme via ConfigMap, but the realm-level setting (
loginTheme: "westside") had to be applied separately via the Keycloak Admin REST API. This is a gap — theme files are in Terraform but realm config is not.The Terraform Keycloak provider (
mrparkers/keycloak) can manage realms, clients, theme assignments, and more as Terraform resources. Adopting it would close this gap and bring all Keycloak config under IaC.[SCOPE] Potential Redundancy with Phase 28
File Targets
Files the agent should modify:
terraform/main.tf— add Keycloak provider, import existing realms/clients as resourcesterraform/providers.tfor equivalent — declare Keycloak provider with admin credentialsFiles the agent should NOT touch:
keycloak/themes/— theme files are already managed correctlyAcceptance Criteria
tofu applysets realm login themes (no manual API calls)Test Expectations
tofu planshows no changes after initial import (clean state)login_themein Terraform and applying updates the realmcd ~/pal-e-platform/terraform && tofu plan -lock=falseConstraints
Checklist
Related
project-pal-e-platform— platform hardeningDesign Spec Review: Keycloak Terraform Onboarding (Revision 2)
Spec:
docs/superpowers/specs/2026-03-21-keycloak-terraform-onboarding-design.mdMUST-FIX VERIFICATION
Checking the 5 must-fix items from the first review:
1. Master realm / pal-e-app excluded with rationale -- RESOLVED
Lines 28-35: Dedicated "Scope Decision: Master Realm" section with four clear bullet points. The exclusion rationale is sound -- master realm is Keycloak's admin realm and managing it via Terraform is a lockout risk. The inventory table (line 51) marks
pal-e-appas**No** (excluded with master realm). Clean.2. Multi-client problem solved -- RESOLVED
Lines 124-162:
var.keycloak_clientsis a new top-level variable, decoupled fromvar.services. The "Why Clients Are Separate From Services" section (lines 156-162) explicitly addresses the original problem:mcd-tracker-ioshas no corresponding deployed service, and multiple clients per project would force service infrastructure duplication. The k3s.tfvars example (lines 251-258) confirms services are unchanged. This is the correct architecture.3. Client scopes contradiction resolved -- RESOLVED
Lines 80-82: Default client scopes are now listed under "Medium" risk with
lifecycle { ignore_changes }as mitigation. Lines 357-367 show the actual lifecycle block onkeycloak_realm.this. Line 350 in "What This Does NOT Manage" reiterates: "managed via lifecycle ignore_changes to prevent drift. Only manage explicitly when customizing." Consistent throughout.4. secrets.auto.tfvars fiction fixed -- RESOLVED
Lines 286-301: "Secret Delivery" section correctly describes the
k3s.tfvarspattern. Verified against actual codebase --/home/ldraney/pal-e-services/terraform/k3s.tfvarshasharbor_admin_password,argocd_admin_password,forgejo_argocd_tokenas plaintext, and*.tfvarsis in.gitignore. The spec's proposedkeycloak_admin_passwordfollows the identical pattern. The CI note (line 301) is accurate -- pal-e-services has no.woodpecker.yaml.5. Provider field names corrected -- RESOLVED
Lines 138, 141, 142: Uses
public_client,pkce_code_challenge_method,valid_redirect_uris. These are the correct field names for themrparkers/keycloakproviderkeycloak_openid_clientresource. The k3s.tfvars example (lines 188-249) uses them consistently.Also addressed items:
realm/client-uuidformat.required_providersblock shown (lines 265-271) withmrparkers/keycloak ~> 5.0.keycloak_openid_user_realm_role_protocol_mapper.All 5 must-fixes are resolved.
DOMAIN REVIEW (Terraform/IaC)
Positive observations:
tofu applyuntil the plan shows zero changes" callout prevents the most dangerous failure mode.lifecycle { ignore_changes }patterns (lines 357-376) correctly protect both client secrets and default client scopes.for_eachfiltering pattern on the protocol mapper (line 386) is idiomatic Terraform.Remaining items (nits, not blockers):
Missing
keycloak_roleresource block. The spec shows import commands forkeycloak_role.this["westside-basketball/admin"](lines 325-327) and the variable hasroles = optional(list(string), []), but the actualkeycloak_roleresource HCL is never shown. The implementer will need to construct thefor_eachthat flattens realm+role into composite keys like"westside-basketball/admin". This is a non-trivial local transform (likely usingflatten+for). Recommend adding the resource block to the spec for completeness, or at minimum noting the flattening pattern.Role import UUIDs are placeholders. Lines 325-327 show
<role-uuid>placeholders with a comment to fetch via Admin API. The client imports (lines 319-322) have real UUIDs. For implementation consistency, either fetch all UUIDs upfront and document them, or note that role UUIDs must be fetched at implementation time. Minor inconsistency.sops_age_private_keyin actual tfvars but not in variable definition. The actualk3s.tfvarshassops_age_private_keyandsource_repo/source_pathfields that don't exist in the currentvariables.tf. This is pre-existing drift unrelated to this spec, but worth noting -- the implementer will encounter it duringtofu plan.Provider version
~> 5.0should be verified. The spec proposesmrparkers/keycloak ~> 5.0. The Keycloak server isquay.io/keycloak/keycloak:26.0.7(confirmed in pal-e-platform main.tf line 1883). Provider v5.x should support Keycloak 26, but this should be confirmed during implementation -- provider/server version compatibility is a common gotcha.direct_access_grants_enableddefault. The variable defaults tofalse(line 140), butwestside-appsets it totrue(line 194). The default is correct (direct access grants should be opt-in), but the spec could note that this is the Resource Owner Password Credentials flow and explain why westside-app needs it (likely legacy basketball-api auth pattern). This helps future onboarding decisions.Missing
access_typeconsideration. Thekeycloak_openid_clientresource in mrparkers/keycloak hasaccess_type(one ofCONFIDENTIAL,PUBLIC,BEARER-ONLY) as an alternative topublic_clientboolean in some provider versions. Verify which attribute the v5.x provider expects. If v5.x usesaccess_typestring instead ofpublic_clientboolean, the variable schema needs adjustment.BLOCKERS
None. This is a design spec, not executable code. All 5 previously identified must-fix items are resolved. The remaining items are implementation guidance (nits).
NITS
See items 1-6 in the domain review above. The most important is nit #1 (missing
keycloak_roleresource block) -- it is the only resource referenced in import commands that has no corresponding HCL shown.SOP COMPLIANCE
docs/superpowers/specs/with date prefixPROCESS OBSERVATIONS
This design spec is high quality. The import-first strategy with a zero-changes gate is the correct approach for bringing existing stateful infrastructure under Terraform management. The risk surface analysis (client secrets, protocol mappers, custom roles, registrationEmailAsUsername) demonstrates deep understanding of the failure modes.
The two-variable architecture (
keycloak_realms+keycloak_clients) is the right call. It mirrors the real-world domain model: realms are project boundaries, clients are app configurations, and they have independent lifecycles. This will scale cleanly as new projects are onboarded.The spec is ready for implementation.
VERDICT: APPROVED
Scope Review: NEEDS_REFINEMENT
Review note:
review-270-2026-03-27Well-structured feature issue with complete template sections, but has critical scope questions that must be resolved before execution.
Key issues:
story:Xorarch:Xlabels on board item #270. Recommendstory:superuser-deploy+arch:keycloak.terraform/main.tf(has Keycloak module),terraform/providers.tf(no Keycloak provider yet),keycloak/themes/(correctly excluded) all confirmed.Issue body updated per scope review corrections.
Scope Review: NEEDS_REFINEMENT
Review note:
review-142-2026-03-28This ticket is redundant. Phase 28 (board items #276, #277, #278 — all DONE) already delivered all three acceptance criteria in
pal-e-services:login_theme = "westside"is declared inpal-e-services/terraform/k3s.tfvarsand applied viakeycloak_realm.thiswestside-basketballandmcd-trackerrealms are imported and managed (validated by spike #280)westside-app,westside-spa,mcd-tracker-app,mcd-tracker-iosThe ticket's own
[SCOPE]section anticipated this: "If Phase 28 covers everything, close this ticket as redundant."Recommendations:
[SCOPE]Close this issue as redundant — no implementation work remains[LABEL]Remove board item #270 from board-pal-e-platform or move to done