-
Notifications
You must be signed in to change notification settings - Fork 443
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
Add authorization mechanisms in new Katib UI backend #1983
Add authorization mechanisms in new Katib UI backend #1983
Conversation
* Introduce helper ENV vars and functions for authentication and authorization checks. The authz checks are using SubjectAcessReviews objects. * BACKEND_MODE={dev,prod}: skip authz when in dev mode * APP_DISABLE_AUTH={bool}: skip authz if explicity requested * Introduce a client-go client to construct SubjectAccessReview objects. * Before any request proceed to K8s api-server: * check if authorization must be skipped (BACKEND_MODE, APP_DISBLE_AUTH) * check if a username is proviced in request Header * query the K8s api-server with SAR to ensure that the user has appropriate access privilleges * Replace the /katib/fetch_experiment/ route with /katib/fetch_namespaces_experiments. This route expects a namespace as a query parameter from which all experiments will be fetched. Signed-off-by: Apostolos Gerakaris <apoger@arrikto.com>
dde5a0f
to
0b6e3c1
Compare
/assign @kimwnasptd Can you review this PR for both standalone and Kubeflow mode of deployment? |
Thank you so much for these improvements @apo-ger! |
/hold for the review |
@andreyvelich |
During the review, we took another look at the kubeflow-katib installation manifests and it appears that Istio sidecar injection is currently disabled for the katib-ui component (ui.yaml). The same applies to the other katib components. In addition, we lack the proper AuthorizationPolicies for this PR to work properly, as currently any workloda/pod can set the I can prepare a follow-up manifests PR to address this. Minimum required changes:
I could also prepare another PR, which would allow the injection of istio sidecar for the other components of katib and introduce appropriate AuthorizationPolicies to secure them. However, this is orthogonal to this PR. cc. @kimwnasptd, @andreyvelich, @johnugeorge. |
Looks good @apo-ger |
pkg/new-ui/v1beta1/backend.go
Outdated
return | ||
} | ||
|
||
newTemplates, err := k.updateTrialTemplates(updatedConfigMapNamespace, updatedConfigMapName, "", updatedConfigMapPath, "", ActionTypeDelete, user) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kimwnasptd Currently the updateTrialTemplate() function is called from multiple routes (Edit/Add/DeleteTemplate). It will first try to retrieve the TrialTemplate ConfigMap and then perform update/delete/create depending on the route from which it is called.
The current implementation will either delete the TrialTemplate ConfigMap if its empty or update the ConfigMap when the actiontype is delete. Currently we check only if a user has permissions to delete ConfigMaps.
We could move the authorization checks inside updateTrialTemplate() since it is called from multiple routes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@apo-ger Thanks for driving this PR!
I left a few comments.
aa45849
to
a343ef1
Compare
@tenzen-y |
@apo-ger Should we remove this annotation from our manifests ? I guess, Katib UI should work with istio sidecar injected, right ?
|
a343ef1
to
0377ed3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left few comments.
Yes, removing the annotation will do.
Injecting a sidecar in DB manager means we need to introduce an additional AuthorizationPolicy to explicitly allow traffic from other katib components (katib-ui, katib-controller etc) when in kubeflow mode as by default we deny all traffic in the mesh: https://github.com/kubeflow/manifests/blob/master/common/istio-1-14/istio-install/base/deny_all_authorizationpolicy.yaml. |
This is needed for the new /katib/fetch_namespaced_experiments route. Signed-off-by: Apostolos Gerakaris <apoger@arrikto.com>
Update the README of the web app to expose that devs should set APP_DISABLE_AUTH=true when running locally, since there's no authnz when running locally. Signed-off-by: Apostolos Gerakaris <apoger@arrikto.com>
Signed-off-by: Apostolos Gerakaris <apoger@arrikto.com>
* proper error handling. * switch to Go's build-in errors package. * set appropriate verbs when constructing SAR objects. Signed-off-by: Apostolos Gerakaris <apoger@arrikto.com>
4e83b28
to
e436760
Compare
* fix backend routes. * '/katib/fetch_namespaces' to fetch experiments in a namespace * 'FetchExperiments' handler * hit the appropriate route from frontend and provide namespace as a query parameter to fetch experiments * remove remove BACKEND_MODE env var in favour of the more specific APP_DISABLE_AUTH Signed-off-by: Apostolos Gerakaris <apoger@arrikto.com>
@andreyvelich Thank you for your comments. Please let me know if everything is okay Now, regarding the manifests changes:
|
@apo-ger I am not sure if we should enable istio for DB Manager. Will it block gRPC traffic that call APIs: |
pkg/new-ui/v1beta1/authzn.go
Outdated
if DISABLE_AUTH == "true" { | ||
log.Printf("APP_DISABLE_AUTH set to True. Skipping authentication check") | ||
return "", nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we avoid duplicate check for if DISABLE_AUTH == "true"
by adding GetUsername
logic under IsAuthorized
call ?
Then, we have 1 place where we verify if auth is required.
WDYT @apo-ger ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I moved the GetUsername
logic under IsAuthorized
and introduced the appropriate checks to handle the various errors properly!
Note: We have to test it carefully before any side car changes. The reason is that we don't have any tests in Kubeflow mode. So, manual testing is the only option |
7a581e3
to
ae941c4
Compare
user, err := IsAuthorized(consts.ActionTypeGet, ns, apiv1.ResourceConfigMaps.String(), "", configmapName, apiv1.SchemeGroupVersion, k.katibClient.GetClient(), r) | ||
if err != nil { | ||
log.Printf("The user: %s is not authorized to view configMap: %s in namespace: %s \n", user, configmapName, ns) | ||
return nil, err | ||
} else { | ||
log.Printf("The user: %s is authorized to view configMap: %s in namespace: %s", user, configmapName, ns) | ||
newTrialTemplatesConfigMapList = append(newTrialTemplatesConfigMapList, cmap) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@apo-ger Maybe we should make the IsAuthorized
check before we are getting Trial templates ?
Then, you don't need to have additional condition for kubeflow
namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, let me explain the rationale behind this particular check.
Right now all the TrialTemplates
reside in the kubeflow
namespace. I understand that this might change to have TrialTemplates per namespace at some point (#1546)
Since this is not the case right now, we decided to allow all users to view the default TrialTemplates in the kubeflow
namespace and this is why we perform the authorization checks after getting the Trial Templates. The current implementation:
- fetches the trialTemplate ConfigMaps from all namespaces
- constructs a
trialTemplatesConfigMapList
list which includes:- the default TrialTemplate
ConfigMap
that belong to the kubeflow namespace - the
ConfigMaps
which belong to namespaces that the user has access rights to (e.gkubeflow-user
) - All other CMs are filtered out.
- the default TrialTemplate
Note that the current implementation ensures that users are able to delete/edit TrialTemplates only in their namespace and not the default ones in the kubeflow
ns.
WDYT @andreyvelich ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC the current implementation of the UI only allows users to view the available TrialTemplates
(/katib/fetch_trial_templates/), right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, makes sense @apo-ger.
IIUC the current implementation of the UI only allows users to view the available TrialTemplates (/katib/fetch_trial_templates/), right?
We have API to create/delete template. For example: https://github.com/apo-ger/katib/blob/ae941c4cc66747a7e0db363ec7c9e1f877a1b9c9/pkg/new-ui/v1beta1/backend.go#L280.
The old UI has feature to CRUD Trial templates, but the new UI still don't support it, tracking here: #1440. cc @kimwnasptd
We might need to have discussion around this. Should we show Trial templates in kubeflow
namespace or just avoid it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might need to have discussion around this. Should we show Trial templates in kubeflow namespace or just avoid it.
+1 on having a discussion around this. Although I think the current approach makes sense:
- An admin adds TrialTemplate (ConfigMap) in the
kubeflow
namespace. These are visible from all users- But the backend won't allow users to edit/delete ConfigMaps in the
kubeflow
namespace. For these actions there are SubjectAccessReview checks in place. - If an admin wants to allow a user to manipulate the global (
kubeflow
namespace) ConfigMaps then they just need to give them RBAC permissions
- But the backend won't allow users to edit/delete ConfigMaps in the
- Users will then see/interact-with ConfigMaps in other namespaces that they have permissions for
* Add constants for CRUD actions * Add plural for experiments and suggestions as constants * Add GetUsername logic under IsAuthorized and handle errors properly * Have APP_DISABLE_AUTH by default as true, since currently Katib doesn't support this feature in standalone mode. Signed-off-by: Apostolos Gerakaris <apoger@arrikto.com>
ae941c4
to
ad1e3b0
Compare
Thanks a lot for implementing this @apo-ger! |
@andreyvelich @johnugeorge @tenzen-y @kimwnasptd Thank you for the review! |
The current code looks good from my side. @andreyvelich thank you for the thorough review! /lgtm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@apo-ger Thanks a lot!
/lgtm
🎉 🎉 /approve |
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: andreyvelich, apo-ger, kimwnasptd 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 |
🎉 |
What this PR does / why we need it:
The current backend for the new UI does not perform any authorization checks. It should comply with the authz guidelines (kubeflow/dashboard#41) and use
SubjectAccessReviews
(SAR) to check if a user has permissions to perform an action.This PR:
introduces authz checks for actions on:
Trials
Experiments
TrialTemplates
introduces three ENV variables:
APP_DISABLE_AUTH
: Skip authorization if an admin is explicitly requested it.BACKEND_MODE
: dev or prod mode. Skip authorization when in dev mode.USERID_HEADER
: to check and ensure that a username is provided into the header of every http request towards the api-server.Before any request proceed to K8s api-server:
Other changes:
SubjectAccessReview
objects./katib/fetch_experiment/
route with/katib/fetch_namespaced_experiments
. This route expects a namespace as a query parameter from which all experiments will be fetched.README
of the web app to expose that devs should setAPP_DISABLE_AUTH=true
when running locallyFixes kubeflow/kubeflow#1547