Bootstrap API Types for Structured Authorization Configuration

Signed-off-by: Nabarun Pal <pal.nabarun95@gmail.com>
This commit is contained in:
Nabarun Pal 2023-09-14 19:19:29 +05:30
parent 0241da314e
commit 52c582ca77
No known key found for this signature in database
GPG Key ID: E71158161DF2A2CB
11 changed files with 1673 additions and 1 deletions

View File

@ -44,6 +44,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&AdmissionConfiguration{},
&AuthenticationConfiguration{},
&AuthorizationConfiguration{},
&EgressSelectorConfiguration{},
&TracingConfiguration{},
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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