8000 Signed JWT - Federated: support managed Kubernetes (EKS, GKE, AKS) via dynamic OIDC issuer discovery · Issue #49039 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content

Signed JWT - Federated: support managed Kubernetes (EKS, GKE, AKS) via dynamic OIDC issuer discovery #49039

Description

@slaskawi

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:

  1. The KubernetesIdentityProvider requires loading the Kubernetes /.well-known/openid-configuration dynamically and following the issuer link. All strict validation rules apply (e.g. HTTPS required, HTTP 200 response etc).
  2. The KubernetesJwksEndpointLoader needs 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 iss claim points to an external OIDC provider managed by the cloud (EKS, GKE, AKS).
  • Make the KubernetesJwksEndpointLoader token-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 iss matches 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

Activity

  1. slaskawi commented on May 16, 2026

    @slaskawi
    ContributorAuthor

    Dear Keycloak Maintainers, could you please assign this issue to me? Thank you!

  2. puneetdixit200 commented on May 16, 2026

    @puneetdixit200
    Contributor

    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.

  3. slaskawi commented on May 17, 2026

    @slaskawi
    ContributorAuthor

    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 discoverIssuer method, which hits the Kubernetes API Server and scans the issuer field. 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:

    • Use dynamic issuer resolution (defaults to true) - this is a kill switch to disable this feature
    • Include Service Account Token in requests (defaults to false) - forwards the Service Account Token to the centralized Identity Management Service. The implementation might be similar to the shouldIncludeToken from my PR.

    Please let me know if you need any assistance (or would like to step down from implementing this).

  4. added theissue type on Jun 8, 2026
  5. added
    area/identity-brokeringIdentity brokering — external IdPs (social, OIDC, SAML), account linking
    on Jun 8, 2026
  6. ahus1 commented on Jun 8, 2026

    @ahus1
    Member

    @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.

  7. self-assigned this
    on Jun 8, 2026
  8. added a commit that references this issue on Jun 9, 2026
    662405f
  9. onematchfox commented on Aug 12, 2026

    @onematchfox
    Contributor

    Make the KubernetesJwksEndpointLoader token-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.

    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 KubernetesJwksEndpointLoader wouldn't try to authenticate the request).

  10. J0F3 commented on Aug 18, 2026

    @J0F3

    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 iss claim value) is an internal URL like https://kubernetes-api.intra.corporate.com:8443, while the URL for the OpenID configuration is a public reachable URL like https://api.external.public.com/k8s/main/.well-known/openid-configuration. The jwks_uri defined 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 iss claim 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 iss claim 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 iss claim in Service Account tokens from AKS.

  11. chance-coleman commented on Aug 25, 2026

    @chance-coleman
    Contributor

    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 KubernetesJwksEndpointLoader wouldn't try to authenticate the request).

    @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.

  12. chance-coleman commented on Aug 25, 2026

    @chance-coleman
    Contributor

    @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.

  13. onematchfox commented on Aug 25, 2026

    @onematchfox
    Contributor

    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.

    👍 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.

  14. added a commit that references this issue on Sep 23, 2026
    ce5f9ce
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Fields

Value

None yet

Effort

None yet

Votes

None yet

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

0