Expose Keycloak SSO session lifetimes as KOTS config options#694
Conversation
The allhands realm hardcoded ssoSessionIdleTimeout=1800 (30 min) and ssoSessionMaxLifespan=36000 (10 h). Every Keycloak session expiry sends users back through the brokered identity provider login; for OAuth2 providers like Bitbucket Data Center each of those re-logins records a new authorized-application grant on the user's account (Bitbucket DC has no revocation API, so grants accumulate visibly). Expose both lifetimes as KOTS options (Advanced Options) wired through keycloak.ssoSessionIdleTimeout / keycloak.ssoSessionMaxLifespan chart values. The values are applied to the rendered realm JSON with jq so the realm template stays valid JSON, and they flow through both the realm-create and realm-update paths of the keycloak-config init container, so changes take effect on live installs at the next deploy.
|
✅ Review complete. This review was performed through OpenHands Cloud Automation. You can log in and view the conversation here. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Code Review
🟢 Good taste — Elegant, pragmatic solution to a real production problem.
Analysis
This PR exposes Keycloak SSO session lifetimes as configurable options to solve a legitimate issue: every session expiry forces a fresh Bitbucket Data Center OAuth2 login, which accumulates duplicate "authorized-application" grants on user accounts (Bitbucket DC has no revocation API).
Design choices that work:
- Using
jqto apply numeric session lifetimes after template rendering keeps the realm template valid JSON — the right tool for the job. - The values flow through both realm-create and realm-update paths, so changes take effect on a live install at the next deploy.
- Validation uses
^[1-9][0-9]*$to reject zero, negative numbers, and leading zeros — appropriate for timeout values. - Tests run the actual
jqfilter against the real realm template, verifying end-to-end behavior rather than just mocking function calls.
No critical issues found. The code is clean, well-documented in the PR description, and defaults are unchanged.
[RISK ASSESSMENT]
- [Overall PR]
⚠️ Risk Assessment: 🟢 LOW
This is a Helm/KOTS configuration change that only affects Keycloak session timeouts. Existing behavior is preserved by default (1800s idle, 36000s max lifespan). No breaking changes to APIs, data flows, or security boundaries.
VERDICT:
✅ Worth merging — Core logic is sound, well-tested, and solves a real problem with minimal complexity.
KEY INSIGHT:
The jq-after-envsubst pattern is the right approach here: it keeps the JSON template clean while allowing Helm to inject computed values into the final realm configuration.
This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation. View conversation
Summary
keycloak_sso_session_idle_timeout(default 1800) andkeycloak_sso_session_max_lifespan(default 36000) under Advanced Options, with numeric validation.keycloak.ssoSessionIdleTimeout/keycloak.ssoSessionMaxLifespan.jqin the keycloak-config init container (the realm template must stay valid JSON). They flow through both the realm-create and realm-update paths, so changing the KOTS value updates a live install on the next deploy.Why
The allhands realm hardcodes a 30-minute idle timeout and 10-hour max session lifespan. Every Keycloak session expiry forces a fresh brokered IdP login, and for OAuth2 providers like Bitbucket Data Center each re-login records a new authorized-application grant on the user's Bitbucket account. Bitbucket DC has no token-revocation API (UI-only), so a Replicated customer accumulated 20 duplicate "Openhands Enterprise" entries. Session length is the only lever we control. Defaults are unchanged.
Testing
scripts/test_keycloak_realm_template.py: new tests assert the config script applies both values and run the script's actual jq filter against the realm template (8/8 pass).🤖 Generated with Claude Code