...

Source file src/k8s.io/kubernetes/pkg/registry/rbac/clusterrolebinding/policybased/storage.go

Documentation: k8s.io/kubernetes/pkg/registry/rbac/clusterrolebinding/policybased

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package policybased implements a standard storage for ClusterRoleBinding that prevents privilege escalation.
    18  package policybased
    19  
    20  import (
    21  	"context"
    22  
    23  	rbacv1 "k8s.io/api/rbac/v1"
    24  	"k8s.io/apimachinery/pkg/api/errors"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/apiserver/pkg/authorization/authorizer"
    28  	"k8s.io/apiserver/pkg/registry/rest"
    29  	kapihelper "k8s.io/kubernetes/pkg/apis/core/helper"
    30  	"k8s.io/kubernetes/pkg/apis/rbac"
    31  	rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1"
    32  	rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
    33  	rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
    34  )
    35  
    36  var groupResource = rbac.Resource("clusterrolebindings")
    37  
    38  type Storage struct {
    39  	rest.StandardStorage
    40  
    41  	authorizer authorizer.Authorizer
    42  
    43  	ruleResolver rbacregistryvalidation.AuthorizationRuleResolver
    44  }
    45  
    46  func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleResolver rbacregistryvalidation.AuthorizationRuleResolver) *Storage {
    47  	return &Storage{s, authorizer, ruleResolver}
    48  }
    49  
    50  // Destroy cleans up resources on shutdown.
    51  func (r *Storage) Destroy() {
    52  	r.StandardStorage.Destroy()
    53  }
    54  
    55  func (r *Storage) NamespaceScoped() bool {
    56  	return false
    57  }
    58  
    59  func (r *Storage) StorageVersion() runtime.GroupVersioner {
    60  	svp, ok := r.StandardStorage.(rest.StorageVersionProvider)
    61  	if !ok {
    62  		return nil
    63  	}
    64  	return svp.StorageVersion()
    65  }
    66  
    67  var _ rest.StorageVersionProvider = &Storage{}
    68  
    69  func (s *Storage) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
    70  	if rbacregistry.EscalationAllowed(ctx) {
    71  		return s.StandardStorage.Create(ctx, obj, createValidation, options)
    72  	}
    73  
    74  	clusterRoleBinding := obj.(*rbac.ClusterRoleBinding)
    75  	if rbacregistry.BindingAuthorized(ctx, clusterRoleBinding.RoleRef, metav1.NamespaceNone, s.authorizer) {
    76  		return s.StandardStorage.Create(ctx, obj, createValidation, options)
    77  	}
    78  
    79  	v1RoleRef := rbacv1.RoleRef{}
    80  	err := rbacv1helpers.Convert_rbac_RoleRef_To_v1_RoleRef(&clusterRoleBinding.RoleRef, &v1RoleRef, nil)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  	rules, err := s.ruleResolver.GetRoleReferenceRules(v1RoleRef, metav1.NamespaceNone)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  	if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
    89  		return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err)
    90  	}
    91  	return s.StandardStorage.Create(ctx, obj, createValidation, options)
    92  }
    93  
    94  func (s *Storage) Update(ctx context.Context, name string, obj rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
    95  	if rbacregistry.EscalationAllowed(ctx) {
    96  		return s.StandardStorage.Update(ctx, name, obj, createValidation, updateValidation, forceAllowCreate, options)
    97  	}
    98  
    99  	nonEscalatingInfo := rest.WrapUpdatedObjectInfo(obj, func(ctx context.Context, obj runtime.Object, oldObj runtime.Object) (runtime.Object, error) {
   100  		clusterRoleBinding := obj.(*rbac.ClusterRoleBinding)
   101  
   102  		// if we're only mutating fields needed for the GC to eventually delete this obj, return
   103  		if rbacregistry.IsOnlyMutatingGCFields(obj, oldObj, kapihelper.Semantic) {
   104  			return obj, nil
   105  		}
   106  
   107  		// if we're explicitly authorized to bind this clusterrole, return
   108  		if rbacregistry.BindingAuthorized(ctx, clusterRoleBinding.RoleRef, metav1.NamespaceNone, s.authorizer) {
   109  			return obj, nil
   110  		}
   111  
   112  		// Otherwise, see if we already have all the permissions contained in the referenced clusterrole
   113  		v1RoleRef := rbacv1.RoleRef{}
   114  		err := rbacv1helpers.Convert_rbac_RoleRef_To_v1_RoleRef(&clusterRoleBinding.RoleRef, &v1RoleRef, nil)
   115  		if err != nil {
   116  			return nil, err
   117  		}
   118  		rules, err := s.ruleResolver.GetRoleReferenceRules(v1RoleRef, metav1.NamespaceNone)
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  		if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
   123  			return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err)
   124  		}
   125  		return obj, nil
   126  	})
   127  
   128  	return s.StandardStorage.Update(ctx, name, nonEscalatingInfo, createValidation, updateValidation, forceAllowCreate, options)
   129  }
   130  
   131  var _ rest.SingularNameProvider = &Storage{}
   132  
   133  func (s *Storage) GetSingularName() string {
   134  	snp, ok := s.StandardStorage.(rest.SingularNameProvider)
   135  	if !ok {
   136  		return ""
   137  	}
   138  	return snp.GetSingularName()
   139  }
   140  

View as plain text