docs: add ADRs for Dex as OIDC issuer and Keycloak migration path - #3542
docs: add ADRs for Dex as OIDC issuer and Keycloak migration path#3542CasLubbers wants to merge 19 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds two new ADRs documenting the planned move from Keycloak to Dex as the OIDC issuer and the decision to keep migration for existing clusters manual, and updates the ADR index accordingly.
Changes:
- Added ADR describing why/how Dex replaces Keycloak as the OIDC issuer.
- Added ADR describing the manual migration path for existing clusters.
- Updated
adr/index.mdto include the new ADRs (and reformatted the index list).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
adr/index.md |
Reformats the ADR index list and adds entries for the two new ADRs. |
adr/2026-08-06-dex-as-issuer.md |
New ADR capturing the decision and constraints for using Dex as issuer. |
adr/2026-08-06-keycloak-to-dex-migration-path.md |
New ADR capturing the decision to keep migration manual for existing clusters. |
Suppressed comments (1)
adr/index.md:23
- This index entry uses "favor" while the ADR title uses British spelling ("favour") in the ADR itself (adr/2026-06-25-drop-sops-for-sealedsecrets.md:1). Keeping the index text consistent makes it easier to find the ADR by title search.
* [ADR-2026-06-25](2026-06-25-drop-sops-for-sealedsecrets.md) - Drop SOPS in favor of SealedSecrets
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| * [ADR-2022-04-22](2022-04-22-values-migration.md) - Values migration | ||
| * [ADR-2022-04-23](2022-04-23-pre-upgrade.md) - A new otomi pre-upgrade command | ||
| * [ADR-2022-05-17](2022-05-17-destroy-upon-uninstall.md) - Extra flags to accommodate destroy upon uninstall | ||
| * [ADR-2022-06-07](2022-06-07-ingress-classes.md) - Ingress classes |
| * [ADR-2020-11-06](2020-11-06-konstraint-policy-library.md) - Konstraint library to support Common Rego Language definitions | ||
| * [ADR-2021-10-18](2021-10-18-defaults-and-derived.md) - Derived values | ||
| * [ADR-2021-10-28](2021-10-28-internal-values.md) - Internal values | ||
| * [ADR-2022-03-24](2022-03-24-custom-ca.md) - urice: |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
|
||
| ### How users reach the configuration | ||
|
|
||
| Users are created through the API and stored as SealedSecrets in the `apl-users` namespace. Under Keycloak they reach the issuer at runtime, because the Keycloak operator watches those Secrets. Dex has no operator, so the records must be in hand when the configuration is rendered. |
There was a problem hiding this comment.
In Keycloak, various problems arose from this approach, too. The operator was both watching Secrets and a common ConfigMap, and had several issues synchronizing data correctly. We eventually decided for a plan to abandon the operator and instead have the API act as a direct proxy into Keycloak, but due to the perspective of deprecating Keycloak this was never followed up on.
There was a problem hiding this comment.
The problem now is that we cannot fully use the Dex API for users as it is missing the Group attribute. That one only works in the configuration file. So the our apl-api cannot suffice as an proxy for Dex.
But it is good to keep in mind for future reference that we do not want to create a dex-operator.
| Bringing an external identity provider remains supported, and the two populations stay mutually exclusive, as they are under Keycloak: | ||
|
|
||
| - **Users created in APL** originate in the values repository and are rendered into Dex's `staticPasswords` from their materialised form on the cluster, as described above. The values repository remains their system of record. | ||
| - **Federated users** arrive through a Dex `oidc` connector configured from the existing `oidc.*` settings. They are never written to the values repository, and their team membership comes from group claims. |
There was a problem hiding this comment.
Will this also be the migration path for Keycloak? Adding Keycloak as an OIDC connector but excluding it from direct APL management would leave an option for legacy installations to keep the user base, and migrate at their own choice (if ever). This would require them to exclusively create and update users through the Keycloak UI from that point on, but that would be acceptable.
There was a problem hiding this comment.
I read the options below, what I meant is a fourth option, somewhat a mix of option 2 and 3: Making Dex the OIDC provider on all installations, but on migrated ones leave Keycloak behind it. Cut off apl-keycloak-operator, creating new users through API exclusively in Dex.
There was a problem hiding this comment.
Yes that sounds as a good option. The only problem I have seen so far is that if we switch a Keycloak cluster to Dex as issuer. The users will lose their Harbor and Gitea account.
The subject that Dex returns is different. Gitea and Harbor will therefore create new accounts automatically. Maybe further down the line we can fix this or have a better solution for it.
There was a problem hiding this comment.
Especially in Harbor I doubt individual users have significant amounts of data attached to their personal account. But in that case there is indeed little use in adding Dex as a layer on migrated installations.
|
|
||
| Bringing an external identity provider remains supported, and the two populations stay mutually exclusive, as they are under Keycloak: | ||
|
|
||
| - **Users created in APL** originate in the values repository and are rendered into Dex's `staticPasswords` from their materialised form on the cluster, as described above. The values repository remains their system of record. |
There was a problem hiding this comment.
Why is the only considered approach to render the configuration?
There were ideas before to not use apl-operator for purposes anymore, where it has to deal with mixes of resources and states of the cluster. Teams are somewhere on the border of this, but too many templates need the information which teams exist. With users however, reading resources, processing them, and writing them back to another resource seems quite complicated.
What if API were to read and write the configuration file resource directly? It would require a separate backup. Are there other reasons this was not considered?
There was a problem hiding this comment.
TBH I did not think of it. Could be a valid option. The apl-operator seemed the easiest one to me because it has the values structure and needs the configuration file on start up. So with some extra templating it can create users.
There was a problem hiding this comment.
What I am aiming at is that I would rather avoid adding more complexity to the operator. Considering our discussions of possibly migrating code, actually simplifying would help in the long run.
I do see the advantage of keeping everything in the values repository however. One similar idea: The API could write out the users as SealedSecret resources, and External Secrets Operator could select the resulting Secrets to produce the configuration file. That is all components we already have.
| - **Runs a pre-release Dex.** Auth sessions and RP-initiated logout are merged on Dex's master branch but unreleased (dexidp/dex#4560). Without sessions there is no single sign-on across applications that run their own OIDC flow, and no logout endpoint. The image is therefore pinned to a master digest with `DEX_SESSIONS_ENABLED=true`. **APL must not be released while this pin stands.** | ||
| - **Single sign-on needs explicit configuration.** `sessions.ssoSharedWithDefault` defaults to `none`, which gives no SSO at all. It is set to `all`. | ||
| - **Every claim must be requested.** Keycloak attached `groups` through a protocol mapper regardless of scope; Dex only emits a claim when its scope is requested (`server/tokens/issuer.go`). Consumers that previously asked for `openid` alone now need the full scope list, or they authenticate successfully with no authorization. | ||
| - **Logout requires the ID token.** Dex refuses `post_logout_redirect_uri` without `id_token_hint`, and a browser redirect cannot carry one. Logout is therefore driven from oauth2-proxy's `backend_logout_url`, which substitutes `{id_token}`. |
There was a problem hiding this comment.
Is that a problem, or the solution (i.e. OAuth2-Proxy)? To be fair this parameter is also recommended in Keycloak, but optional.
There was a problem hiding this comment.
A solution, did not test the logout option in the PoC
📌 Summary
PRD's created from the ADR's:
🔍 Reviewer Notes
🧹 Checklist