Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authorino accepts the JWT signed with newly created JWKS signing key even with jwt.ttl set to zero #463

Open
trepel opened this issue Apr 9, 2024 · 1 comment

Comments

@trepel
Copy link

trepel commented Apr 9, 2024

Describe the bug
According to the docs (https://github.com/Kuadrant/authorino/blob/main/docs/features.md#jwt-verification-authenticationjwt) if .jwt.ttl is set to zero the OIDC connect discovery should be disabled. I am using Keycloak as OIDC provider. When a signing key is removed in Keycloak from JWKS and a new signing key is created in JWKS and a new JWT is created (using the new signing key) Authorino should reject (401) requests using that JWT since it should have no way of knowing about the signing key change in JWKS -> its cache should only contain the old signing key which is not good for validating JWT signed with the new signing key. However, the 200 OK response is what one gets.

It seems as if the proper signing key was used to validate the JWT despite the OIDC connect discovery being disabled. There must be some communication with Keycloak to get the new signing key somewhere -> either in Authorino itself or in the oidc library it uses under the hood.

Help us Reproduce it

  1. Get a Keycloak instance, Realm, Client, User; get an Authorino instance; deploy some app
  2. Secure you app by Authorino
  3. Make sure that TTL is set to zero in Authconfig CR:
spec:
  rules:
    authentication:
      rhsso:
        credentials:
          authorizationHeader:
            prefix: Bearer
        jwt:
          issuerUrl: 'keycloak-url//auth/realms/your-realm-name'
          ttl: 0
        metrics: false
        priority: 0
  1. At this point Authorino should have cached Keycloak JWKS, delete the signing key from JWKS in Keycloak
  2. Create a new signing key in JWKS in Keycloak (Authorino has no way of knowing about this due to TTL being set to zero)
  3. Create a new JWT (it can only be validated by new signing key)
  4. Use the new JWT to access the app

Expected behavior

HTTP Error 401 since Authorino is not aware of signing JWK replacement since this was done after Authorino updated its cache

Instead one gets

HTTP 200 OK - it indicates that there were some communication with Keycloak to get the current signing key since the JWT was successfully validated. However, there should not be any such communication there according to the documentation

Environment (please complete the following information):

  • Cluster information: kubernetes v1.27.9+e36e183
  • Authorino version : quay.io/kuadrant/authorino:latest
  • Link to the Authorino AuthConfig resource (e.g. in some GitHub gist): see the snippet above
@guicassolato
Copy link
Collaborator

I can confirm this. The JWKSs cached by Authorino are updated more often than any TTL config in the AuthConfig resource (especially zero) would suggest.

This is because there’s a second cache mechanism inside Authorino’s controlled one. Authorino lets the user control the caching of the overall OIDC config (on or off according to the ttl field of the AuthConfig), while the internal one is for the actual JWKS.

The internal mechanism kicks in whenever it fails to find a valid key in the pre-cached key set. And it does not use the ttl config for that at all. Rather, it guesses the expiry time of the JWKS based on the response headers returned on the JWKS URL request – occasionally, no caching at all, depending on the server's response.

Here's a representation more or less of the 2-layer caching system:

Layer 1 - OIDC config
  • loaded every time an AuthConfig changes, refreshed automatically on the ttl setting
  • starts with 0 JWKs in the cache
  • when loaded/refreshed, invalidates all pre-cached JWKs in layer 2
Layer 2 - JWKS
  • loaded from the JWKS URL stored in the pre-cached OIDC config
  • refreshed automatically whenever there's a request
    1. whose JWT's signature is not in the cache
    2. if the cache is deemed expired (based on previous responses from the auth server)
  • does not depend on the ttl setting

I can see how one would see this as a bug, though it's not a vulnerability. If anything, it's safer the way it is now, albeit unexpected, I agree.

In v1beta1, this authentication method was called oidc, making it more clear that the TTL refers to the OIDC config, not to the JWKS. Now, in v1beta2, with the method renamed to jwt, this is confusing. At the very least, we should fix this for better UX around the ttl config.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Todo
Development

No branches or pull requests

2 participants