diff --git a/pkg/kubectl/cmd/auth/BUILD b/pkg/kubectl/cmd/auth/BUILD index 62bdd0995d4..ee161a7aef8 100644 --- a/pkg/kubectl/cmd/auth/BUILD +++ b/pkg/kubectl/cmd/auth/BUILD @@ -24,7 +24,6 @@ go_library( "//vendor/github.com/spf13/cobra:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", ], ) diff --git a/pkg/kubectl/cmd/auth/cani.go b/pkg/kubectl/cmd/auth/cani.go index 89f7c5de28a..5e4b84c80cc 100644 --- a/pkg/kubectl/cmd/auth/cani.go +++ b/pkg/kubectl/cmd/auth/cani.go @@ -28,7 +28,6 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" - utilerrors "k8s.io/apimachinery/pkg/util/errors" authorizationapi "k8s.io/kubernetes/pkg/apis/authorization" internalauthorizationclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/authorization/internalversion" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" @@ -43,10 +42,11 @@ type CanIOptions struct { Namespace string SelfSARClient internalauthorizationclient.SelfSubjectAccessReviewsGetter - Verb string - Resource schema.GroupVersionResource - Subresource string - ResourceName string + Verb string + Resource schema.GroupVersionResource + NonResourceURL string + Subresource string + ResourceName string Out io.Writer Err io.Writer @@ -57,7 +57,8 @@ var ( Check whether an action is allowed. VERB is a logical Kubernetes API verb like 'get', 'list', 'watch', 'delete', etc. - TYPE is a Kubernetes resource. Shortcuts and groups will be resolved. + TYPE is a Kubernetes resource. Shortcuts and groups will be resolved. + NONRESOURCEURL is a partial URL starts with "/". NAME is the name of a particular Kubernetes resource.`) canIExample = templates.Examples(` @@ -73,8 +74,11 @@ var ( # Check to see if I can get the job named "bar" in namespace "foo" kubectl auth can-i list jobs.batch/bar -n foo - # check to see if I can read pod logs - kubectl auth can-i get pods --subresource=log`) + # Check to see if I can read pod logs + kubectl auth can-i get pods --subresource=log + + # Check to see if I can access the URL /logs/ + kubectl auth can-i get /logs/`) ) func NewCmdCanI(f cmdutil.Factory, out, err io.Writer) *cobra.Command { @@ -84,7 +88,7 @@ func NewCmdCanI(f cmdutil.Factory, out, err io.Writer) *cobra.Command { } cmd := &cobra.Command{ - Use: "can-i VERB [TYPE | TYPE/NAME]", + Use: "can-i VERB [TYPE | TYPE/NAME | NONRESOURCEURL]", Short: "Check whether an action is allowed", Long: canILong, Example: canIExample, @@ -116,9 +120,13 @@ func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error { switch len(args) { case 2: + o.Verb = args[0] + if strings.HasPrefix(args[1], "/") { + o.NonResourceURL = args[1] + break + } resourceTokens := strings.SplitN(args[1], "/", 2) restMapper, _ := f.Object() - o.Verb = args[0] o.Resource = o.resourceFor(restMapper, resourceTokens[0]) if len(resourceTokens) > 1 { o.ResourceName = resourceTokens[1] @@ -146,22 +154,42 @@ func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error { } func (o *CanIOptions) Validate() error { - errors := []error{} - return utilerrors.NewAggregate(errors) + if o.NonResourceURL != "" { + if o.Subresource != "" { + return fmt.Errorf("--subresource can not be used with nonResourceURL") + } + if o.Resource != (schema.GroupVersionResource{}) || o.ResourceName != "" { + return fmt.Errorf("nonResourceURL and Resource can not specified together") + } + } + return nil } func (o *CanIOptions) RunAccessCheck() (bool, error) { - sar := &authorizationapi.SelfSubjectAccessReview{ - Spec: authorizationapi.SelfSubjectAccessReviewSpec{ - ResourceAttributes: &authorizationapi.ResourceAttributes{ - Namespace: o.Namespace, - Verb: o.Verb, - Group: o.Resource.Group, - Resource: o.Resource.Resource, - Subresource: o.Subresource, - Name: o.ResourceName, + var sar *authorizationapi.SelfSubjectAccessReview + if o.NonResourceURL == "" { + sar = &authorizationapi.SelfSubjectAccessReview{ + Spec: authorizationapi.SelfSubjectAccessReviewSpec{ + ResourceAttributes: &authorizationapi.ResourceAttributes{ + Namespace: o.Namespace, + Verb: o.Verb, + Group: o.Resource.Group, + Resource: o.Resource.Resource, + Subresource: o.Subresource, + Name: o.ResourceName, + }, }, - }, + } + } else { + sar = &authorizationapi.SelfSubjectAccessReview{ + Spec: authorizationapi.SelfSubjectAccessReviewSpec{ + NonResourceAttributes: &authorizationapi.NonResourceAttributes{ + Verb: o.Verb, + Path: o.NonResourceURL, + }, + }, + } + } response, err := o.SelfSARClient.SelfSubjectAccessReviews().Create(sar) diff --git a/pkg/kubectl/cmd/auth/cani_test.go b/pkg/kubectl/cmd/auth/cani_test.go index 52940efd077..522361d30d5 100644 --- a/pkg/kubectl/cmd/auth/cani_test.go +++ b/pkg/kubectl/cmd/auth/cani_test.go @@ -104,6 +104,15 @@ func TestRunAccessCheck(t *testing.T) { `{"resourceAttributes":{"verb":"get","resource":"pods","subresource":"log"}}`, }, }, + { + name: "nonResourceURL", + o: &CanIOptions{}, + args: []string{"get", "/logs"}, + allowed: true, + expectedBodyStrings: []string{ + `{"nonResourceAttributes":{"path":"/logs","verb":"get"}}`, + }, + }, } for _, test := range tests {