mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 07:20:13 +00:00
support NonResourceURL for kubectl create clusterrole
This commit is contained in:
parent
749ac27e9a
commit
93e50b167e
@ -3125,6 +3125,9 @@ runTests() {
|
|||||||
kube::test::get_object_assert clusterrole/resourcename-reader "{{range.rules}}{{range.resources}}{{.}}:{{end}}{{end}}" 'pods:'
|
kube::test::get_object_assert clusterrole/resourcename-reader "{{range.rules}}{{range.resources}}{{.}}:{{end}}{{end}}" 'pods:'
|
||||||
kube::test::get_object_assert clusterrole/resourcename-reader "{{range.rules}}{{range.apiGroups}}{{.}}:{{end}}{{end}}" ':'
|
kube::test::get_object_assert clusterrole/resourcename-reader "{{range.rules}}{{range.apiGroups}}{{.}}:{{end}}{{end}}" ':'
|
||||||
kube::test::get_object_assert clusterrole/resourcename-reader "{{range.rules}}{{range.resourceNames}}{{.}}:{{end}}{{end}}" 'foo:'
|
kube::test::get_object_assert clusterrole/resourcename-reader "{{range.rules}}{{range.resourceNames}}{{.}}:{{end}}{{end}}" 'foo:'
|
||||||
|
kubectl create "${kube_flags[@]}" clusterrole url-reader --verb=get --non-resource-url=/logs/* --non-resource-url=/healthz/*
|
||||||
|
kube::test::get_object_assert clusterrole/url-reader "{{range.rules}}{{range.verbs}}{{.}}:{{end}}{{end}}" 'get:'
|
||||||
|
kube::test::get_object_assert clusterrole/url-reader "{{range.rules}}{{range.nonResourceURLs}}{{.}}:{{end}}{{end}}" '/logs/\*:/healthz/\*:'
|
||||||
|
|
||||||
# test `kubectl create rolebinding/clusterrolebinding`
|
# test `kubectl create rolebinding/clusterrolebinding`
|
||||||
# test `kubectl set subject rolebinding/clusterrolebinding`
|
# test `kubectl set subject rolebinding/clusterrolebinding`
|
||||||
|
@ -508,6 +508,7 @@ node-sync-period
|
|||||||
no-headers
|
no-headers
|
||||||
no-headers
|
no-headers
|
||||||
non-masquerade-cidr
|
non-masquerade-cidr
|
||||||
|
non-resource-url
|
||||||
no-suggestions
|
no-suggestions
|
||||||
no-suggestions
|
no-suggestions
|
||||||
num-nodes
|
num-nodes
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -42,11 +43,18 @@ var (
|
|||||||
kubectl create clusterrole foo --verb=get,list,watch --resource=rs.extensions
|
kubectl create clusterrole foo --verb=get,list,watch --resource=rs.extensions
|
||||||
|
|
||||||
# Create a ClusterRole named "foo" with SubResource specified
|
# Create a ClusterRole named "foo" with SubResource specified
|
||||||
kubectl create clusterrole foo --verb=get,list,watch --resource=pods,pods/status`))
|
kubectl create clusterrole foo --verb=get,list,watch --resource=pods,pods/status
|
||||||
|
|
||||||
|
# Create a ClusterRole name "foo" with NonResourceURL specified
|
||||||
|
kubectl create clusterrole "foo" --verb=get --non-resource-url=/logs/*`))
|
||||||
|
|
||||||
|
// Valid nonResource verb list for validation.
|
||||||
|
validNonResourceVerbs = []string{"*", "get", "post", "put", "delete", "patch", "head", "options"}
|
||||||
)
|
)
|
||||||
|
|
||||||
type CreateClusterRoleOptions struct {
|
type CreateClusterRoleOptions struct {
|
||||||
*CreateRoleOptions
|
*CreateRoleOptions
|
||||||
|
NonResourceURLs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClusterRole is a command to ease creating ClusterRoles.
|
// ClusterRole is a command to ease creating ClusterRoles.
|
||||||
@ -72,16 +80,69 @@ func NewCmdCreateClusterRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command
|
|||||||
cmdutil.AddPrinterFlags(cmd)
|
cmdutil.AddPrinterFlags(cmd)
|
||||||
cmdutil.AddDryRunFlag(cmd)
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
cmd.Flags().StringSliceVar(&c.Verbs, "verb", []string{}, "verb that applies to the resources contained in the rule")
|
cmd.Flags().StringSliceVar(&c.Verbs, "verb", []string{}, "verb that applies to the resources contained in the rule")
|
||||||
|
cmd.Flags().StringSliceVar(&c.NonResourceURLs, "non-resource-url", []string{}, "a partial url that user should have access to.")
|
||||||
cmd.Flags().StringSlice("resource", []string{}, "resource that the rule applies to")
|
cmd.Flags().StringSlice("resource", []string{}, "resource that the rule applies to")
|
||||||
cmd.Flags().StringArrayVar(&c.ResourceNames, "resource-name", []string{}, "resource in the white list that the rule applies to, repeat this flag for multiple items")
|
cmd.Flags().StringArrayVar(&c.ResourceNames, "resource-name", []string{}, "resource in the white list that the rule applies to, repeat this flag for multiple items")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CreateClusterRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||||
|
// Remove duplicate nonResourceURLs
|
||||||
|
nonResourceURLs := []string{}
|
||||||
|
for _, n := range c.NonResourceURLs {
|
||||||
|
if !arrayContains(nonResourceURLs, n) {
|
||||||
|
nonResourceURLs = append(nonResourceURLs, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.NonResourceURLs = nonResourceURLs
|
||||||
|
|
||||||
|
return c.CreateRoleOptions.Complete(f, cmd, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CreateClusterRoleOptions) Validate() error {
|
||||||
|
if c.Name == "" {
|
||||||
|
return fmt.Errorf("name must be specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate verbs.
|
||||||
|
if len(c.Verbs) == 0 {
|
||||||
|
return fmt.Errorf("at least one verb must be specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.Resources) == 0 && len(c.NonResourceURLs) == 0 {
|
||||||
|
return fmt.Errorf("one of resource or nonResourceURL must be specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate resources
|
||||||
|
if len(c.Resources) > 0 {
|
||||||
|
for _, v := range c.Verbs {
|
||||||
|
if !arrayContains(validResourceVerbs, v) {
|
||||||
|
return fmt.Errorf("invalid verb: '%s'", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := c.validateResource(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//validate non-resource-url
|
||||||
|
if len(c.NonResourceURLs) > 0 {
|
||||||
|
for _, v := range c.Verbs {
|
||||||
|
if !arrayContains(validNonResourceVerbs, v) {
|
||||||
|
return fmt.Errorf("invalid verb: '%s' for nonResourceURL", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (c *CreateClusterRoleOptions) RunCreateRole() error {
|
func (c *CreateClusterRoleOptions) RunCreateRole() error {
|
||||||
clusterRole := &rbac.ClusterRole{}
|
clusterRole := &rbac.ClusterRole{}
|
||||||
clusterRole.Name = c.Name
|
clusterRole.Name = c.Name
|
||||||
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames)
|
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames, c.NonResourceURLs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -232,6 +232,10 @@ func (c *CreateRoleOptions) Validate() error {
|
|||||||
return fmt.Errorf("at least one resource must be specified")
|
return fmt.Errorf("at least one resource must be specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return c.validateResource()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CreateRoleOptions) validateResource() error {
|
||||||
for _, r := range c.Resources {
|
for _, r := range c.Resources {
|
||||||
if len(r.Resource) == 0 {
|
if len(r.Resource) == 0 {
|
||||||
return fmt.Errorf("resource must be specified if apiGroup/subresource specified")
|
return fmt.Errorf("resource must be specified if apiGroup/subresource specified")
|
||||||
@ -263,14 +267,13 @@ func (c *CreateRoleOptions) Validate() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CreateRoleOptions) RunCreateRole() error {
|
func (c *CreateRoleOptions) RunCreateRole() error {
|
||||||
role := &rbac.Role{}
|
role := &rbac.Role{}
|
||||||
role.Name = c.Name
|
role.Name = c.Name
|
||||||
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames)
|
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames, []string{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -301,7 +304,7 @@ func arrayContains(s []string, e string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateResourcePolicyRules(mapper meta.RESTMapper, verbs []string, resources []ResourceOptions, resourceNames []string) ([]rbac.PolicyRule, error) {
|
func generateResourcePolicyRules(mapper meta.RESTMapper, verbs []string, resources []ResourceOptions, resourceNames []string, nonResourceURLs []string) ([]rbac.PolicyRule, error) {
|
||||||
// groupResourceMapping is a apigroup-resource map. The key of this map is api group, while the value
|
// groupResourceMapping is a apigroup-resource map. The key of this map is api group, while the value
|
||||||
// is a string array of resources under this api group.
|
// is a string array of resources under this api group.
|
||||||
// E.g. groupResourceMapping = {"extensions": ["replicasets", "deployments"], "batch":["jobs"]}
|
// E.g. groupResourceMapping = {"extensions": ["replicasets", "deployments"], "batch":["jobs"]}
|
||||||
@ -337,5 +340,12 @@ func generateResourcePolicyRules(mapper meta.RESTMapper, verbs []string, resourc
|
|||||||
rules = append(rules, rule)
|
rules = append(rules, rule)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(nonResourceURLs) > 0 {
|
||||||
|
rule := rbac.PolicyRule{}
|
||||||
|
rule.Verbs = verbs
|
||||||
|
rule.NonResourceURLs = nonResourceURLs
|
||||||
|
rules = append(rules, rule)
|
||||||
|
}
|
||||||
|
|
||||||
return rules, nil
|
return rules, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user