Switch to pointer to policy rule, visit and short circuit during authorization

This commit is contained in:
Jordan Liggitt
2017-04-13 10:33:28 -04:00
parent 2c6fbc95c4
commit 67360883bc
7 changed files with 176 additions and 32 deletions

View File

@@ -24,6 +24,7 @@ import (
"bytes"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/kubernetes/pkg/apis/rbac"
@@ -36,15 +37,41 @@ type RequestToRuleMapper interface {
// 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) ([]rbac.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(rule *rbac.PolicyRule, err error) bool)
}
type RBACAuthorizer struct {
authorizationRuleResolver RequestToRuleMapper
}
// authorizingVisitor short-circuits once allowed, and collects any resolution errors encountered
type authorizingVisitor struct {
requestAttributes authorizer.Attributes
allowed bool
errors []error
}
func (v *authorizingVisitor) visit(rule *rbac.PolicyRule, err error) bool {
if rule != nil && RuleAllows(v.requestAttributes, rule) {
v.allowed = true
return false
}
if err != nil {
v.errors = append(v.errors, err)
}
return true
}
func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (bool, string, error) {
rules, ruleResolutionError := r.authorizationRuleResolver.RulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace())
if RulesAllow(requestAttributes, rules...) {
ruleCheckingVisitor := &authorizingVisitor{requestAttributes: requestAttributes}
r.authorizationRuleResolver.VisitRulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace(), ruleCheckingVisitor.visit)
if ruleCheckingVisitor.allowed {
return true, "", nil
}
@@ -88,8 +115,8 @@ func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (boo
}
reason := ""
if ruleResolutionError != nil {
reason = fmt.Sprintf("%v", ruleResolutionError)
if len(ruleCheckingVisitor.errors) > 0 {
reason = fmt.Sprintf("%v", utilerrors.NewAggregate(ruleCheckingVisitor.errors))
}
return false, reason, nil
}
@@ -104,8 +131,8 @@ func New(roles rbacregistryvalidation.RoleGetter, roleBindings rbacregistryvalid
}
func RulesAllow(requestAttributes authorizer.Attributes, rules ...rbac.PolicyRule) bool {
for _, rule := range rules {
if RuleAllows(requestAttributes, rule) {
for i := range rules {
if RuleAllows(requestAttributes, &rules[i]) {
return true
}
}
@@ -113,7 +140,7 @@ func RulesAllow(requestAttributes authorizer.Attributes, rules ...rbac.PolicyRul
return false
}
func RuleAllows(requestAttributes authorizer.Attributes, rule rbac.PolicyRule) bool {
func RuleAllows(requestAttributes authorizer.Attributes, rule *rbac.PolicyRule) bool {
if requestAttributes.IsResourceRequest() {
resource := requestAttributes.GetResource()
if len(requestAttributes.GetSubresource()) > 0 {