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

proposal: Uniform way for handling JWTs #2748

Conversation

kimwnasptd
Copy link
Member

Continuing from the discussion in #2747

After the oauth2-proxy PRs are merged we have made some changes on how JWTs are used from within the cluster (RequestAuthentication) and how headers are added from these tokens.

This lead to some issues in KFP, for which to resolve we'll need to have an agreed upon story on how to be working in the future with JWTs.

After agreeing on the above, this can also enable us to push the effort for supporting groups since we'll have an agreed upon way of working with identity information.

/cc @juliusvonkohout @kromanow94 @thesuperzapper @axel7083
cc @rimolive @DnPlas

@kimwnasptd kimwnasptd force-pushed the feature-kimwnasptd-jwt-handling-proposal branch from 72342a4 to 44f5f39 Compare June 5, 2024 22:09
@kimwnasptd kimwnasptd force-pushed the feature-kimwnasptd-jwt-handling-proposal branch from 4bfdcd8 to 0121ae8 Compare June 6, 2024 17:13
@juliusvonkohout
Copy link
Member

The general approach looks good, although i did not check the technical details yet.

@kromanow94
Copy link
Contributor

Hey, this is the continuation of my thoughts from #2747 (comment).

In general, I like this approach. In the comment linked above, I mentioned that I'd personally vote for not removing implementation of JWTs in Kubeflow components but after some thoughts over the weekend, I don't emphasize that so much right now.

While I personally would love Kubeflow to be natively supporting JWTs, I understand that we have to take into account the balance between functionality and maintenance/development and offload whatever possible. With this in mind, if you decide to drop JWT implementation from kubeflow components and just rely on the kubeflow-userid and kubeflow-groups headers and enforce those through Istio, I'm ok with that and you have my support.

  • If possible, I'd suggest standardizing the auth headers to X-Auth-Request-Groups and X-Auth-Request-Email.

I also mentioned that I'd prefer to specify AuthorizationPolicy objects with custom action and oauth2-proxy as the provider for every component that's exposed to users (api-server, jupyter-web-app, central-dashboard, etc...), not just for the istio-ingressgateway, to bring security closer to the components.

  • While this would move the security layer closer to the components and allow increased flexibility in implementation of how the requests are routed and authorized to reach an endpoint, this is also not something I'm putting strong emphasis on. If you like that approach, I'd be happy to help with hands-on, but this is not something we have to have.
  • So, to put it short: from in-cluster perspective, using a pair of AuthorizationPolicy and RequestAuthentication would be enough and the requests wouldn't have to go trough ouath2-proxy.

And then to continue some other thoughts:

  • Since this proposal is suggesting removal of the JWT implementation from Kubeflow components, it also means that we don't need to check for pipelines.kubeflow.org audience and we don't have to add PodDefaults that adds the projected token.

    • I suggest to drop the pipelines.kubeflow.org audience at some form either way so I like that.
  • I suggest dropping the istio-ingressgateway-service-account from the AuthorizationPolicices principal and just ensure that any principal is available through rules.from.source.requestPrincipals. This would also ease integration with externally installed Istio since the service account name for istio-ingressgateway depends on if you install through Helm Chart or the istio operator/istioctl.

@kimwnasptd
Copy link
Member Author

kimwnasptd commented Jun 17, 2024

Thanks for the review @kromanow94!

To avoid answering multiple parts in the same message, ending in big messages, could you provide also the above points as concrete comments on the proposal so we keep the discussions focused/separate?

https://github.com/kubeflow/manifests/pull/2748/files

