-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds ruleResolvers for PRTBs and CRTBs.
- Loading branch information
1 parent
2619688
commit f3573f6
Showing
11 changed files
with
252 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package resolvers | ||
|
||
import ( | ||
"fmt" | ||
|
||
rbacv1 "k8s.io/api/rbac/v1" | ||
"k8s.io/apiserver/pkg/authentication/user" | ||
"k8s.io/kubernetes/pkg/registry/rbac/validation" | ||
) | ||
|
||
// AggregateRuleResolver conforms to the rbac/validation.AuthorizationRuleResolver interface and is used to aggregate multiple other AuthorizationRuleResolver into one resolver. | ||
type AggregateRuleResolver struct { | ||
resolvers []validation.AuthorizationRuleResolver | ||
} | ||
|
||
// NewAggregateRuleResolver creates a new AggregateRuleResolver that will combine the outputs of all resolvers provided. | ||
func NewAggregateRuleResolver(resolvers ...validation.AuthorizationRuleResolver) *AggregateRuleResolver { | ||
return &AggregateRuleResolver{ | ||
resolvers: resolvers, | ||
} | ||
} | ||
|
||
// GetRoleReferenceRules calls GetRoleReferenceRules on each resolver and returns all returned rules and errors. | ||
func (a *AggregateRuleResolver) GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error) { | ||
visitor := &ruleAccumulator{} | ||
for _, resolver := range a.resolvers { | ||
rules, err := resolver.GetRoleReferenceRules(roleRef, namespace) | ||
visitRules(nil, rules, err, visitor.visit) | ||
} | ||
return visitor.rules, visitor.getError() | ||
} | ||
|
||
// RulesFor returns the list of rules that apply to a given user in a given namespace and error for all Resolvers. 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. | ||
func (a *AggregateRuleResolver) RulesFor(user user.Info, namespace string) (rules []rbacv1.PolicyRule, retError error) { | ||
visitor := &ruleAccumulator{} | ||
a.VisitRulesFor(user, namespace, visitor.visit) | ||
return visitor.rules, visitor.getError() | ||
} | ||
|
||
// VisitRulesFor invokes VisitRulesFor() on each resolver. | ||
// If visitor() returns false, visiting is short-circuited for that resolver. | ||
func (a *AggregateRuleResolver) VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool) { | ||
for _, resolver := range a.resolvers { | ||
resolver.VisitRulesFor(user, namespace, visitor) | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package resolvers | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/rancher/webhook/pkg/auth" | ||
v3 "github.com/rancher/webhook/pkg/generated/controllers/management.cattle.io/v3" | ||
rbacv1 "k8s.io/api/rbac/v1" | ||
"k8s.io/apimachinery/pkg/labels" | ||
"k8s.io/apiserver/pkg/authentication/user" | ||
) | ||
|
||
// CRTBRuleResolver implements the rbacv1.AuthorizationRuleResolver interface. | ||
type CRTBRuleResolver struct { | ||
ClusterRoleTemplateBindings v3.ClusterRoleTemplateBindingCache | ||
RoleTemplateResolver *auth.RoleTemplateResolver | ||
} | ||
|
||
// NewCRTBRuleResolver returns a new resolver for resolving rules given through ClusterRoleTemplateBindings. | ||
func NewCRTBRuleResolver(crtbCache v3.ClusterRoleTemplateBindingCache, roleTemplateResolver *auth.RoleTemplateResolver) *CRTBRuleResolver { | ||
return &CRTBRuleResolver{ | ||
ClusterRoleTemplateBindings: crtbCache, | ||
RoleTemplateResolver: roleTemplateResolver, | ||
} | ||
} | ||
|
||
// GetRoleReferenceRules is used to find which roles are granted by a rolebinding/clusterrolebinding. Since we don't | ||
// use these primitives to refer to role templates, we don't have to implement this method. | ||
func (c *CRTBRuleResolver) GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error) { | ||
return nil, ErrUnimplemented | ||
} | ||
|
||
// 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. | ||
func (c *CRTBRuleResolver) RulesFor(user user.Info, namespace string) (rules []rbacv1.PolicyRule, retError error) { | ||
visitor := &ruleAccumulator{} | ||
c.VisitRulesFor(user, namespace, visitor.visit) | ||
return visitor.rules, visitor.getError() | ||
} | ||
|
||
// 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. | ||
func (c *CRTBRuleResolver) VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool) { | ||
crtbs, err := c.ClusterRoleTemplateBindings.List(namespace, labels.Everything()) | ||
if err != nil { | ||
visitor(nil, nil, err) | ||
} | ||
|
||
for _, crtb := range crtbs { | ||
if crtb.UserName != user.GetName() { | ||
continue | ||
} | ||
rtRules, err := c.RoleTemplateResolver.RulesFromTemplateName(crtb.RoleTemplateName) | ||
if !visitRules(nil, rtRules, err, visitor) { | ||
return | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package resolvers | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/rancher/webhook/pkg/auth" | ||
v3 "github.com/rancher/webhook/pkg/generated/controllers/management.cattle.io/v3" | ||
rbacv1 "k8s.io/api/rbac/v1" | ||
"k8s.io/apimachinery/pkg/labels" | ||
"k8s.io/apiserver/pkg/authentication/user" | ||
) | ||
|
||
// PRTBRuleResolver implements the validation.AuthorizationRuleResolver interface. | ||
type PRTBRuleResolver struct { | ||
ProjectRoleTemplateBindings v3.ProjectRoleTemplateBindingCache | ||
RoleTemplateResolver *auth.RoleTemplateResolver | ||
} | ||
|
||
// NewPRTBRuleResolver will create a new PRTBRuleResolver. | ||
func NewPRTBRuleResolver(prtb v3.ProjectRoleTemplateBindingCache, roleTemplateResolver *auth.RoleTemplateResolver) *PRTBRuleResolver { | ||
return &PRTBRuleResolver{ | ||
ProjectRoleTemplateBindings: prtb, | ||
RoleTemplateResolver: roleTemplateResolver, | ||
} | ||
} | ||
|
||
// GetRoleReferenceRules is used to find which roles are granted by a rolebinding/clusterrolebinding. Since we don't | ||
// use these primitives to refer to role templates, we don't have to implement this method. | ||
func (p *PRTBRuleResolver) GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error) { | ||
return nil, ErrUnimplemented | ||
} | ||
|
||
// 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. | ||
func (p *PRTBRuleResolver) RulesFor(user user.Info, namespace string) ([]rbacv1.PolicyRule, error) { | ||
visitor := &ruleAccumulator{} | ||
p.VisitRulesFor(user, namespace, visitor.visit) | ||
return visitor.rules, visitor.getError() | ||
} | ||
|
||
// 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. | ||
func (p *PRTBRuleResolver) VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool) { | ||
prtbs, err := p.ProjectRoleTemplateBindings.List(namespace, labels.Everything()) | ||
if err != nil { | ||
visitor(nil, nil, err) | ||
} | ||
|
||
for _, prtb := range prtbs { | ||
if prtb.UserName != user.GetName() { | ||
continue | ||
} | ||
rtRules, err := p.RoleTemplateResolver.RulesFromTemplateName(prtb.RoleTemplateName) | ||
if !visitRules(nil, rtRules, err, visitor) { | ||
return | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package resolvers | ||
|
||
// TODO scrap request for test cases |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// Package resolvers resolves what rules different users and roleTemplates our bound to | ||
package resolvers | ||
|
||
import ( | ||
"fmt" | ||
|
||
rbacv1 "k8s.io/api/rbac/v1" | ||
) | ||
|
||
// ErrUnimplemented is an error returned when a function is not implemented. | ||
var ErrUnimplemented = fmt.Errorf("not implemented") | ||
|
||
// ruleAccumulator based off kubernetes struct | ||
// https://github.com/kubernetes/kubernetes/blob/d5fdf3135e7c99e5f81e67986ae930f6a2ffb047/pkg/registry/rbac/validation/rule.go#L124#L137 | ||
type ruleAccumulator struct { | ||
rules []rbacv1.PolicyRule | ||
errors []error | ||
} | ||
|
||
func (r *ruleAccumulator) visit(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool { | ||
if rule != nil { | ||
r.rules = append(r.rules, *rule) | ||
} | ||
if err != nil { | ||
r.errors = append(r.errors, err) | ||
} | ||
return true | ||
} | ||
|
||
// getError will combine all of the recorded errors into a single error. | ||
func (r *ruleAccumulator) getError() error { | ||
if len(r.errors) == 0 { | ||
return nil | ||
} | ||
if len(r.errors) == 1 { | ||
return r.errors[0] | ||
} | ||
var errorStr string | ||
for _, err := range r.errors { | ||
errorStr += fmt.Sprintf(", %s", err.Error()) | ||
} | ||
const leadingChars = 2 | ||
return fmt.Errorf("[%s]", errorStr[leadingChars:]) | ||
} | ||
|
||
// visitRules calls visitor on each rule in the list with the given Stringer and error. | ||
func visitRules(source fmt.Stringer, rules []rbacv1.PolicyRule, err error, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool) bool { | ||
if err != nil && rules == nil { | ||
return visitor(source, nil, err) | ||
} | ||
for i := range rules { | ||
// we do not care about the return here | ||
if !visitor(source, &rules[i], err) { | ||
return false | ||
} | ||
} | ||
return true | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.