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

feat(bff): authorize endpoints based on kubeflow-userid and kubeflow-groups header #660

Merged
merged 1 commit into from
Dec 19, 2024

Conversation

ederign
Copy link
Member

@ederign ederign commented Dec 17, 2024

Authorize endpoints based on kubeflow-userid and kubeflow-groups header

Description

This PR sits on top of #644

Important: THIS PR makes namespace parameter mandatory. It will require a FUP PR with frontend by @lucferbux to don't disrupt our develoopment

How this works?

Authorization is performed using Kubernetes SubjectAccessReview (SAR), which validates user access to resources.

  • kubeflow-userid: Required header that specifies the user’s email. Access is checked directly for the user via SAR.
  • kubeflow-groups: Optional header with a comma-separated list of groups. If the user does not have access, SAR checks group permissions using OR logic. If any group has access, the request is authorized.

Access to Model Registry List:

  • To list all model registries (/v1/model_registry), we perform a SAR check for get and list verbs on services within the specified namespace.
  • If the user or any group has permission to get and list services in the namespace, the request is authorized.

Access to Specific Model Registry Endpoints:

  • For other endpoints (e.g., /v1/model_registry/{model_registry_id}/...), we perform a SAR check for get and list verbs on the specific service (identified by model_registry_id) within the namespace.
  • If the user or any group has permission to get or list the specific service, the request is authorized.

In this PR:

  • clients/ui/bff/README.md: changed URLs to include namespace, added some samples for groups and documentation for authorization
  • clients/ui/bff/internal/api/app.go: core piece of this PR, created the middleware interceptors that execute SARs for given endpoints and also attach namespace parameter and kubeflow headers
  • clients/ui/bff/internal/api/healthcheck__handler_test.go: small test change
  • clients/ui/bff/internal/api/healthcheck_handler.go: receive the user from context
  • clients/ui/bff/internal/api/middleware.go: another core piece of this PRs, include header extraction logic, namespace extraction logic, and sar for endpoints
  • clients/ui/bff/internal/api/model_registry_handler.go : make namespace mandatory
  • clients/ui/bff/internal/api/model_registry_handler.go : companion test changes
  • clients/ui/bff/internal/api/model_versions_handler.go : small refactoring
  • clients/ui/bff/internal/api/model_versions_handler_test.go: companion test changes
  • clients/ui/bff/internal/api/namespaces_handler.go from feat(bff): list user namespaces in dev mode #644
  • clients/ui/bff/internal/api/namespaces_handler_test.go: companion test from feat(bff): list user namespaces in dev mode #644
  • clients/ui/bff/internal/api/registered_models_handler.go: small refactoring
  • clients/ui/bff/internal/api/registered_models_handler.go: test changes to include namespace as parameter
  • clients/ui/bff/internal/api/registered_models_handler.go: test utils change to include headers
  • clients/ui/bff/internal/api/user_handler.go: extract user from context
  • clients/ui/bff/internal/api/user_handler_test.go: companion test changes
  • clients/ui/bff/internal/integrations/http.go: added model registry id identifier (for SAR)
  • clients/ui/bff/internal/integrations/k8s.go: include namespace filtering and sar methods
  • clients/ui/bff/internal/mocks/http_mock.go: companion mock changes
  • clients/ui/bff/internal/mocks/k8s_mock_test.go: companion mock changes
  • clients/ui/bff/internal/models/namespace.go: from feat(bff): list user namespaces in dev mode #644
  • clients/ui/bff/internal/repositories/model_registry.go: small refactoring
  • clients/ui/bff/internal/repositories/model_registry_test.go include namespace on test
  • clients/ui/bff/internal/repositories/namespace.go from feat(bff): list user namespaces in dev mode #644

How Has This Been Tested?

Regular query filtering by namespace ([email protected] is a cluster admin)

curl -i -H "kubeflow-userid: [email protected]" "localhost:4000/api/v1/model_registry?namespace=kubeflow"                                      (kind-kind/default)
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 17 Dec 2024 13:51:35 GMT
Content-Length: 271

{
	"data": [
		{
			"name": "model-registry",
			"displayName": "Model Registry",
			"description": "Model Registry Description"
		},
		{
			"name": "model-registry-one",
			"displayName": "Model Registry One",
			"description": "Model Registry One description"
		}
	]
}

Dora user cannot see services on kubeflow namespace

curl -i -H "kubeflow-userid: [email protected]" "localhost:4000/api/v1/model_registry?namespace=kubeflow"                              (kind-kind/default)
HTTP/1.1 403 Forbidden
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 17 Dec 2024 13:52:16 GMT
Content-Length: 65

{
	"error": {
		"code": "403",
		"message": "access denied"
	}
}

But can access on it's namespace

curl -i -H "kubeflow-userid: [email protected]" "localhost:4000/api/v1/model_registry?namespace=dora-namespace"                        (kind-kind/default)
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 17 Dec 2024 13:52:31 GMT
Content-Length: 153

