mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
kubectl: add aggregation rule support to clusterrole
This commit is contained in:
parent
1b950d1e8e
commit
5e9e3afb2e
@ -3802,6 +3802,8 @@ run_clusterroles_tests() {
|
|||||||
kubectl create "${kube_flags[@]}" clusterrole url-reader --verb=get --non-resource-url=/logs/* --non-resource-url=/healthz/*
|
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.verbs}}{{.}}:{{end}}{{end}}" 'get:'
|
||||||
kube::test::get_object_assert clusterrole/url-reader "{{range.rules}}{{range.nonResourceURLs}}{{.}}:{{end}}{{end}}" '/logs/\*:/healthz/\*:'
|
kube::test::get_object_assert clusterrole/url-reader "{{range.rules}}{{range.nonResourceURLs}}{{.}}:{{end}}{{end}}" '/logs/\*:/healthz/\*:'
|
||||||
|
kubectl create "${kube_flags[@]}" clusterrole aggregation-reader --aggregation-rule="foo1=foo2"
|
||||||
|
kube::test::get_object_assert clusterrole/aggregation-reader "{{$id_field}}" 'aggregation-reader'
|
||||||
|
|
||||||
# test `kubectl create clusterrolebinding`
|
# test `kubectl create clusterrolebinding`
|
||||||
# test `kubectl set subject clusterrolebinding`
|
# test `kubectl set subject clusterrolebinding`
|
||||||
|
@ -45,6 +45,7 @@ go_library(
|
|||||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||||
|
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
|
||||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||||
"//vendor/k8s.io/client-go/kubernetes/typed/batch/v1:go_default_library",
|
"//vendor/k8s.io/client-go/kubernetes/typed/batch/v1:go_default_library",
|
||||||
"//vendor/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library",
|
"//vendor/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library",
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
|
|
||||||
rbacv1 "k8s.io/api/rbac/v1"
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
utilflag "k8s.io/apiserver/pkg/util/flag"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
@ -48,7 +49,10 @@ var (
|
|||||||
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
|
# Create a ClusterRole name "foo" with NonResourceURL specified
|
||||||
kubectl create clusterrole "foo" --verb=get --non-resource-url=/logs/*`))
|
kubectl create clusterrole "foo" --verb=get --non-resource-url=/logs/*
|
||||||
|
|
||||||
|
# Create a ClusterRole name "monitoring" with AggregationRule specified
|
||||||
|
kubectl create clusterrole monitoring --aggregation-rule="rbac.example.com/aggregate-to-monitoring=true"`))
|
||||||
|
|
||||||
// Valid nonResource verb list for validation.
|
// Valid nonResource verb list for validation.
|
||||||
validNonResourceVerbs = []string{"*", "get", "post", "put", "delete", "patch", "head", "options"}
|
validNonResourceVerbs = []string{"*", "get", "post", "put", "delete", "patch", "head", "options"}
|
||||||
@ -57,12 +61,14 @@ var (
|
|||||||
type CreateClusterRoleOptions struct {
|
type CreateClusterRoleOptions struct {
|
||||||
*CreateRoleOptions
|
*CreateRoleOptions
|
||||||
NonResourceURLs []string
|
NonResourceURLs []string
|
||||||
|
AggregationRule map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClusterRole is a command to ease creating ClusterRoles.
|
// ClusterRole is a command to ease creating ClusterRoles.
|
||||||
func NewCmdCreateClusterRole(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
func NewCmdCreateClusterRole(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||||
c := &CreateClusterRoleOptions{
|
c := &CreateClusterRoleOptions{
|
||||||
CreateRoleOptions: NewCreateRoleOptions(ioStreams),
|
CreateRoleOptions: NewCreateRoleOptions(ioStreams),
|
||||||
|
AggregationRule: map[string]string{},
|
||||||
}
|
}
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "clusterrole NAME --verb=verb --resource=resource.group [--resource-name=resourcename] [--dry-run]",
|
Use: "clusterrole NAME --verb=verb --resource=resource.group [--resource-name=resourcename] [--dry-run]",
|
||||||
@ -86,6 +92,7 @@ func NewCmdCreateClusterRole(f cmdutil.Factory, ioStreams genericclioptions.IOSt
|
|||||||
cmd.Flags().StringSliceVar(&c.NonResourceURLs, "non-resource-url", c.NonResourceURLs, "A partial url that user should have access to.")
|
cmd.Flags().StringSliceVar(&c.NonResourceURLs, "non-resource-url", c.NonResourceURLs, "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", c.ResourceNames, "Resource in the white list that the rule applies to, repeat this flag for multiple items")
|
cmd.Flags().StringArrayVar(&c.ResourceNames, "resource-name", c.ResourceNames, "Resource in the white list that the rule applies to, repeat this flag for multiple items")
|
||||||
|
cmd.Flags().Var(utilflag.NewMapStringString(&c.AggregationRule), "aggregation-rule", "An aggregation label selector for combining ClusterRoles.")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
@ -108,6 +115,13 @@ func (c *CreateClusterRoleOptions) Validate() error {
|
|||||||
return fmt.Errorf("name must be specified")
|
return fmt.Errorf("name must be specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(c.AggregationRule) > 0 {
|
||||||
|
if len(c.NonResourceURLs) > 0 || len(c.Verbs) > 0 || len(c.Resources) > 0 || len(c.ResourceNames) > 0 {
|
||||||
|
return fmt.Errorf("aggregation rule must be specified without nonResourceURLs, verbs, resources or resourceNames")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// validate verbs.
|
// validate verbs.
|
||||||
if len(c.Verbs) == 0 {
|
if len(c.Verbs) == 0 {
|
||||||
return fmt.Errorf("at least one verb must be specified")
|
return fmt.Errorf("at least one verb must be specified")
|
||||||
@ -162,11 +176,23 @@ func (c *CreateClusterRoleOptions) RunCreateRole() error {
|
|||||||
TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "ClusterRole"},
|
TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "ClusterRole"},
|
||||||
}
|
}
|
||||||
clusterRole.Name = c.Name
|
clusterRole.Name = c.Name
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if len(c.AggregationRule) == 0 {
|
||||||
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames, c.NonResourceURLs)
|
rules, err := generateResourcePolicyRules(c.Mapper, c.Verbs, c.Resources, c.ResourceNames, c.NonResourceURLs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
clusterRole.Rules = rules
|
clusterRole.Rules = rules
|
||||||
|
} else {
|
||||||
|
clusterRole.AggregationRule = &rbacv1.AggregationRule{
|
||||||
|
ClusterRoleSelectors: []metav1.LabelSelector{
|
||||||
|
{
|
||||||
|
MatchLabels: c.AggregationRule,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create ClusterRole.
|
// Create ClusterRole.
|
||||||
if !c.DryRun {
|
if !c.DryRun {
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
rbac "k8s.io/api/rbac/v1"
|
rbac "k8s.io/api/rbac/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/equality"
|
"k8s.io/apimachinery/pkg/api/equality"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
@ -47,6 +48,7 @@ func TestCreateClusterRole(t *testing.T) {
|
|||||||
resources string
|
resources string
|
||||||
nonResourceURL string
|
nonResourceURL string
|
||||||
resourceNames string
|
resourceNames string
|
||||||
|
aggregationRule string
|
||||||
expectedClusterRole *rbac.ClusterRole
|
expectedClusterRole *rbac.ClusterRole
|
||||||
}{
|
}{
|
||||||
"test-duplicate-resources": {
|
"test-duplicate-resources": {
|
||||||
@ -130,6 +132,25 @@ func TestCreateClusterRole(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"test-aggregation-rules": {
|
||||||
|
aggregationRule: "foo1=foo2,foo3=foo4",
|
||||||
|
expectedClusterRole: &rbac.ClusterRole{
|
||||||
|
TypeMeta: v1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||||
|
ObjectMeta: v1.ObjectMeta{
|
||||||
|
Name: clusterRoleName,
|
||||||
|
},
|
||||||
|
AggregationRule: &rbac.AggregationRule{
|
||||||
|
ClusterRoleSelectors: []metav1.LabelSelector{
|
||||||
|
{
|
||||||
|
MatchLabels: map[string]string{
|
||||||
|
"foo1": "foo2",
|
||||||
|
"foo3": "foo4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
@ -140,6 +161,7 @@ func TestCreateClusterRole(t *testing.T) {
|
|||||||
cmd.Flags().Set("verb", test.verbs)
|
cmd.Flags().Set("verb", test.verbs)
|
||||||
cmd.Flags().Set("resource", test.resources)
|
cmd.Flags().Set("resource", test.resources)
|
||||||
cmd.Flags().Set("non-resource-url", test.nonResourceURL)
|
cmd.Flags().Set("non-resource-url", test.nonResourceURL)
|
||||||
|
cmd.Flags().Set("aggregation-rule", test.aggregationRule)
|
||||||
if test.resourceNames != "" {
|
if test.resourceNames != "" {
|
||||||
cmd.Flags().Set("resource-name", test.resourceNames)
|
cmd.Flags().Set("resource-name", test.resourceNames)
|
||||||
}
|
}
|
||||||
@ -433,6 +455,50 @@ func TestClusterRoleValidate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
|
"test-aggregation-rule-with-verb": {
|
||||||
|
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||||
|
CreateRoleOptions: &CreateRoleOptions{
|
||||||
|
Name: "my-clusterrole",
|
||||||
|
Verbs: []string{"get"},
|
||||||
|
},
|
||||||
|
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||||
|
},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
"test-aggregation-rule-with-resource": {
|
||||||
|
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||||
|
CreateRoleOptions: &CreateRoleOptions{
|
||||||
|
Name: "my-clusterrole",
|
||||||
|
Resources: []ResourceOptions{
|
||||||
|
{
|
||||||
|
Resource: "replicasets",
|
||||||
|
SubResource: "scale",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||||
|
},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
"test-aggregation-rule-with-no-resource-url": {
|
||||||
|
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||||
|
CreateRoleOptions: &CreateRoleOptions{
|
||||||
|
Name: "my-clusterrole",
|
||||||
|
},
|
||||||
|
NonResourceURLs: []string{"/logs/"},
|
||||||
|
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||||
|
},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
"test-aggregation-rule": {
|
||||||
|
clusterRoleOptions: &CreateClusterRoleOptions{
|
||||||
|
CreateRoleOptions: &CreateRoleOptions{
|
||||||
|
Name: "my-clusterrole",
|
||||||
|
},
|
||||||
|
AggregationRule: map[string]string{"foo-key": "foo-vlue"},
|
||||||
|
},
|
||||||
|
expectErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
|
Loading…
Reference in New Issue
Block a user