Move kube-apiserver authz validation functions

This commit is contained in:
Jordan Liggitt 2023-11-07 10:15:56 -06:00
parent eeefc299e5
commit 5f4cb8b09a
No known key found for this signature in database
2 changed files with 65 additions and 50 deletions

View File

@ -19,10 +19,15 @@ package authorizer
import (
"errors"
"fmt"
"strings"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait"
authzconfig "k8s.io/apiserver/pkg/apis/apiserver"
"k8s.io/apiserver/pkg/apis/apiserver/load"
"k8s.io/apiserver/pkg/apis/apiserver/validation"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
@ -156,3 +161,56 @@ func (config Config) New() (authorizer.Authorizer, authorizer.RuleResolver, erro
return union.New(authorizers...), union.NewRuleResolvers(ruleResolvers...), nil
}
// RepeatableAuthorizerTypes is the list of Authorizer that can be repeated in the Authorization Config
var repeatableAuthorizerTypes = []string{modes.ModeWebhook}
// GetNameForAuthorizerMode returns the name to be set for the mode in AuthorizationConfiguration
// For now, lower cases the mode name
func GetNameForAuthorizerMode(mode string) string {
return strings.ToLower(mode)
}
func LoadAndValidateFile(configFile string, requireNonWebhookTypes sets.Set[authzconfig.AuthorizerType]) (*authzconfig.AuthorizationConfiguration, error) {
// load the file and check for errors
authorizationConfiguration, err := load.LoadFromFile(configFile)
if err != nil {
return nil, fmt.Errorf("failed to load AuthorizationConfiguration from file: %v", err)
}
// validate the file and return any error
if errors := validation.ValidateAuthorizationConfiguration(nil, authorizationConfiguration,
sets.NewString(modes.AuthorizationModeChoices...),
sets.NewString(repeatableAuthorizerTypes...),
); len(errors) != 0 {
return nil, fmt.Errorf(errors.ToAggregate().Error())
}
// test to check if the authorizer names passed conform to the authorizers for type!=Webhook
// this test is only for kube-apiserver and hence checked here
// it preserves compatibility with o.buildAuthorizationConfiguration
var allErrors []error
seenModes := sets.New[authzconfig.AuthorizerType]()
for _, authorizer := range authorizationConfiguration.Authorizers {
if string(authorizer.Type) == modes.ModeWebhook {
continue
}
seenModes.Insert(authorizer.Type)
expectedName := GetNameForAuthorizerMode(string(authorizer.Type))
if expectedName != authorizer.Name {
allErrors = append(allErrors, fmt.Errorf("expected name %s for authorizer %s instead of %s", expectedName, authorizer.Type, authorizer.Name))
}
}
if missingTypes := requireNonWebhookTypes.Difference(seenModes); missingTypes.Len() > 0 {
allErrors = append(allErrors, fmt.Errorf("missing required types: %v", sets.List(missingTypes)))
}
if len(allErrors) > 0 {
return nil, utilerrors.NewAggregate(allErrors)
}
return authorizationConfiguration, nil
}

View File

@ -21,7 +21,6 @@ import (
"strings"
"time"
"k8s.io/apiserver/pkg/apis/apiserver/load"
genericfeatures "k8s.io/apiserver/pkg/features"
utilfeature "k8s.io/apiserver/pkg/util/feature"
@ -31,7 +30,6 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait"
authzconfig "k8s.io/apiserver/pkg/apis/apiserver"
"k8s.io/apiserver/pkg/apis/apiserver/validation"
genericoptions "k8s.io/apiserver/pkg/server/options"
versionedinformers "k8s.io/client-go/informers"
@ -50,9 +48,6 @@ const (
authorizationConfigFlag = "authorization-config"
)
// RepeatableAuthorizerTypes is the list of Authorizer that can be repeated in the Authorization Config
var repeatableAuthorizerTypes = []string{authzmodes.ModeWebhook}
// BuiltInAuthorizationOptions contains all build-in authorization options for API Server
type BuiltInAuthorizationOptions struct {
Modes []string
@ -118,32 +113,10 @@ func (o *BuiltInAuthorizationOptions) Validate() []error {
return append(allErrors, fmt.Errorf("--%s can not be specified when --%s or --authorization-webhook-* flags are defined", authorizationConfigFlag, authorizationModeFlag))
}
// load the file and check for errors
config, err := load.LoadFromFile(o.AuthorizationConfigurationFile)
// load/validate kube-apiserver authz config with no opinion about required modes
_, err := authorizer.LoadAndValidateFile(o.AuthorizationConfigurationFile, nil)
if err != nil {
return append(allErrors, fmt.Errorf("failed to load AuthorizationConfiguration from file: %v", err))
}
// validate the file and return any error
if errors := validation.ValidateAuthorizationConfiguration(nil, config,
sets.NewString(authzmodes.AuthorizationModeChoices...),
sets.NewString(repeatableAuthorizerTypes...),
); len(errors) != 0 {
allErrors = append(allErrors, errors.ToAggregate().Errors()...)
}
// test to check if the authorizer names passed conform to the authorizers for type!=Webhook
// this test is only for kube-apiserver and hence checked here
// it preserves compatibility with o.buildAuthorizationConfiguration
for _, authorizer := range config.Authorizers {
if string(authorizer.Type) == authzmodes.ModeWebhook {
continue
}
expectedName := getNameForAuthorizerMode(string(authorizer.Type))
if expectedName != authorizer.Name {
allErrors = append(allErrors, fmt.Errorf("expected name %s for authorizer %s instead of %s", expectedName, authorizer.Type, authorizer.Name))
}
return append(allErrors, err)
}
return allErrors
@ -255,24 +228,14 @@ func (o *BuiltInAuthorizationOptions) ToAuthorizationConfig(versionedInformerFac
if !utilfeature.DefaultFeatureGate.Enabled(genericfeatures.StructuredAuthorizationConfiguration) {
return nil, fmt.Errorf("--%s cannot be used without enabling StructuredAuthorizationConfiguration feature flag", authorizationConfigFlag)
}
// error out if legacy flags are defined
if o.AreLegacyFlagsSet != nil && o.AreLegacyFlagsSet() {
return nil, fmt.Errorf("--%s can not be specified when --%s or --authorization-webhook-* flags are defined", authorizationConfigFlag, authorizationModeFlag)
}
// load the file and check for errors
authorizationConfiguration, err = load.LoadFromFile(o.AuthorizationConfigurationFile)
// load/validate kube-apiserver authz config with no opinion about required modes
authorizationConfiguration, err = authorizer.LoadAndValidateFile(o.AuthorizationConfigurationFile, nil)
if err != nil {
return nil, fmt.Errorf("failed to load AuthorizationConfiguration from file: %v", err)
}
// validate the file and return any error
if errors := validation.ValidateAuthorizationConfiguration(nil, authorizationConfiguration,
sets.NewString(authzmodes.AuthorizationModeChoices...),
sets.NewString(repeatableAuthorizerTypes...),
); len(errors) != 0 {
return nil, fmt.Errorf(errors.ToAggregate().Error())
return nil, err
}
} else {
authorizationConfiguration, err = o.buildAuthorizationConfiguration()
@ -321,16 +284,10 @@ func (o *BuiltInAuthorizationOptions) buildAuthorizationConfiguration() (*authzc
default:
authorizers = append(authorizers, authzconfig.AuthorizerConfiguration{
Type: authzconfig.AuthorizerType(mode),
Name: getNameForAuthorizerMode(mode),
Name: authorizer.GetNameForAuthorizerMode(mode),
})
}
}
return &authzconfig.AuthorizationConfiguration{Authorizers: authorizers}, nil
}
// getNameForAuthorizerMode returns the name to be set for the mode in AuthorizationConfiguration
// For now, lower cases the mode name
func getNameForAuthorizerMode(mode string) string {
return strings.ToLower(mode)
}