Giter Club home page Giter Club logo

Comments (8)

CesarStef avatar CesarStef commented on June 16, 2024 1

Hi @jkroepke,

Kubernetes has a .well-known endpoint + JWKS endpoints.

Perfect, so you can validate Kubernetes without problem.

That a good idea, but not mention in the spec. Other scenarios should be supported as well.

I completly agree with you and if you look at alpha configs you will see that the maintainers tried to allow other scenarios.
There is the possibility to change the claim to which oauth2-proxy will try to match the clientId with the optionaudienceClaims and then, you can add more "audiences" with extraAudiences but for now, to let the system use extraAudiences you need the old option --skip-jwt-bearer-tokens set to true ( I expect that you already set this option to true ).
So in these way you can can validate the sub claim if you want.

But there are one big problems with alpha configs now:
You can't have more than one provider active at the same time, and so there is no way to validate tokens from two or more issuers at the same time.
(I hope that some PR will be merged about this soon, because by my opinion this is a big usability issue)

You will still have the "clientID" problem, but if you want to use oauth2-proxy only as resource-server + reverse-proxy it's just a naming problem.

I know that the "clientID" parameter name is missleading, but I can see why the maintainers had decided to not create another config parameter with the exactly same scope just for the resource-server only scenario.
Maybe, if there were an option to completely disable the client part, then this would be useful.

from oauth2-proxy.

matzegebbe avatar matzegebbe commented on June 16, 2024

Sorry for the advertising, for this challenge I have published this tool. You might want to fork it and rebuild it locally
https://github.com/matzegebbe/web-jwks-validator

from oauth2-proxy.

CesarStef avatar CesarStef commented on June 16, 2024

Hi @jkroepke, can you put an example of token that you want to validate?
I'm asking this because if you want to validate a token that follow the standard described in the page ServiceAccount token volume projection, I think that if and only if k8s sign the token (it's not visible in the example and I don't have any cluster to try it now) this is theorically already working with some tricks in the configs.

The idea is that you set the client-id value as the same of the audience of the token ("aud" claim), disable the login page, activate the function to check bearer token and put a random value as client-secret(this will never be used).

Let me know if this was helpful or not 😄

from oauth2-proxy.

jkroepke avatar jkroepke commented on June 16, 2024

Hey @CesarStef

thanks for your detailed answers.

Yes, I want to valid JWT issued by Service Account and secondly I also want to validate tokens issued by Entra ID that are coming trough Managed Identity (like AWS Instance Roles, but the token is an OIDC compatible JWT), Ref: https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http

In case you are not familiar with Azure Managed Identity, you can assume its the same concept as Kubernetes Service Accounts, but only for Virtual Machines and the token is available via http.

The only difference here is that the aud claim is not fully free to choice. In the case, the audience claim must be pre-registered on the Entra ID first.

Additionally, I also would like to authenticate JWT tokens from different sources. While I'm fully flexible at Kubernetes side, for Entra ID I have to use the same audience claim at Entra ID side.

I'm also missing the client ID verification.

The idea is that you set the client-id value as the same of the audience of the token ("aud" claim)

But not secure! The audience value at the ServiceAccount token volume projection is not validated. Any user could create a service account token with the "correct" audience value to successfully validate against oauth2-proxy.

from oauth2-proxy.

CesarStef avatar CesarStef commented on June 16, 2024

Hi @jkroepke,

Sorry for the late response!

But not secure! The audience value at the ServiceAccount token volume projection is not validated. Any user could create a service account token with the "correct" audience value to successfully validate against oauth2-proxy.

The audience check is only a part of all the process to validate a token.

In my previous message I putted a condition as necessary to make the validation work:

I think that if and only if k8s sign the token (it's not visible in the example and I don't have any cluster to try it now) this is theorically already working with some tricks in the configs.

Attackers can't simply put a valid clientId in the token because oauth2-proxy need to verify that the signature of the token is really made by the correct issuer.
Every IdP use their private key to sign their access token and give you an endpoint to find their public key to verify that a token is really issued by them.

If somebody manipulate the token, the signature just change and the token is invaid.

oauth2-proxy (at least for the oidc standard provider) follow the standard and checks three things to validate the token:

  1. The iss claim (issuer) must be the correct one
  2. The aud claim must contain the clientID (you can change the claim to check)
  3. The signature is really made by the issuer

Additionally, I also would like to authenticate JWT tokens from different sources.

As I know this can't be done now but there are some PR in working to make this possible (maybe some of maintainers can help more then me on this point).

from oauth2-proxy.

jkroepke avatar jkroepke commented on June 16, 2024

Attackers can't simply put a valid clientId in the token because oauth2-proxy need to verify that the signature of the token is really made by the correct issuer.
Every IdP use their private key to sign their access token and give you an endpoint to find their public key to verify that a token is really issued by them.

This is true, but audience is a free-text value field at kubernetes. On kubernetes, you get signed a token with any aud value of your choice.

For example:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
    volumeMounts:
    - mountPath: /var/run/secrets/tokens
      name: vault-token
  serviceAccountName: build-robot
  volumes:
  - name: vault-token
    projected:
      sources:
      - serviceAccountToken:
          path: vault-token
          expirationSeconds: 7200
          audience: vault

In that case, the aud value is vault here. As I know, I can put any value of my choice here and it gets signed.

oidc standard provider

But Kubernetes isn't OIDC standard provider and doesn't want to be, maybe doesn't have to be.

In terms of OAuth2, the aud claim has a different purpose (https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3)

The "aud" (audience) claim identifies the recipients that the JWT is intended for.

