Adapt the codebase to the Authorizer interface change

This commit is contained in:
Lucas Käldström 2026-05-13 18:34:51 +03:00
parent 6d78dfd60c
commit 69a8b4dd7a
27 changed files with 290 additions and 53 deletions

View file

@ -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 (

View file

@ -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

View file

@ -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")
}

View file

@ -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
)

View file

@ -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)
}

View file

@ -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) {

View file

@ -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)
}

View file

@ -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) {

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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.")

View file

@ -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")
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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 {

View file

@ -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

View file

@ -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},

View file

@ -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

View file

@ -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() {

View file

@ -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
}

View file

@ -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...))

View file

@ -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(),

View file

@ -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

View file

@ -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{

View file

@ -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)

View file

@ -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.