mirror of
https://github.com/kubernetes/kubernetes.git
synced 2026-05-28 04:04:39 -04:00
Adapt the codebase to the Authorizer interface change
This commit is contained in:
parent
6d78dfd60c
commit
69a8b4dd7a
27 changed files with 290 additions and 53 deletions
|
|
@ -241,6 +241,16 @@ func (pl PolicyList) Authorize(ctx context.Context, a authorizer.Attributes) (au
|
|||
// Then, add Caching only if needed.
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (pl PolicyList) ConditionsAwareAuthorize(ctx context.Context, a authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(pl.Authorize(ctx, a))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (PolicyList) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
// RulesFor returns rules for the given user and namespace.
|
||||
func (pl PolicyList) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ func BuildGenericConfig(
|
|||
}
|
||||
|
||||
// BuildAuthorizer constructs the authorizer. If authorization is not set in s, it returns nil, nil, false, nil
|
||||
func BuildAuthorizer(ctx context.Context, s options.CompletedOptions, egressSelector *egressselector.EgressSelector, apiserverID string, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.UnconditionalAuthorizer, authorizer.RuleResolver, bool, error) {
|
||||
func BuildAuthorizer(ctx context.Context, s options.CompletedOptions, egressSelector *egressselector.EgressSelector, apiserverID string, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.Authorizer, authorizer.RuleResolver, bool, error) {
|
||||
authorizationConfig, err := s.Authorization.ToAuthorizationConfig(versionedInformers)
|
||||
if err != nil {
|
||||
return nil, nil, false, err
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ type Config struct {
|
|||
// stopCh is used to shut down config reload goroutines when the server is shutting down.
|
||||
//
|
||||
// Note: the cel compiler construction depends on feature gates and the compatibility version to be initialized.
|
||||
func (config Config) New(ctx context.Context, serverID string) (authorizer.UnconditionalAuthorizer, authorizer.RuleResolver, error) {
|
||||
func (config Config) New(ctx context.Context, serverID string) (authorizer.Authorizer, authorizer.RuleResolver, error) {
|
||||
if len(config.AuthorizationConfiguration.Authorizers) == 0 {
|
||||
return nil, nil, fmt.Errorf("at least one authorization mode must be passed")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ type reloadableAuthorizerResolver struct {
|
|||
}
|
||||
|
||||
type authorizerResolver struct {
|
||||
authorizer authorizer.UnconditionalAuthorizer
|
||||
authorizer authorizer.Authorizer
|
||||
ruleResolver authorizer.RuleResolver
|
||||
}
|
||||
|
||||
|
|
@ -82,18 +82,28 @@ func (r *reloadableAuthorizerResolver) Authorize(ctx context.Context, a authoriz
|
|||
return r.current.Load().authorizer.Authorize(ctx, a)
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize delegates to the current authorizer.
|
||||
func (r *reloadableAuthorizerResolver) ConditionsAwareAuthorize(ctx context.Context, a authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return r.current.Load().authorizer.ConditionsAwareAuthorize(ctx, a)
|
||||
}
|
||||
|
||||
// EvaluateConditions delegates to the current authorizer.
|
||||
func (r *reloadableAuthorizerResolver) EvaluateConditions(ctx context.Context, decision authorizer.ConditionsAwareDecision, data authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return r.current.Load().authorizer.EvaluateConditions(ctx, decision, data)
|
||||
}
|
||||
|
||||
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
|
||||
func (r *reloadableAuthorizerResolver) newForConfig(authzConfig *authzconfig.AuthorizationConfiguration) (authorizer.UnconditionalAuthorizer, authorizer.RuleResolver, error) {
|
||||
func (r *reloadableAuthorizerResolver) newForConfig(authzConfig *authzconfig.AuthorizationConfiguration) (authorizer.Authorizer, authorizer.RuleResolver, error) {
|
||||
if len(authzConfig.Authorizers) == 0 {
|
||||
return nil, nil, fmt.Errorf("at least one authorization mode must be passed")
|
||||
}
|
||||
|
||||
var (
|
||||
authorizers []authorizer.UnconditionalAuthorizer
|
||||
authorizers []authorizer.Authorizer
|
||||
ruleResolvers []authorizer.RuleResolver
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ func TestAuthorization(t *testing.T) {
|
|||
name string
|
||||
userInfo user.Info
|
||||
obj *admissionregistration.MutatingAdmissionPolicy
|
||||
auth AuthFunc
|
||||
auth authorizer.AuthorizerFunc
|
||||
resourceResolver resolver.ResourceResolverFunc
|
||||
expectErr bool
|
||||
}{
|
||||
|
|
@ -123,9 +123,3 @@ func TestAuthorization(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
type AuthFunc func(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error)
|
||||
|
||||
func (f AuthFunc) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||
return f(ctx, a)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ func TestAuthorization(t *testing.T) {
|
|||
for _, tc := range []struct {
|
||||
name string
|
||||
userInfo user.Info
|
||||
auth AuthFunc
|
||||
auth authorizer.AuthorizerFunc
|
||||
policyGetter PolicyGetterFunc
|
||||
resourceResolver resolver.ResourceResolverFunc
|
||||
expectErrContains string
|
||||
|
|
@ -242,12 +242,6 @@ func TestAuthorization(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
type AuthFunc func(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error)
|
||||
|
||||
func (f AuthFunc) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||
return f(ctx, a)
|
||||
}
|
||||
|
||||
type PolicyGetterFunc func(ctx context.Context, name string) (*admissionregistration.MutatingAdmissionPolicy, error)
|
||||
|
||||
func (f PolicyGetterFunc) GetMutatingAdmissionPolicy(ctx context.Context, name string) (*admissionregistration.MutatingAdmissionPolicy, error) {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ func TestAuthorization(t *testing.T) {
|
|||
name string
|
||||
userInfo user.Info
|
||||
obj *admissionregistration.ValidatingAdmissionPolicy
|
||||
auth AuthFunc
|
||||
auth authorizer.AuthorizerFunc
|
||||
resourceResolver resolver.ResourceResolverFunc
|
||||
expectErr bool
|
||||
}{
|
||||
|
|
@ -122,9 +122,3 @@ func TestAuthorization(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
type AuthFunc func(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error)
|
||||
|
||||
func (f AuthFunc) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||
return f(ctx, a)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ func TestAuthorization(t *testing.T) {
|
|||
for _, tc := range []struct {
|
||||
name string
|
||||
userInfo user.Info
|
||||
auth AuthFunc
|
||||
auth authorizer.AuthorizerFunc
|
||||
policyGetter PolicyGetterFunc
|
||||
resourceResolver resolver.ResourceResolverFunc
|
||||
expectErrContains string
|
||||
|
|
@ -220,12 +220,6 @@ func TestAuthorization(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
type AuthFunc func(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error)
|
||||
|
||||
func (f AuthFunc) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||
return f(ctx, a)
|
||||
}
|
||||
|
||||
type PolicyGetterFunc func(ctx context.Context, name string) (*admissionregistration.ValidatingAdmissionPolicy, error)
|
||||
|
||||
func (f PolicyGetterFunc) GetValidatingAdmissionPolicy(ctx context.Context, name string) (*admissionregistration.ValidatingAdmissionPolicy, error) {
|
||||
|
|
|
|||
|
|
@ -106,6 +106,16 @@ func (r *NodeAuthorizer) RulesFor(ctx context.Context, user user.Info, namespace
|
|||
return nil, nil, false, nil
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (r *NodeAuthorizer) ConditionsAwareAuthorize(ctx context.Context, attrs authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(r.Authorize(ctx, attrs))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (*NodeAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
func (r *NodeAuthorizer) Authorize(ctx context.Context, attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
nodeName, isNode := r.identifier.NodeIdentity(attrs.GetUser())
|
||||
if !isNode {
|
||||
|
|
|
|||
|
|
@ -129,6 +129,16 @@ func (r *RBACAuthorizer) Authorize(ctx context.Context, requestAttributes author
|
|||
return authorizer.DecisionNoOpinion, reason, nil
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (r *RBACAuthorizer) ConditionsAwareAuthorize(ctx context.Context, requestAttributes authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(r.Authorize(ctx, requestAttributes))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (*RBACAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
func (r *RBACAuthorizer) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
var (
|
||||
resourceRules []authorizer.ResourceRuleInfo
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ type authzResult struct {
|
|||
err error
|
||||
}
|
||||
|
||||
var _ = authorizer.Authorizer(&cachingAuthorizer{})
|
||||
// For now, secondary authorization checks in admission only support unconditional authorization
|
||||
var _ = authorizer.UnconditionalAuthorizer(&cachingAuthorizer{})
|
||||
|
||||
type cachingAuthorizer struct {
|
||||
authorizer authorizer.UnconditionalAuthorizer
|
||||
|
|
|
|||
|
|
@ -36,6 +36,16 @@ func (alwaysAllowAuthorizer) Authorize(ctx context.Context, a authorizer.Attribu
|
|||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (a alwaysAllowAuthorizer) ConditionsAwareAuthorize(ctx context.Context, attrs authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(a.Authorize(ctx, attrs))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (alwaysAllowAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
func (alwaysAllowAuthorizer) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
return []authorizer.ResourceRuleInfo{
|
||||
&authorizer.DefaultResourceRuleInfo{
|
||||
|
|
@ -67,6 +77,16 @@ func (alwaysDenyAuthorizer) Authorize(ctx context.Context, a authorizer.Attribut
|
|||
return authorizer.DecisionNoOpinion, "Everything is forbidden.", nil
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (d alwaysDenyAuthorizer) ConditionsAwareAuthorize(ctx context.Context, attrs authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(d.Authorize(ctx, attrs))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (alwaysDenyAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
func (alwaysDenyAuthorizer) RulesFor(ctx context.Context, user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||
return []authorizer.ResourceRuleInfo{}, []authorizer.NonResourceRuleInfo{}, false, nil
|
||||
}
|
||||
|
|
@ -81,6 +101,16 @@ type privilegedGroupAuthorizer struct {
|
|||
groups []string
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (r *privilegedGroupAuthorizer) ConditionsAwareAuthorize(ctx context.Context, attr authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(r.Authorize(ctx, attr))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (r *privilegedGroupAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
func (r *privilegedGroupAuthorizer) Authorize(ctx context.Context, attr authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
if attr.GetUser() == nil {
|
||||
return authorizer.DecisionNoOpinion, "Error", errors.New("no user on request.")
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ type DelegatingAuthorizerConfig struct {
|
|||
WebhookRetryBackoff *wait.Backoff
|
||||
}
|
||||
|
||||
func (c DelegatingAuthorizerConfig) New() (authorizer.UnconditionalAuthorizer, error) {
|
||||
func (c DelegatingAuthorizerConfig) New() (authorizer.Authorizer, error) {
|
||||
if c.WebhookRetryBackoff == nil {
|
||||
return nil, errors.New("retry backoff parameters for delegating authorization webhook has not been specified")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ func RecordAuthorizationDecision(authorizerType, authorizerName, decision string
|
|||
authorizationDecisionsTotal.WithLabelValues(authorizerType, authorizerName, decision).Inc()
|
||||
}
|
||||
|
||||
func InstrumentedAuthorizer(authorizerType string, authorizerName string, delegate authorizer.UnconditionalAuthorizer) authorizer.UnconditionalAuthorizer {
|
||||
func InstrumentedAuthorizer(authorizerType string, authorizerName string, delegate authorizer.Authorizer) authorizer.Authorizer {
|
||||
RegisterMetrics()
|
||||
return &instrumentedAuthorizer{
|
||||
authorizerType: string(authorizerType),
|
||||
|
|
@ -73,7 +73,7 @@ var _ = authorizer.Authorizer(&instrumentedAuthorizer{})
|
|||
type instrumentedAuthorizer struct {
|
||||
authorizerType string
|
||||
authorizerName string
|
||||
delegate authorizer.UnconditionalAuthorizer
|
||||
delegate authorizer.Authorizer
|
||||
}
|
||||
|
||||
func (a *instrumentedAuthorizer) Authorize(ctx context.Context, attributes authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
|
|
@ -92,3 +92,42 @@ func (a *instrumentedAuthorizer) Authorize(ctx context.Context, attributes autho
|
|||
}
|
||||
return decision, reason, err
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize delegates to the wrapped authorizer.
|
||||
func (a *instrumentedAuthorizer) ConditionsAwareAuthorize(ctx context.Context, attributes authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
decision := a.delegate.ConditionsAwareAuthorize(ctx, attributes)
|
||||
switch {
|
||||
case decision.IsNoOpinion():
|
||||
// non-terminal, not reported
|
||||
case decision.IsAllowed():
|
||||
// matches SubjectAccessReview status.allowed field name
|
||||
RecordAuthorizationDecision(a.authorizerType, a.authorizerName, "allowed")
|
||||
case decision.IsDenied():
|
||||
// matches SubjectAccessReview status.denied field name
|
||||
RecordAuthorizationDecision(a.authorizerType, a.authorizerName, "denied")
|
||||
default:
|
||||
// the ConditionsAwareDecision enforces that there are no other possible states
|
||||
// than Allow/Deny/NoOpinion/ConditionsMap/Union. The latter two are conditional
|
||||
// decisions.
|
||||
RecordAuthorizationDecision(a.authorizerType, a.authorizerName, "conditional")
|
||||
}
|
||||
return decision
|
||||
}
|
||||
|
||||
// EvaluateConditions delegates to the wrapped authorizer, and registers the metric just like Authorize.
|
||||
func (a *instrumentedAuthorizer) EvaluateConditions(ctx context.Context, unevaluatedDecision authorizer.ConditionsAwareDecision, data authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
decision, reason, err := a.delegate.EvaluateConditions(ctx, unevaluatedDecision, data)
|
||||
switch decision {
|
||||
case authorizer.DecisionNoOpinion:
|
||||
// non-terminal, not reported
|
||||
case authorizer.DecisionAllow:
|
||||
// matches SubjectAccessReview status.allowed field name
|
||||
RecordAuthorizationDecision(a.authorizerType, a.authorizerName, "allowed")
|
||||
case authorizer.DecisionDeny:
|
||||
// matches SubjectAccessReview status.denied field name
|
||||
RecordAuthorizationDecision(a.authorizerType, a.authorizerName, "denied")
|
||||
default:
|
||||
RecordAuthorizationDecision(a.authorizerType, a.authorizerName, "unknown")
|
||||
}
|
||||
return decision, reason, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ func TestRecordAuthorizationDecisionsTotal(t *testing.T) {
|
|||
RegisterMetrics()
|
||||
|
||||
dummyAuthorizer := &dummyAuthorizer{}
|
||||
dummyConditionalAuthorizer := &dummyConditionalAuthorizer{}
|
||||
a := InstrumentedAuthorizer("mytype", "myname", dummyAuthorizer)
|
||||
ac := InstrumentedAuthorizer("myconditionaltype", "myconditionalname", dummyConditionalAuthorizer)
|
||||
|
||||
// allow
|
||||
{
|
||||
|
|
@ -53,6 +55,19 @@ func TestRecordAuthorizationDecisionsTotal(t *testing.T) {
|
|||
authorizationDecisionsTotal.Reset()
|
||||
}
|
||||
|
||||
// allow (conditional authorizer)
|
||||
{
|
||||
dummyConditionalAuthorizer.authorizeDecision = authorizer.ConditionsAwareDecisionAllow("", nil)
|
||||
_, _, _ = ac.Authorize(context.Background(), nil)
|
||||
expectedValue := prefix + `
|
||||
apiserver_authorization_decisions_total{decision="allowed",name="myconditionalname",type="myconditionaltype"} 1
|
||||
`
|
||||
if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(expectedValue), metrics...); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
authorizationDecisionsTotal.Reset()
|
||||
}
|
||||
|
||||
// deny
|
||||
{
|
||||
dummyAuthorizer.decision = authorizer.DecisionDeny
|
||||
|
|
@ -67,6 +82,20 @@ func TestRecordAuthorizationDecisionsTotal(t *testing.T) {
|
|||
authorizationDecisionsTotal.Reset()
|
||||
}
|
||||
|
||||
// deny (conditional authorizer)
|
||||
{
|
||||
dummyConditionalAuthorizer.authorizeDecision = authorizer.ConditionsAwareDecisionDeny("", nil)
|
||||
_, _, _ = ac.Authorize(context.Background(), nil)
|
||||
_, _, _ = ac.Authorize(context.Background(), nil)
|
||||
expectedValue := prefix + `
|
||||
apiserver_authorization_decisions_total{decision="denied",name="myconditionalname",type="myconditionaltype"} 2
|
||||
`
|
||||
if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(expectedValue), metrics...); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
authorizationDecisionsTotal.Reset()
|
||||
}
|
||||
|
||||
// no-opinion emits no metric
|
||||
{
|
||||
dummyAuthorizer.decision = authorizer.DecisionNoOpinion
|
||||
|
|
@ -80,6 +109,19 @@ func TestRecordAuthorizationDecisionsTotal(t *testing.T) {
|
|||
authorizationDecisionsTotal.Reset()
|
||||
}
|
||||
|
||||
// no-opinion emits no metric (conditional authorizer)
|
||||
{
|
||||
dummyConditionalAuthorizer.authorizeDecision = authorizer.ConditionsAwareDecisionNoOpinion("", nil)
|
||||
_, _, _ = ac.Authorize(context.Background(), nil)
|
||||
_, _, _ = ac.Authorize(context.Background(), nil)
|
||||
expectedValue := prefix + `
|
||||
`
|
||||
if err := testutil.GatherAndCompare(legacyregistry.DefaultGatherer, strings.NewReader(expectedValue), metrics...); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
authorizationDecisionsTotal.Reset()
|
||||
}
|
||||
|
||||
// unknown decision emits a metric
|
||||
{
|
||||
dummyAuthorizer.decision = authorizer.DecisionDeny + 10
|
||||
|
|
@ -92,7 +134,7 @@ func TestRecordAuthorizationDecisionsTotal(t *testing.T) {
|
|||
}
|
||||
authorizationDecisionsTotal.Reset()
|
||||
}
|
||||
|
||||
// TODO(luxas): Add a test for getting a conditional decision from ConditionsAwareAuthorize, and evaluating a condition, once introduced
|
||||
}
|
||||
|
||||
type dummyAuthorizer struct {
|
||||
|
|
@ -103,3 +145,31 @@ type dummyAuthorizer struct {
|
|||
func (d *dummyAuthorizer) Authorize(ctx context.Context, attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
return d.decision, "", d.err
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (d *dummyAuthorizer) ConditionsAwareAuthorize(ctx context.Context, attrs authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(d.Authorize(ctx, attrs))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (*dummyAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
type dummyConditionalAuthorizer struct {
|
||||
authorizeDecision authorizer.ConditionsAwareDecision
|
||||
evalDecision authorizer.Decision
|
||||
evalErr error
|
||||
}
|
||||
|
||||
func (d *dummyConditionalAuthorizer) Authorize(ctx context.Context, attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
return d.ConditionsAwareAuthorize(ctx, attrs).UnconditionalParts()
|
||||
}
|
||||
|
||||
func (d *dummyConditionalAuthorizer) ConditionsAwareAuthorize(ctx context.Context, attrs authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return d.authorizeDecision
|
||||
}
|
||||
|
||||
func (d *dummyConditionalAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return d.evalDecision, "", d.evalErr
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import (
|
|||
|
||||
// NewAuthorizer returns an authorizer which accepts a given set of paths.
|
||||
// Each path is either a fully matching path or it ends in * in case a prefix match is done. A leading / is optional.
|
||||
func NewAuthorizer(alwaysAllowPaths []string) (authorizer.UnconditionalAuthorizer, error) {
|
||||
func NewAuthorizer(alwaysAllowPaths []string) (authorizer.Authorizer, error) {
|
||||
var prefixes []string
|
||||
paths := sets.NewString()
|
||||
for _, p := range alwaysAllowPaths {
|
||||
|
|
|
|||
|
|
@ -36,10 +36,10 @@ import (
|
|||
var _ = authorizer.Authorizer(unionAuthzHandler{})
|
||||
|
||||
// unionAuthzHandler authorizer against a chain of authorizer.Authorizer
|
||||
type unionAuthzHandler []authorizer.UnconditionalAuthorizer
|
||||
type unionAuthzHandler []authorizer.Authorizer
|
||||
|
||||
// New returns an authorizer that authorizes against a chain of authorizer.Authorizer objects
|
||||
func New(authorizationHandlers ...authorizer.UnconditionalAuthorizer) authorizer.UnconditionalAuthorizer {
|
||||
func New(authorizationHandlers ...authorizer.Authorizer) authorizer.Authorizer {
|
||||
return unionAuthzHandler(authorizationHandlers)
|
||||
}
|
||||
|
||||
|
|
@ -70,6 +70,16 @@ func (authzHandler unionAuthzHandler) Authorize(ctx context.Context, a authorize
|
|||
return authorizer.DecisionNoOpinion, strings.Join(reasonlist, "\n"), utilerrors.NewAggregate(errlist)
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (authzHandler unionAuthzHandler) ConditionsAwareAuthorize(ctx context.Context, a authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(authzHandler.Authorize(ctx, a))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (unionAuthzHandler) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
// unionAuthzRulesHandler authorizer against a chain of authorizer.RuleResolver
|
||||
type unionAuthzRulesHandler []authorizer.RuleResolver
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,16 @@ func (mock *mockAuthzHandler) Authorize(ctx context.Context, a authorizer.Attrib
|
|||
return mock.decision, "", mock.err
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (mock *mockAuthzHandler) ConditionsAwareAuthorize(ctx context.Context, a authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(mock.Authorize(ctx, a))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (*mockAuthzHandler) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
func TestAuthorizationSecondPasses(t *testing.T) {
|
||||
handler1 := &mockAuthzHandler{decision: authorizer.DecisionNoOpinion}
|
||||
handler2 := &mockAuthzHandler{decision: authorizer.DecisionAllow}
|
||||
|
|
@ -223,15 +233,15 @@ func getNonResourceRules(infos []authorizer.NonResourceRuleInfo) []authorizer.De
|
|||
|
||||
func TestAuthorizationUnequivocalDeny(t *testing.T) {
|
||||
cs := []struct {
|
||||
authorizers []authorizer.UnconditionalAuthorizer
|
||||
authorizers []authorizer.Authorizer
|
||||
decision authorizer.Decision
|
||||
}{
|
||||
{
|
||||
authorizers: []authorizer.UnconditionalAuthorizer{},
|
||||
authorizers: []authorizer.Authorizer{},
|
||||
decision: authorizer.DecisionNoOpinion,
|
||||
},
|
||||
{
|
||||
authorizers: []authorizer.UnconditionalAuthorizer{
|
||||
authorizers: []authorizer.Authorizer{
|
||||
&mockAuthzHandler{decision: authorizer.DecisionNoOpinion},
|
||||
&mockAuthzHandler{decision: authorizer.DecisionAllow},
|
||||
&mockAuthzHandler{decision: authorizer.DecisionDeny},
|
||||
|
|
@ -239,7 +249,7 @@ func TestAuthorizationUnequivocalDeny(t *testing.T) {
|
|||
decision: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
authorizers: []authorizer.UnconditionalAuthorizer{
|
||||
authorizers: []authorizer.Authorizer{
|
||||
&mockAuthzHandler{decision: authorizer.DecisionNoOpinion},
|
||||
&mockAuthzHandler{decision: authorizer.DecisionDeny},
|
||||
&mockAuthzHandler{decision: authorizer.DecisionAllow},
|
||||
|
|
@ -247,7 +257,7 @@ func TestAuthorizationUnequivocalDeny(t *testing.T) {
|
|||
decision: authorizer.DecisionDeny,
|
||||
},
|
||||
{
|
||||
authorizers: []authorizer.UnconditionalAuthorizer{
|
||||
authorizers: []authorizer.Authorizer{
|
||||
&mockAuthzHandler{decision: authorizer.DecisionNoOpinion},
|
||||
&mockAuthzHandler{decision: authorizer.DecisionDeny, err: errors.New("webhook failed closed")},
|
||||
&mockAuthzHandler{decision: authorizer.DecisionAllow},
|
||||
|
|
|
|||
|
|
@ -275,7 +275,8 @@ func (t *impersonationModesTracker) getImpersonatedUser(ctx context.Context, wan
|
|||
return nil, errors.New("all impersonation modes failed")
|
||||
}
|
||||
|
||||
var _ = authorizer.Authorizer(&metricsAuthorizer{})
|
||||
// For now, constrained impersonation only supports unconditional authorization
|
||||
var _ = authorizer.UnconditionalAuthorizer(&metricsAuthorizer{})
|
||||
|
||||
type metricsAuthorizer struct {
|
||||
delegate authorizer.UnconditionalAuthorizer
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ type AuthenticationInfo struct {
|
|||
type AuthorizationInfo struct {
|
||||
// Authorizer determines whether the subject is allowed to make the request based only
|
||||
// on the RequestURI
|
||||
Authorizer authorizer.UnconditionalAuthorizer
|
||||
Authorizer authorizer.Authorizer
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
|
|||
|
|
@ -534,6 +534,16 @@ func (authz *mockAuthorizer) Authorize(ctx context.Context, a authorizer.Attribu
|
|||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (authz *mockAuthorizer) ConditionsAwareAuthorize(ctx context.Context, a authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(authz.Authorize(ctx, a))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (*mockAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
type testGetterStorage struct {
|
||||
Version string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,8 +174,8 @@ func (s *DelegatingAuthorizationOptions) ApplyTo(c *server.AuthorizationInfo) er
|
|||
return err
|
||||
}
|
||||
|
||||
func (s *DelegatingAuthorizationOptions) toAuthorizer(client kubernetes.Interface) (authorizer.UnconditionalAuthorizer, error) {
|
||||
var authorizers []authorizer.UnconditionalAuthorizer
|
||||
func (s *DelegatingAuthorizationOptions) toAuthorizer(client kubernetes.Interface) (authorizer.Authorizer, error) {
|
||||
var authorizers []authorizer.Authorizer
|
||||
|
||||
if len(s.AlwaysAllowGroups) > 0 {
|
||||
authorizers = append(authorizers, authorizerfactory.NewPrivilegedGroups(s.AlwaysAllowGroups...))
|
||||
|
|
|
|||
|
|
@ -293,6 +293,16 @@ func (w *WebhookAuthorizer) Authorize(ctx context.Context, attr authorizer.Attri
|
|||
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (w *WebhookAuthorizer) ConditionsAwareAuthorize(ctx context.Context, a authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(w.Authorize(ctx, a))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (*WebhookAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
func resourceAttributesFrom(attr authorizer.Attributes) *authorizationv1.ResourceAttributes {
|
||||
ret := &authorizationv1.ResourceAttributes{
|
||||
Namespace: attr.GetNamespace(),
|
||||
|
|
|
|||
|
|
@ -132,6 +132,16 @@ func (d *noxuDelayingAuthorizer) Authorize(ctx context.Context, a authorizer.Att
|
|||
return d.Authorizer.Authorize(ctx, a)
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (d *noxuDelayingAuthorizer) ConditionsAwareAuthorize(ctx context.Context, a authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(d.Authorize(ctx, a))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (*noxuDelayingAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
// TestConcurrencyIsolation tests the concurrency isolation between priority levels.
|
||||
// The test defines two priority levels for this purpose, and corresponding flow schemas.
|
||||
// To one priority level, this test sends many more concurrent requests than the configuration
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ func (sarAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (au
|
|||
return authorizer.DecisionAllow, "you're not dave", nil
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (s sarAuthorizer) ConditionsAwareAuthorize(ctx context.Context, a authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(s.Authorize(ctx, a))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (sarAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
func alwaysAlice(req *http.Request) (*authenticator.Response, bool, error) {
|
||||
return &authenticator.Response{
|
||||
User: &user.DefaultInfo{
|
||||
|
|
|
|||
|
|
@ -814,6 +814,16 @@ func (impersonateAuthorizer) Authorize(ctx context.Context, a authorizer.Attribu
|
|||
return authorizer.DecisionNoOpinion, "I can't allow that. Go ask alice.", nil
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (i impersonateAuthorizer) ConditionsAwareAuthorize(ctx context.Context, a authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(i.Authorize(ctx, a))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (impersonateAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
func TestImpersonateIsForbidden(t *testing.T) {
|
||||
tCtx := ktesting.Init(t)
|
||||
kubeClient, kubeConfig, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
|
||||
|
|
@ -1832,6 +1842,16 @@ func (a *trackingAuthorizer) Authorize(ctx context.Context, attributes authorize
|
|||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
|
||||
// ConditionsAwareAuthorize is not conditions-aware, converts the Authorize decision.
|
||||
func (a *trackingAuthorizer) ConditionsAwareAuthorize(ctx context.Context, attributes authorizer.Attributes) authorizer.ConditionsAwareDecision {
|
||||
return authorizer.ConditionsAwareDecisionFromParts(a.Authorize(ctx, attributes))
|
||||
}
|
||||
|
||||
// EvaluateConditions is not supported by this authorizer.
|
||||
func (a *trackingAuthorizer) EvaluateConditions(_ context.Context, _ authorizer.ConditionsAwareDecision, _ authorizer.ConditionsData) (authorizer.Decision, string, error) {
|
||||
return authorizer.DecisionDeny, "", authorizer.ErrorConditionEvaluationNotSupported
|
||||
}
|
||||
|
||||
// TestAuthorizationAttributeDetermination tests that authorization attributes are built correctly
|
||||
func TestAuthorizationAttributeDetermination(t *testing.T) {
|
||||
tCtx := ktesting.Init(t)
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ func (getter *testRESTOptionsGetter) GetRESTOptions(resource schema.GroupResourc
|
|||
return generic.RESTOptions{StorageConfig: storageConfig, Decorator: generic.UndecoratedStorage, ResourcePrefix: resource.Resource}, nil
|
||||
}
|
||||
|
||||
func newRBACAuthorizer(t *testing.T, config *controlplane.Config) (authorizer.UnconditionalAuthorizer, func()) {
|
||||
func newRBACAuthorizer(t *testing.T, config *controlplane.Config) (authorizer.Authorizer, func()) {
|
||||
optsGetter := &testRESTOptionsGetter{config}
|
||||
roleRest, err := rolestore.NewREST(optsGetter)
|
||||
if err != nil {
|
||||
|
|
@ -566,7 +566,7 @@ func TestRBAC(t *testing.T) {
|
|||
// Append our custom test authenticator
|
||||
config.ControlPlane.Generic.Authentication.Authenticator = unionauthn.New(config.ControlPlane.Generic.Authentication.Authenticator, authenticator)
|
||||
// Append our custom test authorizer
|
||||
var rbacAuthz authorizer.UnconditionalAuthorizer
|
||||
var rbacAuthz authorizer.Authorizer
|
||||
rbacAuthz, tearDownAuthorizerFn = newRBACAuthorizer(t, config)
|
||||
config.ControlPlane.Generic.Authorization.Authorizer = unionauthz.New(config.ControlPlane.Generic.Authorization.Authorizer, rbacAuthz)
|
||||
},
|
||||
|
|
@ -972,7 +972,7 @@ func TestRBACContextContamination(t *testing.T) {
|
|||
tearDownAuthorizerFn()
|
||||
}
|
||||
}()
|
||||
var rbacAuthz authorizer.UnconditionalAuthorizer
|
||||
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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue