apiserver/authconfig: wire CEL compiler through lower layers to allow sharing
Signed-off-by: Dr. Stefan Schimanski <stefan.schimanski@gmail.com> Kubernetes-commit: 4024390d8c8a19056ab7ced95eef5cce43c8096d
This commit is contained in:
parent
b907ccabbe
commit
4b46916a7b
|
@ -38,14 +38,13 @@ import (
|
||||||
authenticationcel "k8s.io/apiserver/pkg/authentication/cel"
|
authenticationcel "k8s.io/apiserver/pkg/authentication/cel"
|
||||||
authorizationcel "k8s.io/apiserver/pkg/authorization/cel"
|
authorizationcel "k8s.io/apiserver/pkg/authorization/cel"
|
||||||
"k8s.io/apiserver/pkg/cel"
|
"k8s.io/apiserver/pkg/cel"
|
||||||
"k8s.io/apiserver/pkg/cel/environment"
|
|
||||||
"k8s.io/apiserver/pkg/features"
|
"k8s.io/apiserver/pkg/features"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
"k8s.io/client-go/util/cert"
|
"k8s.io/client-go/util/cert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateAuthenticationConfiguration validates a given AuthenticationConfiguration.
|
// ValidateAuthenticationConfiguration validates a given AuthenticationConfiguration.
|
||||||
func ValidateAuthenticationConfiguration(c *api.AuthenticationConfiguration, disallowedIssuers []string) field.ErrorList {
|
func ValidateAuthenticationConfiguration(compiler authenticationcel.Compiler, c *api.AuthenticationConfiguration, disallowedIssuers []string) field.ErrorList {
|
||||||
root := field.NewPath("jwt")
|
root := field.NewPath("jwt")
|
||||||
var allErrs field.ErrorList
|
var allErrs field.ErrorList
|
||||||
|
|
||||||
|
@ -62,7 +61,7 @@ func ValidateAuthenticationConfiguration(c *api.AuthenticationConfiguration, dis
|
||||||
seenDiscoveryURLs := sets.New[string]()
|
seenDiscoveryURLs := sets.New[string]()
|
||||||
for i, a := range c.JWT {
|
for i, a := range c.JWT {
|
||||||
fldPath := root.Index(i)
|
fldPath := root.Index(i)
|
||||||
_, errs := validateJWTAuthenticator(a, fldPath, sets.New(disallowedIssuers...), utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthenticationConfiguration))
|
_, errs := validateJWTAuthenticator(compiler, a, fldPath, sets.New(disallowedIssuers...), utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthenticationConfiguration))
|
||||||
allErrs = append(allErrs, errs...)
|
allErrs = append(allErrs, errs...)
|
||||||
|
|
||||||
if seenIssuers.Has(a.Issuer.URL) {
|
if seenIssuers.Has(a.Issuer.URL) {
|
||||||
|
@ -93,15 +92,13 @@ func ValidateAuthenticationConfiguration(c *api.AuthenticationConfiguration, dis
|
||||||
// CompileAndValidateJWTAuthenticator validates a given JWTAuthenticator and returns a CELMapper with the compiled
|
// CompileAndValidateJWTAuthenticator validates a given JWTAuthenticator and returns a CELMapper with the compiled
|
||||||
// CEL expressions for claim mappings and validation rules.
|
// CEL expressions for claim mappings and validation rules.
|
||||||
// This is exported for use in oidc package.
|
// This is exported for use in oidc package.
|
||||||
func CompileAndValidateJWTAuthenticator(authenticator api.JWTAuthenticator, disallowedIssuers []string) (authenticationcel.CELMapper, field.ErrorList) {
|
func CompileAndValidateJWTAuthenticator(compiler authenticationcel.Compiler, authenticator api.JWTAuthenticator, disallowedIssuers []string) (authenticationcel.CELMapper, field.ErrorList) {
|
||||||
return validateJWTAuthenticator(authenticator, nil, sets.New(disallowedIssuers...), utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthenticationConfiguration))
|
return validateJWTAuthenticator(compiler, authenticator, nil, sets.New(disallowedIssuers...), utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthenticationConfiguration))
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateJWTAuthenticator(authenticator api.JWTAuthenticator, fldPath *field.Path, disallowedIssuers sets.Set[string], structuredAuthnFeatureEnabled bool) (authenticationcel.CELMapper, field.ErrorList) {
|
func validateJWTAuthenticator(compiler authenticationcel.Compiler, authenticator api.JWTAuthenticator, fldPath *field.Path, disallowedIssuers sets.Set[string], structuredAuthnFeatureEnabled bool) (authenticationcel.CELMapper, field.ErrorList) {
|
||||||
var allErrs field.ErrorList
|
var allErrs field.ErrorList
|
||||||
|
|
||||||
// strictCost is set to true which enables the strict cost for CEL validation.
|
|
||||||
compiler := authenticationcel.NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
|
||||||
state := &validationState{}
|
state := &validationState{}
|
||||||
|
|
||||||
allErrs = append(allErrs, validateIssuer(authenticator.Issuer, disallowedIssuers, fldPath.Child("issuer"), structuredAuthnFeatureEnabled)...)
|
allErrs = append(allErrs, validateIssuer(authenticator.Issuer, disallowedIssuers, fldPath.Child("issuer"), structuredAuthnFeatureEnabled)...)
|
||||||
|
@ -616,7 +613,7 @@ func compileUserCELExpression(compiler authenticationcel.Compiler, expression au
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateAuthorizationConfiguration validates a given AuthorizationConfiguration.
|
// ValidateAuthorizationConfiguration validates a given AuthorizationConfiguration.
|
||||||
func ValidateAuthorizationConfiguration(fldPath *field.Path, c *api.AuthorizationConfiguration, knownTypes sets.String, repeatableTypes sets.String) field.ErrorList {
|
func ValidateAuthorizationConfiguration(compiler authorizationcel.Compiler, fldPath *field.Path, c *api.AuthorizationConfiguration, knownTypes sets.String, repeatableTypes sets.String) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
if len(c.Authorizers) == 0 {
|
if len(c.Authorizers) == 0 {
|
||||||
|
@ -657,7 +654,7 @@ func ValidateAuthorizationConfiguration(fldPath *field.Path, c *api.Authorizatio
|
||||||
allErrs = append(allErrs, field.Required(fldPath.Child("webhook"), "required when type=Webhook"))
|
allErrs = append(allErrs, field.Required(fldPath.Child("webhook"), "required when type=Webhook"))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
allErrs = append(allErrs, ValidateWebhookConfiguration(fldPath, a.Webhook)...)
|
allErrs = append(allErrs, ValidateWebhookConfiguration(compiler, fldPath, a.Webhook)...)
|
||||||
default:
|
default:
|
||||||
if a.Webhook != nil {
|
if a.Webhook != nil {
|
||||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("webhook"), "non-null", "may only be specified when type=Webhook"))
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("webhook"), "non-null", "may only be specified when type=Webhook"))
|
||||||
|
@ -668,7 +665,7 @@ func ValidateAuthorizationConfiguration(fldPath *field.Path, c *api.Authorizatio
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateWebhookConfiguration(fldPath *field.Path, c *api.WebhookConfiguration) field.ErrorList {
|
func ValidateWebhookConfiguration(compiler authorizationcel.Compiler, fldPath *field.Path, c *api.WebhookConfiguration) field.ErrorList {
|
||||||
allErrs := field.ErrorList{}
|
allErrs := field.ErrorList{}
|
||||||
|
|
||||||
if c.Timeout.Duration == 0 {
|
if c.Timeout.Duration == 0 {
|
||||||
|
@ -740,7 +737,7 @@ func ValidateWebhookConfiguration(fldPath *field.Path, c *api.WebhookConfigurati
|
||||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("connectionInfo", "type"), c.ConnectionInfo, []string{api.AuthorizationWebhookConnectionInfoTypeInCluster, api.AuthorizationWebhookConnectionInfoTypeKubeConfigFile}))
|
allErrs = append(allErrs, field.NotSupported(fldPath.Child("connectionInfo", "type"), c.ConnectionInfo, []string{api.AuthorizationWebhookConnectionInfoTypeInCluster, api.AuthorizationWebhookConnectionInfoTypeKubeConfigFile}))
|
||||||
}
|
}
|
||||||
|
|
||||||
_, errs := compileMatchConditions(c.MatchConditions, fldPath, utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthorizationConfiguration))
|
_, errs := compileMatchConditions(compiler, c.MatchConditions, fldPath, utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthorizationConfiguration))
|
||||||
allErrs = append(allErrs, errs...)
|
allErrs = append(allErrs, errs...)
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
|
@ -748,11 +745,11 @@ func ValidateWebhookConfiguration(fldPath *field.Path, c *api.WebhookConfigurati
|
||||||
|
|
||||||
// ValidateAndCompileMatchConditions validates a given webhook's matchConditions.
|
// ValidateAndCompileMatchConditions validates a given webhook's matchConditions.
|
||||||
// This is exported for use in authz package.
|
// This is exported for use in authz package.
|
||||||
func ValidateAndCompileMatchConditions(matchConditions []api.WebhookMatchCondition) (*authorizationcel.CELMatcher, field.ErrorList) {
|
func ValidateAndCompileMatchConditions(compiler authorizationcel.Compiler, matchConditions []api.WebhookMatchCondition) (*authorizationcel.CELMatcher, field.ErrorList) {
|
||||||
return compileMatchConditions(matchConditions, nil, utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthorizationConfiguration))
|
return compileMatchConditions(compiler, matchConditions, nil, utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthorizationConfiguration))
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileMatchConditions(matchConditions []api.WebhookMatchCondition, fldPath *field.Path, structuredAuthzFeatureEnabled bool) (*authorizationcel.CELMatcher, field.ErrorList) {
|
func compileMatchConditions(compiler authorizationcel.Compiler, matchConditions []api.WebhookMatchCondition, fldPath *field.Path, structuredAuthzFeatureEnabled bool) (*authorizationcel.CELMatcher, field.ErrorList) {
|
||||||
var allErrs field.ErrorList
|
var allErrs field.ErrorList
|
||||||
// should fail when match conditions are used without feature enabled
|
// should fail when match conditions are used without feature enabled
|
||||||
if len(matchConditions) > 0 && !structuredAuthzFeatureEnabled {
|
if len(matchConditions) > 0 && !structuredAuthzFeatureEnabled {
|
||||||
|
@ -763,8 +760,6 @@ func compileMatchConditions(matchConditions []api.WebhookMatchCondition, fldPath
|
||||||
return nil, allErrs
|
return nil, allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
// strictCost is set to true which enables the strict cost for CEL validation.
|
|
||||||
compiler := authorizationcel.NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
|
||||||
seenExpressions := sets.NewString()
|
seenExpressions := sets.NewString()
|
||||||
var compilationResults []authorizationcel.CompilationResult
|
var compilationResults []authorizationcel.CompilationResult
|
||||||
var usesFieldSelector, usesLabelSelector bool
|
var usesFieldSelector, usesLabelSelector bool
|
||||||
|
|
|
@ -34,7 +34,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
api "k8s.io/apiserver/pkg/apis/apiserver"
|
api "k8s.io/apiserver/pkg/apis/apiserver"
|
||||||
authenticationcel "k8s.io/apiserver/pkg/authentication/cel"
|
authenticationcel "k8s.io/apiserver/pkg/authentication/cel"
|
||||||
"k8s.io/apiserver/pkg/cel/environment"
|
authorizationcel "k8s.io/apiserver/pkg/authorization/cel"
|
||||||
"k8s.io/apiserver/pkg/features"
|
"k8s.io/apiserver/pkg/features"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
certutil "k8s.io/client-go/util/cert"
|
certutil "k8s.io/client-go/util/cert"
|
||||||
|
@ -42,10 +42,6 @@ import (
|
||||||
"k8s.io/utils/pointer"
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
compiler = authenticationcel.NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestValidateAuthenticationConfiguration(t *testing.T) {
|
func TestValidateAuthenticationConfiguration(t *testing.T) {
|
||||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthenticationConfiguration, true)
|
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthenticationConfiguration, true)
|
||||||
|
|
||||||
|
@ -619,7 +615,7 @@ func TestValidateAuthenticationConfiguration(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range testCases {
|
for _, tt := range testCases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := ValidateAuthenticationConfiguration(tt.in, tt.disallowedIssuers).ToAggregate()
|
got := ValidateAuthenticationConfiguration(authenticationcel.NewDefaultCompiler(), tt.in, tt.disallowedIssuers).ToAggregate()
|
||||||
if d := cmp.Diff(tt.want, errString(got)); d != "" {
|
if d := cmp.Diff(tt.want, errString(got)); d != "" {
|
||||||
t.Fatalf("AuthenticationConfiguration validation mismatch (-want +got):\n%s", d)
|
t.Fatalf("AuthenticationConfiguration validation mismatch (-want +got):\n%s", d)
|
||||||
}
|
}
|
||||||
|
@ -1044,7 +1040,7 @@ func TestValidateClaimValidationRules(t *testing.T) {
|
||||||
for _, tt := range testCases {
|
for _, tt := range testCases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
state := &validationState{}
|
state := &validationState{}
|
||||||
got := validateClaimValidationRules(compiler, state, tt.in, fldPath, tt.structuredAuthnFeatureEnabled).ToAggregate()
|
got := validateClaimValidationRules(authenticationcel.NewDefaultCompiler(), state, tt.in, fldPath, tt.structuredAuthnFeatureEnabled).ToAggregate()
|
||||||
if d := cmp.Diff(tt.want, errString(got)); d != "" {
|
if d := cmp.Diff(tt.want, errString(got)); d != "" {
|
||||||
t.Fatalf("ClaimValidationRules validation mismatch (-want +got):\n%s", d)
|
t.Fatalf("ClaimValidationRules validation mismatch (-want +got):\n%s", d)
|
||||||
}
|
}
|
||||||
|
@ -1572,7 +1568,7 @@ func TestValidateClaimMappings(t *testing.T) {
|
||||||
for _, tt := range testCases {
|
for _, tt := range testCases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
state := &validationState{usesEmailVerifiedClaim: tt.usesEmailVerifiedClaim}
|
state := &validationState{usesEmailVerifiedClaim: tt.usesEmailVerifiedClaim}
|
||||||
got := validateClaimMappings(compiler, state, tt.in, fldPath, tt.structuredAuthnFeatureEnabled).ToAggregate()
|
got := validateClaimMappings(authenticationcel.NewDefaultCompiler(), state, tt.in, fldPath, tt.structuredAuthnFeatureEnabled).ToAggregate()
|
||||||
if d := cmp.Diff(tt.want, errString(got)); d != "" {
|
if d := cmp.Diff(tt.want, errString(got)); d != "" {
|
||||||
fmt.Println(errString(got))
|
fmt.Println(errString(got))
|
||||||
t.Fatalf("ClaimMappings validation mismatch (-want +got):\n%s", d)
|
t.Fatalf("ClaimMappings validation mismatch (-want +got):\n%s", d)
|
||||||
|
@ -1661,7 +1657,7 @@ func TestValidateUserValidationRules(t *testing.T) {
|
||||||
for _, tt := range testCases {
|
for _, tt := range testCases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
state := &validationState{}
|
state := &validationState{}
|
||||||
got := validateUserValidationRules(compiler, state, tt.in, fldPath, tt.structuredAuthnFeatureEnabled).ToAggregate()
|
got := validateUserValidationRules(authenticationcel.NewDefaultCompiler(), state, tt.in, fldPath, tt.structuredAuthnFeatureEnabled).ToAggregate()
|
||||||
if d := cmp.Diff(tt.want, errString(got)); d != "" {
|
if d := cmp.Diff(tt.want, errString(got)); d != "" {
|
||||||
t.Fatalf("UserValidationRules validation mismatch (-want +got):\n%s", d)
|
t.Fatalf("UserValidationRules validation mismatch (-want +got):\n%s", d)
|
||||||
}
|
}
|
||||||
|
@ -2458,7 +2454,7 @@ func TestValidateAuthorizationConfiguration(t *testing.T) {
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
errList := ValidateAuthorizationConfiguration(nil, &test.configuration, test.knownTypes, test.repeatableTypes)
|
errList := ValidateAuthorizationConfiguration(authorizationcel.NewDefaultCompiler(), nil, &test.configuration, test.knownTypes, test.repeatableTypes)
|
||||||
if len(errList) != len(test.expectedErrList) {
|
if len(errList) != len(test.expectedErrList) {
|
||||||
t.Errorf("expected %d errs, got %d, errors %v", len(test.expectedErrList), len(errList), errList)
|
t.Errorf("expected %d errs, got %d, errors %v", len(test.expectedErrList), len(errList), errList)
|
||||||
}
|
}
|
||||||
|
@ -2568,7 +2564,7 @@ func TestValidateAndCompileMatchConditions(t *testing.T) {
|
||||||
for _, tt := range testCases {
|
for _, tt := range testCases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthorizationConfiguration, tt.featureEnabled)
|
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthorizationConfiguration, tt.featureEnabled)
|
||||||
celMatcher, errList := ValidateAndCompileMatchConditions(tt.matchConditions)
|
celMatcher, errList := ValidateAndCompileMatchConditions(authorizationcel.NewDefaultCompiler(), tt.matchConditions)
|
||||||
if len(tt.expectedErr) == 0 && len(tt.matchConditions) > 0 && len(errList) == 0 && celMatcher == nil {
|
if len(tt.expectedErr) == 0 && len(tt.matchConditions) > 0 && len(errList) == 0 && celMatcher == nil {
|
||||||
t.Errorf("celMatcher should not be nil when there are matchCondition and no error returned")
|
t.Errorf("celMatcher should not be nil when there are matchCondition and no error returned")
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,12 @@ type compiler struct {
|
||||||
varEnvs map[string]*environment.EnvSet
|
varEnvs map[string]*environment.EnvSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDefaultCompiler returns a new Compiler following the default compatibility version.
|
||||||
|
// Note: the compiler construction depends on feature gates and the compatibility version to be initialized.
|
||||||
|
func NewDefaultCompiler() Compiler {
|
||||||
|
return NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
||||||
|
}
|
||||||
|
|
||||||
// NewCompiler returns a new Compiler.
|
// NewCompiler returns a new Compiler.
|
||||||
func NewCompiler(env *environment.EnvSet) Compiler {
|
func NewCompiler(env *environment.EnvSet) Compiler {
|
||||||
return &compiler{
|
return &compiler{
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
|
|
||||||
authenticationv1 "k8s.io/api/authentication/v1"
|
authenticationv1 "k8s.io/api/authentication/v1"
|
||||||
apiservercel "k8s.io/apiserver/pkg/cel"
|
apiservercel "k8s.io/apiserver/pkg/cel"
|
||||||
"k8s.io/apiserver/pkg/cel/environment"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCompileClaimsExpression(t *testing.T) {
|
func TestCompileClaimsExpression(t *testing.T) {
|
||||||
|
@ -57,12 +56,10 @@ func TestCompileClaimsExpression(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler := NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
for _, expressionAccessor := range tc.expressionAccessors {
|
for _, expressionAccessor := range tc.expressionAccessors {
|
||||||
_, err := compiler.CompileClaimsExpression(expressionAccessor)
|
_, err := NewDefaultCompiler().CompileClaimsExpression(expressionAccessor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -86,12 +83,10 @@ func TestCompileUserExpression(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler := NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
for _, expressionAccessor := range tc.expressionAccessors {
|
for _, expressionAccessor := range tc.expressionAccessors {
|
||||||
_, err := compiler.CompileUserExpression(expressionAccessor)
|
_, err := NewDefaultCompiler().CompileUserExpression(expressionAccessor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -135,12 +130,10 @@ func TestCompileClaimsExpressionError(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler := NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
for _, expressionAccessor := range tc.expressionAccessors {
|
for _, expressionAccessor := range tc.expressionAccessors {
|
||||||
_, err := compiler.CompileClaimsExpression(expressionAccessor)
|
_, err := NewDefaultCompiler().CompileClaimsExpression(expressionAccessor)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("expected error but got nil")
|
t.Errorf("expected error but got nil")
|
||||||
}
|
}
|
||||||
|
@ -205,12 +198,10 @@ func TestCompileUserExpressionError(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
compiler := NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
for _, expressionAccessor := range tc.expressionAccessors {
|
for _, expressionAccessor := range tc.expressionAccessors {
|
||||||
_, err := compiler.CompileUserExpression(expressionAccessor)
|
_, err := NewDefaultCompiler().CompileUserExpression(expressionAccessor)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("expected error but got nil")
|
t.Errorf("expected error but got nil")
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
|
authorizationcel "k8s.io/apiserver/pkg/authorization/cel"
|
||||||
"k8s.io/apiserver/plugin/pkg/authorizer/webhook"
|
"k8s.io/apiserver/plugin/pkg/authorizer/webhook"
|
||||||
authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1"
|
authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1"
|
||||||
)
|
)
|
||||||
|
@ -31,6 +32,9 @@ import (
|
||||||
type DelegatingAuthorizerConfig struct {
|
type DelegatingAuthorizerConfig struct {
|
||||||
SubjectAccessReviewClient authorizationclient.AuthorizationV1Interface
|
SubjectAccessReviewClient authorizationclient.AuthorizationV1Interface
|
||||||
|
|
||||||
|
// Compiler is the CEL compiler to use for evaluating policies. If nil, a default compiler will be used.
|
||||||
|
Compiler authorizationcel.Compiler
|
||||||
|
|
||||||
// AllowCacheTTL is the length of time that a successful authorization response will be cached
|
// AllowCacheTTL is the length of time that a successful authorization response will be cached
|
||||||
AllowCacheTTL time.Duration
|
AllowCacheTTL time.Duration
|
||||||
|
|
||||||
|
@ -48,6 +52,10 @@ func (c DelegatingAuthorizerConfig) New() (authorizer.Authorizer, error) {
|
||||||
if c.WebhookRetryBackoff == nil {
|
if c.WebhookRetryBackoff == nil {
|
||||||
return nil, errors.New("retry backoff parameters for delegating authorization webhook has not been specified")
|
return nil, errors.New("retry backoff parameters for delegating authorization webhook has not been specified")
|
||||||
}
|
}
|
||||||
|
compiler := c.Compiler
|
||||||
|
if compiler == nil {
|
||||||
|
compiler = authorizationcel.NewDefaultCompiler()
|
||||||
|
}
|
||||||
|
|
||||||
return webhook.NewFromInterface(
|
return webhook.NewFromInterface(
|
||||||
c.SubjectAccessReviewClient,
|
c.SubjectAccessReviewClient,
|
||||||
|
@ -56,5 +64,6 @@ func (c DelegatingAuthorizerConfig) New() (authorizer.Authorizer, error) {
|
||||||
*c.WebhookRetryBackoff,
|
*c.WebhookRetryBackoff,
|
||||||
authorizer.DecisionNoOpinion,
|
authorizer.DecisionNoOpinion,
|
||||||
NewDelegatingAuthorizerMetrics(),
|
NewDelegatingAuthorizerMetrics(),
|
||||||
|
compiler,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,12 @@ type compiler struct {
|
||||||
envSet *environment.EnvSet
|
envSet *environment.EnvSet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDefaultCompiler returns a new Compiler following the default compatibility version.
|
||||||
|
// Note: the compiler construction depends on feature gates and the compatibility version to be initialized.
|
||||||
|
func NewDefaultCompiler() Compiler {
|
||||||
|
return NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
||||||
|
}
|
||||||
|
|
||||||
// NewCompiler returns a new Compiler.
|
// NewCompiler returns a new Compiler.
|
||||||
func NewCompiler(env *environment.EnvSet) Compiler {
|
func NewCompiler(env *environment.EnvSet) Compiler {
|
||||||
return &compiler{
|
return &compiler{
|
||||||
|
|
|
@ -25,7 +25,6 @@ import (
|
||||||
v1 "k8s.io/api/authorization/v1"
|
v1 "k8s.io/api/authorization/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
apiservercel "k8s.io/apiserver/pkg/cel"
|
apiservercel "k8s.io/apiserver/pkg/cel"
|
||||||
"k8s.io/apiserver/pkg/cel/environment"
|
|
||||||
genericfeatures "k8s.io/apiserver/pkg/features"
|
genericfeatures "k8s.io/apiserver/pkg/features"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
|
@ -100,7 +99,10 @@ func TestCompileCELExpression(t *testing.T) {
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.AuthorizeWithSelectors, tc.authorizeWithSelectorsEnabled)
|
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.AuthorizeWithSelectors, tc.authorizeWithSelectorsEnabled)
|
||||||
compiler := NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
|
|
||||||
|
// create new compiler because it depends on the feature gate
|
||||||
|
compiler := NewDefaultCompiler()
|
||||||
|
|
||||||
_, err := compiler.CompileCELExpression(&SubjectAccessReviewMatchCondition{
|
_, err := compiler.CompileCELExpression(&SubjectAccessReviewMatchCondition{
|
||||||
Expression: tc.expression,
|
Expression: tc.expression,
|
||||||
})
|
})
|
||||||
|
|
|
@ -86,6 +86,12 @@ type Options struct {
|
||||||
// Optional http.Client used to make all requests to the remote issuer. Mutually exclusive with CAContentProvider.
|
// Optional http.Client used to make all requests to the remote issuer. Mutually exclusive with CAContentProvider.
|
||||||
Client *http.Client
|
Client *http.Client
|
||||||
|
|
||||||
|
// Optional CEL compiler used to compile the CEL expressions. This is useful to use a shared instance
|
||||||
|
// of the compiler as these compilers holding a CEL environment are expensive to create. If not provided,
|
||||||
|
// a default compiler will be created.
|
||||||
|
// Note: the compiler construction depends on feature gates and the compatibility version to be initialized.
|
||||||
|
Compiler authenticationcel.Compiler
|
||||||
|
|
||||||
// SupportedSigningAlgs sets the accepted set of JOSE signing algorithms that
|
// SupportedSigningAlgs sets the accepted set of JOSE signing algorithms that
|
||||||
// can be used by the provider to sign tokens.
|
// can be used by the provider to sign tokens.
|
||||||
//
|
//
|
||||||
|
@ -245,7 +251,11 @@ type AuthenticatorTokenWithHealthCheck interface {
|
||||||
// Thus, once the lifecycleCtx is canceled, the authenticator must not be used.
|
// Thus, once the lifecycleCtx is canceled, the authenticator must not be used.
|
||||||
// A caller may check if the authenticator is healthy by calling the HealthCheck method.
|
// A caller may check if the authenticator is healthy by calling the HealthCheck method.
|
||||||
func New(lifecycleCtx context.Context, opts Options) (AuthenticatorTokenWithHealthCheck, error) {
|
func New(lifecycleCtx context.Context, opts Options) (AuthenticatorTokenWithHealthCheck, error) {
|
||||||
celMapper, fieldErr := apiservervalidation.CompileAndValidateJWTAuthenticator(opts.JWTAuthenticator, opts.DisallowedIssuers)
|
compiler := opts.Compiler
|
||||||
|
if compiler == nil {
|
||||||
|
compiler = authenticationcel.NewDefaultCompiler()
|
||||||
|
}
|
||||||
|
celMapper, fieldErr := apiservervalidation.CompileAndValidateJWTAuthenticator(compiler, opts.JWTAuthenticator, opts.DisallowedIssuers)
|
||||||
if err := fieldErr.ToAggregate(); err != nil {
|
if err := fieldErr.ToAggregate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ func TestAuthorizerMetrics(t *testing.T) {
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
fakeAuthzMetrics := &fakeAuthorizerMetrics{}
|
fakeAuthzMetrics := &fakeAuthorizerMetrics{}
|
||||||
wh, err := newV1Authorizer(server.URL, scenario.clientCert, scenario.clientKey, scenario.clientCA, 0, fakeAuthzMetrics, []apiserver.WebhookMatchCondition{}, "")
|
wh, err := newV1Authorizer(server.URL, scenario.clientCert, scenario.clientKey, scenario.clientCA, 0, fakeAuthzMetrics, cel.NewDefaultCompiler(), []apiserver.WebhookMatchCondition{}, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("failed to create client")
|
t.Error("failed to create client")
|
||||||
return
|
return
|
||||||
|
|
|
@ -82,8 +82,8 @@ type WebhookAuthorizer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFromInterface creates a WebhookAuthorizer using the given subjectAccessReview client
|
// NewFromInterface creates a WebhookAuthorizer using the given subjectAccessReview client
|
||||||
func NewFromInterface(subjectAccessReview authorizationv1client.AuthorizationV1Interface, authorizedTTL, unauthorizedTTL time.Duration, retryBackoff wait.Backoff, decisionOnError authorizer.Decision, metrics metrics.AuthorizerMetrics) (*WebhookAuthorizer, error) {
|
func NewFromInterface(subjectAccessReview authorizationv1client.AuthorizationV1Interface, authorizedTTL, unauthorizedTTL time.Duration, retryBackoff wait.Backoff, decisionOnError authorizer.Decision, metrics metrics.AuthorizerMetrics, compiler authorizationcel.Compiler) (*WebhookAuthorizer, error) {
|
||||||
return newWithBackoff(&subjectAccessReviewV1Client{subjectAccessReview.RESTClient()}, authorizedTTL, unauthorizedTTL, retryBackoff, decisionOnError, nil, metrics, "")
|
return newWithBackoff(&subjectAccessReviewV1Client{subjectAccessReview.RESTClient()}, authorizedTTL, unauthorizedTTL, retryBackoff, decisionOnError, nil, metrics, compiler, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new WebhookAuthorizer from the provided kubeconfig file.
|
// New creates a new WebhookAuthorizer from the provided kubeconfig file.
|
||||||
|
@ -105,18 +105,18 @@ func NewFromInterface(subjectAccessReview authorizationv1client.AuthorizationV1I
|
||||||
//
|
//
|
||||||
// For additional HTTP configuration, refer to the kubeconfig documentation
|
// For additional HTTP configuration, refer to the kubeconfig documentation
|
||||||
// https://kubernetes.io/docs/user-guide/kubeconfig-file/.
|
// https://kubernetes.io/docs/user-guide/kubeconfig-file/.
|
||||||
func New(config *rest.Config, version string, authorizedTTL, unauthorizedTTL time.Duration, retryBackoff wait.Backoff, decisionOnError authorizer.Decision, matchConditions []apiserver.WebhookMatchCondition, name string, metrics metrics.AuthorizerMetrics) (*WebhookAuthorizer, error) {
|
func New(config *rest.Config, version string, authorizedTTL, unauthorizedTTL time.Duration, retryBackoff wait.Backoff, decisionOnError authorizer.Decision, matchConditions []apiserver.WebhookMatchCondition, name string, metrics metrics.AuthorizerMetrics, compiler authorizationcel.Compiler) (*WebhookAuthorizer, error) {
|
||||||
subjectAccessReview, err := subjectAccessReviewInterfaceFromConfig(config, version, retryBackoff)
|
subjectAccessReview, err := subjectAccessReviewInterfaceFromConfig(config, version, retryBackoff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return newWithBackoff(subjectAccessReview, authorizedTTL, unauthorizedTTL, retryBackoff, decisionOnError, matchConditions, metrics, name)
|
return newWithBackoff(subjectAccessReview, authorizedTTL, unauthorizedTTL, retryBackoff, decisionOnError, matchConditions, metrics, compiler, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newWithBackoff allows tests to skip the sleep.
|
// newWithBackoff allows tests to skip the sleep.
|
||||||
func newWithBackoff(subjectAccessReview subjectAccessReviewer, authorizedTTL, unauthorizedTTL time.Duration, retryBackoff wait.Backoff, decisionOnError authorizer.Decision, matchConditions []apiserver.WebhookMatchCondition, am metrics.AuthorizerMetrics, name string) (*WebhookAuthorizer, error) {
|
func newWithBackoff(subjectAccessReview subjectAccessReviewer, authorizedTTL, unauthorizedTTL time.Duration, retryBackoff wait.Backoff, decisionOnError authorizer.Decision, matchConditions []apiserver.WebhookMatchCondition, am metrics.AuthorizerMetrics, compiler authorizationcel.Compiler, name string) (*WebhookAuthorizer, error) {
|
||||||
// compile all expressions once in validation and save the results to be used for eval later
|
// compile all expressions once in validation and save the results to be used for eval later
|
||||||
cm, fieldErr := apiservervalidation.ValidateAndCompileMatchConditions(matchConditions)
|
cm, fieldErr := apiservervalidation.ValidateAndCompileMatchConditions(compiler, matchConditions)
|
||||||
if err := fieldErr.ToAggregate(); err != nil {
|
if err := fieldErr.ToAggregate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,6 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
utiltesting "k8s.io/client-go/util/testing"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
authorizationv1 "k8s.io/api/authorization/v1"
|
authorizationv1 "k8s.io/api/authorization/v1"
|
||||||
|
@ -47,12 +45,13 @@ import (
|
||||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
celmetrics "k8s.io/apiserver/pkg/authorization/cel"
|
authorizationcel "k8s.io/apiserver/pkg/authorization/cel"
|
||||||
"k8s.io/apiserver/pkg/features"
|
"k8s.io/apiserver/pkg/features"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
||||||
"k8s.io/apiserver/plugin/pkg/authorizer/webhook/metrics"
|
"k8s.io/apiserver/plugin/pkg/authorizer/webhook/metrics"
|
||||||
v1 "k8s.io/client-go/tools/clientcmd/api/v1"
|
v1 "k8s.io/client-go/tools/clientcmd/api/v1"
|
||||||
|
utiltesting "k8s.io/client-go/util/testing"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
"k8s.io/component-base/metrics/legacyregistry"
|
"k8s.io/component-base/metrics/legacyregistry"
|
||||||
"k8s.io/component-base/metrics/testutil"
|
"k8s.io/component-base/metrics/testutil"
|
||||||
|
@ -217,7 +216,7 @@ current-context: default
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error building sar client: %v", err)
|
return fmt.Errorf("error building sar client: %v", err)
|
||||||
}
|
}
|
||||||
_, err = newWithBackoff(sarClient, 0, 0, testRetryBackoff, authorizer.DecisionNoOpinion, []apiserver.WebhookMatchCondition{}, noopAuthorizerMetrics(), "")
|
_, err = newWithBackoff(sarClient, 0, 0, testRetryBackoff, authorizer.DecisionNoOpinion, []apiserver.WebhookMatchCondition{}, noopAuthorizerMetrics(), authorizationcel.NewDefaultCompiler(), "")
|
||||||
return err
|
return err
|
||||||
}()
|
}()
|
||||||
if err != nil && !tt.wantErr {
|
if err != nil && !tt.wantErr {
|
||||||
|
@ -337,7 +336,7 @@ func (m *mockV1Service) HTTPStatusCode() int { return m.statusCode }
|
||||||
|
|
||||||
// newV1Authorizer creates a temporary kubeconfig file from the provided arguments and attempts to load
|
// newV1Authorizer creates a temporary kubeconfig file from the provided arguments and attempts to load
|
||||||
// a new WebhookAuthorizer from it.
|
// a new WebhookAuthorizer from it.
|
||||||
func newV1Authorizer(callbackURL string, clientCert, clientKey, ca []byte, cacheTime time.Duration, metrics metrics.AuthorizerMetrics, expressions []apiserver.WebhookMatchCondition, authzName string) (*WebhookAuthorizer, error) {
|
func newV1Authorizer(callbackURL string, clientCert, clientKey, ca []byte, cacheTime time.Duration, metrics metrics.AuthorizerMetrics, compiler authorizationcel.Compiler, expressions []apiserver.WebhookMatchCondition, authzName string) (*WebhookAuthorizer, error) {
|
||||||
tempfile, err := ioutil.TempFile("", "")
|
tempfile, err := ioutil.TempFile("", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -367,7 +366,7 @@ func newV1Authorizer(callbackURL string, clientCert, clientKey, ca []byte, cache
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error building sar client: %v", err)
|
return nil, fmt.Errorf("error building sar client: %v", err)
|
||||||
}
|
}
|
||||||
return newWithBackoff(sarClient, cacheTime, cacheTime, testRetryBackoff, authorizer.DecisionNoOpinion, expressions, metrics, authzName)
|
return newWithBackoff(sarClient, cacheTime, cacheTime, testRetryBackoff, authorizer.DecisionNoOpinion, expressions, metrics, compiler, authzName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestV1TLSConfig(t *testing.T) {
|
func TestV1TLSConfig(t *testing.T) {
|
||||||
|
@ -426,7 +425,7 @@ func TestV1TLSConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
wh, err := newV1Authorizer(server.URL, tt.clientCert, tt.clientKey, tt.clientCA, 0, noopAuthorizerMetrics(), []apiserver.WebhookMatchCondition{}, "")
|
wh, err := newV1Authorizer(server.URL, tt.clientCert, tt.clientKey, tt.clientCA, 0, noopAuthorizerMetrics(), authorizationcel.NewDefaultCompiler(), []apiserver.WebhookMatchCondition{}, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: failed to create client: %v", tt.test, err)
|
t.Errorf("%s: failed to create client: %v", tt.test, err)
|
||||||
return
|
return
|
||||||
|
@ -491,7 +490,7 @@ func TestV1Webhook(t *testing.T) {
|
||||||
}
|
}
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), []apiserver.WebhookMatchCondition{}, "")
|
wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), authorizationcel.NewDefaultCompiler(), []apiserver.WebhookMatchCondition{}, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -598,7 +597,7 @@ func TestV1WebhookCache(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Create an authorizer that caches successful responses "forever" (100 days).
|
// Create an authorizer that caches successful responses "forever" (100 days).
|
||||||
wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 2400*time.Hour, noopAuthorizerMetrics(), expressions, "")
|
wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 2400*time.Hour, noopAuthorizerMetrics(), authorizationcel.NewDefaultCompiler(), expressions, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -693,7 +692,6 @@ func TestV1WebhookCache(t *testing.T) {
|
||||||
|
|
||||||
// TestStructuredAuthzConfigFeatureEnablement verifies cel expressions can only be used when feature is enabled
|
// TestStructuredAuthzConfigFeatureEnablement verifies cel expressions can only be used when feature is enabled
|
||||||
func TestStructuredAuthzConfigFeatureEnablement(t *testing.T) {
|
func TestStructuredAuthzConfigFeatureEnablement(t *testing.T) {
|
||||||
|
|
||||||
service := new(mockV1Service)
|
service := new(mockV1Service)
|
||||||
service.statusCode = 200
|
service.statusCode = 200
|
||||||
service.Allow()
|
service.Allow()
|
||||||
|
@ -804,7 +802,11 @@ func TestStructuredAuthzConfigFeatureEnablement(t *testing.T) {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthorizationConfiguration, test.featureEnabled)
|
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthorizationConfiguration, test.featureEnabled)
|
||||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AuthorizeWithSelectors, test.selectorEnabled)
|
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AuthorizeWithSelectors, test.selectorEnabled)
|
||||||
wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), test.expressions, "")
|
|
||||||
|
// create new compiler because it depends on the feature gate
|
||||||
|
compiler := authorizationcel.NewDefaultCompiler()
|
||||||
|
|
||||||
|
wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), compiler, test.expressions, "")
|
||||||
if test.expectedCompileErr && err == nil {
|
if test.expectedCompileErr && err == nil {
|
||||||
t.Fatalf("%d: Expected compile error", i)
|
t.Fatalf("%d: Expected compile error", i)
|
||||||
} else if !test.expectedCompileErr && err != nil {
|
} else if !test.expectedCompileErr && err != nil {
|
||||||
|
@ -910,13 +912,13 @@ func TestWebhookMetrics(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range testCases {
|
for _, tt := range testCases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
celmetrics.ResetMetricsForTest()
|
authorizationcel.ResetMetricsForTest()
|
||||||
defer celmetrics.ResetMetricsForTest()
|
defer authorizationcel.ResetMetricsForTest()
|
||||||
wh1, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, celAuthorizerMetrics(), tt.expressions1, "wh1.example.com")
|
wh1, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, celAuthorizerMetrics(), authorizationcel.NewDefaultCompiler(), tt.expressions1, "wh1.example.com")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
wh2, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, celAuthorizerMetrics(), tt.expressions2, "wh2.example.com")
|
wh2, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, celAuthorizerMetrics(), authorizationcel.NewDefaultCompiler(), tt.expressions2, "wh2.example.com")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1092,7 +1094,7 @@ func benchmarkNewWebhookAuthorizer(b *testing.B, expressions []apiserver.Webhook
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
// Create an authorizer with or without expressions to compile
|
// Create an authorizer with or without expressions to compile
|
||||||
_, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), expressions, "")
|
_, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), authorizationcel.NewDefaultCompiler(), expressions, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1122,7 +1124,7 @@ func benchmarkWebhookAuthorize(b *testing.B, expressions []apiserver.WebhookMatc
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, features.StructuredAuthorizationConfiguration, featureEnabled)
|
featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, features.StructuredAuthorizationConfiguration, featureEnabled)
|
||||||
// Create an authorizer with or without expressions to compile
|
// Create an authorizer with or without expressions to compile
|
||||||
wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), expressions, "")
|
wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), authorizationcel.NewDefaultCompiler(), expressions, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1409,7 +1411,7 @@ func TestV1WebhookMatchConditions(t *testing.T) {
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), test.expressions, "")
|
wh, err := newV1Authorizer(s.URL, clientCert, clientKey, caCert, 0, noopAuthorizerMetrics(), authorizationcel.NewDefaultCompiler(), test.expressions, "")
|
||||||
if len(test.expectedCompileErr) > 0 && err == nil {
|
if len(test.expectedCompileErr) > 0 && err == nil {
|
||||||
t.Fatalf("%d: Expected compile error", i)
|
t.Fatalf("%d: Expected compile error", i)
|
||||||
} else if len(test.expectedCompileErr) == 0 && err != nil {
|
} else if len(test.expectedCompileErr) == 0 && err != nil {
|
||||||
|
@ -1448,12 +1450,12 @@ func noopAuthorizerMetrics() metrics.AuthorizerMetrics {
|
||||||
|
|
||||||
func celAuthorizerMetrics() metrics.AuthorizerMetrics {
|
func celAuthorizerMetrics() metrics.AuthorizerMetrics {
|
||||||
return celAuthorizerMetricsType{
|
return celAuthorizerMetricsType{
|
||||||
MatcherMetrics: celmetrics.NewMatcherMetrics(),
|
MatcherMetrics: authorizationcel.NewMatcherMetrics(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type celAuthorizerMetricsType struct {
|
type celAuthorizerMetricsType struct {
|
||||||
metrics.NoopRequestMetrics
|
metrics.NoopRequestMetrics
|
||||||
metrics.NoopWebhookMetrics
|
metrics.NoopWebhookMetrics
|
||||||
celmetrics.MatcherMetrics
|
authorizationcel.MatcherMetrics
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ import (
|
||||||
authzconfig "k8s.io/apiserver/pkg/apis/apiserver"
|
authzconfig "k8s.io/apiserver/pkg/apis/apiserver"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
|
authorizationcel "k8s.io/apiserver/pkg/authorization/cel"
|
||||||
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
webhookutil "k8s.io/apiserver/pkg/util/webhook"
|
||||||
v1 "k8s.io/client-go/tools/clientcmd/api/v1"
|
v1 "k8s.io/client-go/tools/clientcmd/api/v1"
|
||||||
)
|
)
|
||||||
|
@ -197,7 +198,7 @@ current-context: default
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error building sar client: %v", err)
|
return fmt.Errorf("error building sar client: %v", err)
|
||||||
}
|
}
|
||||||
_, err = newWithBackoff(sarClient, 0, 0, testRetryBackoff, authorizer.DecisionNoOpinion, []authzconfig.WebhookMatchCondition{}, noopAuthorizerMetrics(), "")
|
_, err = newWithBackoff(sarClient, 0, 0, testRetryBackoff, authorizer.DecisionNoOpinion, []authzconfig.WebhookMatchCondition{}, noopAuthorizerMetrics(), authorizationcel.NewDefaultCompiler(), "")
|
||||||
return err
|
return err
|
||||||
}()
|
}()
|
||||||
if err != nil && !tt.wantErr {
|
if err != nil && !tt.wantErr {
|
||||||
|
@ -340,7 +341,7 @@ func newV1beta1Authorizer(callbackURL string, clientCert, clientKey, ca []byte,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error building sar client: %v", err)
|
return nil, fmt.Errorf("error building sar client: %v", err)
|
||||||
}
|
}
|
||||||
return newWithBackoff(sarClient, cacheTime, cacheTime, testRetryBackoff, authorizer.DecisionNoOpinion, []authzconfig.WebhookMatchCondition{}, noopAuthorizerMetrics(), "")
|
return newWithBackoff(sarClient, cacheTime, cacheTime, testRetryBackoff, authorizer.DecisionNoOpinion, []authzconfig.WebhookMatchCondition{}, noopAuthorizerMetrics(), authorizationcel.NewDefaultCompiler(), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestV1beta1TLSConfig(t *testing.T) {
|
func TestV1beta1TLSConfig(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue