diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go index 815f3787c7..0b85a76dcb 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go @@ -28,6 +28,7 @@ import ( ) var ( + Write = []string{"create", "update", "patch", "delete", "deletecollection"} ReadWrite = []string{"get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"} Read = []string{"get", "list", "watch"} ReadUpdate = []string{"get", "list", "watch", "update", "patch"} @@ -203,59 +204,36 @@ func ClusterRoles() []rbacv1.ClusterRole { // a role for a namespace level admin. It is `edit` plus the power to grant permissions to other users. ObjectMeta: metav1.ObjectMeta{Name: "admin"}, AggregationRule: &rbacv1.AggregationRule{ - ClusterRoleSelectors: []metav1.LabelSelector{{MatchLabels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-admin": "true"}}}, + ClusterRoleSelectors: []metav1.LabelSelector{ + {MatchLabels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-admin": "true"}}, + }, }, }, { // a role for a namespace level editor. It grants access to all user level actions in a namespace. // It does not grant powers for "privileged" resources which are domain of the system: `/status` // subresources or `quota`/`limits` which are used to control namespaces - ObjectMeta: metav1.ObjectMeta{Name: "edit"}, + ObjectMeta: metav1.ObjectMeta{Name: "edit", Labels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-admin": "true"}}, AggregationRule: &rbacv1.AggregationRule{ - ClusterRoleSelectors: []metav1.LabelSelector{{MatchLabels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-edit": "true"}}}, + ClusterRoleSelectors: []metav1.LabelSelector{ + {MatchLabels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-edit": "true"}}, + }, }, }, { // a role for namespace level viewing. It grants Read-only access to non-escalating resources in // a namespace. - ObjectMeta: metav1.ObjectMeta{Name: "view"}, + ObjectMeta: metav1.ObjectMeta{Name: "view", Labels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-edit": "true"}}, AggregationRule: &rbacv1.AggregationRule{ - ClusterRoleSelectors: []metav1.LabelSelector{{MatchLabels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-view": "true"}}}, + ClusterRoleSelectors: []metav1.LabelSelector{ + {MatchLabels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-view": "true"}}, + }, }, }, { // a role for a namespace level admin. It is `edit` plus the power to grant permissions to other users. ObjectMeta: metav1.ObjectMeta{Name: "system:aggregate-to-admin", Labels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-admin": "true"}}, Rules: []rbacv1.PolicyRule{ - rbacv1helpers.NewRule(ReadWrite...).Groups(legacyGroup).Resources("pods", "pods/attach", "pods/proxy", "pods/exec", "pods/portforward").RuleOrDie(), - rbacv1helpers.NewRule(ReadWrite...).Groups(legacyGroup).Resources("replicationcontrollers", "replicationcontrollers/scale", "serviceaccounts", - "services", "services/proxy", "endpoints", "persistentvolumeclaims", "configmaps", "secrets").RuleOrDie(), - rbacv1helpers.NewRule(Read...).Groups(legacyGroup).Resources("limitranges", "resourcequotas", "bindings", "events", - "pods/status", "resourcequotas/status", "namespaces/status", "replicationcontrollers/status", "pods/log").RuleOrDie(), - // read access to namespaces at the namespace scope means you can read *this* namespace. This can be used as an - // indicator of which namespaces you have access to. - rbacv1helpers.NewRule(Read...).Groups(legacyGroup).Resources("namespaces").RuleOrDie(), - rbacv1helpers.NewRule("impersonate").Groups(legacyGroup).Resources("serviceaccounts").RuleOrDie(), - - rbacv1helpers.NewRule(ReadWrite...).Groups(appsGroup).Resources( - "statefulsets", "statefulsets/scale", - "daemonsets", - "deployments", "deployments/scale", "deployments/rollback", - "replicasets", "replicasets/scale").RuleOrDie(), - - rbacv1helpers.NewRule(ReadWrite...).Groups(autoscalingGroup).Resources("horizontalpodautoscalers").RuleOrDie(), - - rbacv1helpers.NewRule(ReadWrite...).Groups(batchGroup).Resources("jobs", "cronjobs").RuleOrDie(), - - rbacv1helpers.NewRule(ReadWrite...).Groups(extensionsGroup).Resources("daemonsets", - "deployments", "deployments/scale", "deployments/rollback", "ingresses", - "replicasets", "replicasets/scale", "replicationcontrollers/scale", - "networkpolicies").RuleOrDie(), - - rbacv1helpers.NewRule(ReadWrite...).Groups(policyGroup).Resources("poddisruptionbudgets").RuleOrDie(), - - rbacv1helpers.NewRule(ReadWrite...).Groups(networkingGroup).Resources("networkpolicies").RuleOrDie(), - // additional admin powers rbacv1helpers.NewRule("create").Groups(authorizationGroup).Resources("localsubjectaccessreviews").RuleOrDie(), rbacv1helpers.NewRule(ReadWrite...).Groups(rbacGroup).Resources("roles", "rolebindings").RuleOrDie(), @@ -267,34 +245,32 @@ func ClusterRoles() []rbacv1.ClusterRole { // subresources or `quota`/`limits` which are used to control namespaces ObjectMeta: metav1.ObjectMeta{Name: "system:aggregate-to-edit", Labels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-edit": "true"}}, Rules: []rbacv1.PolicyRule{ - rbacv1helpers.NewRule(ReadWrite...).Groups(legacyGroup).Resources("pods", "pods/attach", "pods/proxy", "pods/exec", "pods/portforward").RuleOrDie(), - rbacv1helpers.NewRule(ReadWrite...).Groups(legacyGroup).Resources("replicationcontrollers", "replicationcontrollers/scale", "serviceaccounts", - "services", "services/proxy", "endpoints", "persistentvolumeclaims", "configmaps", "secrets").RuleOrDie(), - rbacv1helpers.NewRule(Read...).Groups(legacyGroup).Resources("limitranges", "resourcequotas", "bindings", "events", - "pods/status", "resourcequotas/status", "namespaces/status", "replicationcontrollers/status", "pods/log").RuleOrDie(), - // read access to namespaces at the namespace scope means you can read *this* namespace. This can be used as an - // indicator of which namespaces you have access to. - rbacv1helpers.NewRule(Read...).Groups(legacyGroup).Resources("namespaces").RuleOrDie(), + // Allow read on escalating resources + rbacv1helpers.NewRule(Read...).Groups(legacyGroup).Resources("pods/attach", "pods/proxy", "pods/exec", "pods/portforward", "secrets", "services/proxy").RuleOrDie(), rbacv1helpers.NewRule("impersonate").Groups(legacyGroup).Resources("serviceaccounts").RuleOrDie(), - rbacv1helpers.NewRule(ReadWrite...).Groups(appsGroup).Resources( + rbacv1helpers.NewRule(Write...).Groups(legacyGroup).Resources("pods", "pods/attach", "pods/proxy", "pods/exec", "pods/portforward").RuleOrDie(), + rbacv1helpers.NewRule(Write...).Groups(legacyGroup).Resources("replicationcontrollers", "replicationcontrollers/scale", "serviceaccounts", + "services", "services/proxy", "endpoints", "persistentvolumeclaims", "configmaps", "secrets").RuleOrDie(), + + rbacv1helpers.NewRule(Write...).Groups(appsGroup).Resources( "statefulsets", "statefulsets/scale", "daemonsets", "deployments", "deployments/scale", "deployments/rollback", "replicasets", "replicasets/scale").RuleOrDie(), - rbacv1helpers.NewRule(ReadWrite...).Groups(autoscalingGroup).Resources("horizontalpodautoscalers").RuleOrDie(), + rbacv1helpers.NewRule(Write...).Groups(autoscalingGroup).Resources("horizontalpodautoscalers").RuleOrDie(), - rbacv1helpers.NewRule(ReadWrite...).Groups(batchGroup).Resources("jobs", "cronjobs").RuleOrDie(), + rbacv1helpers.NewRule(Write...).Groups(batchGroup).Resources("jobs", "cronjobs").RuleOrDie(), - rbacv1helpers.NewRule(ReadWrite...).Groups(extensionsGroup).Resources("daemonsets", + rbacv1helpers.NewRule(Write...).Groups(extensionsGroup).Resources("daemonsets", "deployments", "deployments/scale", "deployments/rollback", "ingresses", "replicasets", "replicasets/scale", "replicationcontrollers/scale", "networkpolicies").RuleOrDie(), - rbacv1helpers.NewRule(ReadWrite...).Groups(policyGroup).Resources("poddisruptionbudgets").RuleOrDie(), + rbacv1helpers.NewRule(Write...).Groups(policyGroup).Resources("poddisruptionbudgets").RuleOrDie(), - rbacv1helpers.NewRule(ReadWrite...).Groups(networkingGroup).Resources("networkpolicies").RuleOrDie(), + rbacv1helpers.NewRule(Write...).Groups(networkingGroup).Resources("networkpolicies").RuleOrDie(), }, }, { diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy_test.go b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy_test.go index 1b024c4414..20ba3b3c0b 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy_test.go +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy_test.go @@ -64,49 +64,6 @@ func getSemanticRoles(roles []rbacv1.ClusterRole) semanticRoles { return ret } -// Some roles should always cover others -func TestCovers(t *testing.T) { - semanticRoles := getSemanticRoles(bootstrappolicy.ClusterRoles()) - - if covers, miss := rbacregistryvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.edit.Rules); !covers { - t.Errorf("failed to cover: %#v", miss) - } - if covers, miss := rbacregistryvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.view.Rules); !covers { - t.Errorf("failed to cover: %#v", miss) - } - if covers, miss := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.view.Rules); !covers { - t.Errorf("failed to cover: %#v", miss) - } -} - -// additionalAdminPowers is the list of powers that we expect to be different than the editor role. -// one resource per rule to make the "does not already contain" check easy -var additionalAdminPowers = []rbacv1.PolicyRule{ - rbacv1helpers.NewRule("create").Groups("authorization.k8s.io").Resources("localsubjectaccessreviews").RuleOrDie(), - rbacv1helpers.NewRule(bootstrappolicy.ReadWrite...).Groups("rbac.authorization.k8s.io").Resources("rolebindings").RuleOrDie(), - rbacv1helpers.NewRule(bootstrappolicy.ReadWrite...).Groups("rbac.authorization.k8s.io").Resources("roles").RuleOrDie(), -} - -func TestAdminEditRelationship(t *testing.T) { - semanticRoles := getSemanticRoles(bootstrappolicy.ClusterRoles()) - - // confirm that the edit role doesn't already have extra powers - for _, rule := range additionalAdminPowers { - if covers, _ := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, []rbacv1.PolicyRule{rule}); covers { - t.Errorf("edit has extra powers: %#v", rule) - } - } - semanticRoles.edit.Rules = append(semanticRoles.edit.Rules, additionalAdminPowers...) - - // at this point, we should have a two way covers relationship - if covers, miss := rbacregistryvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.edit.Rules); !covers { - t.Errorf("admin has lost rules for: %#v", miss) - } - if covers, miss := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.admin.Rules); !covers { - t.Errorf("edit is missing rules for: %#v\nIf these should only be admin powers, add them to the list. Otherwise, add them to the edit role.", miss) - } -} - // viewEscalatingNamespaceResources is the list of rules that would allow privilege escalation attacks based on // ability to view (GET) them var viewEscalatingNamespaceResources = []rbacv1.PolicyRule{ @@ -156,14 +113,6 @@ func TestEditViewRelationship(t *testing.T) { } } semanticRoles.view.Rules = append(semanticRoles.view.Rules, ungettableResources...) - - // at this point, we should have a two way covers relationship - if covers, miss := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.view.Rules); !covers { - t.Errorf("edit has lost rules for: %#v", miss) - } - if covers, miss := rbacregistryvalidation.Covers(semanticRoles.view.Rules, semanticRoles.edit.Rules); !covers { - t.Errorf("view is missing rules for: %#v\nIf these are escalating powers, add them to the list. Otherwise, add them to the view role.", miss) - } } func TestBootstrapNamespaceRoles(t *testing.T) { diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml index 0aee48909f..4f3d010fe4 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml @@ -46,6 +46,7 @@ items: creationTimestamp: null labels: kubernetes.io/bootstrapping: rbac-defaults + rbac.authorization.k8s.io/aggregate-to-admin: "true" name: edit rules: null - apiVersion: rbac.authorization.k8s.io/v1 @@ -59,168 +60,6 @@ items: rbac.authorization.k8s.io/aggregate-to-admin: "true" name: system:aggregate-to-admin rules: - - apiGroups: - - "" - resources: - - pods - - pods/attach - - pods/exec - - pods/portforward - - pods/proxy - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - configmaps - - endpoints - - persistentvolumeclaims - - replicationcontrollers - - replicationcontrollers/scale - - secrets - - serviceaccounts - - services - - services/proxy - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - bindings - - events - - limitranges - - namespaces/status - - pods/log - - pods/status - - replicationcontrollers/status - - resourcequotas - - resourcequotas/status - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - namespaces - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - impersonate - - apiGroups: - - apps - resources: - - daemonsets - - deployments - - deployments/rollback - - deployments/scale - - replicasets - - replicasets/scale - - statefulsets - - statefulsets/scale - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - autoscaling - resources: - - horizontalpodautoscalers - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - batch - resources: - - cronjobs - - jobs - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - extensions - resources: - - daemonsets - - deployments - - deployments/rollback - - deployments/scale - - ingresses - - networkpolicies - - replicasets - - replicasets/scale - - replicationcontrollers/scale - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - policy - resources: - - poddisruptionbudgets - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - - apiGroups: - - networking.k8s.io - resources: - - networkpolicies - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch - apiGroups: - authorization.k8s.io resources: @@ -252,6 +91,25 @@ items: rbac.authorization.k8s.io/aggregate-to-edit: "true" name: system:aggregate-to-edit rules: + - apiGroups: + - "" + resources: + - pods/attach + - pods/exec + - pods/portforward + - pods/proxy + - secrets + - services/proxy + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - impersonate - apiGroups: - "" resources: @@ -264,11 +122,8 @@ items: - create - delete - deletecollection - - get - - list - patch - update - - watch - apiGroups: - "" resources: @@ -285,41 +140,8 @@ items: - create - delete - deletecollection - - get - - list - patch - update - - watch - - apiGroups: - - "" - resources: - - bindings - - events - - limitranges - - namespaces/status - - pods/log - - pods/status - - replicationcontrollers/status - - resourcequotas - - resourcequotas/status - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - namespaces - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - impersonate - apiGroups: - apps resources: @@ -335,11 +157,8 @@ items: - create - delete - deletecollection - - get - - list - patch - update - - watch - apiGroups: - autoscaling resources: @@ -348,11 +167,8 @@ items: - create - delete - deletecollection - - get - - list - patch - update - - watch - apiGroups: - batch resources: @@ -362,11 +178,8 @@ items: - create - delete - deletecollection - - get - - list - patch - update - - watch - apiGroups: - extensions resources: @@ -383,11 +196,8 @@ items: - create - delete - deletecollection - - get - - list - patch - update - - watch - apiGroups: - policy resources: @@ -396,11 +206,8 @@ items: - create - delete - deletecollection - - get - - list - patch - update - - watch - apiGroups: - networking.k8s.io resources: @@ -409,11 +216,8 @@ items: - create - delete - deletecollection - - get - - list - patch - update - - watch - apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: @@ -1324,6 +1128,7 @@ items: creationTimestamp: null labels: kubernetes.io/bootstrapping: rbac-defaults + rbac.authorization.k8s.io/aggregate-to-edit: "true" name: view rules: null kind: List