{
	"data": [
		{
			"name": "model-registry-dora",
			"displayName": "Model Registry Dora",
			"description": "Model Registry Dora description"
		}
	]
}

If I miss namespace:

curl -i -H "kubeflow-userid: [email protected]" localhost:4000/api/v1/model_registry/model-registry/registered_models                          (kind-kind/default)
HTTP/1.1 400 Bad Request
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 17 Dec 2024 13:53:02 GMT
Content-Length: 95

{
	"error": {
		"code": "400",
		"message": "missing required query parameter: namespace"
	}
}

If I add namespace

 curl -i -H "kubeflow-userid: [email protected]" "localhost:4000/api/v1/model_registry/model-registry/registered_models?namespace=kubeflow"     (kind-kind/default)
HTTP/1.1 200 OK
...

Dora user cannot access service directly

curl -i -H "kubeflow-userid: [email protected]" "localhost:4000/api/v1/model_registry/model-registry/registered_models?namespace=kubeflow"
HTTP/1.1 403 Forbidden
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 17 Dec 2024 13:54:12 GMT
Content-Length: 65

{
	"error": {
		"code": "403",
		"message": "access denied"
	}
}

We now return 404 for a non existent service

curl -i -H "kubeflow-userid: [email protected]" "localhost:4000/api/v1/model_registry/model-registry/registered_models?namespace=dora-namespace"
HTTP/1.1 404 Not Found

Dora user has access for a service

curl -i -H "kubeflow-userid: [email protected]" "localhost:4000/api/v1/model_registry/model-registry-dora/registered_models?namespace=dora-namespace"
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 17 Dec 2024 13:55:06 GMT

Group permissions work (note that the user is invalid)

curl -i \                                                            
  -H "kubeflow-userid: [email protected]" \
  -H "kubeflow-groups: group1,group2,group3" \
  "http://localhost:4000/api/v1/model_registry?namespace=kubeflow"
HTTP/1.1 403 Forbidden
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 17 Dec 2024 15:25:04 GMT
Content-Length: 65

{
	"error": {
		"code": "403",
		"message": "access denied"
	}
}

With the right groups

curl -i \                                                                                                                                     (kind-kind/default)
  -H "kubeflow-userid: [email protected]" \
  -H "kubeflow-groups: dora-namespace-group ,group2,group3" \
  "http://localhost:4000/api/v1/model_registry?namespace=dora-namespace"
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 17 Dec 2024 15:26:07 GMT
Content-Length: 153

{
	"data": [
		{
			"name": "model-registry-dora",
			"displayName": "Model Registry Dora",
			"description": "Model Registry Dora description"
		}
	]
}

Right group for services

 curl -i \                                                                                                                                     (kind-kind/default)
  -H "kubeflow-userid: [email protected]" \
  -H "kubeflow-groups: dora-namespace-group ,dora-service-group,group3" \
  "http://localhost:4000/api/v1/model_registry/model-registry-dora/registered_models?namespace=dora-namespace"
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 17 Dec 2024 15:29:10 GMT
Transfer-Encoding: chunked
...

Wrong group for service

curl -i \                                                                   
  -H "kubeflow-userid: [email protected]" \
  -H "kubeflow-groups: dora--wrongnamespace-group ,dora-bad-service-group,group3" \
  "http://localhost:4000/api/v1/model_registry/model-registry-dora/registered_models?namespace=dora-namespace"
HTTP/1.1 403 Forbidden
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Tue, 17 Dec 2024 15:29:42 GMT
Content-Length: 65

{
	"error": {
		"code": "403",
		"message": "access denied"
	}
}

Merge criteria:

  • All the commits have been signed-off (To pass the DCO check)
  • The commits have meaningful messages; the author will squash them after approval or in case of manual merges will ask to merge with squash.
  • Testing instructions have been added in the PR body (for PRs involving changes that are not immediately obvious).
  • The developer has manually tested the changes and verified that the changes work.
  • Code changes follow the kubeflow contribution guidelines.

@ederign
Copy link
Member Author

ederign commented Dec 17, 2024

@lucferbux @alexcreasy @Griffin-Sullivan just to reinforce that before merge this PR, we need support on frontend to ?namespace parameter. Otherwise, we will break it.

@ederign
Copy link
Member Author

ederign commented Dec 17, 2024

Also, as soon as we merge #644 , I'll rebase this one.

@ederign
Copy link
Member Author

ederign commented Dec 19, 2024

@alexcreasy rebased!

Copy link
Contributor

@lucferbux lucferbux left a comment

Choose a reason for hiding this comment

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

/lgtm

Tested and it's working, need this to raise my PR, we can do a follow up if there anything else.

Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: lucferbux

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 9f68ddc into kubeflow:main Dec 19, 2024
16 checks passed
@lucferbux lucferbux mentioned this pull request Dec 20, 2024
7 tasks
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.

2 participants