mirror of https://github.com/k3s-io/k3s
handle clusterrole migration
parent
e52383c486
commit
f34fb9b0ab
|
@ -42,7 +42,10 @@ func NewStorage(s rest.StandardStorage, ruleResolver rbacregistryvalidation.Auth
|
|||
return &Storage{s, ruleResolver}
|
||||
}
|
||||
|
||||
var fullAuthority = []rbac.PolicyRule{rbac.NewRule("*").Groups("*").Resources("*").RuleOrDie()}
|
||||
var fullAuthority = []rbac.PolicyRule{
|
||||
rbac.NewRule("*").Groups("*").Resources("*").RuleOrDie(),
|
||||
rbac.NewRule("*").URLs("*").RuleOrDie(),
|
||||
}
|
||||
|
||||
func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, createValidatingAdmission rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
|
||||
if rbacregistry.EscalationAllowed(ctx) {
|
||||
|
|
|
@ -18,6 +18,7 @@ go_test(
|
|||
"//pkg/apis/core/helper:go_default_library",
|
||||
"//pkg/apis/rbac:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -66,6 +66,14 @@ func (o ClusterRoleRuleOwner) SetRules(in []rbac.PolicyRule) {
|
|||
o.ClusterRole.Rules = in
|
||||
}
|
||||
|
||||
func (o ClusterRoleRuleOwner) GetAggregationRule() *rbac.AggregationRule {
|
||||
return o.ClusterRole.AggregationRule
|
||||
}
|
||||
|
||||
func (o ClusterRoleRuleOwner) SetAggregationRule(in *rbac.AggregationRule) {
|
||||
o.ClusterRole.AggregationRule = in
|
||||
}
|
||||
|
||||
type ClusterRoleModifier struct {
|
||||
Client internalversion.ClusterRoleInterface
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
"k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||
|
@ -51,6 +53,8 @@ type RuleOwner interface {
|
|||
SetAnnotations(map[string]string)
|
||||
GetRules() []rbac.PolicyRule
|
||||
SetRules([]rbac.PolicyRule)
|
||||
GetAggregationRule() *rbac.AggregationRule
|
||||
SetAggregationRule(*rbac.AggregationRule)
|
||||
DeepCopyRuleOwner() RuleOwner
|
||||
}
|
||||
|
||||
|
@ -75,6 +79,11 @@ type ReconcileClusterRoleResult struct {
|
|||
// ExtraRules contains extra permissions the currently persisted role had
|
||||
ExtraRules []rbac.PolicyRule
|
||||
|
||||
// MissingAggregationRuleSelectors contains expected selectors that were missing from the currently persisted role
|
||||
MissingAggregationRuleSelectors []metav1.LabelSelector
|
||||
// ExtraAggregationRuleSelectors contains extra selectors the currently persisted role had
|
||||
ExtraAggregationRuleSelectors []metav1.LabelSelector
|
||||
|
||||
// Operation is the API operation required to reconcile.
|
||||
// If no reconciliation was needed, it is set to ReconcileNone.
|
||||
// If options.Confirm == false, the reconcile was in dry-run mode, so the operation was not performed.
|
||||
|
@ -101,10 +110,15 @@ func (o *ReconcileRoleOptions) run(attempts int) (*ReconcileClusterRoleResult, e
|
|||
existing, err := o.Client.Get(o.Role.GetNamespace(), o.Role.GetName())
|
||||
switch {
|
||||
case errors.IsNotFound(err):
|
||||
aggregationRule := o.Role.GetAggregationRule()
|
||||
if aggregationRule == nil {
|
||||
aggregationRule = &rbac.AggregationRule{}
|
||||
}
|
||||
result = &ReconcileClusterRoleResult{
|
||||
Role: o.Role,
|
||||
MissingRules: o.Role.GetRules(),
|
||||
Operation: ReconcileCreate,
|
||||
Role: o.Role,
|
||||
MissingRules: o.Role.GetRules(),
|
||||
MissingAggregationRuleSelectors: aggregationRule.ClusterRoleSelectors,
|
||||
Operation: ReconcileCreate,
|
||||
}
|
||||
|
||||
case err != nil:
|
||||
|
@ -195,6 +209,26 @@ func computeReconciledRole(existing, expected RuleOwner, removeExtraPermissions
|
|||
result.Operation = ReconcileUpdate
|
||||
}
|
||||
|
||||
// Compute extra and missing rules
|
||||
_, result.ExtraAggregationRuleSelectors = aggregationRuleCovers(expected.GetAggregationRule(), existing.GetAggregationRule())
|
||||
_, result.MissingAggregationRuleSelectors = aggregationRuleCovers(existing.GetAggregationRule(), expected.GetAggregationRule())
|
||||
|
||||
switch {
|
||||
case !removeExtraPermissions && len(result.MissingAggregationRuleSelectors) > 0:
|
||||
// add missing rules in the union case
|
||||
aggregationRule := result.Role.GetAggregationRule()
|
||||
if aggregationRule == nil {
|
||||
aggregationRule = &rbac.AggregationRule{}
|
||||
}
|
||||
aggregationRule.ClusterRoleSelectors = append(aggregationRule.ClusterRoleSelectors, result.MissingAggregationRuleSelectors...)
|
||||
result.Role.SetAggregationRule(aggregationRule)
|
||||
result.Operation = ReconcileUpdate
|
||||
|
||||
case removeExtraPermissions && (len(result.MissingAggregationRuleSelectors) > 0 || len(result.ExtraAggregationRuleSelectors) > 0):
|
||||
result.Role.SetAggregationRule(expected.GetAggregationRule())
|
||||
result.Operation = ReconcileUpdate
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
@ -211,3 +245,37 @@ func merge(maps ...map[string]string) map[string]string {
|
|||
}
|
||||
return output
|
||||
}
|
||||
|
||||
// aggregationRuleCovers determines whether or not the ownerSelectors cover the servantSelectors in terms of semantically
|
||||
// equal label selectors.
|
||||
// It returns whether or not the ownerSelectors cover and a list of the rules that the ownerSelectors do not cover.
|
||||
func aggregationRuleCovers(ownerRule, servantRule *rbac.AggregationRule) (bool, []metav1.LabelSelector) {
|
||||
switch {
|
||||
case ownerRule == nil && servantRule == nil:
|
||||
return true, []metav1.LabelSelector{}
|
||||
case ownerRule == nil && servantRule != nil:
|
||||
return false, servantRule.ClusterRoleSelectors
|
||||
case ownerRule != nil && servantRule == nil:
|
||||
return true, []metav1.LabelSelector{}
|
||||
|
||||
}
|
||||
|
||||
ownerSelectors := ownerRule.ClusterRoleSelectors
|
||||
servantSelectors := servantRule.ClusterRoleSelectors
|
||||
uncoveredSelectors := []metav1.LabelSelector{}
|
||||
|
||||
for _, servantSelector := range servantSelectors {
|
||||
covered := false
|
||||
for _, ownerSelector := range ownerSelectors {
|
||||
if equality.Semantic.DeepEqual(ownerSelector, servantSelector) {
|
||||
covered = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !covered {
|
||||
uncoveredSelectors = append(uncoveredSelectors, servantSelector)
|
||||
}
|
||||
}
|
||||
|
||||
return (len(uncoveredSelectors) == 0), uncoveredSelectors
|
||||
}
|
||||
|
|
|
@ -20,12 +20,16 @@ import (
|
|||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/kubernetes/pkg/apis/core/helper"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
)
|
||||
|
||||
func role(rules []rbac.PolicyRule, labels map[string]string, annotations map[string]string) *rbac.ClusterRole {
|
||||
return &rbac.ClusterRole{Rules: rules, ObjectMeta: metav1.ObjectMeta{Labels: labels, Annotations: annotations}}
|
||||
return &rbac.ClusterRole{
|
||||
Rules: rules,
|
||||
ObjectMeta: metav1.ObjectMeta{Labels: labels, Annotations: annotations},
|
||||
}
|
||||
}
|
||||
|
||||
func rules(resources ...string) []rbac.PolicyRule {
|
||||
|
@ -38,7 +42,7 @@ func rules(resources ...string) []rbac.PolicyRule {
|
|||
|
||||
type ss map[string]string
|
||||
|
||||
func TestComputeReconciledRole(t *testing.T) {
|
||||
func TestComputeReconciledRoleRules(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
expectedRole *rbac.ClusterRole
|
||||
actualRole *rbac.ClusterRole
|
||||
|
@ -273,3 +277,96 @@ func TestComputeReconciledRole(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func aggregatedRole(aggregationRule *rbac.AggregationRule) *rbac.ClusterRole {
|
||||
return &rbac.ClusterRole{
|
||||
AggregationRule: aggregationRule,
|
||||
}
|
||||
}
|
||||
|
||||
func aggregationrule(selectors []map[string]string) *rbac.AggregationRule {
|
||||
ret := &rbac.AggregationRule{}
|
||||
for _, selector := range selectors {
|
||||
ret.ClusterRoleSelectors = append(ret.ClusterRoleSelectors,
|
||||
metav1.LabelSelector{MatchLabels: selector})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func TestComputeReconciledRoleAggregationRules(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
expectedRole *rbac.ClusterRole
|
||||
actualRole *rbac.ClusterRole
|
||||
removeExtraPermissions bool
|
||||
|
||||
expectedReconciledRole *rbac.ClusterRole
|
||||
expectedReconciliationNeeded bool
|
||||
}{
|
||||
"empty": {
|
||||
expectedRole: aggregatedRole(&rbac.AggregationRule{}),
|
||||
actualRole: aggregatedRole(nil),
|
||||
removeExtraPermissions: true,
|
||||
|
||||
expectedReconciledRole: nil,
|
||||
expectedReconciliationNeeded: false,
|
||||
},
|
||||
"empty-2": {
|
||||
expectedRole: aggregatedRole(&rbac.AggregationRule{}),
|
||||
actualRole: aggregatedRole(&rbac.AggregationRule{}),
|
||||
removeExtraPermissions: true,
|
||||
|
||||
expectedReconciledRole: nil,
|
||||
expectedReconciliationNeeded: false,
|
||||
},
|
||||
"match without union": {
|
||||
expectedRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
|
||||
actualRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
|
||||
removeExtraPermissions: true,
|
||||
|
||||
expectedReconciledRole: nil,
|
||||
expectedReconciliationNeeded: false,
|
||||
},
|
||||
"match with union": {
|
||||
expectedRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
|
||||
actualRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
|
||||
removeExtraPermissions: false,
|
||||
|
||||
expectedReconciledRole: nil,
|
||||
expectedReconciliationNeeded: false,
|
||||
},
|
||||
"different rules without union": {
|
||||
expectedRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
|
||||
actualRole: aggregatedRole(aggregationrule([]map[string]string{{"alpha": "bravo"}})),
|
||||
removeExtraPermissions: true,
|
||||
|
||||
expectedReconciledRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
|
||||
expectedReconciliationNeeded: true,
|
||||
},
|
||||
"different rules with union": {
|
||||
expectedRole: aggregatedRole(aggregationrule([]map[string]string{{"foo": "bar"}})),
|
||||
actualRole: aggregatedRole(aggregationrule([]map[string]string{{"alpha": "bravo"}})),
|
||||
removeExtraPermissions: false,
|
||||
|
||||
expectedReconciledRole: aggregatedRole(aggregationrule([]map[string]string{{"alpha": "bravo"}, {"foo": "bar"}})),
|
||||
expectedReconciliationNeeded: true,
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range tests {
|
||||
actualRole := ClusterRoleRuleOwner{ClusterRole: tc.actualRole}
|
||||
expectedRole := ClusterRoleRuleOwner{ClusterRole: tc.expectedRole}
|
||||
result, err := computeReconciledRole(actualRole, expectedRole, tc.removeExtraPermissions)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %v", k, err)
|
||||
continue
|
||||
}
|
||||
reconciliationNeeded := result.Operation != ReconcileNone
|
||||
if reconciliationNeeded != tc.expectedReconciliationNeeded {
|
||||
t.Errorf("%s: Expected\n\t%v\ngot\n\t%v", k, tc.expectedReconciliationNeeded, reconciliationNeeded)
|
||||
continue
|
||||
}
|
||||
if reconciliationNeeded && !helper.Semantic.DeepEqual(result.Role.(ClusterRoleRuleOwner).ClusterRole, tc.expectedReconciledRole) {
|
||||
t.Errorf("%s: %v", k, diff.ObjectDiff(tc.expectedReconciledRole, result.Role.(ClusterRoleRuleOwner).ClusterRole))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,13 @@ func (o RoleRuleOwner) SetRules(in []rbac.PolicyRule) {
|
|||
o.Role.Rules = in
|
||||
}
|
||||
|
||||
func (o RoleRuleOwner) GetAggregationRule() *rbac.AggregationRule {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o RoleRuleOwner) SetAggregationRule(in *rbac.AggregationRule) {
|
||||
}
|
||||
|
||||
type RoleModifier struct {
|
||||
Client internalversion.RolesGetter
|
||||
NamespaceClient core.NamespaceInterface
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
rbacapiv1 "k8s.io/api/rbac/v1"
|
||||
rbacapiv1alpha1 "k8s.io/api/rbac/v1alpha1"
|
||||
rbacapiv1beta1 "k8s.io/api/rbac/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
|
@ -134,10 +135,11 @@ func (p RESTStorageProvider) storage(version schema.GroupVersion, apiResourceCon
|
|||
|
||||
func (p RESTStorageProvider) PostStartHook() (string, genericapiserver.PostStartHookFunc, error) {
|
||||
policy := &PolicyData{
|
||||
ClusterRoles: append(bootstrappolicy.ClusterRoles(), bootstrappolicy.ControllerRoles()...),
|
||||
ClusterRoleBindings: append(bootstrappolicy.ClusterRoleBindings(), bootstrappolicy.ControllerRoleBindings()...),
|
||||
Roles: bootstrappolicy.NamespaceRoles(),
|
||||
RoleBindings: bootstrappolicy.NamespaceRoleBindings(),
|
||||
ClusterRoles: append(bootstrappolicy.ClusterRoles(), bootstrappolicy.ControllerRoles()...),
|
||||
ClusterRoleBindings: append(bootstrappolicy.ClusterRoleBindings(), bootstrappolicy.ControllerRoleBindings()...),
|
||||
Roles: bootstrappolicy.NamespaceRoles(),
|
||||
RoleBindings: bootstrappolicy.NamespaceRoleBindings(),
|
||||
ClusterRolesToAggregate: bootstrappolicy.ClusterRolesToAggregate(),
|
||||
}
|
||||
return PostStartHookName, policy.EnsureRBACPolicy(), nil
|
||||
}
|
||||
|
@ -147,6 +149,8 @@ type PolicyData struct {
|
|||
ClusterRoleBindings []rbac.ClusterRoleBinding
|
||||
Roles map[string][]rbac.Role
|
||||
RoleBindings map[string][]rbac.RoleBinding
|
||||
// ClusterRolesToAggregate maps from previous clusterrole name to the new clusterrole name
|
||||
ClusterRolesToAggregate map[string]string
|
||||
}
|
||||
|
||||
func (p *PolicyData) EnsureRBACPolicy() genericapiserver.PostStartHookFunc {
|
||||
|
@ -176,6 +180,13 @@ func (p *PolicyData) EnsureRBACPolicy() genericapiserver.PostStartHookFunc {
|
|||
return false, nil
|
||||
}
|
||||
|
||||
// if the new cluster roles to aggregate do not yet exist, then we need to copy the old roles if they don't exist
|
||||
// in new locations
|
||||
if err := primeAggregatedClusterRoles(p.ClusterRolesToAggregate, clientset); err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("unable to prime aggregated clusterroles: %v", err))
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// ensure bootstrap roles are created or reconciled
|
||||
for _, clusterRole := range p.ClusterRoles {
|
||||
opts := reconciliation.ReconcileRoleOptions{
|
||||
|
@ -310,3 +321,32 @@ func (p *PolicyData) EnsureRBACPolicy() genericapiserver.PostStartHookFunc {
|
|||
func (p RESTStorageProvider) GroupName() string {
|
||||
return rbac.GroupName
|
||||
}
|
||||
|
||||
// primeAggregatedClusterRoles copies roles that have transitioned to aggregated roles and may need to pick up changes
|
||||
// that were done to the legacy roles.
|
||||
func primeAggregatedClusterRoles(clusterRolesToAggregate map[string]string, clusterRoleClient rbacclient.ClusterRolesGetter) error {
|
||||
for oldName, newName := range clusterRolesToAggregate {
|
||||
_, err := clusterRoleClient.ClusterRoles().Get(newName, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
existingRole, err := clusterRoleClient.ClusterRoles().Get(oldName, metav1.GetOptions{})
|
||||
if apierrors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
glog.V(1).Infof("migrating %v to %v", existingRole.Name, newName)
|
||||
existingRole.Name = newName
|
||||
if _, err := clusterRoleClient.ClusterRoles().Create(existingRole); err != nil && !apierrors.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -68,6 +68,14 @@ func buildControllerRoles() ([]rbac.ClusterRole, []rbac.ClusterRoleBinding) {
|
|||
eventsRule(),
|
||||
},
|
||||
})
|
||||
addControllerRole(&controllerRoles, &controllerRoleBindings, rbac.ClusterRole{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: saRolePrefix + "clusterrole-aggregation-controller"},
|
||||
Rules: []rbac.PolicyRule{
|
||||
// this controller must have full permissions to allow it to mutate any role in any way
|
||||
rbac.NewRule("*").Groups("*").Resources("*").RuleOrDie(),
|
||||
rbac.NewRule("*").URLs("*").RuleOrDie(),
|
||||
},
|
||||
})
|
||||
addControllerRole(&controllerRoles, &controllerRoleBindings, rbac.ClusterRole{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: saRolePrefix + "cronjob-controller"},
|
||||
Rules: []rbac.PolicyRule{
|
||||
|
|
|
@ -32,6 +32,7 @@ var rolesWithAllowStar = sets.NewString(
|
|||
saRolePrefix+"generic-garbage-collector",
|
||||
saRolePrefix+"resourcequota-controller",
|
||||
saRolePrefix+"horizontal-pod-autoscaler",
|
||||
saRolePrefix+"clusterrole-aggregation-controller",
|
||||
)
|
||||
|
||||
// TestNoStarsForControllers confirms that no controller role has star verbs, groups,
|
||||
|
|
|
@ -176,6 +176,30 @@ func ClusterRoles() []rbac.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: &rbac.AggregationRule{
|
||||
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"},
|
||||
AggregationRule: &rbac.AggregationRule{
|
||||
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"},
|
||||
AggregationRule: &rbac.AggregationRule{
|
||||
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: []rbac.PolicyRule{
|
||||
rbac.NewRule(ReadWrite...).Groups(legacyGroup).Resources("pods", "pods/attach", "pods/proxy", "pods/exec", "pods/portforward").RuleOrDie(),
|
||||
rbac.NewRule(ReadWrite...).Groups(legacyGroup).Resources("replicationcontrollers", "replicationcontrollers/scale", "serviceaccounts",
|
||||
|
@ -211,7 +235,7 @@ func ClusterRoles() []rbac.ClusterRole {
|
|||
// 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: "system:aggregate-to-edit", Labels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-edit": "true"}},
|
||||
Rules: []rbac.PolicyRule{
|
||||
rbac.NewRule(ReadWrite...).Groups(legacyGroup).Resources("pods", "pods/attach", "pods/proxy", "pods/exec", "pods/portforward").RuleOrDie(),
|
||||
rbac.NewRule(ReadWrite...).Groups(legacyGroup).Resources("replicationcontrollers", "replicationcontrollers/scale", "serviceaccounts",
|
||||
|
@ -242,7 +266,7 @@ func ClusterRoles() []rbac.ClusterRole {
|
|||
{
|
||||
// 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: "system:aggregate-to-view", Labels: map[string]string{"rbac.authorization.k8s.io/aggregate-to-view": "true"}},
|
||||
Rules: []rbac.PolicyRule{
|
||||
rbac.NewRule(Read...).Groups(legacyGroup).Resources("pods", "replicationcontrollers", "replicationcontrollers/scale", "serviceaccounts",
|
||||
"services", "endpoints", "persistentvolumeclaims", "configmaps").RuleOrDie(),
|
||||
|
@ -444,3 +468,11 @@ func ClusterRoleBindings() []rbac.ClusterRoleBinding {
|
|||
|
||||
return rolebindings
|
||||
}
|
||||
|
||||
func ClusterRolesToAggregate() map[string]string {
|
||||
return map[string]string{
|
||||
"admin": "system:aggregate-to-admin",
|
||||
"edit": "system:aggregate-to-edit",
|
||||
"view": "system:aggregate-to-view",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,11 +53,11 @@ func getSemanticRoles(roles []rbac.ClusterRole) semanticRoles {
|
|||
for i := range roles {
|
||||
role := roles[i]
|
||||
switch role.Name {
|
||||
case "admin":
|
||||
case "system:aggregate-to-admin":
|
||||
ret.admin = &role
|
||||
case "edit":
|
||||
case "system:aggregate-to-edit":
|
||||
ret.edit = &role
|
||||
case "view":
|
||||
case "system:aggregate-to-view":
|
||||
ret.view = &role
|
||||
}
|
||||
}
|
||||
|
@ -319,8 +319,9 @@ func TestClusterRoleLabel(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if got, want := accessor.GetLabels(), map[string]string{"kubernetes.io/bootstrapping": "rbac-defaults"}; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("ClusterRole: %s GetLabels() = %s, want %s", accessor.GetName(), got, want)
|
||||
|
||||
if accessor.GetLabels()["kubernetes.io/bootstrapping"] != "rbac-defaults" {
|
||||
t.Errorf("ClusterRole: %s GetLabels() = %s, want %s", accessor.GetName(), accessor.GetLabels(), map[string]string{"kubernetes.io/bootstrapping": "rbac-defaults"})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
apiVersion: v1
|
||||
items:
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
- aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.authorization.k8s.io/aggregate-to-admin: "true"
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations:
|
||||
|
@ -9,6 +13,51 @@ items:
|
|||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
name: admin
|
||||
rules: null
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations:
|
||||
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
name: cluster-admin
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- nonResourceURLs:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.authorization.k8s.io/aggregate-to-edit: "true"
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations:
|
||||
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
name: edit
|
||||
rules: null
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations:
|
||||
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
rbac.authorization.k8s.io/aggregate-to-admin: "true"
|
||||
name: system:aggregate-to-admin
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
|
@ -185,27 +234,8 @@ items:
|
|||
creationTimestamp: null
|
||||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
name: cluster-admin
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- nonResourceURLs:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations:
|
||||
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
name: edit
|
||||
rbac.authorization.k8s.io/aggregate-to-edit: "true"
|
||||
name: system:aggregate-to-edit
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
|
@ -354,6 +384,108 @@ items:
|
|||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations:
|
||||
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
rbac.authorization.k8s.io/aggregate-to-view: "true"
|
||||
name: system:aggregate-to-view
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
- endpoints
|
||||
- persistentvolumeclaims
|
||||
- pods
|
||||
- replicationcontrollers
|
||||
- replicationcontrollers/scale
|
||||
- serviceaccounts
|
||||
- services
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- 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:
|
||||
- apps
|
||||
resources:
|
||||
- daemonsets
|
||||
- deployments
|
||||
- deployments/scale
|
||||
- replicasets
|
||||
- replicasets/scale
|
||||
- statefulsets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- autoscaling
|
||||
resources:
|
||||
- horizontalpodautoscalers
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- batch
|
||||
resources:
|
||||
- cronjobs
|
||||
- jobs
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- extensions
|
||||
resources:
|
||||
- daemonsets
|
||||
- deployments
|
||||
- deployments/scale
|
||||
- ingresses
|
||||
- replicasets
|
||||
- replicasets/scale
|
||||
- replicationcontrollers/scale
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- policy
|
||||
resources:
|
||||
- poddisruptionbudgets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
|
@ -935,7 +1067,11 @@ items:
|
|||
- create
|
||||
- patch
|
||||
- update
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
- aggregationRule:
|
||||
clusterRoleSelectors:
|
||||
- matchLabels:
|
||||
rbac.authorization.k8s.io/aggregate-to-view: "true"
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations:
|
||||
|
@ -944,97 +1080,6 @@ items:
|
|||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
name: view
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
- endpoints
|
||||
- persistentvolumeclaims
|
||||
- pods
|
||||
- replicationcontrollers
|
||||
- replicationcontrollers/scale
|
||||
- serviceaccounts
|
||||
- services
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- 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:
|
||||
- apps
|
||||
resources:
|
||||
- daemonsets
|
||||
- deployments
|
||||
- deployments/scale
|
||||
- replicasets
|
||||
- replicasets/scale
|
||||
- statefulsets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- autoscaling
|
||||
resources:
|
||||
- horizontalpodautoscalers
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- batch
|
||||
resources:
|
||||
- cronjobs
|
||||
- jobs
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- extensions
|
||||
resources:
|
||||
- daemonsets
|
||||
- deployments
|
||||
- deployments/scale
|
||||
- ingresses
|
||||
- replicasets
|
||||
- replicasets/scale
|
||||
- replicationcontrollers/scale
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- policy
|
||||
resources:
|
||||
- poddisruptionbudgets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
rules: null
|
||||
kind: List
|
||||
metadata: {}
|
||||
|
|
|
@ -34,6 +34,23 @@ items:
|
|||
- kind: ServiceAccount
|
||||
name: certificate-controller
|
||||
namespace: kube-system
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
annotations:
|
||||
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
name: system:controller:clusterrole-aggregation-controller
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:controller:clusterrole-aggregation-controller
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: clusterrole-aggregation-controller
|
||||
namespace: kube-system
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
|
|
|
@ -87,6 +87,26 @@ items:
|
|||
- create
|
||||
- patch
|
||||
- update
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
annotations:
|
||||
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
kubernetes.io/bootstrapping: rbac-defaults
|
||||
name: system:controller:clusterrole-aggregation-controller
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- nonResourceURLs:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
|
|
Loading…
Reference in New Issue