diff --git a/pkg/kubectl/cmd/create_role.go b/pkg/kubectl/cmd/create_role.go index 151122c98fc..cd8d0ef5e33 100644 --- a/pkg/kubectl/cmd/create_role.go +++ b/pkg/kubectl/cmd/create_role.go @@ -53,6 +53,40 @@ var ( // Valid resource verb list for validation. validResourceVerbs = []string{"*", "get", "delete", "list", "create", "update", "patch", "watch", "proxy", "redirect", "deletecollection", "use", "bind", "impersonate"} + + // Specialized verbs and GroupResources + specialVerbs = map[string][]schema.GroupResource{ + "use": { + { + Group: "extensions", + Resource: "podsecuritypolicies", + }, + }, + "bind": { + { + Group: "rbac.authorization.k8s.io", + Resource: "roles", + }, + { + Group: "rbac.authorization.k8s.io", + Resource: "clusterroles", + }, + }, + "impersonate": { + { + Group: "", + Resource: "users", + }, + { + Group: "", + Resource: "groups", + }, + { + Group: "authentication.k8s.io", + Resource: "userextras", + }, + }, + } ) type ResourceOptions struct { @@ -202,7 +236,30 @@ func (c *CreateRoleOptions) Validate() error { if len(r.Resource) == 0 { return fmt.Errorf("resource must be specified if apiGroup/subresource specified") } - if _, err := c.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}); err != nil { + + resource := schema.GroupVersionResource{Resource: r.Resource, Group: r.Group} + groupVersionResource, err := c.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}) + if err == nil { + resource = groupVersionResource + } + + for _, v := range c.Verbs { + if groupResources, ok := specialVerbs[v]; ok { + match := false + for _, extra := range groupResources { + if resource.Resource == extra.Resource && resource.Group == extra.Group { + match = true + err = nil + break + } + } + if !match { + return fmt.Errorf("can not perform '%s' on '%s' in group '%s'", v, resource.Resource, resource.Group) + } + } + } + + if err != nil { return err } } @@ -255,10 +312,12 @@ func generateResourcePolicyRules(mapper meta.RESTMapper, verbs []string, resourc // 2. Prevents pointing to non-existent resources. // 3. Transfers resource short name to long name. E.g. rs.extensions is transferred to replicasets.extensions for _, r := range resources { - resource, err := mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}) - if err != nil { - return []rbac.PolicyRule{}, err + resource := schema.GroupVersionResource{Resource: r.Resource, Group: r.Group} + groupVersionResource, err := mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}) + if err == nil { + resource = groupVersionResource } + if len(r.SubResource) > 0 { resource.Resource = resource.Resource + "/" + r.SubResource } diff --git a/pkg/kubectl/cmd/create_role_test.go b/pkg/kubectl/cmd/create_role_test.go index c57e6d232ea..a15ef075cc4 100644 --- a/pkg/kubectl/cmd/create_role_test.go +++ b/pkg/kubectl/cmd/create_role_test.go @@ -229,6 +229,45 @@ func TestValidate(t *testing.T) { }, expectErr: true, }, + "test-special-verb": { + roleOptions: &CreateRoleOptions{ + Name: "my-role", + Verbs: []string{"use"}, + Resources: []ResourceOptions{ + { + Resource: "pods", + }, + }, + }, + expectErr: true, + }, + "test-mix-verbs": { + roleOptions: &CreateRoleOptions{ + Name: "my-role", + Verbs: []string{"impersonate", "use"}, + Resources: []ResourceOptions{ + { + Resource: "userextras", + SubResource: "scopes", + }, + }, + }, + expectErr: true, + }, + "test-special-verb-with-wrong-apigroup": { + roleOptions: &CreateRoleOptions{ + Name: "my-role", + Verbs: []string{"impersonate"}, + Resources: []ResourceOptions{ + { + Resource: "userextras", + SubResource: "scopes", + Group: "extensions", + }, + }, + }, + expectErr: true, + }, "test-invalid-resource": { roleOptions: &CreateRoleOptions{ Name: "my-role", @@ -286,6 +325,20 @@ func TestValidate(t *testing.T) { }, expectErr: false, }, + "test-valid-case-with-additional-resource": { + roleOptions: &CreateRoleOptions{ + Name: "my-role", + Verbs: []string{"impersonate"}, + Resources: []ResourceOptions{ + { + Resource: "userextras", + SubResource: "scopes", + Group: "authentication.k8s.io", + }, + }, + }, + expectErr: false, + }, } for name, test := range tests {