Merge pull request #119099 from palnabarun/authz-config
[StructuredAuthorizationConfiguration] Implement API types and wire kube-apiserver to use them
This commit is contained in:
		@@ -174,7 +174,10 @@ func BuildGenericConfig(
 | 
			
		||||
 | 
			
		||||
// BuildAuthorizer constructs the authorizer
 | 
			
		||||
func BuildAuthorizer(s controlplaneapiserver.CompletedOptions, EgressSelector *egressselector.EgressSelector, versionedInformers clientgoinformers.SharedInformerFactory) (authorizer.Authorizer, authorizer.RuleResolver, error) {
 | 
			
		||||
	authorizationConfig := s.Authorization.ToAuthorizationConfig(versionedInformers)
 | 
			
		||||
	authorizationConfig, err := s.Authorization.ToAuthorizationConfig(versionedInformers)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if EgressSelector != nil {
 | 
			
		||||
		egressDialer, err := EgressSelector.Lookup(egressselector.ControlPlane.AsNetworkContext())
 | 
			
		||||
 
 | 
			
		||||
@@ -19,10 +19,9 @@ package authorizer
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	utilnet "k8s.io/apimachinery/pkg/util/net"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
			
		||||
	authzconfig "k8s.io/apiserver/pkg/apis/apiserver"
 | 
			
		||||
	"k8s.io/apiserver/pkg/authentication/user"
 | 
			
		||||
	"k8s.io/apiserver/pkg/authorization/authorizer"
 | 
			
		||||
	"k8s.io/apiserver/pkg/authorization/authorizerfactory"
 | 
			
		||||
@@ -40,8 +39,6 @@ import (
 | 
			
		||||
 | 
			
		||||
// Config contains the data on how to authorize a request to the Kube API Server
 | 
			
		||||
type Config struct {
 | 
			
		||||
	AuthorizationModes []string
 | 
			
		||||
 | 
			
		||||
	// Options for ModeABAC
 | 
			
		||||
 | 
			
		||||
	// Path to an ABAC policy file.
 | 
			
		||||
@@ -49,14 +46,6 @@ type Config struct {
 | 
			
		||||
 | 
			
		||||
	// Options for ModeWebhook
 | 
			
		||||
 | 
			
		||||
	// Kubeconfig file for Webhook authorization plugin.
 | 
			
		||||
	WebhookConfigFile string
 | 
			
		||||
	// API version of subject access reviews to send to the webhook (e.g. "v1", "v1beta1")
 | 
			
		||||
	WebhookVersion string
 | 
			
		||||
	// TTL for caching of authorized responses from the webhook server.
 | 
			
		||||
	WebhookCacheAuthorizedTTL time.Duration
 | 
			
		||||
	// TTL for caching of unauthorized responses from the webhook server.
 | 
			
		||||
	WebhookCacheUnauthorizedTTL time.Duration
 | 
			
		||||
	// WebhookRetryBackoff specifies the backoff parameters for the authorization webhook retry logic.
 | 
			
		||||
	// This allows us to configure the sleep time at each iteration and the maximum number of retries allowed
 | 
			
		||||
	// before we fail the webhook call in order to limit the fan out that ensues when the system is degraded.
 | 
			
		||||
@@ -66,12 +55,16 @@ type Config struct {
 | 
			
		||||
 | 
			
		||||
	// Optional field, custom dial function used to connect to webhook
 | 
			
		||||
	CustomDial utilnet.DialFunc
 | 
			
		||||
 | 
			
		||||
	// AuthorizationConfiguration stores the configuration for the Authorizer chain
 | 
			
		||||
	// It will deprecate most of the above flags when GA
 | 
			
		||||
	AuthorizationConfiguration *authzconfig.AuthorizationConfiguration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns the right sort of union of multiple authorizer.Authorizer objects
 | 
			
		||||
// based on the authorizationMode or an error.
 | 
			
		||||
func (config Config) New() (authorizer.Authorizer, authorizer.RuleResolver, error) {
 | 
			
		||||
	if len(config.AuthorizationModes) == 0 {
 | 
			
		||||
	if len(config.AuthorizationConfiguration.Authorizers) == 0 {
 | 
			
		||||
		return nil, nil, fmt.Errorf("at least one authorization mode must be passed")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -84,10 +77,10 @@ func (config Config) New() (authorizer.Authorizer, authorizer.RuleResolver, erro
 | 
			
		||||
	superuserAuthorizer := authorizerfactory.NewPrivilegedGroups(user.SystemPrivilegedGroup)
 | 
			
		||||
	authorizers = append(authorizers, superuserAuthorizer)
 | 
			
		||||
 | 
			
		||||
	for _, authorizationMode := range config.AuthorizationModes {
 | 
			
		||||
	for _, configuredAuthorizer := range config.AuthorizationConfiguration.Authorizers {
 | 
			
		||||
		// Keep cases in sync with constant list in k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes/modes.go.
 | 
			
		||||
		switch authorizationMode {
 | 
			
		||||
		case modes.ModeNode:
 | 
			
		||||
		switch configuredAuthorizer.Type {
 | 
			
		||||
		case authzconfig.AuthorizerType(modes.ModeNode):
 | 
			
		||||
			node.RegisterMetrics()
 | 
			
		||||
			graph := node.NewGraph()
 | 
			
		||||
			node.AddGraphEventHandlers(
 | 
			
		||||
@@ -101,33 +94,33 @@ func (config Config) New() (authorizer.Authorizer, authorizer.RuleResolver, erro
 | 
			
		||||
			authorizers = append(authorizers, nodeAuthorizer)
 | 
			
		||||
			ruleResolvers = append(ruleResolvers, nodeAuthorizer)
 | 
			
		||||
 | 
			
		||||
		case modes.ModeAlwaysAllow:
 | 
			
		||||
		case authzconfig.AuthorizerType(modes.ModeAlwaysAllow):
 | 
			
		||||
			alwaysAllowAuthorizer := authorizerfactory.NewAlwaysAllowAuthorizer()
 | 
			
		||||
			authorizers = append(authorizers, alwaysAllowAuthorizer)
 | 
			
		||||
			ruleResolvers = append(ruleResolvers, alwaysAllowAuthorizer)
 | 
			
		||||
		case modes.ModeAlwaysDeny:
 | 
			
		||||
		case authzconfig.AuthorizerType(modes.ModeAlwaysDeny):
 | 
			
		||||
			alwaysDenyAuthorizer := authorizerfactory.NewAlwaysDenyAuthorizer()
 | 
			
		||||
			authorizers = append(authorizers, alwaysDenyAuthorizer)
 | 
			
		||||
			ruleResolvers = append(ruleResolvers, alwaysDenyAuthorizer)
 | 
			
		||||
		case modes.ModeABAC:
 | 
			
		||||
		case authzconfig.AuthorizerType(modes.ModeABAC):
 | 
			
		||||
			abacAuthorizer, err := abac.NewFromFile(config.PolicyFile)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, nil, err
 | 
			
		||||
			}
 | 
			
		||||
			authorizers = append(authorizers, abacAuthorizer)
 | 
			
		||||
			ruleResolvers = append(ruleResolvers, abacAuthorizer)
 | 
			
		||||
		case modes.ModeWebhook:
 | 
			
		||||
		case authzconfig.AuthorizerType(modes.ModeWebhook):
 | 
			
		||||
			if config.WebhookRetryBackoff == nil {
 | 
			
		||||
				return nil, nil, errors.New("retry backoff parameters for authorization webhook has not been specified")
 | 
			
		||||
			}
 | 
			
		||||
			clientConfig, err := webhookutil.LoadKubeconfig(config.WebhookConfigFile, config.CustomDial)
 | 
			
		||||
			clientConfig, err := webhookutil.LoadKubeconfig(*configuredAuthorizer.Webhook.ConnectionInfo.KubeConfigFile, config.CustomDial)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, nil, err
 | 
			
		||||
			}
 | 
			
		||||
			webhookAuthorizer, err := webhook.New(clientConfig,
 | 
			
		||||
				config.WebhookVersion,
 | 
			
		||||
				config.WebhookCacheAuthorizedTTL,
 | 
			
		||||
				config.WebhookCacheUnauthorizedTTL,
 | 
			
		||||
				configuredAuthorizer.Webhook.SubjectAccessReviewVersion,
 | 
			
		||||
				configuredAuthorizer.Webhook.AuthorizedTTL.Duration,
 | 
			
		||||
				configuredAuthorizer.Webhook.UnauthorizedTTL.Duration,
 | 
			
		||||
				*config.WebhookRetryBackoff,
 | 
			
		||||
			)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
@@ -135,7 +128,7 @@ func (config Config) New() (authorizer.Authorizer, authorizer.RuleResolver, erro
 | 
			
		||||
			}
 | 
			
		||||
			authorizers = append(authorizers, webhookAuthorizer)
 | 
			
		||||
			ruleResolvers = append(ruleResolvers, webhookAuthorizer)
 | 
			
		||||
		case modes.ModeRBAC:
 | 
			
		||||
		case authzconfig.AuthorizerType(modes.ModeRBAC):
 | 
			
		||||
			rbacAuthorizer := rbac.New(
 | 
			
		||||
				&rbac.RoleGetter{Lister: config.VersionedInformerFactory.Rbac().V1().Roles().Lister()},
 | 
			
		||||
				&rbac.RoleBindingLister{Lister: config.VersionedInformerFactory.Rbac().V1().RoleBindings().Lister()},
 | 
			
		||||
@@ -145,7 +138,7 @@ func (config Config) New() (authorizer.Authorizer, authorizer.RuleResolver, erro
 | 
			
		||||
			authorizers = append(authorizers, rbacAuthorizer)
 | 
			
		||||
			ruleResolvers = append(ruleResolvers, rbacAuthorizer)
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, nil, fmt.Errorf("unknown authorization mode %s specified", authorizationMode)
 | 
			
		||||
			return nil, nil, fmt.Errorf("unknown authorization mode %s specified", configuredAuthorizer.Type)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,14 +23,20 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/spf13/pflag"
 | 
			
		||||
 | 
			
		||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/wait"
 | 
			
		||||
	authzconfig "k8s.io/apiserver/pkg/apis/apiserver"
 | 
			
		||||
	genericoptions "k8s.io/apiserver/pkg/server/options"
 | 
			
		||||
	versionedinformers "k8s.io/client-go/informers"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/kubeapiserver/authorizer"
 | 
			
		||||
	authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	defaultWebhookName = "default"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// BuiltInAuthorizationOptions contains all build-in authorization options for API Server
 | 
			
		||||
type BuiltInAuthorizationOptions struct {
 | 
			
		||||
	Modes                       []string
 | 
			
		||||
@@ -62,7 +68,6 @@ func (o *BuiltInAuthorizationOptions) Validate() []error {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	var allErrors []error
 | 
			
		||||
 | 
			
		||||
	if len(o.Modes) == 0 {
 | 
			
		||||
		allErrors = append(allErrors, fmt.Errorf("at least one authorization-mode must be passed"))
 | 
			
		||||
	}
 | 
			
		||||
@@ -125,15 +130,54 @@ func (o *BuiltInAuthorizationOptions) AddFlags(fs *pflag.FlagSet) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToAuthorizationConfig convert BuiltInAuthorizationOptions to authorizer.Config
 | 
			
		||||
func (o *BuiltInAuthorizationOptions) ToAuthorizationConfig(versionedInformerFactory versionedinformers.SharedInformerFactory) authorizer.Config {
 | 
			
		||||
func (o *BuiltInAuthorizationOptions) ToAuthorizationConfig(versionedInformerFactory versionedinformers.SharedInformerFactory) (authorizer.Config, error) {
 | 
			
		||||
 | 
			
		||||
	authzConfiguration, err := o.buildAuthorizationConfiguration()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return authorizer.Config{}, fmt.Errorf("failed to build authorization config: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return authorizer.Config{
 | 
			
		||||
		AuthorizationModes:          o.Modes,
 | 
			
		||||
		PolicyFile:               o.PolicyFile,
 | 
			
		||||
		WebhookConfigFile:           o.WebhookConfigFile,
 | 
			
		||||
		WebhookVersion:              o.WebhookVersion,
 | 
			
		||||
		WebhookCacheAuthorizedTTL:   o.WebhookCacheAuthorizedTTL,
 | 
			
		||||
		WebhookCacheUnauthorizedTTL: o.WebhookCacheUnauthorizedTTL,
 | 
			
		||||
		VersionedInformerFactory: versionedInformerFactory,
 | 
			
		||||
		WebhookRetryBackoff:      o.WebhookRetryBackoff,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		AuthorizationConfiguration: authzConfiguration,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// buildAuthorizationConfiguration converts existing flags to the AuthorizationConfiguration format
 | 
			
		||||
func (o *BuiltInAuthorizationOptions) buildAuthorizationConfiguration() (*authzconfig.AuthorizationConfiguration, error) {
 | 
			
		||||
	var authorizers []authzconfig.AuthorizerConfiguration
 | 
			
		||||
 | 
			
		||||
	if len(o.Modes) != sets.NewString(o.Modes...).Len() {
 | 
			
		||||
		return nil, fmt.Errorf("modes should not be repeated in --authorization-mode")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, mode := range o.Modes {
 | 
			
		||||
		switch mode {
 | 
			
		||||
		case authzmodes.ModeWebhook:
 | 
			
		||||
			authorizers = append(authorizers, authzconfig.AuthorizerConfiguration{
 | 
			
		||||
				Type: authzconfig.TypeWebhook,
 | 
			
		||||
				Webhook: &authzconfig.WebhookConfiguration{
 | 
			
		||||
					Name:            defaultWebhookName,
 | 
			
		||||
					AuthorizedTTL:   metav1.Duration{Duration: o.WebhookCacheAuthorizedTTL},
 | 
			
		||||
					UnauthorizedTTL: metav1.Duration{Duration: o.WebhookCacheUnauthorizedTTL},
 | 
			
		||||
					// Timeout and FailurePolicy are required for the new configuration.
 | 
			
		||||
					// Setting these two implicitly to preserve backward compatibility.
 | 
			
		||||
					Timeout:                    metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
					FailurePolicy:              authzconfig.FailurePolicyNoOpinion,
 | 
			
		||||
					SubjectAccessReviewVersion: o.WebhookVersion,
 | 
			
		||||
					ConnectionInfo: authzconfig.WebhookConnectionInfo{
 | 
			
		||||
						Type:           authzconfig.AuthorizationWebhookConnectionInfoTypeKubeConfig,
 | 
			
		||||
						KubeConfigFile: &o.WebhookConfigFile,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
		default:
 | 
			
		||||
			authorizers = append(authorizers, authzconfig.AuthorizerConfiguration{Type: authzconfig.AuthorizerType(mode)})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &authzconfig.AuthorizationConfiguration{Authorizers: authorizers}, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
 | 
			
		||||
	scheme.AddKnownTypes(SchemeGroupVersion,
 | 
			
		||||
		&AdmissionConfiguration{},
 | 
			
		||||
		&AuthenticationConfiguration{},
 | 
			
		||||
		&AuthorizationConfiguration{},
 | 
			
		||||
		&EgressSelectorConfiguration{},
 | 
			
		||||
		&TracingConfiguration{},
 | 
			
		||||
	)
 | 
			
		||||
 
 | 
			
		||||
@@ -198,3 +198,120 @@ type PrefixedClaimOrExpression struct {
 | 
			
		||||
	Claim  string
 | 
			
		||||
	Prefix *string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
			
		||||
 | 
			
		||||
type AuthorizationConfiguration struct {
 | 
			
		||||
	metav1.TypeMeta
 | 
			
		||||
 | 
			
		||||
	// Authorizers is an ordered list of authorizers to
 | 
			
		||||
	// authorize requests against.
 | 
			
		||||
	// This is similar to the --authorization-modes kube-apiserver flag
 | 
			
		||||
	// Must be at least one.
 | 
			
		||||
	Authorizers []AuthorizerConfiguration `json:"authorizers"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	TypeWebhook                                      AuthorizerType = "Webhook"
 | 
			
		||||
	FailurePolicyNoOpinion                           string         = "NoOpinion"
 | 
			
		||||
	FailurePolicyDeny                                string         = "Deny"
 | 
			
		||||
	AuthorizationWebhookConnectionInfoTypeKubeConfig string         = "KubeConfigFile"
 | 
			
		||||
	AuthorizationWebhookConnectionInfoTypeInCluster  string         = "InClusterConfig"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AuthorizerType string
 | 
			
		||||
 | 
			
		||||
type AuthorizerConfiguration struct {
 | 
			
		||||
	// Type refers to the type of the authorizer
 | 
			
		||||
	// "Webhook" is supported in the generic API server
 | 
			
		||||
	// Other API servers may support additional authorizer
 | 
			
		||||
	// types like Node, RBAC, ABAC, etc.
 | 
			
		||||
	Type AuthorizerType
 | 
			
		||||
 | 
			
		||||
	// Webhook defines the configuration for a Webhook authorizer
 | 
			
		||||
	// Must be defined when Type=Webhook
 | 
			
		||||
	Webhook *WebhookConfiguration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebhookConfiguration struct {
 | 
			
		||||
	// Name used to describe the webhook
 | 
			
		||||
	// This is explicitly used in monitoring machinery for metrics
 | 
			
		||||
	// Note: Names must be DNS1123 labels like `mywebhookname` or
 | 
			
		||||
	//		 subdomains like `webhookname.example.domain`
 | 
			
		||||
	// Required, with no default
 | 
			
		||||
	Name string
 | 
			
		||||
	// The duration to cache 'authorized' responses from the webhook
 | 
			
		||||
	// authorizer.
 | 
			
		||||
	// Same as setting `--authorization-webhook-cache-authorized-ttl` flag
 | 
			
		||||
	// Default: 5m0s
 | 
			
		||||
	AuthorizedTTL metav1.Duration
 | 
			
		||||
	// The duration to cache 'unauthorized' responses from the webhook
 | 
			
		||||
	// authorizer.
 | 
			
		||||
	// Same as setting `--authorization-webhook-cache-unauthorized-ttl` flag
 | 
			
		||||
	// Default: 30s
 | 
			
		||||
	UnauthorizedTTL metav1.Duration
 | 
			
		||||
	// Timeout for the webhook request
 | 
			
		||||
	// Maximum allowed value is 30s.
 | 
			
		||||
	// Required, no default value.
 | 
			
		||||
	Timeout metav1.Duration
 | 
			
		||||
	// The API version of the authorization.k8s.io SubjectAccessReview to
 | 
			
		||||
	// send to and expect from the webhook.
 | 
			
		||||
	// Same as setting `--authorization-webhook-version` flag
 | 
			
		||||
	// Valid values: v1beta1, v1
 | 
			
		||||
	// Required, no default value
 | 
			
		||||
	SubjectAccessReviewVersion string
 | 
			
		||||
	// MatchConditionSubjectAccessReviewVersion specifies the SubjectAccessReview
 | 
			
		||||
	// version the CEL expressions are evaluated against
 | 
			
		||||
	// Valid values: v1
 | 
			
		||||
	// Required, no default value
 | 
			
		||||
	MatchConditionSubjectAccessReviewVersion string
 | 
			
		||||
	// Controls the authorization decision when a webhook request fails to
 | 
			
		||||
	// complete or returns a malformed response or errors evaluating
 | 
			
		||||
	// matchConditions.
 | 
			
		||||
	// Valid values:
 | 
			
		||||
	//   - NoOpinion: continue to subsequent authorizers to see if one of
 | 
			
		||||
	//     them allows the request
 | 
			
		||||
	//   - Deny: reject the request without consulting subsequent authorizers
 | 
			
		||||
	// Required, with no default.
 | 
			
		||||
	FailurePolicy string
 | 
			
		||||
 | 
			
		||||
	// ConnectionInfo defines how we talk to the webhook
 | 
			
		||||
	ConnectionInfo WebhookConnectionInfo
 | 
			
		||||
 | 
			
		||||
	// matchConditions is a list of conditions that must be met for a request to be sent to this
 | 
			
		||||
	// webhook. An empty list of matchConditions matches all requests.
 | 
			
		||||
	// There are a maximum of 64 match conditions allowed.
 | 
			
		||||
	//
 | 
			
		||||
	// The exact matching logic is (in order):
 | 
			
		||||
	//   1. If at least one matchCondition evaluates to FALSE, then the webhook is skipped.
 | 
			
		||||
	//   2. If ALL matchConditions evaluate to TRUE, then the webhook is called.
 | 
			
		||||
	//   3. If at least one matchCondition evaluates to an error (but none are FALSE):
 | 
			
		||||
	//      - If failurePolicy=Deny, then the webhook rejects the request
 | 
			
		||||
	//      - If failurePolicy=NoOpinion, then the error is ignored and the webhook is skipped
 | 
			
		||||
	MatchConditions []WebhookMatchCondition
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebhookConnectionInfo struct {
 | 
			
		||||
	// Controls how the webhook should communicate with the server.
 | 
			
		||||
	// Valid values:
 | 
			
		||||
	// - KubeConfig: use the file specified in kubeConfigFile to locate the
 | 
			
		||||
	//   server.
 | 
			
		||||
	// - InClusterConfig: use the in-cluster configuration to call the
 | 
			
		||||
	//   SubjectAccessReview API hosted by kube-apiserver. This mode is not
 | 
			
		||||
	//   allowed for kube-apiserver.
 | 
			
		||||
	Type string
 | 
			
		||||
 | 
			
		||||
	// Path to KubeConfigFile for connection info
 | 
			
		||||
	// Required, if connectionInfo.Type is KubeConfig
 | 
			
		||||
	KubeConfigFile *string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebhookMatchCondition struct {
 | 
			
		||||
	// expression represents the expression which will be evaluated by CEL. Must evaluate to bool.
 | 
			
		||||
	// CEL expressions have access to the contents of the SubjectAccessReview in v1 version.
 | 
			
		||||
	// If version specified by subjectAccessReviewVersion in the request variable is v1beta1,
 | 
			
		||||
	// the contents would be converted to the v1 version before evaluating the CEL expression.
 | 
			
		||||
	//
 | 
			
		||||
	// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
 | 
			
		||||
	Expression string
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
/*
 | 
			
		||||
Copyright 2023 The Kubernetes Authors.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package v1alpha1
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func addDefaultingFuncs(scheme *runtime.Scheme) error {
 | 
			
		||||
	return RegisterDefaults(scheme)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetDefaults_WebhookConfiguration(obj *WebhookConfiguration) {
 | 
			
		||||
	if obj.AuthorizedTTL.Duration == 0 {
 | 
			
		||||
		obj.AuthorizedTTL.Duration = 5 * time.Minute
 | 
			
		||||
	}
 | 
			
		||||
	if obj.UnauthorizedTTL.Duration == 0 {
 | 
			
		||||
		obj.UnauthorizedTTL.Duration = 30 * time.Second
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -43,7 +43,7 @@ func init() {
 | 
			
		||||
	// We only register manually written functions here. The registration of the
 | 
			
		||||
	// generated functions takes place in the generated files. The separation
 | 
			
		||||
	// makes the code compile even when the generated files are missing.
 | 
			
		||||
	localSchemeBuilder.Register(addKnownTypes)
 | 
			
		||||
	localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Adds the list of known types to the given scheme.
 | 
			
		||||
@@ -54,6 +54,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
 | 
			
		||||
	)
 | 
			
		||||
	scheme.AddKnownTypes(ConfigSchemeGroupVersion,
 | 
			
		||||
		&AuthenticationConfiguration{},
 | 
			
		||||
		&AuthorizationConfiguration{},
 | 
			
		||||
		&TracingConfiguration{},
 | 
			
		||||
	)
 | 
			
		||||
	metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
 | 
			
		||||
 
 | 
			
		||||
@@ -268,3 +268,121 @@ type PrefixedClaimOrExpression struct {
 | 
			
		||||
	// +required
 | 
			
		||||
	Prefix *string `json:"prefix"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 | 
			
		||||
 | 
			
		||||
type AuthorizationConfiguration struct {
 | 
			
		||||
	metav1.TypeMeta
 | 
			
		||||
 | 
			
		||||
	// Authorizers is an ordered list of authorizers to
 | 
			
		||||
	// authorize requests against.
 | 
			
		||||
	// This is similar to the --authorization-modes kube-apiserver flag
 | 
			
		||||
	// Must be at least one.
 | 
			
		||||
	Authorizers []AuthorizerConfiguration `json:"authorizers"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	TypeWebhook                                      AuthorizerType = "Webhook"
 | 
			
		||||
	FailurePolicyNoOpinion                           string         = "NoOpinion"
 | 
			
		||||
	FailurePolicyDeny                                string         = "Deny"
 | 
			
		||||
	AuthorizationWebhookConnectionInfoTypeKubeConfig string         = "KubeConfigFile"
 | 
			
		||||
	AuthorizationWebhookConnectionInfoTypeInCluster  string         = "InClusterConfig"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AuthorizerType string
 | 
			
		||||
 | 
			
		||||
type AuthorizerConfiguration struct {
 | 
			
		||||
	// Type refers to the type of the authorizer
 | 
			
		||||
	// "Webhook" is supported in the generic API server
 | 
			
		||||
	// Other API servers may support additional authorizer
 | 
			
		||||
	// types like Node, RBAC, ABAC, etc.
 | 
			
		||||
	Type string `json:"type"`
 | 
			
		||||
 | 
			
		||||
	// Webhook defines the configuration for a Webhook authorizer
 | 
			
		||||
	// Must be defined when Type=Webhook
 | 
			
		||||
	// Must not be defined when Type!=Webhook
 | 
			
		||||
	Webhook *WebhookConfiguration `json:"webhook,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebhookConfiguration struct {
 | 
			
		||||
	// Name used to describe the webhook
 | 
			
		||||
	// This is explicitly used in monitoring machinery for metrics
 | 
			
		||||
	// Note: Names must be DNS1123 labels like `mywebhookname` or
 | 
			
		||||
	//		 subdomains like `webhookname.example.domain`
 | 
			
		||||
	// Required, with no default
 | 
			
		||||
	Name string `json:"name"`
 | 
			
		||||
	// The duration to cache 'authorized' responses from the webhook
 | 
			
		||||
	// authorizer.
 | 
			
		||||
	// Same as setting `--authorization-webhook-cache-authorized-ttl` flag
 | 
			
		||||
	// Default: 5m0s
 | 
			
		||||
	AuthorizedTTL metav1.Duration `json:"authorizedTTL"`
 | 
			
		||||
	// The duration to cache 'unauthorized' responses from the webhook
 | 
			
		||||
	// authorizer.
 | 
			
		||||
	// Same as setting `--authorization-webhook-cache-unauthorized-ttl` flag
 | 
			
		||||
	// Default: 30s
 | 
			
		||||
	UnauthorizedTTL metav1.Duration `json:"unauthorizedTTL"`
 | 
			
		||||
	// Timeout for the webhook request
 | 
			
		||||
	// Maximum allowed value is 30s.
 | 
			
		||||
	// Required, no default value.
 | 
			
		||||
	Timeout metav1.Duration `json:"timeout"`
 | 
			
		||||
	// The API version of the authorization.k8s.io SubjectAccessReview to
 | 
			
		||||
	// send to and expect from the webhook.
 | 
			
		||||
	// Same as setting `--authorization-webhook-version` flag
 | 
			
		||||
	// Valid values: v1beta1, v1
 | 
			
		||||
	// Required, no default value
 | 
			
		||||
	SubjectAccessReviewVersion string `json:"subjectAccessReviewVersion"`
 | 
			
		||||
	// MatchConditionSubjectAccessReviewVersion specifies the SubjectAccessReview
 | 
			
		||||
	// version the CEL expressions are evaluated against
 | 
			
		||||
	// Valid values: v1
 | 
			
		||||
	// Required, no default value
 | 
			
		||||
	MatchConditionSubjectAccessReviewVersion string `json:"matchConditionSubjectAccessReviewVersion"`
 | 
			
		||||
	// Controls the authorization decision when a webhook request fails to
 | 
			
		||||
	// complete or returns a malformed response or errors evaluating
 | 
			
		||||
	// matchConditions.
 | 
			
		||||
	// Valid values:
 | 
			
		||||
	//   - NoOpinion: continue to subsequent authorizers to see if one of
 | 
			
		||||
	//     them allows the request
 | 
			
		||||
	//   - Deny: reject the request without consulting subsequent authorizers
 | 
			
		||||
	// Required, with no default.
 | 
			
		||||
	FailurePolicy string `json:"failurePolicy"`
 | 
			
		||||
 | 
			
		||||
	// ConnectionInfo defines how we talk to the webhook
 | 
			
		||||
	ConnectionInfo WebhookConnectionInfo `json:"connectionInfo"`
 | 
			
		||||
 | 
			
		||||
	// matchConditions is a list of conditions that must be met for a request to be sent to this
 | 
			
		||||
	// webhook. An empty list of matchConditions matches all requests.
 | 
			
		||||
	// There are a maximum of 64 match conditions allowed.
 | 
			
		||||
	//
 | 
			
		||||
	// The exact matching logic is (in order):
 | 
			
		||||
	//   1. If at least one matchCondition evaluates to FALSE, then the webhook is skipped.
 | 
			
		||||
	//   2. If ALL matchConditions evaluate to TRUE, then the webhook is called.
 | 
			
		||||
	//   3. If at least one matchCondition evaluates to an error (but none are FALSE):
 | 
			
		||||
	//      - If failurePolicy=Deny, then the webhook rejects the request
 | 
			
		||||
	//      - If failurePolicy=NoOpinion, then the error is ignored and the webhook is skipped
 | 
			
		||||
	MatchConditions []WebhookMatchCondition `json:"matchConditions"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebhookConnectionInfo struct {
 | 
			
		||||
	// Controls how the webhook should communicate with the server.
 | 
			
		||||
	// Valid values:
 | 
			
		||||
	// - KubeConfig: use the file specified in kubeConfigFile to locate the
 | 
			
		||||
	//   server.
 | 
			
		||||
	// - InClusterConfig: use the in-cluster configuration to call the
 | 
			
		||||
	//   SubjectAccessReview API hosted by kube-apiserver. This mode is not
 | 
			
		||||
	//   allowed for kube-apiserver.
 | 
			
		||||
	Type string `json:"type"`
 | 
			
		||||
 | 
			
		||||
	// Path to KubeConfigFile for connection info
 | 
			
		||||
	// Required, if connectionInfo.Type is KubeConfig
 | 
			
		||||
	KubeConfigFile *string `json:"kubeConfigFile"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebhookMatchCondition struct {
 | 
			
		||||
	// expression represents the expression which will be evaluated by CEL. Must evaluate to bool.
 | 
			
		||||
	// CEL expressions have access to the contents of the SubjectAccessReview in v1 version.
 | 
			
		||||
	// If version specified by subjectAccessReviewVersion in the request variable is v1beta1,
 | 
			
		||||
	// the contents would be converted to the v1 version before evaluating the CEL expression.
 | 
			
		||||
	//
 | 
			
		||||
	// Documentation on CEL: https://kubernetes.io/docs/reference/using-api/cel/
 | 
			
		||||
	Expression string `json:"expression"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -66,6 +66,26 @@ func RegisterConversions(s *runtime.Scheme) error {
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*AuthorizationConfiguration)(nil), (*apiserver.AuthorizationConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1alpha1_AuthorizationConfiguration_To_apiserver_AuthorizationConfiguration(a.(*AuthorizationConfiguration), b.(*apiserver.AuthorizationConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*apiserver.AuthorizationConfiguration)(nil), (*AuthorizationConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_apiserver_AuthorizationConfiguration_To_v1alpha1_AuthorizationConfiguration(a.(*apiserver.AuthorizationConfiguration), b.(*AuthorizationConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*AuthorizerConfiguration)(nil), (*apiserver.AuthorizerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1alpha1_AuthorizerConfiguration_To_apiserver_AuthorizerConfiguration(a.(*AuthorizerConfiguration), b.(*apiserver.AuthorizerConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*apiserver.AuthorizerConfiguration)(nil), (*AuthorizerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_apiserver_AuthorizerConfiguration_To_v1alpha1_AuthorizerConfiguration(a.(*apiserver.AuthorizerConfiguration), b.(*AuthorizerConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*ClaimMappings)(nil), (*apiserver.ClaimMappings)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1alpha1_ClaimMappings_To_apiserver_ClaimMappings(a.(*ClaimMappings), b.(*apiserver.ClaimMappings), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
@@ -191,6 +211,36 @@ func RegisterConversions(s *runtime.Scheme) error {
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*WebhookConfiguration)(nil), (*apiserver.WebhookConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1alpha1_WebhookConfiguration_To_apiserver_WebhookConfiguration(a.(*WebhookConfiguration), b.(*apiserver.WebhookConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*apiserver.WebhookConfiguration)(nil), (*WebhookConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_apiserver_WebhookConfiguration_To_v1alpha1_WebhookConfiguration(a.(*apiserver.WebhookConfiguration), b.(*WebhookConfiguration), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*WebhookConnectionInfo)(nil), (*apiserver.WebhookConnectionInfo)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1alpha1_WebhookConnectionInfo_To_apiserver_WebhookConnectionInfo(a.(*WebhookConnectionInfo), b.(*apiserver.WebhookConnectionInfo), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*apiserver.WebhookConnectionInfo)(nil), (*WebhookConnectionInfo)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_apiserver_WebhookConnectionInfo_To_v1alpha1_WebhookConnectionInfo(a.(*apiserver.WebhookConnectionInfo), b.(*WebhookConnectionInfo), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*WebhookMatchCondition)(nil), (*apiserver.WebhookMatchCondition)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1alpha1_WebhookMatchCondition_To_apiserver_WebhookMatchCondition(a.(*WebhookMatchCondition), b.(*apiserver.WebhookMatchCondition), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddGeneratedConversionFunc((*apiserver.WebhookMatchCondition)(nil), (*WebhookMatchCondition)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_apiserver_WebhookMatchCondition_To_v1alpha1_WebhookMatchCondition(a.(*apiserver.WebhookMatchCondition), b.(*WebhookMatchCondition), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := s.AddConversionFunc((*EgressSelection)(nil), (*apiserver.EgressSelection)(nil), func(a, b interface{}, scope conversion.Scope) error {
 | 
			
		||||
		return Convert_v1alpha1_EgressSelection_To_apiserver_EgressSelection(a.(*EgressSelection), b.(*apiserver.EgressSelection), scope)
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
@@ -263,6 +313,48 @@ func Convert_apiserver_AuthenticationConfiguration_To_v1alpha1_AuthenticationCon
 | 
			
		||||
	return autoConvert_apiserver_AuthenticationConfiguration_To_v1alpha1_AuthenticationConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_v1alpha1_AuthorizationConfiguration_To_apiserver_AuthorizationConfiguration(in *AuthorizationConfiguration, out *apiserver.AuthorizationConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.Authorizers = *(*[]apiserver.AuthorizerConfiguration)(unsafe.Pointer(&in.Authorizers))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_v1alpha1_AuthorizationConfiguration_To_apiserver_AuthorizationConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_v1alpha1_AuthorizationConfiguration_To_apiserver_AuthorizationConfiguration(in *AuthorizationConfiguration, out *apiserver.AuthorizationConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_v1alpha1_AuthorizationConfiguration_To_apiserver_AuthorizationConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_apiserver_AuthorizationConfiguration_To_v1alpha1_AuthorizationConfiguration(in *apiserver.AuthorizationConfiguration, out *AuthorizationConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.Authorizers = *(*[]AuthorizerConfiguration)(unsafe.Pointer(&in.Authorizers))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_apiserver_AuthorizationConfiguration_To_v1alpha1_AuthorizationConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_apiserver_AuthorizationConfiguration_To_v1alpha1_AuthorizationConfiguration(in *apiserver.AuthorizationConfiguration, out *AuthorizationConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_apiserver_AuthorizationConfiguration_To_v1alpha1_AuthorizationConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_v1alpha1_AuthorizerConfiguration_To_apiserver_AuthorizerConfiguration(in *AuthorizerConfiguration, out *apiserver.AuthorizerConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.Type = apiserver.AuthorizerType(in.Type)
 | 
			
		||||
	out.Webhook = (*apiserver.WebhookConfiguration)(unsafe.Pointer(in.Webhook))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_v1alpha1_AuthorizerConfiguration_To_apiserver_AuthorizerConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_v1alpha1_AuthorizerConfiguration_To_apiserver_AuthorizerConfiguration(in *AuthorizerConfiguration, out *apiserver.AuthorizerConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_v1alpha1_AuthorizerConfiguration_To_apiserver_AuthorizerConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_apiserver_AuthorizerConfiguration_To_v1alpha1_AuthorizerConfiguration(in *apiserver.AuthorizerConfiguration, out *AuthorizerConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.Type = string(in.Type)
 | 
			
		||||
	out.Webhook = (*WebhookConfiguration)(unsafe.Pointer(in.Webhook))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_apiserver_AuthorizerConfiguration_To_v1alpha1_AuthorizerConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_apiserver_AuthorizerConfiguration_To_v1alpha1_AuthorizerConfiguration(in *apiserver.AuthorizerConfiguration, out *AuthorizerConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_apiserver_AuthorizerConfiguration_To_v1alpha1_AuthorizerConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_v1alpha1_ClaimMappings_To_apiserver_ClaimMappings(in *ClaimMappings, out *apiserver.ClaimMappings, s conversion.Scope) error {
 | 
			
		||||
	if err := Convert_v1alpha1_PrefixedClaimOrExpression_To_apiserver_PrefixedClaimOrExpression(&in.Username, &out.Username, s); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
@@ -583,3 +675,85 @@ func autoConvert_apiserver_UDSTransport_To_v1alpha1_UDSTransport(in *apiserver.U
 | 
			
		||||
func Convert_apiserver_UDSTransport_To_v1alpha1_UDSTransport(in *apiserver.UDSTransport, out *UDSTransport, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_apiserver_UDSTransport_To_v1alpha1_UDSTransport(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_v1alpha1_WebhookConfiguration_To_apiserver_WebhookConfiguration(in *WebhookConfiguration, out *apiserver.WebhookConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.Name = in.Name
 | 
			
		||||
	out.AuthorizedTTL = in.AuthorizedTTL
 | 
			
		||||
	out.UnauthorizedTTL = in.UnauthorizedTTL
 | 
			
		||||
	out.Timeout = in.Timeout
 | 
			
		||||
	out.SubjectAccessReviewVersion = in.SubjectAccessReviewVersion
 | 
			
		||||
	out.MatchConditionSubjectAccessReviewVersion = in.MatchConditionSubjectAccessReviewVersion
 | 
			
		||||
	out.FailurePolicy = in.FailurePolicy
 | 
			
		||||
	if err := Convert_v1alpha1_WebhookConnectionInfo_To_apiserver_WebhookConnectionInfo(&in.ConnectionInfo, &out.ConnectionInfo, s); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	out.MatchConditions = *(*[]apiserver.WebhookMatchCondition)(unsafe.Pointer(&in.MatchConditions))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_v1alpha1_WebhookConfiguration_To_apiserver_WebhookConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_v1alpha1_WebhookConfiguration_To_apiserver_WebhookConfiguration(in *WebhookConfiguration, out *apiserver.WebhookConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_v1alpha1_WebhookConfiguration_To_apiserver_WebhookConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_apiserver_WebhookConfiguration_To_v1alpha1_WebhookConfiguration(in *apiserver.WebhookConfiguration, out *WebhookConfiguration, s conversion.Scope) error {
 | 
			
		||||
	out.Name = in.Name
 | 
			
		||||
	out.AuthorizedTTL = in.AuthorizedTTL
 | 
			
		||||
	out.UnauthorizedTTL = in.UnauthorizedTTL
 | 
			
		||||
	out.Timeout = in.Timeout
 | 
			
		||||
	out.SubjectAccessReviewVersion = in.SubjectAccessReviewVersion
 | 
			
		||||
	out.MatchConditionSubjectAccessReviewVersion = in.MatchConditionSubjectAccessReviewVersion
 | 
			
		||||
	out.FailurePolicy = in.FailurePolicy
 | 
			
		||||
	if err := Convert_apiserver_WebhookConnectionInfo_To_v1alpha1_WebhookConnectionInfo(&in.ConnectionInfo, &out.ConnectionInfo, s); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	out.MatchConditions = *(*[]WebhookMatchCondition)(unsafe.Pointer(&in.MatchConditions))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_apiserver_WebhookConfiguration_To_v1alpha1_WebhookConfiguration is an autogenerated conversion function.
 | 
			
		||||
func Convert_apiserver_WebhookConfiguration_To_v1alpha1_WebhookConfiguration(in *apiserver.WebhookConfiguration, out *WebhookConfiguration, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_apiserver_WebhookConfiguration_To_v1alpha1_WebhookConfiguration(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_v1alpha1_WebhookConnectionInfo_To_apiserver_WebhookConnectionInfo(in *WebhookConnectionInfo, out *apiserver.WebhookConnectionInfo, s conversion.Scope) error {
 | 
			
		||||
	out.Type = in.Type
 | 
			
		||||
	out.KubeConfigFile = (*string)(unsafe.Pointer(in.KubeConfigFile))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_v1alpha1_WebhookConnectionInfo_To_apiserver_WebhookConnectionInfo is an autogenerated conversion function.
 | 
			
		||||
func Convert_v1alpha1_WebhookConnectionInfo_To_apiserver_WebhookConnectionInfo(in *WebhookConnectionInfo, out *apiserver.WebhookConnectionInfo, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_v1alpha1_WebhookConnectionInfo_To_apiserver_WebhookConnectionInfo(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_apiserver_WebhookConnectionInfo_To_v1alpha1_WebhookConnectionInfo(in *apiserver.WebhookConnectionInfo, out *WebhookConnectionInfo, s conversion.Scope) error {
 | 
			
		||||
	out.Type = in.Type
 | 
			
		||||
	out.KubeConfigFile = (*string)(unsafe.Pointer(in.KubeConfigFile))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_apiserver_WebhookConnectionInfo_To_v1alpha1_WebhookConnectionInfo is an autogenerated conversion function.
 | 
			
		||||
func Convert_apiserver_WebhookConnectionInfo_To_v1alpha1_WebhookConnectionInfo(in *apiserver.WebhookConnectionInfo, out *WebhookConnectionInfo, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_apiserver_WebhookConnectionInfo_To_v1alpha1_WebhookConnectionInfo(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_v1alpha1_WebhookMatchCondition_To_apiserver_WebhookMatchCondition(in *WebhookMatchCondition, out *apiserver.WebhookMatchCondition, s conversion.Scope) error {
 | 
			
		||||
	out.Expression = in.Expression
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_v1alpha1_WebhookMatchCondition_To_apiserver_WebhookMatchCondition is an autogenerated conversion function.
 | 
			
		||||
func Convert_v1alpha1_WebhookMatchCondition_To_apiserver_WebhookMatchCondition(in *WebhookMatchCondition, out *apiserver.WebhookMatchCondition, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_v1alpha1_WebhookMatchCondition_To_apiserver_WebhookMatchCondition(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func autoConvert_apiserver_WebhookMatchCondition_To_v1alpha1_WebhookMatchCondition(in *apiserver.WebhookMatchCondition, out *WebhookMatchCondition, s conversion.Scope) error {
 | 
			
		||||
	out.Expression = in.Expression
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert_apiserver_WebhookMatchCondition_To_v1alpha1_WebhookMatchCondition is an autogenerated conversion function.
 | 
			
		||||
func Convert_apiserver_WebhookMatchCondition_To_v1alpha1_WebhookMatchCondition(in *apiserver.WebhookMatchCondition, out *WebhookMatchCondition, s conversion.Scope) error {
 | 
			
		||||
	return autoConvert_apiserver_WebhookMatchCondition_To_v1alpha1_WebhookMatchCondition(in, out, s)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -110,6 +110,59 @@ func (in *AuthenticationConfiguration) DeepCopyObject() runtime.Object {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *AuthorizationConfiguration) DeepCopyInto(out *AuthorizationConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	out.TypeMeta = in.TypeMeta
 | 
			
		||||
	if in.Authorizers != nil {
 | 
			
		||||
		in, out := &in.Authorizers, &out.Authorizers
 | 
			
		||||
		*out = make([]AuthorizerConfiguration, len(*in))
 | 
			
		||||
		for i := range *in {
 | 
			
		||||
			(*in)[i].DeepCopyInto(&(*out)[i])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthorizationConfiguration.
 | 
			
		||||
func (in *AuthorizationConfiguration) DeepCopy() *AuthorizationConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(AuthorizationConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | 
			
		||||
func (in *AuthorizationConfiguration) DeepCopyObject() runtime.Object {
 | 
			
		||||
	if c := in.DeepCopy(); c != nil {
 | 
			
		||||
		return c
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *AuthorizerConfiguration) DeepCopyInto(out *AuthorizerConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	if in.Webhook != nil {
 | 
			
		||||
		in, out := &in.Webhook, &out.Webhook
 | 
			
		||||
		*out = new(WebhookConfiguration)
 | 
			
		||||
		(*in).DeepCopyInto(*out)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthorizerConfiguration.
 | 
			
		||||
func (in *AuthorizerConfiguration) DeepCopy() *AuthorizerConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(AuthorizerConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *ClaimMappings) DeepCopyInto(out *ClaimMappings) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
@@ -383,3 +436,65 @@ func (in *UDSTransport) DeepCopy() *UDSTransport {
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *WebhookConfiguration) DeepCopyInto(out *WebhookConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	out.AuthorizedTTL = in.AuthorizedTTL
 | 
			
		||||
	out.UnauthorizedTTL = in.UnauthorizedTTL
 | 
			
		||||
	out.Timeout = in.Timeout
 | 
			
		||||
	in.ConnectionInfo.DeepCopyInto(&out.ConnectionInfo)
 | 
			
		||||
	if in.MatchConditions != nil {
 | 
			
		||||
		in, out := &in.MatchConditions, &out.MatchConditions
 | 
			
		||||
		*out = make([]WebhookMatchCondition, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookConfiguration.
 | 
			
		||||
func (in *WebhookConfiguration) DeepCopy() *WebhookConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(WebhookConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *WebhookConnectionInfo) DeepCopyInto(out *WebhookConnectionInfo) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	if in.KubeConfigFile != nil {
 | 
			
		||||
		in, out := &in.KubeConfigFile, &out.KubeConfigFile
 | 
			
		||||
		*out = new(string)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookConnectionInfo.
 | 
			
		||||
func (in *WebhookConnectionInfo) DeepCopy() *WebhookConnectionInfo {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(WebhookConnectionInfo)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *WebhookMatchCondition) DeepCopyInto(out *WebhookMatchCondition) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookMatchCondition.
 | 
			
		||||
func (in *WebhookMatchCondition) DeepCopy() *WebhookMatchCondition {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(WebhookMatchCondition)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,5 +29,15 @@ import (
 | 
			
		||||
// Public to allow building arbitrary schemes.
 | 
			
		||||
// All generated defaulters are covering - they call all nested defaulters.
 | 
			
		||||
func RegisterDefaults(scheme *runtime.Scheme) error {
 | 
			
		||||
	scheme.AddTypeDefaultingFunc(&AuthorizationConfiguration{}, func(obj interface{}) { SetObjectDefaults_AuthorizationConfiguration(obj.(*AuthorizationConfiguration)) })
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetObjectDefaults_AuthorizationConfiguration(in *AuthorizationConfiguration) {
 | 
			
		||||
	for i := range in.Authorizers {
 | 
			
		||||
		a := &in.Authorizers[i]
 | 
			
		||||
		if a.Webhook != nil {
 | 
			
		||||
			SetDefaults_WebhookConfiguration(a.Webhook)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,16 @@ package validation
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	v1 "k8s.io/api/authorization/v1"
 | 
			
		||||
	"k8s.io/api/authorization/v1beta1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	utilvalidation "k8s.io/apimachinery/pkg/util/validation"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
			
		||||
	api "k8s.io/apiserver/pkg/apis/apiserver"
 | 
			
		||||
	"k8s.io/client-go/util/cert"
 | 
			
		||||
@@ -202,3 +210,147 @@ func validateClaimMappings(m api.ClaimMappings, fldPath *field.Path) field.Error
 | 
			
		||||
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateAuthorizationConfiguration validates a given AuthorizationConfiguration.
 | 
			
		||||
func ValidateAuthorizationConfiguration(fldPath *field.Path, c *api.AuthorizationConfiguration, knownTypes sets.String, repeatableTypes sets.String) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
 | 
			
		||||
	if len(c.Authorizers) == 0 {
 | 
			
		||||
		allErrs = append(allErrs, field.Required(fldPath.Child("authorizers"), "at least one authorization mode must be defined"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	seenAuthorizerTypes := sets.NewString()
 | 
			
		||||
	seenWebhookNames := sets.NewString()
 | 
			
		||||
	for i, a := range c.Authorizers {
 | 
			
		||||
		fldPath := fldPath.Child("authorizers").Index(i)
 | 
			
		||||
		aType := string(a.Type)
 | 
			
		||||
		if aType == "" {
 | 
			
		||||
			allErrs = append(allErrs, field.Required(fldPath.Child("type"), ""))
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !knownTypes.Has(aType) {
 | 
			
		||||
			allErrs = append(allErrs, field.NotSupported(fldPath.Child("type"), aType, knownTypes.List()))
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if seenAuthorizerTypes.Has(aType) && !repeatableTypes.Has(aType) {
 | 
			
		||||
			allErrs = append(allErrs, field.Duplicate(fldPath.Child("type"), aType))
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		seenAuthorizerTypes.Insert(aType)
 | 
			
		||||
 | 
			
		||||
		switch a.Type {
 | 
			
		||||
		case api.TypeWebhook:
 | 
			
		||||
			if a.Webhook == nil {
 | 
			
		||||
				allErrs = append(allErrs, field.Required(fldPath.Child("webhook"), "required when type=Webhook"))
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			allErrs = append(allErrs, ValidateWebhookConfiguration(fldPath, a.Webhook, seenWebhookNames)...)
 | 
			
		||||
		default:
 | 
			
		||||
			if a.Webhook != nil {
 | 
			
		||||
				allErrs = append(allErrs, field.Invalid(fldPath.Child("webhook"), "non-null", "may only be specified when type=Webhook"))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ValidateWebhookConfiguration(fldPath *field.Path, c *api.WebhookConfiguration, seenNames sets.String) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	if len(c.Name) == 0 {
 | 
			
		||||
		allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
 | 
			
		||||
	} else if seenNames.Has(c.Name) {
 | 
			
		||||
		allErrs = append(allErrs, field.Duplicate(fldPath.Child("name"), c.Name))
 | 
			
		||||
	} else if errs := utilvalidation.IsDNS1123Subdomain(c.Name); len(errs) != 0 {
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), c.Name, fmt.Sprintf("webhook name is invalid: %s", strings.Join(errs, ", "))))
 | 
			
		||||
	}
 | 
			
		||||
	seenNames.Insert(c.Name)
 | 
			
		||||
 | 
			
		||||
	if c.Timeout.Duration == 0 {
 | 
			
		||||
		allErrs = append(allErrs, field.Required(fldPath.Child("timeout"), ""))
 | 
			
		||||
	} else if c.Timeout.Duration > 30*time.Second || c.Timeout.Duration < 0 {
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath.Child("timeout"), c.Timeout.Duration.String(), "must be > 0s and <= 30s"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.AuthorizedTTL.Duration == 0 {
 | 
			
		||||
		allErrs = append(allErrs, field.Required(fldPath.Child("authorizedTTL"), ""))
 | 
			
		||||
	} else if c.AuthorizedTTL.Duration < 0 {
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath.Child("authorizedTTL"), c.AuthorizedTTL.Duration.String(), "must be > 0s"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.UnauthorizedTTL.Duration == 0 {
 | 
			
		||||
		allErrs = append(allErrs, field.Required(fldPath.Child("unauthorizedTTL"), ""))
 | 
			
		||||
	} else if c.UnauthorizedTTL.Duration < 0 {
 | 
			
		||||
		allErrs = append(allErrs, field.Invalid(fldPath.Child("unauthorizedTTL"), c.UnauthorizedTTL.Duration.String(), "must be > 0s"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch c.SubjectAccessReviewVersion {
 | 
			
		||||
	case "":
 | 
			
		||||
		allErrs = append(allErrs, field.Required(fldPath.Child("subjectAccessReviewVersion"), ""))
 | 
			
		||||
	case "v1":
 | 
			
		||||
		_ = &v1.SubjectAccessReview{}
 | 
			
		||||
	case "v1beta1":
 | 
			
		||||
		_ = &v1beta1.SubjectAccessReview{}
 | 
			
		||||
	default:
 | 
			
		||||
		allErrs = append(allErrs, field.NotSupported(fldPath.Child("subjectAccessReviewVersion"), c.SubjectAccessReviewVersion, []string{"v1", "v1beta1"}))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch c.MatchConditionSubjectAccessReviewVersion {
 | 
			
		||||
	case "":
 | 
			
		||||
		allErrs = append(allErrs, field.Required(fldPath.Child("matchConditionSubjectAccessReviewVersion"), ""))
 | 
			
		||||
	case "v1":
 | 
			
		||||
		_ = &v1.SubjectAccessReview{}
 | 
			
		||||
	default:
 | 
			
		||||
		allErrs = append(allErrs, field.NotSupported(fldPath.Child("matchConditionSubjectAccessReviewVersion"), c.MatchConditionSubjectAccessReviewVersion, []string{"v1"}))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch c.FailurePolicy {
 | 
			
		||||
	case "":
 | 
			
		||||
		allErrs = append(allErrs, field.Required(fldPath.Child("failurePolicy"), ""))
 | 
			
		||||
	case api.FailurePolicyNoOpinion, api.FailurePolicyDeny:
 | 
			
		||||
	default:
 | 
			
		||||
		allErrs = append(allErrs, field.NotSupported(fldPath.Child("failurePolicy"), c.FailurePolicy, []string{"NoOpinion", "Deny"}))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch c.ConnectionInfo.Type {
 | 
			
		||||
	case "":
 | 
			
		||||
		allErrs = append(allErrs, field.Required(fldPath.Child("connectionInfo", "type"), ""))
 | 
			
		||||
	case api.AuthorizationWebhookConnectionInfoTypeInCluster:
 | 
			
		||||
		if c.ConnectionInfo.KubeConfigFile != nil {
 | 
			
		||||
			allErrs = append(allErrs, field.Invalid(fldPath.Child("connectionInfo", "kubeConfigFile"), *c.ConnectionInfo.KubeConfigFile, "can only be set when type=KubeConfigFile"))
 | 
			
		||||
		}
 | 
			
		||||
	case api.AuthorizationWebhookConnectionInfoTypeKubeConfig:
 | 
			
		||||
		if c.ConnectionInfo.KubeConfigFile == nil || *c.ConnectionInfo.KubeConfigFile == "" {
 | 
			
		||||
			allErrs = append(allErrs, field.Required(fldPath.Child("connectionInfo", "kubeConfigFile"), ""))
 | 
			
		||||
		} else if !filepath.IsAbs(*c.ConnectionInfo.KubeConfigFile) {
 | 
			
		||||
			allErrs = append(allErrs, field.Invalid(fldPath.Child("connectionInfo", "kubeConfigFile"), *c.ConnectionInfo.KubeConfigFile, "must be an absolute path"))
 | 
			
		||||
		} else if info, err := os.Stat(*c.ConnectionInfo.KubeConfigFile); err != nil {
 | 
			
		||||
			allErrs = append(allErrs, field.Invalid(fldPath.Child("connectionInfo", "kubeConfigFile"), *c.ConnectionInfo.KubeConfigFile, fmt.Sprintf("error loading file: %v", err)))
 | 
			
		||||
		} else if !info.Mode().IsRegular() {
 | 
			
		||||
			allErrs = append(allErrs, field.Invalid(fldPath.Child("connectionInfo", "kubeConfigFile"), *c.ConnectionInfo.KubeConfigFile, "must be a regular file"))
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		allErrs = append(allErrs, field.NotSupported(fldPath.Child("connectionInfo", "type"), c.ConnectionInfo, []string{"InClusterConfig", "KubeConfigFile"}))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: Remove this check and ensure that correct validations below for MatchConditions are added
 | 
			
		||||
	// for i, condition := range c.MatchConditions {
 | 
			
		||||
	//	 fldPath := fldPath.Child("matchConditions").Index(i).Child("expression")
 | 
			
		||||
	//	 if len(strings.TrimSpace(condition.Expression)) == 0 {
 | 
			
		||||
	//	     allErrs = append(allErrs, field.Required(fldPath, ""))
 | 
			
		||||
	//	 } else {
 | 
			
		||||
	//		 allErrs = append(allErrs, ValidateWebhookMatchCondition(fldPath, sampleSAR, condition.Expression)...)
 | 
			
		||||
	//	 }
 | 
			
		||||
	// }
 | 
			
		||||
	if len(c.MatchConditions) != 0 {
 | 
			
		||||
		allErrs = append(allErrs, field.NotSupported(fldPath.Child("matchConditions"), c.MatchConditions, []string{}))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ValidateWebhookMatchCondition(fldPath *field.Path, sampleSAR runtime.Object, expression string) field.ErrorList {
 | 
			
		||||
	allErrs := field.ErrorList{}
 | 
			
		||||
	// TODO: typecheck CEL expression
 | 
			
		||||
	return allErrs
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,11 +21,15 @@ import (
 | 
			
		||||
	"crypto/elliptic"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"encoding/pem"
 | 
			
		||||
	"os"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
 | 
			
		||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/errors"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
			
		||||
	api "k8s.io/apiserver/pkg/apis/apiserver"
 | 
			
		||||
	certutil "k8s.io/client-go/util/cert"
 | 
			
		||||
@@ -412,3 +416,832 @@ func errString(errs errors.Aggregate) string {
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	test struct {
 | 
			
		||||
		name            string
 | 
			
		||||
		configuration   api.AuthorizationConfiguration
 | 
			
		||||
		expectedErrList field.ErrorList
 | 
			
		||||
		knownTypes      sets.String
 | 
			
		||||
		repeatableTypes sets.String
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestValidateAuthorizationConfiguration(t *testing.T) {
 | 
			
		||||
	badKubeConfigFile := "../some/relative/path/kubeconfig"
 | 
			
		||||
 | 
			
		||||
	tempKubeConfigFile, err := os.CreateTemp("/tmp", "kubeconfig")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("failed to set up temp file: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	tempKubeConfigFilePath := tempKubeConfigFile.Name()
 | 
			
		||||
	defer os.Remove(tempKubeConfigFilePath)
 | 
			
		||||
 | 
			
		||||
	tests := []test{
 | 
			
		||||
		{
 | 
			
		||||
			name: "atleast one authorizer should be defined",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("authorizers"), "at least one authorization mode must be defined")},
 | 
			
		||||
			knownTypes:      sets.NewString(),
 | 
			
		||||
			repeatableTypes: sets.NewString(),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "type is required if an authorizer is defined",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("type"), "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "bare minimum configuration with Webhook",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "bare minimum configuration with multiple webhooks",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "second-webhook",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "configuration with unknown types",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Foo",
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.NotSupported(field.NewPath("type"), "Foo", []string{"..."})},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "configuration with not repeatable types",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Foo",
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Foo",
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Duplicate(field.NewPath("type"), "Foo")},
 | 
			
		||||
			knownTypes:      sets.NewString([]string{string("Foo"), string("Webhook")}...),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "when type=Webhook, webhook needs to be defined",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("webhook"), "required when type=Webhook")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "when type!=Webhook, webhooks needs to be nil",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type:    "Foo",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Invalid(field.NewPath("webhook"), "non-null", "may only be specified when type=Webhook")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Foo")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "webhook name should be of non-zero length",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("name"), "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "webhook names should be unique",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "name-1",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "name-1",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Duplicate(field.NewPath("name"), "name-1")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "webhook names should be DNS1123 labels",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "mywebhookname",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "webhook names should be DNS1123 subdomains",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "webhookname.example.domain",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "webhook names should not be invalid DNS1123 labels or subdomains",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "WEBHOOKNAME.example.domain",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Invalid(field.NewPath("name"), "WEBHOOKNAME.example.domain", "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "timeout should be specified",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("timeout"), "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		//
 | 
			
		||||
		{
 | 
			
		||||
			name: "timeout shouldn't be zero",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 0 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("timeout"), "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "timeout shouldn't be negative",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: -30 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Invalid(field.NewPath("timeout"), time.Duration(-30*time.Second).String(), "must be > 0s and <= 30s")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "timeout shouldn't be greater than 30seconds",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 60 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Invalid(field.NewPath("timeout"), time.Duration(60*time.Second).String(), "must be > 0s and <= 30s")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "authorizedTTL should be defined ",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("authorizedTTL"), "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "authorizedTTL shouldn't be negative",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: -30 * time.Second},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Invalid(field.NewPath("authorizedTTL"), time.Duration(-30*time.Second).String(), "must be > 0s")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "unauthorizedTTL should be defined ",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("unauthorizedTTL"), "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "unauthorizedTTL shouldn't be negative",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: -30 * time.Second},
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Invalid(field.NewPath("unauthorizedTTL"), time.Duration(-30*time.Second).String(), "must be > 0s")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "SAR should be defined",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("subjectAccessReviewVersion"), "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "SAR should be one of v1 and v1beta1",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v2beta1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.NotSupported(field.NewPath("subjectAccessReviewVersion"), "v2beta1", []string{"v1", "v1beta1"})},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "MatchConditionSAR should be defined",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                       "default",
 | 
			
		||||
							Timeout:                    metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:              metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:            metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:              "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("matchConditionSubjectAccessReviewVersion"), "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "MatchConditionSAR must not be anything other than v1",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1beta1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.NotSupported(field.NewPath("matchConditionSubjectAccessReviewVersion"), "v1beta1", []string{"v1"})},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "failurePolicy should be defined",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("failurePolicy"), "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "failurePolicy should be one of \"NoOpinion\" or \"Deny\"",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "AlwaysAllow",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "InClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.NotSupported(field.NewPath("failurePolicy"), "AlwaysAllow", []string{"NoOpinion", "Deny"})},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "connectionInfo should be defined",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("connectionInfo"), "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "connectionInfo should be one of InClusterConfig or KubeConfigFile",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "ExternalClusterConfig",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{
 | 
			
		||||
				field.NotSupported(field.NewPath("connectionInfo"), api.WebhookConnectionInfo{Type: "ExternalClusterConfig"}, []string{"InClusterConfig", "KubeConfigFile"}),
 | 
			
		||||
			},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "if connectionInfo=InClusterConfig, then kubeConfigFile should be nil",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type:           "InClusterConfig",
 | 
			
		||||
								KubeConfigFile: new(string),
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{
 | 
			
		||||
				field.Invalid(field.NewPath("connectionInfo", "kubeConfigFile"), "", "can only be set when type=KubeConfigFile"),
 | 
			
		||||
			},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "if connectionInfo=KubeConfigFile, then KubeConfigFile should be defined",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type: "KubeConfigFile",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Required(field.NewPath("kubeConfigFile"), "")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "if connectionInfo=KubeConfigFile, then KubeConfigFile should be defined, must be an absolute path, should exist, shouldn't be a symlink",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type:           "KubeConfigFile",
 | 
			
		||||
								KubeConfigFile: &badKubeConfigFile,
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{field.Invalid(field.NewPath("kubeConfigFile"), badKubeConfigFile, "must be an absolute path")},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "if connectionInfo=KubeConfigFile, an existent file needs to be passed",
 | 
			
		||||
			configuration: api.AuthorizationConfiguration{
 | 
			
		||||
				Authorizers: []api.AuthorizerConfiguration{
 | 
			
		||||
					{
 | 
			
		||||
						Type: "Webhook",
 | 
			
		||||
						Webhook: &api.WebhookConfiguration{
 | 
			
		||||
							Name:                                     "default",
 | 
			
		||||
							Timeout:                                  metav1.Duration{Duration: 5 * time.Second},
 | 
			
		||||
							AuthorizedTTL:                            metav1.Duration{Duration: 5 * time.Minute},
 | 
			
		||||
							UnauthorizedTTL:                          metav1.Duration{Duration: 30 * time.Second},
 | 
			
		||||
							FailurePolicy:                            "NoOpinion",
 | 
			
		||||
							SubjectAccessReviewVersion:               "v1",
 | 
			
		||||
							MatchConditionSubjectAccessReviewVersion: "v1",
 | 
			
		||||
							ConnectionInfo: api.WebhookConnectionInfo{
 | 
			
		||||
								Type:           "KubeConfigFile",
 | 
			
		||||
								KubeConfigFile: &tempKubeConfigFilePath,
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedErrList: field.ErrorList{},
 | 
			
		||||
			knownTypes:      sets.NewString(string("Webhook")),
 | 
			
		||||
			repeatableTypes: sets.NewString(string("Webhook")),
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// TODO: When the CEL expression validator is implemented, add a few test cases to typecheck the expression
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		t.Run(test.name, func(t *testing.T) {
 | 
			
		||||
			errList := ValidateAuthorizationConfiguration(nil, &test.configuration, test.knownTypes, test.repeatableTypes)
 | 
			
		||||
			if len(errList) != len(test.expectedErrList) {
 | 
			
		||||
				t.Errorf("expected %d errs, got %d, errors %v", len(test.expectedErrList), len(errList), errList)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for i, expected := range test.expectedErrList {
 | 
			
		||||
				if expected.Type.String() != errList[i].Type.String() {
 | 
			
		||||
					t.Errorf("expected err type %s, got %s",
 | 
			
		||||
						expected.Type.String(),
 | 
			
		||||
						errList[i].Type.String())
 | 
			
		||||
				}
 | 
			
		||||
				if expected.BadValue != errList[i].BadValue {
 | 
			
		||||
					t.Errorf("expected bad value '%s', got '%s'",
 | 
			
		||||
						expected.BadValue,
 | 
			
		||||
						errList[i].BadValue)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -110,6 +110,59 @@ func (in *AuthenticationConfiguration) DeepCopyObject() runtime.Object {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *AuthorizationConfiguration) DeepCopyInto(out *AuthorizationConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	out.TypeMeta = in.TypeMeta
 | 
			
		||||
	if in.Authorizers != nil {
 | 
			
		||||
		in, out := &in.Authorizers, &out.Authorizers
 | 
			
		||||
		*out = make([]AuthorizerConfiguration, len(*in))
 | 
			
		||||
		for i := range *in {
 | 
			
		||||
			(*in)[i].DeepCopyInto(&(*out)[i])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthorizationConfiguration.
 | 
			
		||||
func (in *AuthorizationConfiguration) DeepCopy() *AuthorizationConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(AuthorizationConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | 
			
		||||
func (in *AuthorizationConfiguration) DeepCopyObject() runtime.Object {
 | 
			
		||||
	if c := in.DeepCopy(); c != nil {
 | 
			
		||||
		return c
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *AuthorizerConfiguration) DeepCopyInto(out *AuthorizerConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	if in.Webhook != nil {
 | 
			
		||||
		in, out := &in.Webhook, &out.Webhook
 | 
			
		||||
		*out = new(WebhookConfiguration)
 | 
			
		||||
		(*in).DeepCopyInto(*out)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthorizerConfiguration.
 | 
			
		||||
func (in *AuthorizerConfiguration) DeepCopy() *AuthorizerConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(AuthorizerConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *ClaimMappings) DeepCopyInto(out *ClaimMappings) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
@@ -383,3 +436,65 @@ func (in *UDSTransport) DeepCopy() *UDSTransport {
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *WebhookConfiguration) DeepCopyInto(out *WebhookConfiguration) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	out.AuthorizedTTL = in.AuthorizedTTL
 | 
			
		||||
	out.UnauthorizedTTL = in.UnauthorizedTTL
 | 
			
		||||
	out.Timeout = in.Timeout
 | 
			
		||||
	in.ConnectionInfo.DeepCopyInto(&out.ConnectionInfo)
 | 
			
		||||
	if in.MatchConditions != nil {
 | 
			
		||||
		in, out := &in.MatchConditions, &out.MatchConditions
 | 
			
		||||
		*out = make([]WebhookMatchCondition, len(*in))
 | 
			
		||||
		copy(*out, *in)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookConfiguration.
 | 
			
		||||
func (in *WebhookConfiguration) DeepCopy() *WebhookConfiguration {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(WebhookConfiguration)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *WebhookConnectionInfo) DeepCopyInto(out *WebhookConnectionInfo) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	if in.KubeConfigFile != nil {
 | 
			
		||||
		in, out := &in.KubeConfigFile, &out.KubeConfigFile
 | 
			
		||||
		*out = new(string)
 | 
			
		||||
		**out = **in
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookConnectionInfo.
 | 
			
		||||
func (in *WebhookConnectionInfo) DeepCopy() *WebhookConnectionInfo {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(WebhookConnectionInfo)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | 
			
		||||
func (in *WebhookMatchCondition) DeepCopyInto(out *WebhookMatchCondition) {
 | 
			
		||||
	*out = *in
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookMatchCondition.
 | 
			
		||||
func (in *WebhookMatchCondition) DeepCopy() *WebhookMatchCondition {
 | 
			
		||||
	if in == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	out := new(WebhookMatchCondition)
 | 
			
		||||
	in.DeepCopyInto(out)
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user