Repository navigation
Description
Description
The current "Signed JWT - Federated" client authenticator assumes the Kubernetes API server is the OIDC issuer for service account tokens. On managed clusters (EKS, GKE, AKS) this assumption does not hold: the iss claim points to an external OIDC provider (e.g. https://oidc.eks.<region>.amazonaws.com/id/<id>), not the cluster API server. As a result, issuer-based client lookup fails and the authenticator cannot validate tokens minted in those environments.
Two changes are needed to make the authenticator usable on managed clusters:
- The
KubernetesIdentityProviderrequires loading the Kubernetes/.well-known/openid-configurationdynamically and following theissuerlink. All strict validation rules apply (e.g. HTTPS required, HTTP 200 response etc). - The
KubernetesJwksEndpointLoaderneeds to expose whether the Service Account token should be forwarded to the IdP. Most of the managed cluster will not need it but there might be some that do.
Value Proposition
Without this change, Keycloak's Signed JWT - Federated authenticator is unusable on the most common managed Kubernetes platforms. Adding dynamic issuer discovery and a fallback lookup strategy makes the feature work out of the box for EKS, GKE, and AKS workloads, which covers the majority of production Kubernetes deployments today.
Goals
- Allow the Signed JWT - Federated authenticator to validate service account tokens whose
issclaim points to an external OIDC provider managed by the cloud (EKS, GKE, AKS). - Make the
KubernetesJwksEndpointLoadertoken-inclusion behavior configurable (or document why it is not needed) so IdPs that do not accept a bearer token on the JWKS request still work.
Non-Goals
- No change to the existing in-cluster Kubernetes flow when
issmatches the cluster API server. - No general-purpose OIDC client registration or trust mechanism beyond what is required for service account assertions.
- No replacement for the existing static configuration path; dynamic discovery should be additive.
Discussion
#48130 — see the "Managed Kubernetes Support" sub-section.
Notes
- The UDS Core-based implementation (which has already been tested on a living EKS cluster): feat(CORE-152): re-introduce the Signed JWTs to the UDS Operator defenseunicorns/uds-identity-config#838
- Related but distinct upstream issue: Kubernetes Identity Provider: support a configurable JWKS URL in addition to Discovery #47439 (configurable JWKS URL). That issue addresses static JWKS configuration; this one addresses dynamic discovery and client lookup.
- Once merged, the Signed JWT client authenticator will be re-introduced into uds-identity-config / UDS Core using the upstream implementation (it was previously reverted while waiting on this).
Metadata
Metadata
Assignees
Labels
Type
Fields
Value
Effort
Votes
Projects
- StatusShow more project fieldsDone
Activity
slaskawi commentedon May 16, 2026
Dear Keycloak Maintainers, could you please assign this issue to me? Thank you!
puneetdixit200 commentedon May 16, 2026
Hello maintainers, I would like to work on this issue. I will review the current Signed JWT Federated authenticator flow, add support for dynamic OIDC issuer discovery for managed Kubernetes providers, and include tests for EKS/GKE/AKS-style issuer metadata. Please assign this to me if this approach is acceptable.
slaskawi commentedon May 17, 2026
Thanks for stepping up @puneetdixit200 !
If you have some spare cycles, and wish to make some first steps in Keycloak land, this might be a good opportunity. I'm not 100% sure there's a consensus on this approach but it would be great to have a draft Pull Request, so that we can have a meaningful discussion.
The suggested approach is based on my prior work for UDS Core - https://github.com/defenseunicorns/uds-identity-config/pull/838/changes#diff-7c70dea4512d9d9c1e79965a8cdc26dda4563782727335de751f20c7ecaed92eR128. The most signifficant change is the new
discoverIssuermethod, which hits the Kubernetes API Server and scans theissuerfield. In case of AKS/EKS (and other) clusters, this would be a centralized Identity Management Service. For Minikube/K3s (and similar) that will be the local Kube cluster.We probably need two extra configuration options:
shouldIncludeTokenfrom my PR.Please let me know if you need any assistance (or would like to step down from implementing this).
ahus1 commentedon Jun 8, 2026
@slaskawi - it seems that this issue was created from the CLI, so it was missing an issue type and labels which I now added. For future issues, use the UI.
fix: resolve Kubernetes IdP issuer from discovery
onematchfox commentedon Aug 12, 2026
Just commenting to link a related ticket - I ran into this exact issue in GKE when trying to add the local cluster as an identity provider. This failed (see reproduction steps in #51682) with hidden errors which I worked around by removing the service account token mount (so that
KubernetesJwksEndpointLoaderwouldn't try to authenticate the request).J0F3 commentedon Aug 18, 2026
I have a similar case, but I am not sure if it exactly matches the case described here.
Basically, I need to define the issuer separately from the URL where the OpenID configuration is retrieved.
In my case, the issuer (and the
issclaim value) is an internal URL likehttps://kubernetes-api.intra.corporate.com:8443, while the URL for the OpenID configuration is a public reachable URL likehttps://api.external.public.com/k8s/main/.well-known/openid-configuration. Thejwks_uridefined in the OpenID configuration also points to the publicly reachable URL.Currently, I have the problem that I can only configure one issuer URL, and this must be the publicly reachable URL so that Keycloak can retrieve the OpenID configuration. But then the URLs do not match the issuer defined in the OpenID configuration and the
issclaim in the service account tokens.So I see two possible solutions:
Either I can define the issuer separately from the OpenID configuration URL in the Kubernetes identity provider, or Keycloak takes the issuer from the OpenID configuration and checks that the
issclaim matches. This seems to match very well what is described here.Ironically, the issue I have is with an internal private Kubernetes cluster, while Keycloak is running in a public cloud. With AKS, everything works as expected out of the box. The issuer URL https://switzerlandnorth.oic.prod-aks.azure.com// matches the issuer and the
issclaim in Service Account tokens from AKS.chance-coleman commentedon Aug 25, 2026
@onematchfox Thanks for sharing this. The PR only sends the service account token to trusted Kubernetes API URLs. It doesn't send it to external OIDC discovery or JWKS endpoints, so this should address the GKE case. The hidden error issue in #51682 is separate and would need its own fix.
chance-coleman commentedon Aug 25, 2026
@J0F3 Thanks, this is close to what the PR is trying to support, but it is not fully covered yet. The PR uses the discovery URL to find and save the issuer. After that, Keycloak loads the discovery document from the saved issuer URL again. If that URL is private and unreachable from Keycloak, this setup will still fail.
onematchfox commentedon Aug 25, 2026
👍 Have already opened #51686 to make this (type of) error more visible - but it wouldn't have occurred in the first place with the fix in place.
Resolve Kubernetes IdP issuer from discovery