Comments (8)
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.
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.
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.
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.
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:
- The iss claim (issuer) must be the correct one
- The aud claim must contain the clientID (you can change the claim to check)
- 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.
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.
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:
-
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. -
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"...)
- 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.
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.
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)
- [Bug]: Invalid authentication via OAuth2 via Github for the owner of the organisation HOT 8
- [Bug]: Possible typo in source code for static upstreams HOT 2
- [Bug]: Incomplete source of request urls for skip_auth_routes feature
- [Bug]: Redirect after second google login to home page not working
- [Support]: 401 Authorization Required even finished authentication HOT 1
- [Feature]: use username (or any other attribute from the provider) in basic auth header instead of the ID
- [Bug]: An invalid redirect to a non-whitelisted domain creates a valid session cookie after redirecting to "/"
- Pass bearer token to the backend with nginx
- [Support]: Multi-Domain Forward-Auth with Traefik/k3s
- [Feature]: [Azure] Support certificate-based flow for requesting access token HOT 1
- [Feature]: Support for dry-run
- [Support]: failed to verify id token signature
- [Bug]: Setting `proxy-prefix` in helm seems to break login
- [Bug]: Azure provider: problem with ProfileURL/ userInfoURL (duplicate of closed issue #2162 )
- [Support]: <Keycloak-OIDC failed> HOT 1
- [Bug]: GitHub private repo check throwing 500 instead of 403 when user does not have access
- [Bug]: Keycloak OIDC Provider Multiple Calls to Fetch Keys to Verify JWT in Auth Header
- [Support]: Add scope field inside bearer token
- [Support]: How to configure oauth2 with kubernetes HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from oauth2-proxy.