Skip to content

Commit

Permalink
feat(backend): Upload namespaced pipeline definitions. Part of #4197 (#…
Browse files Browse the repository at this point in the history
…8511)

* feat(backend) Fix authentication in upload requests

Fix the way KFP API server authenticates pipeline upload requests.
We leverage 'isAuthenticated()` function which requires proper
initialization of the context object to include user identity.

* feat(backend): Add namespace field in pipeline upload swagger definition

Extend swagger defintion of the pipeline upload API with a namespace
parameter in order to support uploading namespaced pipelines.

* chore(backend): Generate Go & Python clients

Autogenerate the Go and Python clients after extending the swagger
definitions of upload pipeline APIs with a namespace field.
  • Loading branch information
elikatsis authored Dec 1, 2022
1 parent 6cd7cbc commit 931c14a
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 13 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions backend/api/v1beta1/swagger/kfp_api_single_file.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1406,6 +1406,12 @@
"in": "query",
"required": false,
"type": "string"
},
{
"name": "namespace",
"in": "query",
"required": false,
"type": "string"
}
],
"tags": [
Expand Down Expand Up @@ -1461,6 +1467,12 @@
"in": "query",
"required": false,
"type": "string"
},
{
"name": "namespace",
"in": "query",
"required": false,
"type": "string"
}
],
"tags": [
Expand Down
14 changes: 13 additions & 1 deletion backend/api/v1beta1/swagger/pipeline.upload.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@
"in": "query",
"required": false,
"type": "string"
},
{
"name": "namespace",
"in": "query",
"required": false,
"type": "string"
}
],
"tags": [
Expand Down Expand Up @@ -106,6 +112,12 @@
"in": "query",
"required": false,
"type": "string"
},
{
"name": "namespace",
"in": "query",
"required": false,
"type": "string"
}
],
"tags": [
Expand Down Expand Up @@ -298,4 +310,4 @@
"Bearer": []
}
]
}
}
50 changes: 38 additions & 12 deletions backend/src/apiserver/server/pipeline_upload_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"net/http"
"net/url"

"google.golang.org/grpc/metadata"
"github.com/golang/glog"
"github.com/golang/protobuf/jsonpb"
api "github.com/kubeflow/pipelines/backend/api/v1beta1/go_client"
Expand Down Expand Up @@ -99,7 +100,11 @@ func (s *PipelineUploadServer) UploadPipeline(w http.ResponseWriter, r *http.Req
return
}

err = s.canUploadVersionedPipeline(r, pipelineNamespace)
resourceAttributes := &authorizationv1.ResourceAttributes{
Namespace: pipelineNamespace,
Verb: common.RbacResourceVerbCreate,
}
err = s.canUploadVersionedPipeline(r, "", resourceAttributes)
if err != nil {
s.writeErrorToResponse(w, http.StatusBadRequest, util.Wrap(err, "Authorization to namespace failed."))
return
Expand Down Expand Up @@ -178,7 +183,11 @@ func (s *PipelineUploadServer) UploadPipelineVersion(w http.ResponseWriter, r *h
return
}

err = s.canUploadVersionedPipeline(r, namespace)
resourceAttributes := &authorizationv1.ResourceAttributes{
Namespace: namespace,
Verb: common.RbacResourceVerbCreate,
}
err = s.canUploadVersionedPipeline(r, pipelineId, resourceAttributes)
if err != nil {
s.writeErrorToResponse(w, http.StatusBadRequest, util.Wrap(err, "Authorization to namespace failed."))
return
Expand Down Expand Up @@ -221,19 +230,36 @@ func (s *PipelineUploadServer) UploadPipelineVersion(w http.ResponseWriter, r *h
}
}

func (s *PipelineUploadServer) canUploadVersionedPipeline(r *http.Request, namespace string) error {
if namespace == "" {
func (s *PipelineUploadServer) canUploadVersionedPipeline(r *http.Request, pipelineId string, resourceAttributes *authorizationv1.ResourceAttributes) error {
if !common.IsMultiUserMode() {
// Skip authorization if not multi-user mode.
return nil
}
userIdentityHeader := r.Header.Get(common.GetKubeflowUserIDHeader())
resourceAttributes := &authorizationv1.ResourceAttributes{
Namespace: namespace,
Verb: common.RbacResourceVerbCreate,
Group: common.RbacPipelinesGroup,
Version: common.RbacPipelinesVersion,
Resource: common.RbacResourceTypePipelines,
if len(pipelineId) > 0 {
namespace, err := s.resourceManager.GetNamespaceFromPipelineID(pipelineId)
if err != nil {
return util.Wrap(err, "Failed to authorize with the Pipeline ID.")
}
if len(resourceAttributes.Namespace) == 0 {
resourceAttributes.Namespace = namespace
}
}
if resourceAttributes.Namespace == "" {
return nil
}
err := s.resourceManager.IsRequestAuthorized(context.TODO(), userIdentityHeader, resourceAttributes)

resourceAttributes.Group = common.RbacPipelinesGroup
resourceAttributes.Version = common.RbacPipelinesVersion
resourceAttributes.Resource = common.RbacResourceTypePipelines

ctx := context.Background()
md := metadata.MD{}
for key, values := range r.Header {
md.Set(key, values...)
}
ctx = metadata.NewIncomingContext(ctx, md)

err := isAuthorized(s.resourceManager, ctx, resourceAttributes)
if err != nil {
return util.Wrap(err, "Authorization Failure.")
}
Expand Down

0 comments on commit 931c14a

Please sign in to comment.