-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(bff): use 'kubeflow-userid' header to authorize BFF endpoints (#599
) * feat(bff): use 'kubeflow-userid' header to authorize BFF endpoints Signed-off-by: Eder Ignatowicz <[email protected]> * fixing lint Signed-off-by: Eder Ignatowicz <[email protected]> --------- Signed-off-by: Eder Ignatowicz <[email protected]>
- Loading branch information
Showing
19 changed files
with
364 additions
and
115 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,21 +71,23 @@ make docker-build | |
| POST /api/v1/model_registry/{model_registry_id}/model_versions/{model_version_id}/artifacts | CreateModelArtifactByModelVersion | Create a ModelArtifact entity for a specific ModelVersion | | ||
|
||
### Sample local calls | ||
|
||
You will need to inject your requests with a kubeflow-userid header for authorization purposes. When running the service with the mocked Kubernetes client (MOCK_K8S_CLIENT=true), the user [email protected] is preconfigured with the necessary RBAC permissions to perform these actions. | ||
``` | ||
# GET /v1/healthcheck | ||
curl -i localhost:4000/api/v1/healthcheck | ||
curl -i -H "kubeflow-userid: [email protected]" localhost:4000/api/v1/healthcheck | ||
``` | ||
``` | ||
# GET /v1/model_registry | ||
curl -i localhost:4000/api/v1/model_registry | ||
curl -i -H "kubeflow-userid: [email protected]" localhost:4000/api/v1/model_registry | ||
``` | ||
``` | ||
# GET /v1/model_registry/{model_registry_id}/registered_models | ||
curl -i localhost:4000/api/v1/model_registry/model-registry/registered_models | ||
curl -i -H "kubeflow-userid: [email protected]" localhost:4000/api/v1/model_registry/model-registry/registered_models | ||
``` | ||
``` | ||
#POST /v1/model_registry/{model_registry_id}/registered_models | ||
curl -i -X POST "http://localhost:4000/api/v1/model_registry/model-registry/registered_models" \ | ||
curl -i -H "kubeflow-userid: [email protected]" -X POST "http://localhost:4000/api/v1/model_registry/model-registry/registered_models" \ | ||
-H "Content-Type: application/json" \ | ||
-d '{ "data": { | ||
"customProperties": { | ||
|
@@ -103,23 +105,23 @@ curl -i -X POST "http://localhost:4000/api/v1/model_registry/model-registry/regi | |
``` | ||
``` | ||
# GET /v1/model_registry/{model_registry_id}/registered_models/{registered_model_id} | ||
curl -i localhost:4000/api/v1/model_registry/model-registry/registered_models/1 | ||
curl -i -H "kubeflow-userid: [email protected]" localhost:4000/api/v1/model_registry/model-registry/registered_models/1 | ||
``` | ||
``` | ||
# PATCH /v1/model_registry/{model_registry_id}/registered_models/{registered_model_id} | ||
curl -i -X PATCH "http://localhost:4000/api/v1/model_registry/model-registry/registered_models/1" \ | ||
curl -i -H "kubeflow-userid: [email protected]" -X PATCH "http://localhost:4000/api/v1/model_registry/model-registry/registered_models/1" \ | ||
-H "Content-Type: application/json" \ | ||
-d '{ "data": { | ||
"description": "New description" | ||
}}' | ||
``` | ||
``` | ||
# GET /api/v1/model_registry/{model_registry_id}/model_versions/{model_version_id} | ||
curl -i http://localhost:4000/api/v1/model_registry/model-registry/model_versions/1 | ||
curl -i -H "kubeflow-userid: [email protected]" http://localhost:4000/api/v1/model_registry/model-registry/model_versions/1 | ||
``` | ||
``` | ||
# POST /api/v1/model_registry/{model_registry_id}/model_versions | ||
curl -i -X POST "http://localhost:4000/api/v1/model_registry/model-registry/model_versions" \ | ||
curl -i -H "kubeflow-userid: [email protected]" -X POST "http://localhost:4000/api/v1/model_registry/model-registry/model_versions" \ | ||
-H "Content-Type: application/json" \ | ||
-d '{ "data": { | ||
"customProperties": { | ||
|
@@ -138,19 +140,19 @@ curl -i -X POST "http://localhost:4000/api/v1/model_registry/model-registry/mode | |
``` | ||
``` | ||
# PATCH /api/v1/model_registry/{model_registry_id}/model_versions/{model_version_id} | ||
curl -i -X PATCH "http://localhost:4000/api/v1/model_registry/model-registry/model_versions/1" \ | ||
curl -i -H "kubeflow-userid: [email protected]" -X PATCH "http://localhost:4000/api/v1/model_registry/model-registry/model_versions/1" \ | ||
-H "Content-Type: application/json" \ | ||
-d '{ "data": { | ||
"description": "New description 2" | ||
}}' | ||
``` | ||
``` | ||
# GET /v1/model_registry/{model_registry_id}/registered_models/{registered_model_id}/versions | ||
curl -i localhost:4000/api/v1/model_registry/model-registry/registered_models/1/versions | ||
curl -i -H "kubeflow-userid: [email protected]" localhost:4000/api/v1/model_registry/model-registry/registered_models/1/versions | ||
``` | ||
``` | ||
# POST /v1/model_registry/{model_registry_id}/registered_models/{registered_model_id}/versions | ||
curl -i -X POST "http://localhost:4000/api/v1/model_registry/model-registry/registered_models/1/versions" \ | ||
curl -i -H "kubeflow-userid: [email protected]" -X POST "http://localhost:4000/api/v1/model_registry/model-registry/registered_models/1/versions" \ | ||
-H "Content-Type: application/json" \ | ||
-d '{ "data": { | ||
"customProperties": { | ||
|
@@ -163,17 +165,17 @@ curl -i -X POST "http://localhost:4000/api/v1/model_registry/model-registry/regi | |
"externalId": "9928", | ||
"name": "ModelVersion One", | ||
"state": "LIVE", | ||
"author": "alex" | ||
"author": "alex", | ||
"registeredModelId: "1" | ||
}}' | ||
``` | ||
``` | ||
# GET /api/v1/model_registry/{model_registry_id}/model_versions/{model_version_id}/artifacts | ||
curl -i http://localhost:4000/api/v1/model_registry/model-registry/model_versions/1/artifacts | ||
curl -i -H "kubeflow-userid: [email protected]" http://localhost:4000/api/v1/model_registry/model-registry/model_versions/1/artifacts | ||
``` | ||
``` | ||
# POST /api/v1/model_registry/{model_registry_id}/model_versions/{model_version_id}/artifacts | ||
curl -i -X POST "http://localhost:4000/api/v1/model_registry/model-registry/model_versions/1/artifacts" \ | ||
curl -i -H "kubeflow-userid: [email protected]" -X POST "http://localhost:4000/api/v1/model_registry/model-registry/model_versions/1/artifacts" \ | ||
-H "Content-Type: application/json" \ | ||
-d '{ "data": { | ||
"customProperties": { | ||
|
@@ -203,9 +205,9 @@ The following query parameters are supported by "Get All" style endpoints to con | |
### Sample local calls | ||
``` | ||
# Get with a page size of 5 getting a specific page. | ||
curl -i "http://localhost:4000/api/v1/model_registry/model-registry/registered_models?pageSize=5&nextPageToken=CAEQARoCCAE" | ||
curl -i -H "kubeflow-userid: [email protected]" "http://localhost:4000/api/v1/model_registry/model-registry/registered_models?pageSize=5&nextPageToken=CAEQARoCCAE" | ||
``` | ||
``` | ||
# Get with a page size of 5, order by last update time in descending order. | ||
curl -i "http://localhost:4000/api/v1/model_registry/model-registry/registered_models?pageSize=5&orderBy=LAST_UPDATE_TIME&sortOrder=DESC" | ||
curl -i -H "kubeflow-userid: [email protected]" "http://localhost:4000/api/v1/model_registry/model-registry/registered_models?pageSize=5&orderBy=LAST_UPDATE_TIME&sortOrder=DESC" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ var _ = Describe("TestGetModelVersionHandler", func() { | |
By("fetching a model version") | ||
data := mocks.GetModelVersionMocks()[0] | ||
expected := ModelVersionEnvelope{Data: &data} | ||
actual, rs, err := setupApiTest[ModelVersionEnvelope](http.MethodGet, "/api/v1/model_registry/model-registry/model_versions/1", nil, k8sClient) | ||
actual, rs, err := setupApiTest[ModelVersionEnvelope](http.MethodGet, "/api/v1/model_registry/model-registry/model_versions/1", nil, k8sClient, mocks.KubeflowUserIDHeaderValue) | ||
Expect(err).NotTo(HaveOccurred()) | ||
By("should match the expected model version") | ||
Expect(rs.StatusCode).To(Equal(http.StatusOK)) | ||
|
@@ -27,7 +27,7 @@ var _ = Describe("TestGetModelVersionHandler", func() { | |
data := mocks.GetModelVersionMocks()[0] | ||
expected := ModelVersionEnvelope{Data: &data} | ||
body := ModelVersionEnvelope{Data: openapi.NewModelVersion("Model One", "1")} | ||
actual, rs, err := setupApiTest[ModelVersionEnvelope](http.MethodPost, "/api/v1/model_registry/model-registry/model_versions", body, k8sClient) | ||
actual, rs, err := setupApiTest[ModelVersionEnvelope](http.MethodPost, "/api/v1/model_registry/model-registry/model_versions", body, k8sClient, mocks.KubeflowUserIDHeaderValue) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
By("should match the expected model version created") | ||
|
@@ -46,7 +46,7 @@ var _ = Describe("TestGetModelVersionHandler", func() { | |
} | ||
body := ModelVersionUpdateEnvelope{Data: &reqData} | ||
|
||
actual, rs, err := setupApiTest[ModelVersionEnvelope](http.MethodPatch, "/api/v1/model_registry/model-registry/model_versions/1", body, k8sClient) | ||
actual, rs, err := setupApiTest[ModelVersionEnvelope](http.MethodPatch, "/api/v1/model_registry/model-registry/model_versions/1", body, k8sClient, mocks.KubeflowUserIDHeaderValue) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
By("should match the expected model version updated") | ||
|
@@ -58,7 +58,7 @@ var _ = Describe("TestGetModelVersionHandler", func() { | |
By("getting a model artifacts by model version") | ||
data := mocks.GetModelArtifactListMock() | ||
expected := ModelArtifactListEnvelope{Data: &data} | ||
actual, rs, err := setupApiTest[ModelArtifactListEnvelope](http.MethodGet, "/api/v1/model_registry/model-registry/model_versions/1/artifacts", nil, k8sClient) | ||
actual, rs, err := setupApiTest[ModelArtifactListEnvelope](http.MethodGet, "/api/v1/model_registry/model-registry/model_versions/1/artifacts", nil, k8sClient, mocks.KubeflowUserIDHeaderValue) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
By("should get all expected model version artifacts") | ||
|
@@ -79,7 +79,7 @@ var _ = Describe("TestGetModelVersionHandler", func() { | |
ArtifactType: "ARTIFACT_TYPE_ONE", | ||
} | ||
body := ModelArtifactEnvelope{Data: &artifact} | ||
actual, rs, err := setupApiTest[ModelArtifactEnvelope](http.MethodPost, "/api/v1/model_registry/model-registry/model_versions/1/artifacts", body, k8sClient) | ||
actual, rs, err := setupApiTest[ModelArtifactEnvelope](http.MethodPost, "/api/v1/model_registry/model-registry/model_versions/1/artifacts", body, k8sClient, mocks.KubeflowUserIDHeaderValue) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
By("should get all expected model artifacts") | ||
|
@@ -88,5 +88,54 @@ var _ = Describe("TestGetModelVersionHandler", func() { | |
Expect(rs.Header.Get("Location")).To(Equal("/api/v1/model_registry/model-registry/model_artifacts/1")) | ||
|
||
}) | ||
|
||
It("should return 403 when not using the wrong KubeflowUserIDHeaderValue", func() { | ||
By("making a request with an incorrect username") | ||
wrongUserIDHeader := "[email protected]" // Incorrect username header value | ||
|
||
// Test: GET /model_versions/1 | ||
_, rs, err := setupApiTest[ModelVersionEnvelope](http.MethodGet, "/api/v1/model_registry/model-registry/model_versions/1", nil, k8sClient, wrongUserIDHeader) | ||
|
||
Expect(err).NotTo(HaveOccurred()) | ||
By("should return a 403 Forbidden response") | ||
Expect(rs.StatusCode).To(Equal(http.StatusForbidden)) | ||
|
||
// Test: POST /model_versions/1/artifacts | ||
artifact := openapi.ModelArtifact{ | ||
Name: openapi.PtrString("Artifact One"), | ||
ArtifactType: "ARTIFACT_TYPE_ONE", | ||
} | ||
body := ModelArtifactEnvelope{Data: &artifact} | ||
_, rs, err = setupApiTest[ModelArtifactEnvelope](http.MethodPost, "/api/v1/model_registry/model-registry/model_versions/1/artifacts", body, k8sClient, wrongUserIDHeader) | ||
|
||
Expect(err).NotTo(HaveOccurred()) | ||
By("should return a 403 Forbidden response") | ||
Expect(rs.StatusCode).To(Equal(http.StatusForbidden)) | ||
|
||
// Test: GET /model_versions/1/artifacts | ||
_, rs, err = setupApiTest[ModelArtifactListEnvelope](http.MethodGet, "/api/v1/model_registry/model-registry/model_versions/1/artifacts", nil, k8sClient, wrongUserIDHeader) | ||
|
||
Expect(err).NotTo(HaveOccurred()) | ||
By("should return a 403 Forbidden response") | ||
Expect(rs.StatusCode).To(Equal(http.StatusForbidden)) | ||
|
||
// Test: PATCH /model_versions/1 | ||
reqData := openapi.ModelVersionUpdate{ | ||
Description: openapi.PtrString("New description"), | ||
} | ||
body1 := ModelVersionUpdateEnvelope{Data: &reqData} | ||
_, rs, err = setupApiTest[ModelVersionEnvelope](http.MethodPatch, "/api/v1/model_registry/model-registry/model_versions/1", body1, k8sClient, wrongUserIDHeader) | ||
|
||
Expect(err).NotTo(HaveOccurred()) | ||
By("should return a 403 Forbidden response") | ||
Expect(rs.StatusCode).To(Equal(http.StatusForbidden)) | ||
|
||
// Test: POST /model_versions | ||
body2 := ModelVersionEnvelope{Data: openapi.NewModelVersion("Model One", "1")} | ||
_, rs, err = setupApiTest[ModelVersionEnvelope](http.MethodPost, "/api/v1/model_registry/model-registry/model_versions", body2, k8sClient, wrongUserIDHeader) | ||
Expect(err).NotTo(HaveOccurred()) | ||
By("should return a 403 Forbidden response") | ||
Expect(rs.StatusCode).To(Equal(http.StatusForbidden)) | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.