That the reason, why the aud claim in Kubernetes and Entra ID is free to choice (Note: Not talking about end-user token, more token about identity (machine) tokens). For example in Entra ID, the aud claim must be https://management.azure.com/, if I want to use the token to authenticated against https://management.azure.com/ and has no link against the clientID

From OAuth2 point of view, there is link to the clientID.

Based on your comment, extra-jwt-issuers is designed for OIDC compatible provider and should not used for OAuth2 Providers, like Kubernetes.

A flag like extra-jwt-issuers, but using the sub claim instead the aud claim would be feasible solution.

from oauth2-proxy.

CesarStef avatar CesarStef commented on June 16, 2024

Hi @jkroepke,

I'm not a maintainer of this app but just an user so everything I will say can be completly wrong and/or not in line with their ideas on this topic :)

Said so,

I think that we are missing the point, because "aud" is not really so important as much the signature:

  1. You are pointing out the RFC 7519 but this is for JWTs, while the OAuth2.0 RFC is the number 6749.
    So, to be OAuth2 complaint, Kubernetes must follow some other rules.
    In particular, the RFC 6749 Section 10.3 says:

    The authorization server MUST ensure that access tokens cannot be
    generated, modified, or guessed to produce valid access tokens by
    unauthorized parties.

  2. The JWTs RFC 7519 Section 4.1.3 also say this:

The following Claim Names are registered in the IANA "JSON Web Token
Claims" registry established by Section 10.1.
None of the claims defined below are intended to be mandatory to use or implement in all
cases, but rather they provide a starting point for a set of useful,
interoperable claims. Applications using JWTs should define which
specific claims they use and when they are required or optional. All
the names are short because a core goal of JWTs is for the
representation to be compact.

(This part is the reason that allow some OAuth2 Authorization Server to not use "aud" at all in their access token, for example: AWS Cognito)
So this:

From OAuth2 point of view, there is link to the clientID.

It's just a common practice, but there a OAuth2 authorization Server like AWS Cognito that don't have "aud" at all in their access tokens (but have a custom claim called "client_id"...)

  1. And in the [ JWT RFC Section 7] (https://www.rfc-editor.org/rfc/rfc7519#section-7) the explicit say that you need to validate the signature of the token

Based on your comment, extra-jwt-issuers is designed for OIDC compatible provider and should not used for OAuth2 Providers, like Kubernetes.

Sorry I misspoke, ".well-known" is part of the OAuth2 specification(s) (https://datatracker.ietf.org/doc/html/rfc8414#section-3.2)

So in the end, if Kubernetes don't have a ".well-known" endpoint is theorically not OAuth2 complaint I think.

But the meantime I found out that Kubernetes sign the token and theorically you can have the key:
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#service-account-tokens

So theorically, the problem now is to make them accessible by URL from your oauh2-proxy istance.

A flag like extra-jwt-issuers, but using the sub claim instead the aud claim would be feasible solution.

No, because you still have the signature problem and to that you must add the problem that you can't know the "sub" value before that your authorization server generate at least one token for that "user".

The idea behind having "aud" == "client_id" is to bind the audience to a client and tipically, a client is an application.

from oauth2-proxy.

jkroepke avatar jkroepke commented on June 16, 2024

Hey @CesarStef

In particular, the RFC 6749 Section 10.3 says:

I think, Kubernetes is compliant here. Only users with edit permissions are able to generate such tokens.

It's just a common practice, but there a OAuth2 authorization Server

Common practice isn't a spec.

The JWTs RFC 7519 Section 4.1.3 also say this:

I can't find the quote you mention in that section, however the section clearly describes what the ident of the aud claim is. A URL is common for the aud name.

In the general case, the "aud" value is an array of case-sensitive strings, each containing a StringOrURI value. In the special case when the JWT has one audience, the "aud" value MAY be a single case-sensitive string containing a StringOrURI value.

In that scenario, multiple clients from multiple issue would have the same aud claim value for my endpoint.

I agree, that aud claim is optional. But nothing is mention here about a client ID. Kubernetes service accounts doesn't have a client ID.

So in the end, if Kubernetes don't have a ".well-known" endpoint is theorically not OAuth2 complaint I think.
So theorically, the problem now is to make them accessible by URL from your oauh2-proxy istance.

Kubernetes has a .well-known endpoint + JWKS endpoints.

https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#service-account-issuer-discovery

to that you must add the problem that you can't know the "sub" value before that your authorization server generate at least one token for that "user".

For Kubernetes, the subject value is the service account name + namespace.
For Microsoft Entra ID, the subject value is the client id of the managed identity.
For GitHub Actions, the subject value has the format repo:<orgName/repoName>:environment:<environmentName>.
For Gitlab CI, the subject value has the format project_path:{group}/{project}:ref_type:{type}:ref:{branch_name}.

The idea behind having "aud" == "client_id" is to bind the audience to a client and tipically, a client is an application.

That a good idea, but not mention in the spec. Other scenarios should be supported as well.


The OIDC spec describes scenarios, where a end user needs to be authenticated.

Mention that for machine based authentication, where non-human identities gets an issued token by default or can request one on demand.

For example, in Github Actions having access to an token API to get an signed JWT token where is aud claim is free to choice.

There is no client credential or code authorization flow to get an token with an registered client on behalf. Instead a non standardized/proprietary flow is used. It's just curl (in case of Github/Entra ID), cat (Kubernetes) or env variable (Gitlab CI) to get an signed token.

In case of Github Action, there isn't a client id. because there is not client. sub claim is commonly used to get an stable identifier.

from oauth2-proxy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.