proposals/20240606-jwt-handling.md Outdated Show resolved Hide resolved
proposals/20240606-jwt-handling.md Outdated Show resolved Hide resolved
proposals/20240606-jwt-handling.md Outdated Show resolved Hide resolved
proposals/20240606-jwt-handling.md Outdated Show resolved Hide resolved
proposals/20240606-jwt-handling.md Outdated Show resolved Hide resolved
proposals/20240606-jwt-handling.md Show resolved Hide resolved
### Implementation
The technical details for the above proposal translate to the following
1. Common Kubeflow manifests, for all components, for configuring Istio for supporting multiple issuers ([Dex](https://github.com/kubeflow/manifests/blob/v1.9-branch/common/oidc-client/oauth2-proxy/components/istio-external-auth/requestauthentication.dex-jwt.yaml) and [K8s-m2m](https://github.com/kubeflow/manifests/blob/v1.9-branch/common/oidc-client/oauth2-proxy/components/istio-m2m/requestauthentication.yaml)), via `RequestAuthentication` objects
2. `AuthorizationPolicy` objects of components, for allowing access from Istio IngressGateway, will need to be extended for also requiring a JWT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May I suggest to drop the requirement to allow access only from Istio IngressGateway? AFAIR, this was a security concern from the past so the requests are always going through the EnvoyFilter. We don't use EnvoyFilter anymore and limiting access to requests only going through Istio IngressGateway doesn't bring any more security at this point and just makes the setup more complicated in my opinion.

If we only allow traffic to backends that have a trusted principal in requests (for the principal to be trusted and have it available to use in AuthorizationPolicy, it must be configured through the RequestAuthentication), there is no risk of trusting JWT/Issuer from unknown source.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

" AuthorizationPolicy objects of components, for allowing access from Istio IngressGateway, must be adjusted to enforce the presence of a JWT"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe

"AuthorizationPolicy objects of KF Components have to be adjusted to allow access only when a trusted JWT is present in the Authorization: Bearer <Token> header. We no longer have to enforce access only through istio-ingressgateway."

proposals/20240606-jwt-handling.md Outdated Show resolved Hide resolved
Comment on lines +85 to +101
- from:
- source:
principals:
- cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account
requestPrincipals: # new! Require JWT
- '*'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this rule allows accessing the specific endpoint only if the request went through the istio-ingressgateway and contains a trusted principal.

Can we just leave it like in the suggestion below? It would lower the coupling with this specific istio gateway.

Arguments in favor:

  • the name istio-ingressgateway-service-account couples the kubeflow deployment with istio gateway deployed from operator/istioctl, because istio gateway installed with Helm uses different SA (it should be also possible to use different gateway name and/or SA name if required)
  • it would allow OOB secure access from more gateways/istio LBs to access the service without any additional configuration
  • if some platform uses yet another LB (like ALB in AWS; istio still have to be deployed in-cluster), it's also possible to define a rule where the traffic goes directly to the endpoint (here jupyter-web-app) and omit the istio-ingressgateway
  • I don't see any security risks in dropping this requirement of access only through the istio-ingressgateway because the traffic must be authorized first to access either way

This is only for the reason of flexibility and ease of adoption.

Suggested change
- from:
- source:
principals:
- cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account
requestPrincipals: # new! Require JWT
- '*'
- from:
- source:
requestPrincipals:
- '*'

proposals/20240606-jwt-handling.md Outdated Show resolved Hide resolved
@kimwnasptd
Copy link
Member Author

Thank you so much for the review comments @kromanow94! I'll take a look on them today/tomorrow

@kimwnasptd
Copy link
Member Author

@kromanow94 I've addressed the review comments, and only left the ones that propose the removal of the IngressGateway declaration in the AuthorizationPolicies.

I would like to avoid making this change in this PR. Mainly because this is a bigger discussion, to untangle the Istio IngressGateway, from the Kubeflow components. There are other places that are affected by this, like the AuthorizationPolicies created by Profiles (for allowing traffic for Notebooks and/or ISVCs).

So I'd prefer that we tackle that problem of its own, in a proposal that captures all the aspects rather than doing some changes here that are not fully spec-ed out for the overall effort.

WDYT?

@juliusvonkohout
Copy link
Member

1. The service-mesh must drop (401) a request if the JWT is invalid (`RequestAuthentication`)
2. The service-mesh must drop (403) a request if the JWT is not present, and the application expects requests to have a user identity (`AuthorizationPolicy`)
3. The backends are not responsible for validating the JWTs or their existence
4. The service-mesh must expose user and groups to `kubeflow-userid` and `kubeflow-groups` headers, after validating JWTs
Copy link
Member

@juliusvonkohout juliusvonkohout Jun 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will it remove the bearer token header with the JWT before forwarding the request to the backend or will the backend recieve the userid header and the bearer token?

"The recommended way is to use requestPrincipals: [""], as the Istio docs suggest, to accept only requests that have a JWT. The recommended way is to use requestPrincipals: [""], as the Istio docs suggest, to accept only requests that have a ?valid? JWT." later on suggests that the JWT has to be forwarded as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No no the JWT will stay in the Authorization header, and the mesh will add the headers as an extra

@kromanow94
Copy link
Contributor

@kimwnasptd

@kromanow94 I've addressed the review comments, and only left the ones that propose the removal of the IngressGateway declaration in the AuthorizationPolicies.

I would like to avoid making this change in this PR. Mainly because this is a bigger discussion, to untangle the Istio IngressGateway, from the Kubeflow components. There are other places that are affected by this, like the AuthorizationPolicies created by Profiles (for allowing traffic for Notebooks and/or ISVCs).

So I'd prefer that we tackle that problem of its own, in a proposal that captures all the aspects rather than doing some changes here that are not fully spec-ed out for the overall effort.

WDYT?

Ok, this makes very much sense. Let's do it like that.

Also, I wasn't able to resolve the threads but I either left a comment or a thumbs up where I agree on the resolution.


@juliusvonkohout

Given oauth2-proxy the information in https://www.kubeflow.org/docs/components/pipelines/user-guides/core-functions/connect-api/#full-kubeflow-subfrom-inside-clustersub is is really misleading.

So I understand you suggest to update this docs with information on how to use the SA Token?


BTW, since we're moving around some stuff for authz, maybe you're interested in having a service that will manage programmatic login? This would be something that replaces the Full Kubeflow (from outside cluster) flow. We have this little component that works with a websocket, can redirect to the auth page, get the cookies or a token from login response and send back via websocket to the client. We can also have a call sometime next week so I can showcase how would that work.

@juliusvonkohout
Copy link
Member

So I understand you suggest to update this docs with information on how to use the SA Token?

Yes :-) this session hack i snot what we should advertise.

Signed-off-by: Kimonas Sotirchos <kimwnasptd@gmail.com>
Signed-off-by: Kimonas Sotirchos <kimwnasptd@gmail.com>
Signed-off-by: Kimonas Sotirchos <kimwnasptd@gmail.com>
@kimwnasptd kimwnasptd force-pushed the feature-kimwnasptd-jwt-handling-proposal branch from a3c1ac4 to a4ba96a Compare June 28, 2024 08:26
@kimwnasptd
Copy link
Member Author

@kromanow94 @juliusvonkohout I've done a pass and integrated your comments. Let me know if there's anything else

@juliusvonkohout
Copy link
Member

juliusvonkohout commented Jun 30, 2024

@kromanow94 @juliusvonkohout I've done a pass and integrated your comments. Let me know if there's anything else

For me it is anyway a

/lgtm

for a long time (despite the "nits" :-D)

We can always reiterate and reiterating is easier if it is merged first. In the end it is a proposal that can change.

@juliusvonkohout
Copy link
Member

/approve

Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: juliusvonkohout

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@google-oss-prow google-oss-prow bot merged commit 9e7a98c into kubeflow:master Jun 30, 2024
4 checks passed
@kimwnasptd kimwnasptd deleted the feature-kimwnasptd-jwt-handling-proposal branch July 2, 2024 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants