mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 06:27:05 +00:00
wire in ctx to rbac plugins
This commit is contained in:
parent
8d402c9941
commit
4e4eb8c5c9
@ -239,7 +239,7 @@ func (pl PolicyList) Authorize(ctx context.Context, a authorizer.Attributes) (au
|
||||
}
|
||||
|
||||
// RulesFor returns rules for the given user and namespace.
|
||||
func (pl PolicyList) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
func (pl PolicyList) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
var (
|
||||
resourceRules []authorizer.ResourceRuleInfo
|
||||
nonResourceRules []authorizer.NonResourceRuleInfo
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/kubernetes/pkg/apis/abac"
|
||||
"k8s.io/kubernetes/pkg/apis/abac/v0"
|
||||
"k8s.io/kubernetes/pkg/apis/abac/v1beta1"
|
||||
@ -324,7 +325,7 @@ func TestRulesFor(t *testing.T) {
|
||||
User: &tc.User,
|
||||
Namespace: tc.Namespace,
|
||||
}
|
||||
resourceRules, nonResourceRules, _, _ := a.RulesFor(attr.GetUser(), attr.GetNamespace())
|
||||
resourceRules, nonResourceRules, _, _ := a.RulesFor(genericapirequest.NewContext(), attr.GetUser(), attr.GetNamespace())
|
||||
actualResourceRules := getResourceRules(resourceRules)
|
||||
if !reflect.DeepEqual(tc.ExpectResourceRules, actualResourceRules) {
|
||||
t.Logf("tc: %v -> attr %v", tc, attr)
|
||||
|
@ -78,8 +78,8 @@ func (r *reloadableAuthorizerResolver) Authorize(ctx context.Context, a authoriz
|
||||
return r.current.Load().authorizer.Authorize(ctx, a)
|
||||
}
|
||||
|
||||
func (r *reloadableAuthorizerResolver) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
return r.current.Load().ruleResolver.RulesFor(user, namespace)
|
||||
func (r *reloadableAuthorizerResolver) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
return r.current.Load().ruleResolver.RulesFor(ctx, user, namespace)
|
||||
}
|
||||
|
||||
// newForConfig constructs
|
||||
|
@ -78,7 +78,7 @@ func (r *REST) Create(ctx context.Context, obj runtime.Object, createValidation
|
||||
}
|
||||
}
|
||||
|
||||
resourceInfo, nonResourceInfo, incomplete, err := r.ruleResolver.RulesFor(user, namespace)
|
||||
resourceInfo, nonResourceInfo, incomplete, err := r.ruleResolver.RulesFor(ctx, user, namespace)
|
||||
|
||||
ret := &authorizationapi.SelfSubjectRulesReview{
|
||||
Status: authorizationapi.SubjectRulesReviewStatus{
|
||||
|
@ -62,6 +62,6 @@ type AuthorizerAdapter struct {
|
||||
}
|
||||
|
||||
// GetClusterRole returns the corresponding ClusterRole by name
|
||||
func (a AuthorizerAdapter) GetClusterRole(name string) (*rbacv1.ClusterRole, error) {
|
||||
return a.Registry.GetClusterRole(genericapirequest.NewContext(), name, &metav1.GetOptions{})
|
||||
func (a AuthorizerAdapter) GetClusterRole(ctx context.Context, name string) (*rbacv1.ClusterRole, error) {
|
||||
return a.Registry.GetClusterRole(genericapirequest.WithNamespace(ctx, ""), name, &metav1.GetOptions{})
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ func (s *Storage) Create(ctx context.Context, obj runtime.Object, createValidati
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules, err := s.ruleResolver.GetRoleReferenceRules(v1RoleRef, metav1.NamespaceNone)
|
||||
rules, err := s.ruleResolver.GetRoleReferenceRules(ctx, v1RoleRef, metav1.NamespaceNone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -115,7 +115,7 @@ func (s *Storage) Update(ctx context.Context, name string, obj rest.UpdatedObjec
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules, err := s.ruleResolver.GetRoleReferenceRules(v1RoleRef, metav1.NamespaceNone)
|
||||
rules, err := s.ruleResolver.GetRoleReferenceRules(ctx, v1RoleRef, metav1.NamespaceNone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -61,8 +61,8 @@ type AuthorizerAdapter struct {
|
||||
Registry Registry
|
||||
}
|
||||
|
||||
func (a AuthorizerAdapter) ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error) {
|
||||
list, err := a.Registry.ListClusterRoleBindings(genericapirequest.NewContext(), &metainternalversion.ListOptions{})
|
||||
func (a AuthorizerAdapter) ListClusterRoleBindings(ctx context.Context) ([]*rbacv1.ClusterRoleBinding, error) {
|
||||
list, err := a.Registry.ListClusterRoleBindings(genericapirequest.WithNamespace(ctx, ""), &metainternalversion.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -62,6 +62,6 @@ type AuthorizerAdapter struct {
|
||||
}
|
||||
|
||||
// GetRole returns the corresponding Role by name in specified namespace
|
||||
func (a AuthorizerAdapter) GetRole(namespace, name string) (*rbacv1.Role, error) {
|
||||
return a.Registry.GetRole(genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace), name, &metav1.GetOptions{})
|
||||
func (a AuthorizerAdapter) GetRole(ctx context.Context, namespace, name string) (*rbacv1.Role, error) {
|
||||
return a.Registry.GetRole(genericapirequest.WithNamespace(ctx, namespace), name, &metav1.GetOptions{})
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ func (s *Storage) Create(ctx context.Context, obj runtime.Object, createValidati
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules, err := s.ruleResolver.GetRoleReferenceRules(v1RoleRef, namespace)
|
||||
rules, err := s.ruleResolver.GetRoleReferenceRules(ctx, v1RoleRef, namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -130,7 +130,7 @@ func (s *Storage) Update(ctx context.Context, name string, obj rest.UpdatedObjec
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules, err := s.ruleResolver.GetRoleReferenceRules(v1RoleRef, namespace)
|
||||
rules, err := s.ruleResolver.GetRoleReferenceRules(ctx, v1RoleRef, namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -61,8 +61,8 @@ type AuthorizerAdapter struct {
|
||||
Registry Registry
|
||||
}
|
||||
|
||||
func (a AuthorizerAdapter) ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding, error) {
|
||||
list, err := a.Registry.ListRoleBindings(genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace), &metainternalversion.ListOptions{})
|
||||
func (a AuthorizerAdapter) ListRoleBindings(ctx context.Context, namespace string) ([]*rbacv1.RoleBinding, error) {
|
||||
list, err := a.Registry.ListRoleBindings(genericapirequest.WithNamespace(ctx, namespace), &metainternalversion.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -37,16 +37,16 @@ import (
|
||||
type AuthorizationRuleResolver interface {
|
||||
// GetRoleReferenceRules attempts to resolve the role reference of a RoleBinding or ClusterRoleBinding. The passed namespace should be the namespace
|
||||
// of the role binding, the empty string if a cluster role binding.
|
||||
GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error)
|
||||
GetRoleReferenceRules(ctx context.Context, roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error)
|
||||
|
||||
// RulesFor returns the list of rules that apply to a given user in a given namespace and error. If an error is returned, the slice of
|
||||
// PolicyRules may not be complete, but it contains all retrievable rules. This is done because policy rules are purely additive and policy determinations
|
||||
// can be made on the basis of those rules that are found.
|
||||
RulesFor(user user.Info, namespace string) ([]rbacv1.PolicyRule, error)
|
||||
RulesFor(ctx context.Context, user user.Info, namespace string) ([]rbacv1.PolicyRule, error)
|
||||
|
||||
// VisitRulesFor invokes visitor() with each rule that applies to a given user in a given namespace, and each error encountered resolving those rules.
|
||||
// If visitor() returns false, visiting is short-circuited.
|
||||
VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool)
|
||||
VisitRulesFor(ctx context.Context, user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool)
|
||||
}
|
||||
|
||||
// ConfirmNoEscalation determines if the roles for a given user in a given namespace encompass the provided role.
|
||||
@ -59,7 +59,7 @@ func ConfirmNoEscalation(ctx context.Context, ruleResolver AuthorizationRuleReso
|
||||
}
|
||||
namespace, _ := genericapirequest.NamespaceFrom(ctx)
|
||||
|
||||
ownerRules, err := ruleResolver.RulesFor(user, namespace)
|
||||
ownerRules, err := ruleResolver.RulesFor(ctx, user, namespace)
|
||||
if err != nil {
|
||||
// As per AuthorizationRuleResolver contract, this may return a non fatal error with an incomplete list of policies. Log the error and continue.
|
||||
klog.V(1).Infof("non-fatal error getting local rules for %v: %v", user, err)
|
||||
@ -100,24 +100,24 @@ func NewDefaultRuleResolver(roleGetter RoleGetter, roleBindingLister RoleBinding
|
||||
}
|
||||
|
||||
type RoleGetter interface {
|
||||
GetRole(namespace, name string) (*rbacv1.Role, error)
|
||||
GetRole(ctx context.Context, namespace, name string) (*rbacv1.Role, error)
|
||||
}
|
||||
|
||||
type RoleBindingLister interface {
|
||||
ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding, error)
|
||||
ListRoleBindings(ctx context.Context, namespace string) ([]*rbacv1.RoleBinding, error)
|
||||
}
|
||||
|
||||
type ClusterRoleGetter interface {
|
||||
GetClusterRole(name string) (*rbacv1.ClusterRole, error)
|
||||
GetClusterRole(ctx context.Context, name string) (*rbacv1.ClusterRole, error)
|
||||
}
|
||||
|
||||
type ClusterRoleBindingLister interface {
|
||||
ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error)
|
||||
ListClusterRoleBindings(ctx context.Context) ([]*rbacv1.ClusterRoleBinding, error)
|
||||
}
|
||||
|
||||
func (r *DefaultRuleResolver) RulesFor(user user.Info, namespace string) ([]rbacv1.PolicyRule, error) {
|
||||
func (r *DefaultRuleResolver) RulesFor(ctx context.Context, user user.Info, namespace string) ([]rbacv1.PolicyRule, error) {
|
||||
visitor := &ruleAccumulator{}
|
||||
r.VisitRulesFor(user, namespace, visitor.visit)
|
||||
r.VisitRulesFor(ctx, user, namespace, visitor.visit)
|
||||
return visitor.rules, utilerrors.NewAggregate(visitor.errors)
|
||||
}
|
||||
|
||||
@ -176,8 +176,8 @@ func (d *roleBindingDescriber) String() string {
|
||||
)
|
||||
}
|
||||
|
||||
func (r *DefaultRuleResolver) VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool) {
|
||||
if clusterRoleBindings, err := r.clusterRoleBindingLister.ListClusterRoleBindings(); err != nil {
|
||||
func (r *DefaultRuleResolver) VisitRulesFor(ctx context.Context, user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool) {
|
||||
if clusterRoleBindings, err := r.clusterRoleBindingLister.ListClusterRoleBindings(ctx); err != nil {
|
||||
if !visitor(nil, nil, err) {
|
||||
return
|
||||
}
|
||||
@ -188,7 +188,7 @@ func (r *DefaultRuleResolver) VisitRulesFor(user user.Info, namespace string, vi
|
||||
if !applies {
|
||||
continue
|
||||
}
|
||||
rules, err := r.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "")
|
||||
rules, err := r.GetRoleReferenceRules(ctx, clusterRoleBinding.RoleRef, "")
|
||||
if err != nil {
|
||||
if !visitor(nil, nil, err) {
|
||||
return
|
||||
@ -206,7 +206,7 @@ func (r *DefaultRuleResolver) VisitRulesFor(user user.Info, namespace string, vi
|
||||
}
|
||||
|
||||
if len(namespace) > 0 {
|
||||
if roleBindings, err := r.roleBindingLister.ListRoleBindings(namespace); err != nil {
|
||||
if roleBindings, err := r.roleBindingLister.ListRoleBindings(ctx, namespace); err != nil {
|
||||
if !visitor(nil, nil, err) {
|
||||
return
|
||||
}
|
||||
@ -217,7 +217,7 @@ func (r *DefaultRuleResolver) VisitRulesFor(user user.Info, namespace string, vi
|
||||
if !applies {
|
||||
continue
|
||||
}
|
||||
rules, err := r.GetRoleReferenceRules(roleBinding.RoleRef, namespace)
|
||||
rules, err := r.GetRoleReferenceRules(ctx, roleBinding.RoleRef, namespace)
|
||||
if err != nil {
|
||||
if !visitor(nil, nil, err) {
|
||||
return
|
||||
@ -237,17 +237,17 @@ func (r *DefaultRuleResolver) VisitRulesFor(user user.Info, namespace string, vi
|
||||
}
|
||||
|
||||
// GetRoleReferenceRules attempts to resolve the RoleBinding or ClusterRoleBinding.
|
||||
func (r *DefaultRuleResolver) GetRoleReferenceRules(roleRef rbacv1.RoleRef, bindingNamespace string) ([]rbacv1.PolicyRule, error) {
|
||||
func (r *DefaultRuleResolver) GetRoleReferenceRules(ctx context.Context, roleRef rbacv1.RoleRef, bindingNamespace string) ([]rbacv1.PolicyRule, error) {
|
||||
switch roleRef.Kind {
|
||||
case "Role":
|
||||
role, err := r.roleGetter.GetRole(bindingNamespace, roleRef.Name)
|
||||
role, err := r.roleGetter.GetRole(ctx, bindingNamespace, roleRef.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return role.Rules, nil
|
||||
|
||||
case "ClusterRole":
|
||||
clusterRole, err := r.clusterRoleGetter.GetClusterRole(roleRef.Name)
|
||||
clusterRole, err := r.clusterRoleGetter.GetClusterRole(ctx, roleRef.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -326,7 +326,7 @@ type StaticRoles struct {
|
||||
clusterRoleBindings []*rbacv1.ClusterRoleBinding
|
||||
}
|
||||
|
||||
func (r *StaticRoles) GetRole(namespace, name string) (*rbacv1.Role, error) {
|
||||
func (r *StaticRoles) GetRole(ctx context.Context, namespace, name string) (*rbacv1.Role, error) {
|
||||
if len(namespace) == 0 {
|
||||
return nil, errors.New("must provide namespace when getting role")
|
||||
}
|
||||
@ -338,7 +338,7 @@ func (r *StaticRoles) GetRole(namespace, name string) (*rbacv1.Role, error) {
|
||||
return nil, errors.New("role not found")
|
||||
}
|
||||
|
||||
func (r *StaticRoles) GetClusterRole(name string) (*rbacv1.ClusterRole, error) {
|
||||
func (r *StaticRoles) GetClusterRole(ctx context.Context, name string) (*rbacv1.ClusterRole, error) {
|
||||
for _, clusterRole := range r.clusterRoles {
|
||||
if clusterRole.Name == name {
|
||||
return clusterRole, nil
|
||||
@ -347,7 +347,7 @@ func (r *StaticRoles) GetClusterRole(name string) (*rbacv1.ClusterRole, error) {
|
||||
return nil, errors.New("clusterrole not found")
|
||||
}
|
||||
|
||||
func (r *StaticRoles) ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding, error) {
|
||||
func (r *StaticRoles) ListRoleBindings(ctx context.Context, namespace string) ([]*rbacv1.RoleBinding, error) {
|
||||
if len(namespace) == 0 {
|
||||
return nil, errors.New("must provide namespace when listing role bindings")
|
||||
}
|
||||
@ -363,6 +363,6 @@ func (r *StaticRoles) ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding,
|
||||
return roleBindingList, nil
|
||||
}
|
||||
|
||||
func (r *StaticRoles) ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error) {
|
||||
func (r *StaticRoles) ListClusterRoleBindings(ctx context.Context) ([]*rbacv1.ClusterRoleBinding, error) {
|
||||
return r.clusterRoleBindings, nil
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
// compute a hash of a policy rule so we can sort in a deterministic order
|
||||
@ -145,7 +146,7 @@ func TestDefaultRuleResolver(t *testing.T) {
|
||||
|
||||
for i, tc := range tests {
|
||||
ruleResolver := newMockRuleResolver(&tc.StaticRoles)
|
||||
rules, err := ruleResolver.RulesFor(tc.user, tc.namespace)
|
||||
rules, err := ruleResolver.RulesFor(genericapirequest.NewContext(), tc.user, tc.namespace)
|
||||
if err != nil {
|
||||
t.Errorf("case %d: GetEffectivePolicyRules(context)=%v", i, err)
|
||||
continue
|
||||
|
@ -95,7 +95,7 @@ var (
|
||||
csiNodeResource = storageapi.Resource("csinodes")
|
||||
)
|
||||
|
||||
func (r *NodeAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
func (r *NodeAuthorizer) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
if _, isNode := r.identifier.NodeIdentity(user); isNode {
|
||||
// indicate nodes do not have fully enumerated permissions
|
||||
return nil, nil, true, fmt.Errorf("node authorizer does not support user rule resolution")
|
||||
|
@ -39,12 +39,12 @@ type RequestToRuleMapper interface {
|
||||
// Any rule returned is still valid, since rules are deny by default. If you can pass with the rules
|
||||
// supplied, you do not have to fail the request. If you cannot, you should indicate the error along
|
||||
// with your denial.
|
||||
RulesFor(subject user.Info, namespace string) ([]rbacv1.PolicyRule, error)
|
||||
RulesFor(ctx context.Context, subject user.Info, namespace string) ([]rbacv1.PolicyRule, error)
|
||||
|
||||
// VisitRulesFor invokes visitor() with each rule that applies to a given user in a given namespace,
|
||||
// and each error encountered resolving those rules. Rule may be nil if err is non-nil.
|
||||
// If visitor() returns false, visiting is short-circuited.
|
||||
VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool)
|
||||
VisitRulesFor(ctx context.Context, user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool)
|
||||
}
|
||||
|
||||
type RBACAuthorizer struct {
|
||||
@ -75,7 +75,7 @@ func (v *authorizingVisitor) visit(source fmt.Stringer, rule *rbacv1.PolicyRule,
|
||||
func (r *RBACAuthorizer) Authorize(ctx context.Context, requestAttributes authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
ruleCheckingVisitor := &authorizingVisitor{requestAttributes: requestAttributes}
|
||||
|
||||
r.authorizationRuleResolver.VisitRulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace(), ruleCheckingVisitor.visit)
|
||||
r.authorizationRuleResolver.VisitRulesFor(ctx, requestAttributes.GetUser(), requestAttributes.GetNamespace(), ruleCheckingVisitor.visit)
|
||||
if ruleCheckingVisitor.allowed {
|
||||
return authorizer.DecisionAllow, ruleCheckingVisitor.reason, nil
|
||||
}
|
||||
@ -126,13 +126,13 @@ func (r *RBACAuthorizer) Authorize(ctx context.Context, requestAttributes author
|
||||
return authorizer.DecisionNoOpinion, reason, nil
|
||||
}
|
||||
|
||||
func (r *RBACAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
func (r *RBACAuthorizer) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
var (
|
||||
resourceRules []authorizer.ResourceRuleInfo
|
||||
nonResourceRules []authorizer.NonResourceRuleInfo
|
||||
)
|
||||
|
||||
policyRules, err := r.authorizationRuleResolver.RulesFor(user, namespace)
|
||||
policyRules, err := r.authorizationRuleResolver.RulesFor(ctx, user, namespace)
|
||||
for _, policyRule := range policyRules {
|
||||
if len(policyRule.Resources) > 0 {
|
||||
r := authorizer.DefaultResourceRuleInfo{
|
||||
@ -196,7 +196,7 @@ type RoleGetter struct {
|
||||
Lister rbaclisters.RoleLister
|
||||
}
|
||||
|
||||
func (g *RoleGetter) GetRole(namespace, name string) (*rbacv1.Role, error) {
|
||||
func (g *RoleGetter) GetRole(ctx context.Context, namespace, name string) (*rbacv1.Role, error) {
|
||||
return g.Lister.Roles(namespace).Get(name)
|
||||
}
|
||||
|
||||
@ -204,7 +204,7 @@ type RoleBindingLister struct {
|
||||
Lister rbaclisters.RoleBindingLister
|
||||
}
|
||||
|
||||
func (l *RoleBindingLister) ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding, error) {
|
||||
func (l *RoleBindingLister) ListRoleBindings(ctx context.Context, namespace string) ([]*rbacv1.RoleBinding, error) {
|
||||
return l.Lister.RoleBindings(namespace).List(labels.Everything())
|
||||
}
|
||||
|
||||
@ -212,7 +212,7 @@ type ClusterRoleGetter struct {
|
||||
Lister rbaclisters.ClusterRoleLister
|
||||
}
|
||||
|
||||
func (g *ClusterRoleGetter) GetClusterRole(name string) (*rbacv1.ClusterRole, error) {
|
||||
func (g *ClusterRoleGetter) GetClusterRole(ctx context.Context, name string) (*rbacv1.ClusterRole, error) {
|
||||
return g.Lister.Get(name)
|
||||
}
|
||||
|
||||
@ -220,6 +220,6 @@ type ClusterRoleBindingLister struct {
|
||||
Lister rbaclisters.ClusterRoleBindingLister
|
||||
}
|
||||
|
||||
func (l *ClusterRoleBindingLister) ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error) {
|
||||
func (l *ClusterRoleBindingLister) ListClusterRoleBindings(ctx context.Context) ([]*rbacv1.ClusterRoleBinding, error) {
|
||||
return l.Lister.List(labels.Everything())
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ limitations under the License.
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
@ -28,11 +30,11 @@ import (
|
||||
type RoleToRuleMapper interface {
|
||||
// GetRoleReferenceRules attempts to resolve the role reference of a RoleBinding or ClusterRoleBinding. The passed namespace should be the namespace
|
||||
// of the role binding, the empty string if a cluster role binding.
|
||||
GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error)
|
||||
GetRoleReferenceRules(ctx context.Context, roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error)
|
||||
}
|
||||
|
||||
type SubjectLocator interface {
|
||||
AllowedSubjects(attributes authorizer.Attributes) ([]rbacv1.Subject, error)
|
||||
AllowedSubjects(ctx context.Context, attributes authorizer.Attributes) ([]rbacv1.Subject, error)
|
||||
}
|
||||
|
||||
var _ = SubjectLocator(&SubjectAccessEvaluator{})
|
||||
@ -59,19 +61,19 @@ func NewSubjectAccessEvaluator(roles rbacregistryvalidation.RoleGetter, roleBind
|
||||
|
||||
// AllowedSubjects returns the subjects that can perform an action and any errors encountered while computing the list.
|
||||
// It is possible to have both subjects and errors returned if some rolebindings couldn't be resolved, but others could be.
|
||||
func (r *SubjectAccessEvaluator) AllowedSubjects(requestAttributes authorizer.Attributes) ([]rbacv1.Subject, error) {
|
||||
func (r *SubjectAccessEvaluator) AllowedSubjects(ctx context.Context, requestAttributes authorizer.Attributes) ([]rbacv1.Subject, error) {
|
||||
subjects := []rbacv1.Subject{{Kind: rbacv1.GroupKind, APIGroup: rbacv1.GroupName, Name: user.SystemPrivilegedGroup}}
|
||||
if len(r.superUser) > 0 {
|
||||
subjects = append(subjects, rbacv1.Subject{Kind: rbacv1.UserKind, APIGroup: rbacv1.GroupName, Name: r.superUser})
|
||||
}
|
||||
errorlist := []error{}
|
||||
|
||||
if clusterRoleBindings, err := r.clusterRoleBindingLister.ListClusterRoleBindings(); err != nil {
|
||||
if clusterRoleBindings, err := r.clusterRoleBindingLister.ListClusterRoleBindings(ctx); err != nil {
|
||||
errorlist = append(errorlist, err)
|
||||
|
||||
} else {
|
||||
for _, clusterRoleBinding := range clusterRoleBindings {
|
||||
rules, err := r.roleToRuleMapper.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "")
|
||||
rules, err := r.roleToRuleMapper.GetRoleReferenceRules(ctx, clusterRoleBinding.RoleRef, "")
|
||||
if err != nil {
|
||||
// if we have an error, just keep track of it and keep processing. Since rules are additive,
|
||||
// missing a reference is bad, but we can continue with other rolebindings and still have a list
|
||||
@ -85,12 +87,12 @@ func (r *SubjectAccessEvaluator) AllowedSubjects(requestAttributes authorizer.At
|
||||
}
|
||||
|
||||
if namespace := requestAttributes.GetNamespace(); len(namespace) > 0 {
|
||||
if roleBindings, err := r.roleBindingLister.ListRoleBindings(namespace); err != nil {
|
||||
if roleBindings, err := r.roleBindingLister.ListRoleBindings(ctx, namespace); err != nil {
|
||||
errorlist = append(errorlist, err)
|
||||
|
||||
} else {
|
||||
for _, roleBinding := range roleBindings {
|
||||
rules, err := r.roleToRuleMapper.GetRoleReferenceRules(roleBinding.RoleRef, namespace)
|
||||
rules, err := r.roleToRuleMapper.GetRoleReferenceRules(ctx, roleBinding.RoleRef, namespace)
|
||||
if err != nil {
|
||||
// if we have an error, just keep track of it and keep processing. Since rules are additive,
|
||||
// missing a reference is bad, but we can continue with other rolebindings and still have a list
|
||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@ -139,7 +140,7 @@ func TestSubjectLocator(t *testing.T) {
|
||||
ruleResolver, lister := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
||||
a := SubjectAccessEvaluator{tt.superUser, lister, lister, ruleResolver}
|
||||
for i, action := range tt.actionsToSubjects {
|
||||
actualSubjects, err := a.AllowedSubjects(action.action)
|
||||
actualSubjects, err := a.AllowedSubjects(context.Background(), action.action)
|
||||
if err != nil {
|
||||
t.Errorf("case %q %d: error %v", tt.name, i, err)
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ func (f AuthorizerFunc) Authorize(ctx context.Context, a Attributes) (Decision,
|
||||
// RuleResolver provides a mechanism for resolving the list of rules that apply to a given user within a namespace.
|
||||
type RuleResolver interface {
|
||||
// RulesFor get the list of cluster wide rules, the list of rules in the specific namespace, incomplete status and errors.
|
||||
RulesFor(user user.Info, namespace string) ([]ResourceRuleInfo, []NonResourceRuleInfo, bool, error)
|
||||
RulesFor(ctx context.Context, user user.Info, namespace string) ([]ResourceRuleInfo, []NonResourceRuleInfo, bool, error)
|
||||
}
|
||||
|
||||
// RequestAttributesGetter provides a function that extracts Attributes from an http.Request
|
||||
|
@ -33,7 +33,7 @@ func (alwaysAllowAuthorizer) Authorize(ctx context.Context, a authorizer.Attribu
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
|
||||
func (alwaysAllowAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
func (alwaysAllowAuthorizer) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
return []authorizer.ResourceRuleInfo{
|
||||
&authorizer.DefaultResourceRuleInfo{
|
||||
Verbs: []string{"*"},
|
||||
@ -61,7 +61,7 @@ func (alwaysDenyAuthorizer) Authorize(ctx context.Context, a authorizer.Attribut
|
||||
return authorizer.DecisionNoOpinion, "Everything is forbidden.", nil
|
||||
}
|
||||
|
||||
func (alwaysDenyAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
func (alwaysDenyAuthorizer) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
return []authorizer.ResourceRuleInfo{}, []authorizer.NonResourceRuleInfo{}, false, nil
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ func NewRuleResolvers(authorizationHandlers ...authorizer.RuleResolver) authoriz
|
||||
}
|
||||
|
||||
// RulesFor against a chain of authorizer.RuleResolver objects and returns nil if successful and returns error if unsuccessful
|
||||
func (authzHandler unionAuthzRulesHandler) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
func (authzHandler unionAuthzRulesHandler) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
var (
|
||||
errList []error
|
||||
resourceRulesList []authorizer.ResourceRuleInfo
|
||||
@ -86,7 +86,7 @@ func (authzHandler unionAuthzRulesHandler) RulesFor(user user.Info, namespace st
|
||||
incompleteStatus := false
|
||||
|
||||
for _, currAuthzHandler := range authzHandler {
|
||||
resourceRules, nonResourceRules, incomplete, err := currAuthzHandler.RulesFor(user, namespace)
|
||||
resourceRules, nonResourceRules, incomplete, err := currAuthzHandler.RulesFor(ctx, user, namespace)
|
||||
|
||||
if incomplete {
|
||||
incompleteStatus = true
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
type mockAuthzHandler struct {
|
||||
@ -86,7 +87,7 @@ type mockAuthzRuleHandler struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (mock *mockAuthzRuleHandler) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
func (mock *mockAuthzRuleHandler) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
if mock.err != nil {
|
||||
return []authorizer.ResourceRuleInfo{}, []authorizer.NonResourceRuleInfo{}, false, mock.err
|
||||
}
|
||||
@ -150,7 +151,7 @@ func TestAuthorizationResourceRules(t *testing.T) {
|
||||
|
||||
authzRulesHandler := NewRuleResolvers(handler1, handler2)
|
||||
|
||||
rules, _, _, _ := authzRulesHandler.RulesFor(nil, "")
|
||||
rules, _, _, _ := authzRulesHandler.RulesFor(genericapirequest.NewContext(), nil, "")
|
||||
actual := getResourceRules(rules)
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("Expected: \n%#v\n but actual: \n%#v\n", expected, actual)
|
||||
@ -189,7 +190,7 @@ func TestAuthorizationNonResourceRules(t *testing.T) {
|
||||
|
||||
authzRulesHandler := NewRuleResolvers(handler1, handler2)
|
||||
|
||||
_, rules, _, _ := authzRulesHandler.RulesFor(nil, "")
|
||||
_, rules, _, _ := authzRulesHandler.RulesFor(genericapirequest.NewContext(), nil, "")
|
||||
actual := getNonResourceRules(rules)
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("Expected: \n%#v\n but actual: \n%#v\n", expected, actual)
|
||||
|
@ -402,7 +402,7 @@ func labelSelectorToAuthorizationAPI(attr authorizer.Attributes) ([]metav1.Label
|
||||
}
|
||||
|
||||
// TODO: need to finish the method to get the rules when using webhook mode
|
||||
func (w *WebhookAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
func (w *WebhookAuthorizer) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
var (
|
||||
resourceRules []authorizer.ResourceRuleInfo
|
||||
nonResourceRules []authorizer.NonResourceRuleInfo
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacapi "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -40,6 +41,7 @@ import (
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
unionauthz "k8s.io/apiserver/pkg/authorization/union"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
@ -133,26 +135,27 @@ type bootstrapRoles struct {
|
||||
//
|
||||
// client should be authenticated as the RBAC super user.
|
||||
func (b bootstrapRoles) bootstrap(client clientset.Interface) error {
|
||||
ctx := context.TODO()
|
||||
for _, r := range b.clusterRoles {
|
||||
_, err := client.RbacV1().ClusterRoles().Create(context.TODO(), &r, metav1.CreateOptions{})
|
||||
_, err := client.RbacV1().ClusterRoles().Create(ctx, &r, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to make request: %v", err)
|
||||
}
|
||||
}
|
||||
for _, r := range b.roles {
|
||||
_, err := client.RbacV1().Roles(r.Namespace).Create(context.TODO(), &r, metav1.CreateOptions{})
|
||||
_, err := client.RbacV1().Roles(r.Namespace).Create(ctx, &r, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to make request: %v", err)
|
||||
}
|
||||
}
|
||||
for _, r := range b.clusterRoleBindings {
|
||||
_, err := client.RbacV1().ClusterRoleBindings().Create(context.TODO(), &r, metav1.CreateOptions{})
|
||||
_, err := client.RbacV1().ClusterRoleBindings().Create(ctx, &r, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to make request: %v", err)
|
||||
}
|
||||
}
|
||||
for _, r := range b.roleBindings {
|
||||
_, err := client.RbacV1().RoleBindings(r.Namespace).Create(context.TODO(), &r, metav1.CreateOptions{})
|
||||
_, err := client.RbacV1().RoleBindings(r.Namespace).Create(ctx, &r, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to make request: %v", err)
|
||||
}
|
||||
@ -817,3 +820,220 @@ func TestDiscoveryUpgradeBootstrapping(t *testing.T) {
|
||||
t.Errorf("`system:public-info-viewer` should have inherited Subjects from `system:discovery` Wanted: %v, got %v", newDiscRoleBinding.Subjects, publicInfoViewerRoleBinding.Subjects)
|
||||
}
|
||||
}
|
||||
|
||||
type authorizeRequest struct {
|
||||
ar authorizer.AttributesRecord
|
||||
expected authorizer.Decision
|
||||
}
|
||||
|
||||
// For 1.31 ctx was wired into the authorizers. This tests check that context values
|
||||
// are not used inside the code to resolve namespaces or users with the goal of
|
||||
// preventing regressions in the future.
|
||||
func TestRBACContextContamination(t *testing.T) {
|
||||
superUser := "admin/system:masters"
|
||||
validNamespace := "pod-namespace"
|
||||
invalidNamespace := "forbidden-namespace"
|
||||
|
||||
roles := bootstrapRoles{}
|
||||
testcases := []authorizeRequest{}
|
||||
|
||||
// Tests itself is bit oververbose and each case creates its own objects.
|
||||
// This makes readability bit easier over trying to overoptimize test case.
|
||||
|
||||
// Case 1: clusterrole+clusterbinding
|
||||
// should allow cluster-scoped request
|
||||
// should allow namespace-scoped request in any namespace
|
||||
// should disallow request for resource not in rules
|
||||
{
|
||||
roles.clusterRoles = append(roles.clusterRoles, rbacapi.ClusterRole{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "c1-clusterrole"},
|
||||
Rules: []rbacapi.PolicyRule{ruleReadPods},
|
||||
})
|
||||
roles.clusterRoleBindings = append(roles.clusterRoleBindings, rbacapi.ClusterRoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "c1-clusterrolebinding"},
|
||||
Subjects: []rbacapi.Subject{{Kind: "User", Name: "c1-user"}},
|
||||
RoleRef: rbacapi.RoleRef{Kind: "ClusterRole", Name: "c1-clusterrole"},
|
||||
})
|
||||
|
||||
user := &user.DefaultInfo{Name: "c1-user"}
|
||||
testcases = append(testcases, []authorizeRequest{
|
||||
{
|
||||
ar: authorizer.AttributesRecord{Verb: "list", Resource: "pods", Namespace: "", ResourceRequest: true, User: user},
|
||||
expected: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
ar: authorizer.AttributesRecord{Verb: "list", Resource: "pods", Namespace: validNamespace, ResourceRequest: true, User: user},
|
||||
expected: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
ar: authorizer.AttributesRecord{Verb: "list", Resource: "configmaps", Namespace: "", ResourceRequest: true, User: user},
|
||||
expected: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
}...,
|
||||
)
|
||||
}
|
||||
|
||||
// case 2: clusterrole+rolebinding
|
||||
// should disallow cluster-scoped request
|
||||
// should allow namespace-scoped request in rolebinding namespace
|
||||
// should disallow namespace-scoped request in other namespace
|
||||
// should disallow request for resource not in rules
|
||||
{
|
||||
roles.clusterRoles = append(roles.clusterRoles, rbacapi.ClusterRole{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "c2-clusterrole"},
|
||||
Rules: []rbacapi.PolicyRule{ruleReadPods},
|
||||
})
|
||||
roles.roleBindings = append(roles.roleBindings, rbacapi.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "c2-rolebinding",
|
||||
Namespace: validNamespace,
|
||||
},
|
||||
Subjects: []rbacapi.Subject{{Kind: "User", Name: "c2-user"}},
|
||||
RoleRef: rbacapi.RoleRef{Kind: "ClusterRole", Name: "c2-clusterrole"},
|
||||
})
|
||||
|
||||
user := &user.DefaultInfo{Name: "c2-user"}
|
||||
testcases = append(testcases, []authorizeRequest{
|
||||
{
|
||||
ar: authorizer.AttributesRecord{Verb: "list", Resource: "pods", Namespace: "", ResourceRequest: true, User: user},
|
||||
expected: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
ar: authorizer.AttributesRecord{Verb: "list", Resource: "pods", Namespace: validNamespace, ResourceRequest: true, User: user},
|
||||
expected: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
ar: authorizer.AttributesRecord{Verb: "list", Resource: "configmaps", Namespace: validNamespace, ResourceRequest: true, User: user},
|
||||
expected: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
ar: authorizer.AttributesRecord{Verb: "list", Resource: "pods", Namespace: invalidNamespace, ResourceRequest: true, User: user},
|
||||
expected: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
}...,
|
||||
)
|
||||
}
|
||||
|
||||
// case 3: role+rolebinding
|
||||
// should disallow cluster-scoped request
|
||||
// should allow namespace-scoped request in rolebinding namespace
|
||||
// should disallow namespace-scoped request in other namespace
|
||||
// should disallow request for resource not in rules
|
||||
{
|
||||
roles.roles = append(roles.roles, rbacapi.Role{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "c3-role",
|
||||
Namespace: validNamespace,
|
||||
},
|
||||
Rules: []rbacapi.PolicyRule{ruleReadPods},
|
||||
})
|
||||
roles.roleBindings = append(roles.roleBindings, rbacapi.RoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "c3-rolebinding",
|
||||
Namespace: validNamespace,
|
||||
},
|
||||
Subjects: []rbacapi.Subject{{Kind: "User", Name: "c3-user"}},
|
||||
RoleRef: rbacapi.RoleRef{Kind: "Role", Name: "c3-role"},
|
||||
})
|
||||
|
||||
user := &user.DefaultInfo{Name: "c3-user"}
|
||||
testcases = append(testcases, []authorizeRequest{
|
||||
{
|
||||
ar: authorizer.AttributesRecord{Verb: "list", Resource: "pods", Namespace: "", ResourceRequest: true, User: user},
|
||||
expected: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
ar: authorizer.AttributesRecord{Verb: "list", Resource: "pods", Namespace: validNamespace, ResourceRequest: true, User: user},
|
||||
expected: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
ar: authorizer.AttributesRecord{Verb: "list", Resource: "configmaps", Namespace: validNamespace, ResourceRequest: true, User: user},
|
||||
expected: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
ar: authorizer.AttributesRecord{Verb: "list", Resource: "pods", Namespace: invalidNamespace, ResourceRequest: true, User: user},
|
||||
expected: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
}...,
|
||||
)
|
||||
}
|
||||
|
||||
authenticator := group.NewAuthenticatedGroupAdder(bearertoken.New(tokenfile.New(map[string]*user.DefaultInfo{
|
||||
superUser: {Name: "admin", Groups: []string{"system:masters"}},
|
||||
})))
|
||||
|
||||
var tearDownAuthorizerFn func()
|
||||
defer func() {
|
||||
if tearDownAuthorizerFn != nil {
|
||||
tearDownAuthorizerFn()
|
||||
}
|
||||
}()
|
||||
var rbacAuthz authorizer.Authorizer
|
||||
_, kubeConfig, tearDownFn := framework.StartTestServer(context.Background(), t, framework.TestServerSetup{
|
||||
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
|
||||
// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
|
||||
// Also disable namespace lifecycle to workaroung the test limitation that first creates
|
||||
// roles/rolebindings and only then creates corresponding namespaces.
|
||||
opts.Admission.GenericAdmission.DisablePlugins = []string{"ServiceAccount", "NamespaceLifecycle"}
|
||||
// Disable built-in authorizers
|
||||
opts.Authorization.Modes = []string{"AlwaysDeny"}
|
||||
},
|
||||
ModifyServerConfig: func(config *controlplane.Config) {
|
||||
// Append our custom test authenticator
|
||||
config.ControlPlane.Generic.Authentication.Authenticator = unionauthn.New(config.ControlPlane.Generic.Authentication.Authenticator, authenticator)
|
||||
// Append our custom test authorizer
|
||||
rbacAuthz, tearDownAuthorizerFn = newRBACAuthorizer(t, config)
|
||||
config.ControlPlane.Generic.Authorization.Authorizer = unionauthz.New(config.ControlPlane.Generic.Authorization.Authorizer, rbacAuthz)
|
||||
},
|
||||
})
|
||||
defer tearDownFn()
|
||||
|
||||
// Bootstrap the API Server with the test case's initial roles.
|
||||
superuserClient, _ := clientsetForToken(superUser, kubeConfig)
|
||||
if err := roles.bootstrap(superuserClient); err != nil {
|
||||
t.Errorf("failed to apply initial roles: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, ns := range []string{validNamespace, invalidNamespace} {
|
||||
_, err := superuserClient.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ns,
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("failed to create namespace: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 3 cases shared for all test cases:
|
||||
// 1. Default context
|
||||
// 2. Empty namespace
|
||||
// 3. Invalid namespace in the context
|
||||
for j, r := range testcases {
|
||||
ctx := context.Background()
|
||||
// 1. Default context
|
||||
if decision, _, err := rbacAuthz.Authorize(ctx, &r.ar); err != nil {
|
||||
t.Errorf("req %d: unexpected error: %v", j, err)
|
||||
return
|
||||
} else if decision != r.expected {
|
||||
t.Errorf("req %d: expected %v, got %v", j, r.expected, decision)
|
||||
}
|
||||
// 2. Empty namespace
|
||||
if decision, _, err := rbacAuthz.Authorize(genericapirequest.WithNamespace(ctx, ""), &r.ar); err != nil {
|
||||
t.Errorf("req %d: unexpected error: %v", j, err)
|
||||
return
|
||||
} else if decision != r.expected {
|
||||
t.Errorf("req %d: expected %v, got %v", j, r.expected, decision)
|
||||
}
|
||||
// 3. Invalid namespace in the context
|
||||
if decision, _, err := rbacAuthz.Authorize(genericapirequest.WithNamespace(ctx, invalidNamespace), &r.ar); err != nil {
|
||||
t.Errorf("req %d: unexpected error: %v", j, err)
|
||||
return
|
||||
} else if decision != r.expected {
|
||||
t.Errorf("req %d: expected %v, got %v", j, r.expected, decision)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user