mirror of https://github.com/k3s-io/k3s
rbac api changes for aggregation
parent
41fe3ed5bc
commit
0f0a5223df
|
@ -155,6 +155,18 @@ type ClusterRole struct {
|
||||||
|
|
||||||
// Rules holds all the PolicyRules for this ClusterRole
|
// Rules holds all the PolicyRules for this ClusterRole
|
||||||
Rules []PolicyRule
|
Rules []PolicyRule
|
||||||
|
|
||||||
|
// AggregationRule is an optional field that describes how to build the Rules for this ClusterRole.
|
||||||
|
// If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be
|
||||||
|
// stomped by the controller.
|
||||||
|
AggregationRule *AggregationRule
|
||||||
|
}
|
||||||
|
|
||||||
|
// AggregationRule describes how to locate ClusterRoles to aggregate into the ClusterRole
|
||||||
|
type AggregationRule struct {
|
||||||
|
// ClusterRoleSelectors holds a list of selectors which will be used to find ClusterRoles and create the rules.
|
||||||
|
// If any of the selectors match, then the ClusterRole's permissions will be added
|
||||||
|
ClusterRoleSelectors []metav1.LabelSelector
|
||||||
}
|
}
|
||||||
|
|
||||||
// +genclient
|
// +genclient
|
||||||
|
|
|
@ -18,6 +18,8 @@ package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/apimachinery/pkg/api/validation/path"
|
"k8s.io/apimachinery/pkg/api/validation/path"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
unversionedvalidation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
|
@ -61,6 +63,22 @@ func ValidateClusterRole(role *rbac.ClusterRole) field.ErrorList {
|
||||||
allErrs = append(allErrs, err...)
|
allErrs = append(allErrs, err...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if role.AggregationRule != nil {
|
||||||
|
if len(role.AggregationRule.ClusterRoleSelectors) == 0 {
|
||||||
|
allErrs = append(allErrs, field.Required(field.NewPath("aggregationRule", "clusterRoleSelectors"), "at least one clusterRoleSelector required if aggregationRule is non-nil"))
|
||||||
|
}
|
||||||
|
for i, selector := range role.AggregationRule.ClusterRoleSelectors {
|
||||||
|
fieldPath := field.NewPath("aggregationRule", "clusterRoleSelectors").Index(i)
|
||||||
|
allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(&selector, fieldPath)...)
|
||||||
|
|
||||||
|
selector, err := metav1.LabelSelectorAsSelector(&selector)
|
||||||
|
if err != nil {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fieldPath, selector, "invalid label selector."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(allErrs) != 0 {
|
if len(allErrs) != 0 {
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,9 @@ limitations under the License.
|
||||||
package policybased
|
package policybased
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"errors"
|
||||||
|
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||||
"k8s.io/apiserver/pkg/registry/rest"
|
"k8s.io/apiserver/pkg/registry/rest"
|
||||||
|
@ -40,6 +42,8 @@ func NewStorage(s rest.StandardStorage, ruleResolver rbacregistryvalidation.Auth
|
||||||
return &Storage{s, ruleResolver}
|
return &Storage{s, ruleResolver}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fullAuthority = []rbac.PolicyRule{rbac.NewRule("*").Groups("*").Resources("*").RuleOrDie()}
|
||||||
|
|
||||||
func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, createValidatingAdmission rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
|
func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, createValidatingAdmission rest.ValidateObjectFunc, includeUninitialized bool) (runtime.Object, error) {
|
||||||
if rbacregistry.EscalationAllowed(ctx) {
|
if rbacregistry.EscalationAllowed(ctx) {
|
||||||
return s.StandardStorage.Create(ctx, obj, createValidatingAdmission, includeUninitialized)
|
return s.StandardStorage.Create(ctx, obj, createValidatingAdmission, includeUninitialized)
|
||||||
|
@ -48,8 +52,15 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object, crea
|
||||||
clusterRole := obj.(*rbac.ClusterRole)
|
clusterRole := obj.(*rbac.ClusterRole)
|
||||||
rules := clusterRole.Rules
|
rules := clusterRole.Rules
|
||||||
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
||||||
return nil, errors.NewForbidden(groupResource, clusterRole.Name, err)
|
return nil, apierrors.NewForbidden(groupResource, clusterRole.Name, err)
|
||||||
}
|
}
|
||||||
|
// to set the aggregation rule, since it can gather anything, requires * on *.*
|
||||||
|
if hasAggregationRule(clusterRole) {
|
||||||
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, fullAuthority); err != nil {
|
||||||
|
return nil, apierrors.NewForbidden(groupResource, clusterRole.Name, errors.New("must have cluster-admin privileges to use the aggregationRule"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return s.StandardStorage.Create(ctx, obj, createValidatingAdmission, includeUninitialized)
|
return s.StandardStorage.Create(ctx, obj, createValidatingAdmission, includeUninitialized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +71,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
|
||||||
|
|
||||||
nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx genericapirequest.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) {
|
nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx genericapirequest.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) {
|
||||||
clusterRole := obj.(*rbac.ClusterRole)
|
clusterRole := obj.(*rbac.ClusterRole)
|
||||||
|
oldClusterRole := oldObj.(*rbac.ClusterRole)
|
||||||
|
|
||||||
// if we're only mutating fields needed for the GC to eventually delete this obj, return
|
// if we're only mutating fields needed for the GC to eventually delete this obj, return
|
||||||
if rbacregistry.IsOnlyMutatingGCFields(obj, oldObj, kapihelper.Semantic) {
|
if rbacregistry.IsOnlyMutatingGCFields(obj, oldObj, kapihelper.Semantic) {
|
||||||
|
@ -68,10 +80,21 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
|
||||||
|
|
||||||
rules := clusterRole.Rules
|
rules := clusterRole.Rules
|
||||||
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
|
||||||
return nil, errors.NewForbidden(groupResource, clusterRole.Name, err)
|
return nil, apierrors.NewForbidden(groupResource, clusterRole.Name, err)
|
||||||
}
|
}
|
||||||
|
// to change the aggregation rule, since it can gather anything and prevent tightening, requires * on *.*
|
||||||
|
if hasAggregationRule(clusterRole) || hasAggregationRule(oldClusterRole) {
|
||||||
|
if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, fullAuthority); err != nil {
|
||||||
|
return nil, apierrors.NewForbidden(groupResource, clusterRole.Name, errors.New("must have cluster-admin privileges to use the aggregationRule"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return obj, nil
|
return obj, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
return s.StandardStorage.Update(ctx, name, nonEscalatingInfo, createValidation, updateValidation)
|
return s.StandardStorage.Update(ctx, name, nonEscalatingInfo, createValidation, updateValidation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasAggregationRule(clusterRole *rbac.ClusterRole) bool {
|
||||||
|
return clusterRole.AggregationRule != nil && len(clusterRole.AggregationRule.ClusterRoleSelectors) > 0
|
||||||
|
}
|
||||||
|
|
|
@ -170,6 +170,20 @@ type ClusterRole struct {
|
||||||
|
|
||||||
// Rules holds all the PolicyRules for this ClusterRole
|
// Rules holds all the PolicyRules for this ClusterRole
|
||||||
Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"`
|
Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"`
|
||||||
|
|
||||||
|
// AggregationRule is an optional field that describes how to build the Rules for this ClusterRole.
|
||||||
|
// If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be
|
||||||
|
// stomped by the controller.
|
||||||
|
// +optional
|
||||||
|
AggregationRule *AggregationRule `json:"aggregationRule,omitempty" protobuf:"bytes,3,opt,name=aggregationRule"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AggregationRule describes how to locate ClusterRoles to aggregate into the ClusterRole
|
||||||
|
type AggregationRule struct {
|
||||||
|
// ClusterRoleSelectors holds a list of selectors which will be used to find ClusterRoles and create the rules.
|
||||||
|
// If any of the selectors match, then the ClusterRole's permissions will be added
|
||||||
|
// +optional
|
||||||
|
ClusterRoleSelectors []metav1.LabelSelector `json:"clusterRoleSelectors,omitempty" protobuf:"bytes,1,rep,name=clusterRoleSelectors"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +genclient
|
// +genclient
|
||||||
|
|
|
@ -172,6 +172,20 @@ type ClusterRole struct {
|
||||||
|
|
||||||
// Rules holds all the PolicyRules for this ClusterRole
|
// Rules holds all the PolicyRules for this ClusterRole
|
||||||
Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"`
|
Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"`
|
||||||
|
|
||||||
|
// AggregationRule is an optional field that describes how to build the Rules for this ClusterRole.
|
||||||
|
// If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be
|
||||||
|
// stomped by the controller.
|
||||||
|
// +optional
|
||||||
|
AggregationRule *AggregationRule `json:"aggregationRule,omitempty" protobuf:"bytes,3,opt,name=aggregationRule"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AggregationRule describes how to locate ClusterRoles to aggregate into the ClusterRole
|
||||||
|
type AggregationRule struct {
|
||||||
|
// ClusterRoleSelectors holds a list of selectors which will be used to find ClusterRoles and create the rules.
|
||||||
|
// If any of the selectors match, then the ClusterRole's permissions will be added
|
||||||
|
// +optional
|
||||||
|
ClusterRoleSelectors []metav1.LabelSelector `json:"clusterRoleSelectors,omitempty" protobuf:"bytes,1,rep,name=clusterRoleSelectors"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +genclient
|
// +genclient
|
||||||
|
|
|
@ -171,6 +171,19 @@ type ClusterRole struct {
|
||||||
|
|
||||||
// Rules holds all the PolicyRules for this ClusterRole
|
// Rules holds all the PolicyRules for this ClusterRole
|
||||||
Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"`
|
Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"`
|
||||||
|
// AggregationRule is an optional field that describes how to build the Rules for this ClusterRole.
|
||||||
|
// If AggregationRule is set, then the Rules are controller managed and direct changes to Rules will be
|
||||||
|
// stomped by the controller.
|
||||||
|
// +optional
|
||||||
|
AggregationRule *AggregationRule `json:"aggregationRule,omitempty" protobuf:"bytes,3,opt,name=aggregationRule"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AggregationRule describes how to locate ClusterRoles to aggregate into the ClusterRole
|
||||||
|
type AggregationRule struct {
|
||||||
|
// ClusterRoleSelectors holds a list of selectors which will be used to find ClusterRoles and create the rules.
|
||||||
|
// If any of the selectors match, then the ClusterRole's permissions will be added
|
||||||
|
// +optional
|
||||||
|
ClusterRoleSelectors []metav1.LabelSelector `json:"clusterRoleSelectors,omitempty" protobuf:"bytes,1,rep,name=clusterRoleSelectors"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +genclient
|
// +genclient
|
||||||
|
|
Loading…
Reference in New Issue