mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
rebase: update replaced k8s.io modules to v0.33.0
Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
committed by
mergify[bot]
parent
dd77e72800
commit
107407b44b
226
e2e/vendor/k8s.io/apiserver/pkg/apis/apidiscovery/v2/conversion.go
generated
vendored
226
e2e/vendor/k8s.io/apiserver/pkg/apis/apidiscovery/v2/conversion.go
generated
vendored
@ -1,226 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 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.
|
||||
*/
|
||||
|
||||
// This file was duplicated from the auto-generated file by conversion-gen in
|
||||
// k8s.io/kubernetes/pkg/apis/apidiscovery Unlike most k8s types discovery is
|
||||
// served by all apiservers and conversion is needed by all apiservers. The
|
||||
// concept of internal/hub type does not exist for discovery as we work directly
|
||||
// with the versioned types.
|
||||
|
||||
// The conversion code here facilities conversion strictly between v2beta1 and
|
||||
// v2 types. It is only necessary in k8s versions where mixed state could be
|
||||
// possible before the full removal of the v2beta1 types. It is placed in this
|
||||
// directory such that all apiservers can benefit from the conversion without
|
||||
// having to implement their own if the client/server they're communicating with
|
||||
// only supports one version.
|
||||
|
||||
// Once the v2beta1 types are removed (intended for Kubernetes v1.33), this file
|
||||
// will be removed.
|
||||
package v2
|
||||
|
||||
import (
|
||||
unsafe "unsafe"
|
||||
|
||||
v2 "k8s.io/api/apidiscovery/v2"
|
||||
v2beta1 "k8s.io/api/apidiscovery/v2beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(s *runtime.Scheme) error {
|
||||
if err := s.AddGeneratedConversionFunc((*v2beta1.APIGroupDiscovery)(nil), (*v2.APIGroupDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convertv2beta1APIGroupDiscoveryTov2APIGroupDiscovery(a.(*v2beta1.APIGroupDiscovery), b.(*v2.APIGroupDiscovery), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v2.APIGroupDiscovery)(nil), (*v2beta1.APIGroupDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convertv2APIGroupDiscoveryTov2beta1APIGroupDiscovery(a.(*v2.APIGroupDiscovery), b.(*v2beta1.APIGroupDiscovery), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v2beta1.APIGroupDiscoveryList)(nil), (*v2.APIGroupDiscoveryList)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convertv2beta1APIGroupDiscoveryListTov2APIGroupDiscoveryList(a.(*v2beta1.APIGroupDiscoveryList), b.(*v2.APIGroupDiscoveryList), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v2.APIGroupDiscoveryList)(nil), (*v2beta1.APIGroupDiscoveryList)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convertv2APIGroupDiscoveryListTov2beta1APIGroupDiscoveryList(a.(*v2.APIGroupDiscoveryList), b.(*v2beta1.APIGroupDiscoveryList), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v2beta1.APIResourceDiscovery)(nil), (*v2.APIResourceDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convertv2beta1APIResourceDiscoveryTov2APIResourceDiscovery(a.(*v2beta1.APIResourceDiscovery), b.(*v2.APIResourceDiscovery), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v2.APIResourceDiscovery)(nil), (*v2beta1.APIResourceDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convertv2APIResourceDiscoveryTov2beta1APIResourceDiscovery(a.(*v2.APIResourceDiscovery), b.(*v2beta1.APIResourceDiscovery), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v2beta1.APISubresourceDiscovery)(nil), (*v2.APISubresourceDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convertv2beta1APISubresourceDiscoveryTov2APISubresourceDiscovery(a.(*v2beta1.APISubresourceDiscovery), b.(*v2.APISubresourceDiscovery), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v2.APISubresourceDiscovery)(nil), (*v2beta1.APISubresourceDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convertv2APISubresourceDiscoveryTov2beta1APISubresourceDiscovery(a.(*v2.APISubresourceDiscovery), b.(*v2beta1.APISubresourceDiscovery), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v2beta1.APIVersionDiscovery)(nil), (*v2.APIVersionDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convertv2beta1APIVersionDiscoveryTov2APIVersionDiscovery(a.(*v2beta1.APIVersionDiscovery), b.(*v2.APIVersionDiscovery), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v2.APIVersionDiscovery)(nil), (*v2beta1.APIVersionDiscovery)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convertv2APIVersionDiscoveryTov2beta1APIVersionDiscovery(a.(*v2.APIVersionDiscovery), b.(*v2beta1.APIVersionDiscovery), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvertv2beta1APIGroupDiscoveryTov2APIGroupDiscovery(in *v2beta1.APIGroupDiscovery, out *v2.APIGroupDiscovery, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
out.Versions = *(*[]v2.APIVersionDiscovery)(unsafe.Pointer(&in.Versions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convertv2beta1APIGroupDiscoveryTov2APIGroupDiscovery is an autogenerated conversion function.
|
||||
func Convertv2beta1APIGroupDiscoveryTov2APIGroupDiscovery(in *v2beta1.APIGroupDiscovery, out *v2.APIGroupDiscovery, s conversion.Scope) error {
|
||||
return autoConvertv2beta1APIGroupDiscoveryTov2APIGroupDiscovery(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvertv2APIGroupDiscoveryTov2beta1APIGroupDiscovery(in *v2.APIGroupDiscovery, out *v2beta1.APIGroupDiscovery, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
out.Versions = *(*[]v2beta1.APIVersionDiscovery)(unsafe.Pointer(&in.Versions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convertv2APIGroupDiscoveryTov2beta1APIGroupDiscovery is an autogenerated conversion function.
|
||||
func Convertv2APIGroupDiscoveryTov2beta1APIGroupDiscovery(in *v2.APIGroupDiscovery, out *v2beta1.APIGroupDiscovery, s conversion.Scope) error {
|
||||
return autoConvertv2APIGroupDiscoveryTov2beta1APIGroupDiscovery(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvertv2beta1APIGroupDiscoveryListTov2APIGroupDiscoveryList(in *v2beta1.APIGroupDiscoveryList, out *v2.APIGroupDiscoveryList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
out.Items = *(*[]v2.APIGroupDiscovery)(unsafe.Pointer(&in.Items))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convertv2beta1APIGroupDiscoveryListTov2APIGroupDiscoveryList is an autogenerated conversion function.
|
||||
func Convertv2beta1APIGroupDiscoveryListTov2APIGroupDiscoveryList(in *v2beta1.APIGroupDiscoveryList, out *v2.APIGroupDiscoveryList, s conversion.Scope) error {
|
||||
return autoConvertv2beta1APIGroupDiscoveryListTov2APIGroupDiscoveryList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvertv2APIGroupDiscoveryListTov2beta1APIGroupDiscoveryList(in *v2.APIGroupDiscoveryList, out *v2beta1.APIGroupDiscoveryList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
out.Items = *(*[]v2beta1.APIGroupDiscovery)(unsafe.Pointer(&in.Items))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convertv2APIGroupDiscoveryListTov2beta1APIGroupDiscoveryList is an autogenerated conversion function.
|
||||
func Convertv2APIGroupDiscoveryListTov2beta1APIGroupDiscoveryList(in *v2.APIGroupDiscoveryList, out *v2beta1.APIGroupDiscoveryList, s conversion.Scope) error {
|
||||
return autoConvertv2APIGroupDiscoveryListTov2beta1APIGroupDiscoveryList(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvertv2beta1APIResourceDiscoveryTov2APIResourceDiscovery(in *v2beta1.APIResourceDiscovery, out *v2.APIResourceDiscovery, s conversion.Scope) error {
|
||||
out.Resource = in.Resource
|
||||
out.ResponseKind = (*v1.GroupVersionKind)(unsafe.Pointer(in.ResponseKind))
|
||||
out.Scope = v2.ResourceScope(in.Scope)
|
||||
out.SingularResource = in.SingularResource
|
||||
out.Verbs = *(*[]string)(unsafe.Pointer(&in.Verbs))
|
||||
out.ShortNames = *(*[]string)(unsafe.Pointer(&in.ShortNames))
|
||||
out.Categories = *(*[]string)(unsafe.Pointer(&in.Categories))
|
||||
out.Subresources = *(*[]v2.APISubresourceDiscovery)(unsafe.Pointer(&in.Subresources))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convertv2beta1APIResourceDiscoveryTov2APIResourceDiscovery is an autogenerated conversion function.
|
||||
func Convertv2beta1APIResourceDiscoveryTov2APIResourceDiscovery(in *v2beta1.APIResourceDiscovery, out *v2.APIResourceDiscovery, s conversion.Scope) error {
|
||||
return autoConvertv2beta1APIResourceDiscoveryTov2APIResourceDiscovery(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvertv2APIResourceDiscoveryTov2beta1APIResourceDiscovery(in *v2.APIResourceDiscovery, out *v2beta1.APIResourceDiscovery, s conversion.Scope) error {
|
||||
out.Resource = in.Resource
|
||||
out.ResponseKind = (*v1.GroupVersionKind)(unsafe.Pointer(in.ResponseKind))
|
||||
out.Scope = v2beta1.ResourceScope(in.Scope)
|
||||
out.SingularResource = in.SingularResource
|
||||
out.Verbs = *(*[]string)(unsafe.Pointer(&in.Verbs))
|
||||
out.ShortNames = *(*[]string)(unsafe.Pointer(&in.ShortNames))
|
||||
out.Categories = *(*[]string)(unsafe.Pointer(&in.Categories))
|
||||
out.Subresources = *(*[]v2beta1.APISubresourceDiscovery)(unsafe.Pointer(&in.Subresources))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convertv2APIResourceDiscoveryTov2beta1APIResourceDiscovery is an autogenerated conversion function.
|
||||
func Convertv2APIResourceDiscoveryTov2beta1APIResourceDiscovery(in *v2.APIResourceDiscovery, out *v2beta1.APIResourceDiscovery, s conversion.Scope) error {
|
||||
return autoConvertv2APIResourceDiscoveryTov2beta1APIResourceDiscovery(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvertv2beta1APISubresourceDiscoveryTov2APISubresourceDiscovery(in *v2beta1.APISubresourceDiscovery, out *v2.APISubresourceDiscovery, s conversion.Scope) error {
|
||||
out.Subresource = in.Subresource
|
||||
out.ResponseKind = (*v1.GroupVersionKind)(unsafe.Pointer(in.ResponseKind))
|
||||
out.AcceptedTypes = *(*[]v1.GroupVersionKind)(unsafe.Pointer(&in.AcceptedTypes))
|
||||
out.Verbs = *(*[]string)(unsafe.Pointer(&in.Verbs))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convertv2beta1APISubresourceDiscoveryTov2APISubresourceDiscovery is an autogenerated conversion function.
|
||||
func Convertv2beta1APISubresourceDiscoveryTov2APISubresourceDiscovery(in *v2beta1.APISubresourceDiscovery, out *v2.APISubresourceDiscovery, s conversion.Scope) error {
|
||||
return autoConvertv2beta1APISubresourceDiscoveryTov2APISubresourceDiscovery(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvertv2APISubresourceDiscoveryTov2beta1APISubresourceDiscovery(in *v2.APISubresourceDiscovery, out *v2beta1.APISubresourceDiscovery, s conversion.Scope) error {
|
||||
out.Subresource = in.Subresource
|
||||
out.ResponseKind = (*v1.GroupVersionKind)(unsafe.Pointer(in.ResponseKind))
|
||||
out.AcceptedTypes = *(*[]v1.GroupVersionKind)(unsafe.Pointer(&in.AcceptedTypes))
|
||||
out.Verbs = *(*[]string)(unsafe.Pointer(&in.Verbs))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convertv2APISubresourceDiscoveryTov2beta1APISubresourceDiscovery is an autogenerated conversion function.
|
||||
func Convertv2APISubresourceDiscoveryTov2beta1APISubresourceDiscovery(in *v2.APISubresourceDiscovery, out *v2beta1.APISubresourceDiscovery, s conversion.Scope) error {
|
||||
return autoConvertv2APISubresourceDiscoveryTov2beta1APISubresourceDiscovery(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvertv2beta1APIVersionDiscoveryTov2APIVersionDiscovery(in *v2beta1.APIVersionDiscovery, out *v2.APIVersionDiscovery, s conversion.Scope) error {
|
||||
out.Version = in.Version
|
||||
out.Resources = *(*[]v2.APIResourceDiscovery)(unsafe.Pointer(&in.Resources))
|
||||
out.Freshness = v2.DiscoveryFreshness(in.Freshness)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convertv2beta1APIVersionDiscoveryTov2APIVersionDiscovery is an autogenerated conversion function.
|
||||
func Convertv2beta1APIVersionDiscoveryTov2APIVersionDiscovery(in *v2beta1.APIVersionDiscovery, out *v2.APIVersionDiscovery, s conversion.Scope) error {
|
||||
return autoConvertv2beta1APIVersionDiscoveryTov2APIVersionDiscovery(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvertv2APIVersionDiscoveryTov2beta1APIVersionDiscovery(in *v2.APIVersionDiscovery, out *v2beta1.APIVersionDiscovery, s conversion.Scope) error {
|
||||
out.Version = in.Version
|
||||
out.Resources = *(*[]v2beta1.APIResourceDiscovery)(unsafe.Pointer(&in.Resources))
|
||||
out.Freshness = v2beta1.DiscoveryFreshness(in.Freshness)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convertv2APIVersionDiscoveryTov2beta1APIVersionDiscovery is an autogenerated conversion function.
|
||||
func Convertv2APIVersionDiscoveryTov2beta1APIVersionDiscovery(in *v2.APIVersionDiscovery, out *v2beta1.APIVersionDiscovery, s conversion.Scope) error {
|
||||
return autoConvertv2APIVersionDiscoveryTov2beta1APIVersionDiscovery(in, out, s)
|
||||
}
|
19
e2e/vendor/k8s.io/apiserver/pkg/apis/apidiscovery/v2/doc.go
generated
vendored
19
e2e/vendor/k8s.io/apiserver/pkg/apis/apidiscovery/v2/doc.go
generated
vendored
@ -1,19 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 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.
|
||||
*/
|
||||
|
||||
// +groupName=apidiscovery.k8s.io
|
||||
|
||||
package v2
|
39
e2e/vendor/k8s.io/apiserver/pkg/apis/apidiscovery/v2/register.go
generated
vendored
39
e2e/vendor/k8s.io/apiserver/pkg/apis/apidiscovery/v2/register.go
generated
vendored
@ -1,39 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 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 v2
|
||||
|
||||
import (
|
||||
apidiscoveryv2 "k8s.io/api/apidiscovery/v2"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "apidiscovery.k8s.io"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v2"}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
var (
|
||||
SchemeBuilder = &apidiscoveryv2.SchemeBuilder
|
||||
// AddToScheme adds api to a scheme
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
821
e2e/vendor/k8s.io/apiserver/pkg/apis/apiserver/validation/validation.go
generated
vendored
821
e2e/vendor/k8s.io/apiserver/pkg/apis/apiserver/validation/validation.go
generated
vendored
@ -1,821 +0,0 @@
|
||||
/*
|
||||
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 validation
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
celgo "github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common/operators"
|
||||
exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
|
||||
v1 "k8s.io/api/authorization/v1"
|
||||
"k8s.io/api/authorization/v1beta1"
|
||||
"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"
|
||||
authenticationcel "k8s.io/apiserver/pkg/authentication/cel"
|
||||
authorizationcel "k8s.io/apiserver/pkg/authorization/cel"
|
||||
"k8s.io/apiserver/pkg/cel"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/util/cert"
|
||||
)
|
||||
|
||||
// ValidateAuthenticationConfiguration validates a given AuthenticationConfiguration.
|
||||
func ValidateAuthenticationConfiguration(compiler authenticationcel.Compiler, c *api.AuthenticationConfiguration, disallowedIssuers []string) field.ErrorList {
|
||||
root := field.NewPath("jwt")
|
||||
var allErrs field.ErrorList
|
||||
|
||||
// We allow 0 authenticators in the authentication configuration.
|
||||
// This allows us to support scenarios where the API server is initially set up without
|
||||
// any authenticators and then authenticators are added later via dynamic config.
|
||||
|
||||
if len(c.JWT) > 64 {
|
||||
allErrs = append(allErrs, field.TooMany(root, len(c.JWT), 64))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
seenIssuers := sets.New[string]()
|
||||
seenDiscoveryURLs := sets.New[string]()
|
||||
for i, a := range c.JWT {
|
||||
fldPath := root.Index(i)
|
||||
_, errs := validateJWTAuthenticator(compiler, a, fldPath, sets.New(disallowedIssuers...), utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthenticationConfiguration))
|
||||
allErrs = append(allErrs, errs...)
|
||||
|
||||
if seenIssuers.Has(a.Issuer.URL) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath.Child("issuer").Child("url"), a.Issuer.URL))
|
||||
}
|
||||
seenIssuers.Insert(a.Issuer.URL)
|
||||
|
||||
if len(a.Issuer.DiscoveryURL) > 0 {
|
||||
if seenDiscoveryURLs.Has(a.Issuer.DiscoveryURL) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath.Child("issuer").Child("discoveryURL"), a.Issuer.DiscoveryURL))
|
||||
}
|
||||
seenDiscoveryURLs.Insert(a.Issuer.DiscoveryURL)
|
||||
}
|
||||
}
|
||||
|
||||
if c.Anonymous != nil {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.AnonymousAuthConfigurableEndpoints) {
|
||||
allErrs = append(allErrs, field.Forbidden(field.NewPath("anonymous"), "anonymous is not supported when AnonymousAuthConfigurableEnpoints feature gate is disabled"))
|
||||
}
|
||||
if !c.Anonymous.Enabled && len(c.Anonymous.Conditions) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("anonymous", "conditions"), c.Anonymous.Conditions, "enabled should be set to true when conditions are defined"))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// CompileAndValidateJWTAuthenticator validates a given JWTAuthenticator and returns a CELMapper with the compiled
|
||||
// CEL expressions for claim mappings and validation rules.
|
||||
// This is exported for use in oidc package.
|
||||
func CompileAndValidateJWTAuthenticator(compiler authenticationcel.Compiler, authenticator api.JWTAuthenticator, disallowedIssuers []string) (authenticationcel.CELMapper, field.ErrorList) {
|
||||
return validateJWTAuthenticator(compiler, authenticator, nil, sets.New(disallowedIssuers...), utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthenticationConfiguration))
|
||||
}
|
||||
|
||||
func validateJWTAuthenticator(compiler authenticationcel.Compiler, authenticator api.JWTAuthenticator, fldPath *field.Path, disallowedIssuers sets.Set[string], structuredAuthnFeatureEnabled bool) (authenticationcel.CELMapper, field.ErrorList) {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
state := &validationState{}
|
||||
|
||||
allErrs = append(allErrs, validateIssuer(authenticator.Issuer, disallowedIssuers, fldPath.Child("issuer"), structuredAuthnFeatureEnabled)...)
|
||||
allErrs = append(allErrs, validateClaimValidationRules(compiler, state, authenticator.ClaimValidationRules, fldPath.Child("claimValidationRules"), structuredAuthnFeatureEnabled)...)
|
||||
allErrs = append(allErrs, validateClaimMappings(compiler, state, authenticator.ClaimMappings, fldPath.Child("claimMappings"), structuredAuthnFeatureEnabled)...)
|
||||
allErrs = append(allErrs, validateUserValidationRules(compiler, state, authenticator.UserValidationRules, fldPath.Child("userValidationRules"), structuredAuthnFeatureEnabled)...)
|
||||
|
||||
return state.mapper, allErrs
|
||||
}
|
||||
|
||||
type validationState struct {
|
||||
mapper authenticationcel.CELMapper
|
||||
usesEmailClaim bool
|
||||
usesEmailVerifiedClaim bool
|
||||
}
|
||||
|
||||
func validateIssuer(issuer api.Issuer, disallowedIssuers sets.Set[string], fldPath *field.Path, structuredAuthnFeatureEnabled bool) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
allErrs = append(allErrs, validateIssuerURL(issuer.URL, disallowedIssuers, fldPath.Child("url"))...)
|
||||
allErrs = append(allErrs, validateIssuerDiscoveryURL(issuer.URL, issuer.DiscoveryURL, fldPath.Child("discoveryURL"), structuredAuthnFeatureEnabled)...)
|
||||
allErrs = append(allErrs, validateAudiences(issuer.Audiences, issuer.AudienceMatchPolicy, fldPath.Child("audiences"), fldPath.Child("audienceMatchPolicy"), structuredAuthnFeatureEnabled)...)
|
||||
allErrs = append(allErrs, validateCertificateAuthority(issuer.CertificateAuthority, fldPath.Child("certificateAuthority"))...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateIssuerURL(issuerURL string, disallowedIssuers sets.Set[string], fldPath *field.Path) field.ErrorList {
|
||||
if len(issuerURL) == 0 {
|
||||
return field.ErrorList{field.Required(fldPath, "URL is required")}
|
||||
}
|
||||
|
||||
return validateURL(issuerURL, disallowedIssuers, fldPath)
|
||||
}
|
||||
|
||||
func validateIssuerDiscoveryURL(issuerURL, issuerDiscoveryURL string, fldPath *field.Path, structuredAuthnFeatureEnabled bool) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
if len(issuerDiscoveryURL) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !structuredAuthnFeatureEnabled {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, issuerDiscoveryURL, "discoveryURL is not supported when StructuredAuthenticationConfiguration feature gate is disabled"))
|
||||
}
|
||||
|
||||
if len(issuerURL) > 0 && strings.TrimRight(issuerURL, "/") == strings.TrimRight(issuerDiscoveryURL, "/") {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, issuerDiscoveryURL, "discoveryURL must be different from URL"))
|
||||
}
|
||||
|
||||
// issuerDiscoveryURL is not an issuer URL and does not need to validated against any set of disallowed issuers
|
||||
allErrs = append(allErrs, validateURL(issuerDiscoveryURL, nil, fldPath)...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateURL(issuerURL string, disallowedIssuers sets.Set[string], fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
if disallowedIssuers.Has(issuerURL) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, issuerURL, fmt.Sprintf("URL must not overlap with disallowed issuers: %s", sets.List(disallowedIssuers))))
|
||||
}
|
||||
|
||||
u, err := url.Parse(issuerURL)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, issuerURL, err.Error()))
|
||||
return allErrs
|
||||
}
|
||||
if u.Scheme != "https" {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, issuerURL, "URL scheme must be https"))
|
||||
}
|
||||
if u.User != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, issuerURL, "URL must not contain a username or password"))
|
||||
}
|
||||
if len(u.RawQuery) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, issuerURL, "URL must not contain a query"))
|
||||
}
|
||||
if len(u.Fragment) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, issuerURL, "URL must not contain a fragment"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateAudiences(audiences []string, audienceMatchPolicy api.AudienceMatchPolicyType, fldPath, audienceMatchPolicyFldPath *field.Path, structuredAuthnFeatureEnabled bool) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
if len(audiences) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath, fmt.Sprintf(atLeastOneRequiredErrFmt, fldPath)))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
if len(audiences) > 1 && !structuredAuthnFeatureEnabled {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, audiences, "multiple audiences are not supported when StructuredAuthenticationConfiguration feature gate is disabled"))
|
||||
}
|
||||
|
||||
seenAudiences := sets.NewString()
|
||||
for i, audience := range audiences {
|
||||
fldPath := fldPath.Index(i)
|
||||
if len(audience) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath, "audience can't be empty"))
|
||||
}
|
||||
if seenAudiences.Has(audience) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath, audience))
|
||||
}
|
||||
seenAudiences.Insert(audience)
|
||||
}
|
||||
|
||||
if len(audiences) > 1 && audienceMatchPolicy != api.AudienceMatchPolicyMatchAny {
|
||||
allErrs = append(allErrs, field.Invalid(audienceMatchPolicyFldPath, audienceMatchPolicy, "audienceMatchPolicy must be MatchAny for multiple audiences"))
|
||||
}
|
||||
if len(audiences) == 1 && (len(audienceMatchPolicy) > 0 && audienceMatchPolicy != api.AudienceMatchPolicyMatchAny) {
|
||||
allErrs = append(allErrs, field.Invalid(audienceMatchPolicyFldPath, audienceMatchPolicy, "audienceMatchPolicy must be empty or MatchAny for single audience"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateCertificateAuthority(certificateAuthority string, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
if len(certificateAuthority) == 0 {
|
||||
return allErrs
|
||||
}
|
||||
_, err := cert.NewPoolFromBytes([]byte(certificateAuthority))
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, "<omitted>", err.Error()))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateClaimValidationRules(compiler authenticationcel.Compiler, state *validationState, rules []api.ClaimValidationRule, fldPath *field.Path, structuredAuthnFeatureEnabled bool) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
seenClaims := sets.NewString()
|
||||
seenExpressions := sets.NewString()
|
||||
var compilationResults []authenticationcel.CompilationResult
|
||||
|
||||
for i, rule := range rules {
|
||||
fldPath := fldPath.Index(i)
|
||||
|
||||
if len(rule.Expression) > 0 && !structuredAuthnFeatureEnabled {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("expression"), rule.Expression, "expression is not supported when StructuredAuthenticationConfiguration feature gate is disabled"))
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(rule.Claim) > 0 && len(rule.Expression) > 0:
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, rule.Claim, "claim and expression can't both be set"))
|
||||
case len(rule.Claim) == 0 && len(rule.Expression) == 0:
|
||||
allErrs = append(allErrs, field.Required(fldPath, "claim or expression is required"))
|
||||
case len(rule.Claim) > 0:
|
||||
if len(rule.Message) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("message"), rule.Message, "message can't be set when claim is set"))
|
||||
}
|
||||
if seenClaims.Has(rule.Claim) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath.Child("claim"), rule.Claim))
|
||||
}
|
||||
seenClaims.Insert(rule.Claim)
|
||||
case len(rule.Expression) > 0:
|
||||
if len(rule.RequiredValue) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("requiredValue"), rule.RequiredValue, "requiredValue can't be set when expression is set"))
|
||||
}
|
||||
if seenExpressions.Has(rule.Expression) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath.Child("expression"), rule.Expression))
|
||||
continue
|
||||
}
|
||||
seenExpressions.Insert(rule.Expression)
|
||||
|
||||
compilationResult, err := compileClaimsCELExpression(compiler, &authenticationcel.ClaimValidationCondition{
|
||||
Expression: rule.Expression,
|
||||
Message: rule.Message,
|
||||
}, fldPath.Child("expression"))
|
||||
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
continue
|
||||
}
|
||||
if compilationResult != nil {
|
||||
compilationResults = append(compilationResults, *compilationResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if structuredAuthnFeatureEnabled && len(compilationResults) > 0 {
|
||||
state.mapper.ClaimValidationRules = authenticationcel.NewClaimsMapper(compilationResults)
|
||||
state.usesEmailVerifiedClaim = state.usesEmailVerifiedClaim || anyUsesEmailVerifiedClaim(compilationResults)
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateClaimMappings(compiler authenticationcel.Compiler, state *validationState, m api.ClaimMappings, fldPath *field.Path, structuredAuthnFeatureEnabled bool) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
if !structuredAuthnFeatureEnabled {
|
||||
if len(m.Username.Expression) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("username").Child("expression"), m.Username.Expression, "expression is not supported when StructuredAuthenticationConfiguration feature gate is disabled"))
|
||||
}
|
||||
if len(m.Groups.Expression) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("groups").Child("expression"), m.Groups.Expression, "expression is not supported when StructuredAuthenticationConfiguration feature gate is disabled"))
|
||||
}
|
||||
if len(m.UID.Claim) > 0 || len(m.UID.Expression) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), "", "uid claim mapping is not supported when StructuredAuthenticationConfiguration feature gate is disabled"))
|
||||
}
|
||||
if len(m.Extra) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("extra"), "", "extra claim mapping is not supported when StructuredAuthenticationConfiguration feature gate is disabled"))
|
||||
}
|
||||
}
|
||||
|
||||
compilationResult, err := validatePrefixClaimOrExpression(compiler, m.Username, fldPath.Child("username"), true)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err...)
|
||||
} else if compilationResult != nil && structuredAuthnFeatureEnabled {
|
||||
state.usesEmailClaim = state.usesEmailClaim || usesEmailClaim(compilationResult.AST)
|
||||
state.usesEmailVerifiedClaim = state.usesEmailVerifiedClaim || usesEmailVerifiedClaim(compilationResult.AST)
|
||||
state.mapper.Username = authenticationcel.NewClaimsMapper([]authenticationcel.CompilationResult{*compilationResult})
|
||||
}
|
||||
|
||||
compilationResult, err = validatePrefixClaimOrExpression(compiler, m.Groups, fldPath.Child("groups"), false)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err...)
|
||||
} else if compilationResult != nil && structuredAuthnFeatureEnabled {
|
||||
state.mapper.Groups = authenticationcel.NewClaimsMapper([]authenticationcel.CompilationResult{*compilationResult})
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(m.UID.Claim) > 0 && len(m.UID.Expression) > 0:
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), "", "claim and expression can't both be set"))
|
||||
case len(m.UID.Expression) > 0:
|
||||
compilationResult, err := compileClaimsCELExpression(compiler, &authenticationcel.ClaimMappingExpression{
|
||||
Expression: m.UID.Expression,
|
||||
}, fldPath.Child("uid").Child("expression"))
|
||||
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
} else if structuredAuthnFeatureEnabled && compilationResult != nil {
|
||||
state.mapper.UID = authenticationcel.NewClaimsMapper([]authenticationcel.CompilationResult{*compilationResult})
|
||||
}
|
||||
}
|
||||
|
||||
var extraCompilationResults []authenticationcel.CompilationResult
|
||||
seenExtraKeys := sets.NewString()
|
||||
|
||||
for i, mapping := range m.Extra {
|
||||
fldPath := fldPath.Child("extra").Index(i)
|
||||
// Key should be namespaced to the authenticator or authenticator/authorizer pair making use of them.
|
||||
// For instance: "example.org/foo" instead of "foo".
|
||||
// xref: https://github.com/kubernetes/kubernetes/blob/3825e206cb162a7ad7431a5bdf6a065ae8422cf7/staging/src/k8s.io/apiserver/pkg/authentication/user/user.go#L31-L41
|
||||
// IsDomainPrefixedPath checks for non-empty key and that the key is prefixed with a domain name.
|
||||
allErrs = append(allErrs, utilvalidation.IsDomainPrefixedPath(fldPath.Child("key"), mapping.Key)...)
|
||||
if mapping.Key != strings.ToLower(mapping.Key) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), mapping.Key, "key must be lowercase"))
|
||||
}
|
||||
|
||||
if isKubernetesDomainPrefix(mapping.Key) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), mapping.Key, "k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use"))
|
||||
}
|
||||
|
||||
if seenExtraKeys.Has(mapping.Key) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath.Child("key"), mapping.Key))
|
||||
continue
|
||||
}
|
||||
seenExtraKeys.Insert(mapping.Key)
|
||||
|
||||
if len(mapping.ValueExpression) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("valueExpression"), "valueExpression is required"))
|
||||
continue
|
||||
}
|
||||
|
||||
compilationResult, err := compileClaimsCELExpression(compiler, &authenticationcel.ExtraMappingExpression{
|
||||
Key: mapping.Key,
|
||||
Expression: mapping.ValueExpression,
|
||||
}, fldPath.Child("valueExpression"))
|
||||
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if compilationResult != nil {
|
||||
extraCompilationResults = append(extraCompilationResults, *compilationResult)
|
||||
}
|
||||
}
|
||||
|
||||
if structuredAuthnFeatureEnabled && len(extraCompilationResults) > 0 {
|
||||
state.mapper.Extra = authenticationcel.NewClaimsMapper(extraCompilationResults)
|
||||
state.usesEmailVerifiedClaim = state.usesEmailVerifiedClaim || anyUsesEmailVerifiedClaim(extraCompilationResults)
|
||||
}
|
||||
|
||||
if structuredAuthnFeatureEnabled && state.usesEmailClaim && !state.usesEmailVerifiedClaim {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("username", "expression"), m.Username.Expression,
|
||||
"claims.email_verified must be used in claimMappings.username.expression or claimMappings.extra[*].valueExpression or claimValidationRules[*].expression when claims.email is used in claimMappings.username.expression"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func isKubernetesDomainPrefix(key string) bool {
|
||||
domainPrefix := getDomainPrefix(key)
|
||||
if domainPrefix == "kubernetes.io" || strings.HasSuffix(domainPrefix, ".kubernetes.io") {
|
||||
return true
|
||||
}
|
||||
if domainPrefix == "k8s.io" || strings.HasSuffix(domainPrefix, ".k8s.io") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getDomainPrefix(key string) string {
|
||||
if parts := strings.SplitN(key, "/", 2); len(parts) == 2 {
|
||||
return parts[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func usesEmailClaim(ast *celgo.Ast) bool {
|
||||
return hasSelectExp(ast.Expr(), "claims", "email")
|
||||
}
|
||||
|
||||
func anyUsesEmailVerifiedClaim(results []authenticationcel.CompilationResult) bool {
|
||||
for _, result := range results {
|
||||
if usesEmailVerifiedClaim(result.AST) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func usesEmailVerifiedClaim(ast *celgo.Ast) bool {
|
||||
return hasSelectExp(ast.Expr(), "claims", "email_verified")
|
||||
}
|
||||
|
||||
func hasSelectExp(exp *exprpb.Expr, operand, field string) bool {
|
||||
if exp == nil {
|
||||
return false
|
||||
}
|
||||
switch e := exp.ExprKind.(type) {
|
||||
case *exprpb.Expr_ConstExpr,
|
||||
*exprpb.Expr_IdentExpr:
|
||||
return false
|
||||
case *exprpb.Expr_SelectExpr:
|
||||
s := e.SelectExpr
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
if isIdentOperand(s.Operand, operand) && s.Field == field {
|
||||
return true
|
||||
}
|
||||
return hasSelectExp(s.Operand, operand, field)
|
||||
case *exprpb.Expr_CallExpr:
|
||||
c := e.CallExpr
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
if c.Target == nil && c.Function == operators.OptSelect && len(c.Args) == 2 &&
|
||||
isIdentOperand(c.Args[0], operand) && isConstField(c.Args[1], field) {
|
||||
return true
|
||||
}
|
||||
for _, arg := range c.Args {
|
||||
if hasSelectExp(arg, operand, field) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return hasSelectExp(c.Target, operand, field)
|
||||
case *exprpb.Expr_ListExpr:
|
||||
l := e.ListExpr
|
||||
if l == nil {
|
||||
return false
|
||||
}
|
||||
for _, element := range l.Elements {
|
||||
if hasSelectExp(element, operand, field) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case *exprpb.Expr_StructExpr:
|
||||
s := e.StructExpr
|
||||
if s == nil {
|
||||
return false
|
||||
}
|
||||
for _, entry := range s.Entries {
|
||||
if hasSelectExp(entry.GetMapKey(), operand, field) {
|
||||
return true
|
||||
}
|
||||
if hasSelectExp(entry.Value, operand, field) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
case *exprpb.Expr_ComprehensionExpr:
|
||||
c := e.ComprehensionExpr
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
return hasSelectExp(c.IterRange, operand, field) ||
|
||||
hasSelectExp(c.AccuInit, operand, field) ||
|
||||
hasSelectExp(c.LoopCondition, operand, field) ||
|
||||
hasSelectExp(c.LoopStep, operand, field) ||
|
||||
hasSelectExp(c.Result, operand, field)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isIdentOperand(exp *exprpb.Expr, operand string) bool {
|
||||
if len(operand) == 0 {
|
||||
return false // sanity check against default values
|
||||
}
|
||||
id := exp.GetIdentExpr() // does not panic even if exp is nil
|
||||
return id != nil && id.Name == operand
|
||||
}
|
||||
|
||||
func isConstField(exp *exprpb.Expr, field string) bool {
|
||||
if len(field) == 0 {
|
||||
return false // sanity check against default values
|
||||
}
|
||||
c := exp.GetConstExpr() // does not panic even if exp is nil
|
||||
return c != nil && c.GetStringValue() == field // does not panic even if c is not a string
|
||||
}
|
||||
|
||||
func validatePrefixClaimOrExpression(compiler authenticationcel.Compiler, mapping api.PrefixedClaimOrExpression, fldPath *field.Path, claimOrExpressionRequired bool) (*authenticationcel.CompilationResult, field.ErrorList) {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
var compilationResult *authenticationcel.CompilationResult
|
||||
switch {
|
||||
case len(mapping.Expression) > 0 && len(mapping.Claim) > 0:
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, "", "claim and expression can't both be set"))
|
||||
case len(mapping.Expression) == 0 && len(mapping.Claim) == 0 && claimOrExpressionRequired:
|
||||
allErrs = append(allErrs, field.Required(fldPath, "claim or expression is required"))
|
||||
case len(mapping.Expression) > 0:
|
||||
var err *field.Error
|
||||
|
||||
if mapping.Prefix != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("prefix"), *mapping.Prefix, "prefix can't be set when expression is set"))
|
||||
}
|
||||
compilationResult, err = compileClaimsCELExpression(compiler, &authenticationcel.ClaimMappingExpression{
|
||||
Expression: mapping.Expression,
|
||||
}, fldPath.Child("expression"))
|
||||
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
}
|
||||
|
||||
case len(mapping.Claim) > 0:
|
||||
if mapping.Prefix == nil {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("prefix"), "prefix is required when claim is set. It can be set to an empty string to disable prefixing"))
|
||||
}
|
||||
}
|
||||
|
||||
return compilationResult, allErrs
|
||||
}
|
||||
|
||||
func validateUserValidationRules(compiler authenticationcel.Compiler, state *validationState, rules []api.UserValidationRule, fldPath *field.Path, structuredAuthnFeatureEnabled bool) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
var compilationResults []authenticationcel.CompilationResult
|
||||
|
||||
if len(rules) > 0 && !structuredAuthnFeatureEnabled {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath, "", "user validation rules are not supported when StructuredAuthenticationConfiguration feature gate is disabled"))
|
||||
}
|
||||
|
||||
seenExpressions := sets.NewString()
|
||||
for i, rule := range rules {
|
||||
fldPath := fldPath.Index(i)
|
||||
|
||||
if len(rule.Expression) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("expression"), "expression is required"))
|
||||
continue
|
||||
}
|
||||
|
||||
if seenExpressions.Has(rule.Expression) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath.Child("expression"), rule.Expression))
|
||||
continue
|
||||
}
|
||||
seenExpressions.Insert(rule.Expression)
|
||||
|
||||
compilationResult, err := compileUserCELExpression(compiler, &authenticationcel.UserValidationCondition{
|
||||
Expression: rule.Expression,
|
||||
Message: rule.Message,
|
||||
}, fldPath.Child("expression"))
|
||||
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if compilationResult != nil {
|
||||
compilationResults = append(compilationResults, *compilationResult)
|
||||
}
|
||||
}
|
||||
|
||||
if structuredAuthnFeatureEnabled && len(compilationResults) > 0 {
|
||||
state.mapper.UserValidationRules = authenticationcel.NewUserMapper(compilationResults)
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func compileClaimsCELExpression(compiler authenticationcel.Compiler, expression authenticationcel.ExpressionAccessor, fldPath *field.Path) (*authenticationcel.CompilationResult, *field.Error) {
|
||||
compilationResult, err := compiler.CompileClaimsExpression(expression)
|
||||
if err != nil {
|
||||
return nil, convertCELErrorToValidationError(fldPath, expression.GetExpression(), err)
|
||||
}
|
||||
return &compilationResult, nil
|
||||
}
|
||||
|
||||
func compileUserCELExpression(compiler authenticationcel.Compiler, expression authenticationcel.ExpressionAccessor, fldPath *field.Path) (*authenticationcel.CompilationResult, *field.Error) {
|
||||
compilationResult, err := compiler.CompileUserExpression(expression)
|
||||
if err != nil {
|
||||
return nil, convertCELErrorToValidationError(fldPath, expression.GetExpression(), err)
|
||||
}
|
||||
return &compilationResult, nil
|
||||
}
|
||||
|
||||
// ValidateAuthorizationConfiguration validates a given AuthorizationConfiguration.
|
||||
func ValidateAuthorizationConfiguration(compiler authorizationcel.Compiler, fldPath *field.Path, c *api.AuthorizationConfiguration, knownTypes sets.Set[string], repeatableTypes sets.Set[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()
|
||||
seenAuthorizerNames := 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, sets.List(knownTypes)))
|
||||
continue
|
||||
}
|
||||
if seenAuthorizerTypes.Has(aType) && !repeatableTypes.Has(aType) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath.Child("type"), aType))
|
||||
continue
|
||||
}
|
||||
seenAuthorizerTypes.Insert(aType)
|
||||
|
||||
if len(a.Name) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
|
||||
} else if seenAuthorizerNames.Has(a.Name) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath.Child("name"), a.Name))
|
||||
} else if errs := utilvalidation.IsDNS1123Subdomain(a.Name); len(errs) != 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), a.Name, fmt.Sprintf("authorizer name is invalid: %s", strings.Join(errs, ", "))))
|
||||
}
|
||||
seenAuthorizerNames.Insert(a.Name)
|
||||
|
||||
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(compiler, fldPath, a.Webhook)...)
|
||||
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(compiler authorizationcel.Compiler, fldPath *field.Path, c *api.WebhookConfiguration) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
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 "":
|
||||
if len(c.MatchConditions) > 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("matchConditionSubjectAccessReviewVersion"), "required if match conditions are specified"))
|
||||
}
|
||||
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.AuthorizationWebhookConnectionInfoTypeKubeConfigFile:
|
||||
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{api.AuthorizationWebhookConnectionInfoTypeInCluster, api.AuthorizationWebhookConnectionInfoTypeKubeConfigFile}))
|
||||
}
|
||||
|
||||
_, errs := compileMatchConditions(compiler, c.MatchConditions, fldPath, utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthorizationConfiguration))
|
||||
allErrs = append(allErrs, errs...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateAndCompileMatchConditions validates a given webhook's matchConditions.
|
||||
// This is exported for use in authz package.
|
||||
func ValidateAndCompileMatchConditions(compiler authorizationcel.Compiler, matchConditions []api.WebhookMatchCondition) (*authorizationcel.CELMatcher, field.ErrorList) {
|
||||
return compileMatchConditions(compiler, matchConditions, nil, utilfeature.DefaultFeatureGate.Enabled(features.StructuredAuthorizationConfiguration))
|
||||
}
|
||||
|
||||
func compileMatchConditions(compiler authorizationcel.Compiler, matchConditions []api.WebhookMatchCondition, fldPath *field.Path, structuredAuthzFeatureEnabled bool) (*authorizationcel.CELMatcher, field.ErrorList) {
|
||||
var allErrs field.ErrorList
|
||||
// should fail when match conditions are used without feature enabled
|
||||
if len(matchConditions) > 0 && !structuredAuthzFeatureEnabled {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("matchConditions"), "", "matchConditions are not supported when StructuredAuthorizationConfiguration feature gate is disabled"))
|
||||
}
|
||||
if len(matchConditions) > 64 {
|
||||
allErrs = append(allErrs, field.TooMany(fldPath.Child("matchConditions"), len(matchConditions), 64))
|
||||
return nil, allErrs
|
||||
}
|
||||
|
||||
seenExpressions := sets.NewString()
|
||||
var compilationResults []authorizationcel.CompilationResult
|
||||
var usesFieldSelector, usesLabelSelector bool
|
||||
|
||||
for i, condition := range matchConditions {
|
||||
fldPath := fldPath.Child("matchConditions").Index(i).Child("expression")
|
||||
if len(strings.TrimSpace(condition.Expression)) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath, ""))
|
||||
continue
|
||||
}
|
||||
if seenExpressions.Has(condition.Expression) {
|
||||
allErrs = append(allErrs, field.Duplicate(fldPath, condition.Expression))
|
||||
continue
|
||||
}
|
||||
seenExpressions.Insert(condition.Expression)
|
||||
compilationResult, err := compileMatchConditionsExpression(fldPath, compiler, condition.Expression)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
continue
|
||||
}
|
||||
compilationResults = append(compilationResults, compilationResult)
|
||||
usesFieldSelector = usesFieldSelector || compilationResult.UsesFieldSelector
|
||||
usesLabelSelector = usesLabelSelector || compilationResult.UsesLabelSelector
|
||||
}
|
||||
if len(compilationResults) == 0 {
|
||||
return nil, allErrs
|
||||
}
|
||||
return &authorizationcel.CELMatcher{
|
||||
CompilationResults: compilationResults,
|
||||
UsesFieldSelector: usesFieldSelector,
|
||||
UsesLabelSelector: usesLabelSelector,
|
||||
}, allErrs
|
||||
}
|
||||
|
||||
func compileMatchConditionsExpression(fldPath *field.Path, compiler authorizationcel.Compiler, expression string) (authorizationcel.CompilationResult, *field.Error) {
|
||||
authzExpression := &authorizationcel.SubjectAccessReviewMatchCondition{
|
||||
Expression: expression,
|
||||
}
|
||||
compilationResult, err := compiler.CompileCELExpression(authzExpression)
|
||||
if err != nil {
|
||||
return compilationResult, convertCELErrorToValidationError(fldPath, authzExpression.GetExpression(), err)
|
||||
}
|
||||
return compilationResult, nil
|
||||
}
|
||||
|
||||
func convertCELErrorToValidationError(fldPath *field.Path, expression string, err error) *field.Error {
|
||||
var celErr *cel.Error
|
||||
if errors.As(err, &celErr) {
|
||||
switch celErr.Type {
|
||||
case cel.ErrorTypeRequired:
|
||||
return field.Required(fldPath, celErr.Detail)
|
||||
case cel.ErrorTypeInvalid:
|
||||
return field.Invalid(fldPath, expression, celErr.Detail)
|
||||
default:
|
||||
return field.InternalError(fldPath, celErr)
|
||||
}
|
||||
}
|
||||
return field.InternalError(fldPath, fmt.Errorf("error is not cel error: %w", err))
|
||||
}
|
451
e2e/vendor/k8s.io/apiserver/pkg/apis/apiserver/validation/validation_encryption.go
generated
vendored
451
e2e/vendor/k8s.io/apiserver/pkg/apis/apiserver/validation/validation_encryption.go
generated
vendored
@ -1,451 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 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 validation validates EncryptionConfiguration.
|
||||
package validation
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
)
|
||||
|
||||
const (
|
||||
moreThanOneElementErr = "more than one provider specified in a single element, should split into different list elements"
|
||||
keyLenErrFmt = "secret is not of the expected length, got %d, expected one of %v"
|
||||
unsupportedSchemeErrFmt = "unsupported scheme %q for KMS provider, only unix is supported"
|
||||
unsupportedKMSAPIVersionErrFmt = "unsupported apiVersion %s for KMS provider, only v1 and v2 are supported"
|
||||
atLeastOneRequiredErrFmt = "at least one %s is required"
|
||||
invalidURLErrFmt = "invalid endpoint for kms provider, error: %v"
|
||||
mandatoryFieldErrFmt = "%s is a mandatory field for a %s"
|
||||
base64EncodingErr = "secrets must be base64 encoded"
|
||||
zeroOrNegativeErrFmt = "%s should be a positive value"
|
||||
nonZeroErrFmt = "%s should be a positive value, or negative to disable"
|
||||
encryptionConfigNilErr = "EncryptionConfiguration can't be nil"
|
||||
invalidKMSConfigNameErrFmt = "invalid KMS provider name %s, must not contain ':'"
|
||||
duplicateKMSConfigNameErrFmt = "duplicate KMS provider name %s, names must be unique"
|
||||
eventsGroupErr = "'*.events.k8s.io' objects are stored using the 'events' API group in etcd. Use 'events' instead in the config file"
|
||||
extensionsGroupErr = "'extensions' group has been removed and cannot be used for encryption"
|
||||
starResourceErr = "use '*.' to encrypt all the resources from core API group or *.* to encrypt all resources"
|
||||
overlapErr = "using overlapping resources such as 'secrets' and '*.' in the same resource list is not allowed as they will be masked"
|
||||
nonRESTAPIResourceErr = "resources which do not have REST API/s cannot be encrypted"
|
||||
resourceNameErr = "resource name should not contain capital letters"
|
||||
resourceAcrossGroupErr = "encrypting the same resource across groups is not supported"
|
||||
duplicateResourceErr = "the same resource cannot be specified multiple times"
|
||||
)
|
||||
|
||||
var (
|
||||
// See https://golang.org/pkg/crypto/aes/#NewCipher for details on supported key sizes for AES.
|
||||
aesKeySizes = []int{16, 24, 32}
|
||||
|
||||
// See https://godoc.org/golang.org/x/crypto/nacl/secretbox#Open for details on the supported key sizes for Secretbox.
|
||||
secretBoxKeySizes = []int{32}
|
||||
)
|
||||
|
||||
// ValidateEncryptionConfiguration validates a v1.EncryptionConfiguration.
|
||||
func ValidateEncryptionConfiguration(c *apiserver.EncryptionConfiguration, reload bool) field.ErrorList {
|
||||
root := field.NewPath("resources")
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if c == nil {
|
||||
allErrs = append(allErrs, field.Required(root, encryptionConfigNilErr))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
if len(c.Resources) == 0 {
|
||||
allErrs = append(allErrs, field.Required(root, fmt.Sprintf(atLeastOneRequiredErrFmt, root)))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// kmsProviderNames is used to track config names to ensure they are unique.
|
||||
kmsProviderNames := sets.New[string]()
|
||||
for i, conf := range c.Resources {
|
||||
r := root.Index(i).Child("resources")
|
||||
p := root.Index(i).Child("providers")
|
||||
|
||||
if len(conf.Resources) == 0 {
|
||||
allErrs = append(allErrs, field.Required(r, fmt.Sprintf(atLeastOneRequiredErrFmt, r)))
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, validateResourceOverlap(conf.Resources, r)...)
|
||||
allErrs = append(allErrs, validateResourceNames(conf.Resources, r)...)
|
||||
|
||||
if len(conf.Providers) == 0 {
|
||||
allErrs = append(allErrs, field.Required(p, fmt.Sprintf(atLeastOneRequiredErrFmt, p)))
|
||||
}
|
||||
|
||||
for j, provider := range conf.Providers {
|
||||
path := p.Index(j)
|
||||
allErrs = append(allErrs, validateSingleProvider(provider, path)...)
|
||||
|
||||
switch {
|
||||
case provider.KMS != nil:
|
||||
allErrs = append(allErrs, validateKMSConfiguration(provider.KMS, path.Child("kms"), kmsProviderNames, reload)...)
|
||||
kmsProviderNames.Insert(provider.KMS.Name)
|
||||
case provider.AESGCM != nil:
|
||||
allErrs = append(allErrs, validateKeys(provider.AESGCM.Keys, path.Child("aesgcm").Child("keys"), aesKeySizes)...)
|
||||
case provider.AESCBC != nil:
|
||||
allErrs = append(allErrs, validateKeys(provider.AESCBC.Keys, path.Child("aescbc").Child("keys"), aesKeySizes)...)
|
||||
case provider.Secretbox != nil:
|
||||
allErrs = append(allErrs, validateKeys(provider.Secretbox.Keys, path.Child("secretbox").Child("keys"), secretBoxKeySizes)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
var anyGroupAnyResource = schema.GroupResource{
|
||||
Group: "*",
|
||||
Resource: "*",
|
||||
}
|
||||
|
||||
func validateResourceOverlap(resources []string, fieldPath *field.Path) field.ErrorList {
|
||||
if len(resources) < 2 { // cannot have overlap with a single resource
|
||||
return nil
|
||||
}
|
||||
|
||||
var allErrs field.ErrorList
|
||||
|
||||
r := make([]schema.GroupResource, 0, len(resources))
|
||||
for _, resource := range resources {
|
||||
r = append(r, schema.ParseGroupResource(resource))
|
||||
}
|
||||
|
||||
var hasOverlap, hasDuplicate bool
|
||||
|
||||
for i, r1 := range r {
|
||||
for j, r2 := range r {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
|
||||
if r1 == r2 && !hasDuplicate {
|
||||
hasDuplicate = true
|
||||
continue
|
||||
}
|
||||
|
||||
if hasOverlap {
|
||||
continue
|
||||
}
|
||||
|
||||
if r1 == anyGroupAnyResource {
|
||||
hasOverlap = true
|
||||
continue
|
||||
}
|
||||
|
||||
if r1.Group != r2.Group {
|
||||
continue
|
||||
}
|
||||
|
||||
if r1.Resource == "*" || r2.Resource == "*" {
|
||||
hasOverlap = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hasDuplicate {
|
||||
allErrs = append(
|
||||
allErrs,
|
||||
field.Invalid(
|
||||
fieldPath,
|
||||
resources,
|
||||
duplicateResourceErr,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if hasOverlap {
|
||||
allErrs = append(
|
||||
allErrs,
|
||||
field.Invalid(
|
||||
fieldPath,
|
||||
resources,
|
||||
overlapErr,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateResourceNames(resources []string, fieldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
for j, res := range resources {
|
||||
jj := fieldPath.Index(j)
|
||||
|
||||
// check if resource name has capital letters
|
||||
if hasCapital(res) {
|
||||
allErrs = append(
|
||||
allErrs,
|
||||
field.Invalid(
|
||||
jj,
|
||||
resources[j],
|
||||
resourceNameErr,
|
||||
),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// check if resource is '*'
|
||||
if res == "*" {
|
||||
allErrs = append(
|
||||
allErrs,
|
||||
field.Invalid(
|
||||
jj,
|
||||
resources[j],
|
||||
starResourceErr,
|
||||
),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// check if resource is:
|
||||
// 'apiserveripinfo' OR
|
||||
// 'serviceipallocations' OR
|
||||
// 'servicenodeportallocations' OR
|
||||
if res == "apiserveripinfo" ||
|
||||
res == "serviceipallocations" ||
|
||||
res == "servicenodeportallocations" {
|
||||
allErrs = append(
|
||||
allErrs,
|
||||
field.Invalid(
|
||||
jj,
|
||||
resources[j],
|
||||
nonRESTAPIResourceErr,
|
||||
),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// check if group is 'events.k8s.io'
|
||||
gr := schema.ParseGroupResource(res)
|
||||
if gr.Group == "events.k8s.io" {
|
||||
allErrs = append(
|
||||
allErrs,
|
||||
field.Invalid(
|
||||
jj,
|
||||
resources[j],
|
||||
eventsGroupErr,
|
||||
),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// check if group is 'extensions'
|
||||
if gr.Group == "extensions" {
|
||||
allErrs = append(
|
||||
allErrs,
|
||||
field.Invalid(
|
||||
jj,
|
||||
resources[j],
|
||||
extensionsGroupErr,
|
||||
),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// disallow resource.* as encrypting the same resource across groups does not make sense
|
||||
if gr.Group == "*" && gr.Resource != "*" {
|
||||
allErrs = append(
|
||||
allErrs,
|
||||
field.Invalid(
|
||||
jj,
|
||||
resources[j],
|
||||
resourceAcrossGroupErr,
|
||||
),
|
||||
)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateSingleProvider(provider apiserver.ProviderConfiguration, fieldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
found := 0
|
||||
|
||||
if provider.KMS != nil {
|
||||
found++
|
||||
}
|
||||
if provider.AESGCM != nil {
|
||||
found++
|
||||
}
|
||||
if provider.AESCBC != nil {
|
||||
found++
|
||||
}
|
||||
if provider.Secretbox != nil {
|
||||
found++
|
||||
}
|
||||
if provider.Identity != nil {
|
||||
found++
|
||||
}
|
||||
|
||||
if found == 0 {
|
||||
return append(allErrs, field.Invalid(fieldPath, provider, "provider does not contain any of the expected providers: KMS, AESGCM, AESCBC, Secretbox, Identity"))
|
||||
}
|
||||
|
||||
if found > 1 {
|
||||
return append(allErrs, field.Invalid(fieldPath, provider, moreThanOneElementErr))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateKeys(keys []apiserver.Key, fieldPath *field.Path, expectedLen []int) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if len(keys) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fieldPath, fmt.Sprintf(atLeastOneRequiredErrFmt, "keys")))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
for i, key := range keys {
|
||||
allErrs = append(allErrs, validateKey(key, fieldPath.Index(i), expectedLen)...)
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateKey(key apiserver.Key, fieldPath *field.Path, expectedLen []int) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if key.Name == "" {
|
||||
allErrs = append(allErrs, field.Required(fieldPath.Child("name"), fmt.Sprintf(mandatoryFieldErrFmt, "name", "key")))
|
||||
}
|
||||
|
||||
if key.Secret == "" {
|
||||
allErrs = append(allErrs, field.Required(fieldPath.Child("secret"), fmt.Sprintf(mandatoryFieldErrFmt, "secret", "key")))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
secret, err := base64.StdEncoding.DecodeString(key.Secret)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath.Child("secret"), "REDACTED", base64EncodingErr))
|
||||
return allErrs
|
||||
}
|
||||
|
||||
lenMatched := false
|
||||
for _, l := range expectedLen {
|
||||
if len(secret) == l {
|
||||
lenMatched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !lenMatched {
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath.Child("secret"), "REDACTED", fmt.Sprintf(keyLenErrFmt, len(secret), expectedLen)))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateKMSConfiguration(c *apiserver.KMSConfiguration, fieldPath *field.Path, kmsProviderNames sets.Set[string], reload bool) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
allErrs = append(allErrs, validateKMSConfigName(c, fieldPath.Child("name"), kmsProviderNames, reload)...)
|
||||
allErrs = append(allErrs, validateKMSTimeout(c, fieldPath.Child("timeout"))...)
|
||||
allErrs = append(allErrs, validateKMSEndpoint(c, fieldPath.Child("endpoint"))...)
|
||||
allErrs = append(allErrs, validateKMSCacheSize(c, fieldPath.Child("cachesize"))...)
|
||||
allErrs = append(allErrs, validateKMSAPIVersion(c, fieldPath.Child("apiVersion"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateKMSCacheSize(c *apiserver.KMSConfiguration, fieldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
// In defaulting, we set the cache size to the default value only when API version is v1.
|
||||
// So, for v2 API version, we expect the cache size field to be nil.
|
||||
if c.APIVersion != "v1" && c.CacheSize != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath, *c.CacheSize, "cachesize is not supported in v2"))
|
||||
}
|
||||
if c.APIVersion == "v1" && *c.CacheSize == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath, *c.CacheSize, fmt.Sprintf(nonZeroErrFmt, "cachesize")))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateKMSTimeout(c *apiserver.KMSConfiguration, fieldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if c.Timeout.Duration <= 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath, c.Timeout, fmt.Sprintf(zeroOrNegativeErrFmt, "timeout")))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateKMSEndpoint(c *apiserver.KMSConfiguration, fieldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(c.Endpoint) == 0 {
|
||||
return append(allErrs, field.Invalid(fieldPath, "", fmt.Sprintf(mandatoryFieldErrFmt, "endpoint", "kms")))
|
||||
}
|
||||
|
||||
u, err := url.Parse(c.Endpoint)
|
||||
if err != nil {
|
||||
return append(allErrs, field.Invalid(fieldPath, c.Endpoint, fmt.Sprintf(invalidURLErrFmt, err)))
|
||||
}
|
||||
|
||||
if u.Scheme != "unix" {
|
||||
return append(allErrs, field.Invalid(fieldPath, c.Endpoint, fmt.Sprintf(unsupportedSchemeErrFmt, u.Scheme)))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateKMSAPIVersion(c *apiserver.KMSConfiguration, fieldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if c.APIVersion != "v1" && c.APIVersion != "v2" {
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath, c.APIVersion, fmt.Sprintf(unsupportedKMSAPIVersionErrFmt, "apiVersion")))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateKMSConfigName(c *apiserver.KMSConfiguration, fieldPath *field.Path, kmsProviderNames sets.Set[string], reload bool) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if c.Name == "" {
|
||||
allErrs = append(allErrs, field.Required(fieldPath, fmt.Sprintf(mandatoryFieldErrFmt, "name", "provider")))
|
||||
}
|
||||
|
||||
// kms v2 providers are not allowed to have a ":" in their name
|
||||
if c.APIVersion != "v1" && strings.Contains(c.Name, ":") {
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath, c.Name, fmt.Sprintf(invalidKMSConfigNameErrFmt, c.Name)))
|
||||
}
|
||||
|
||||
// kms v2 providers name must always be unique across all kms providers (v1 and v2)
|
||||
// kms v1 provider names must be unique across all kms providers (v1 and v2) when hot reloading of encryption configuration is enabled (reload=true)
|
||||
if reload || c.APIVersion != "v1" {
|
||||
if kmsProviderNames.Has(c.Name) {
|
||||
allErrs = append(allErrs, field.Invalid(fieldPath, c.Name, fmt.Sprintf(duplicateKMSConfigNameErrFmt, c.Name)))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func hasCapital(input string) bool {
|
||||
return strings.ToLower(input) != input
|
||||
}
|
33
e2e/vendor/k8s.io/apiserver/pkg/apis/audit/install/install.go
generated
vendored
33
e2e/vendor/k8s.io/apiserver/pkg/apis/audit/install/install.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 install installs the experimental API group, making it available as
|
||||
// an option to all of the API encoding/decoding machinery.
|
||||
package install
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/apiserver/pkg/apis/audit/v1"
|
||||
)
|
||||
|
||||
// Install registers the API group and adds types to a scheme
|
||||
func Install(scheme *runtime.Scheme) {
|
||||
utilruntime.Must(audit.AddToScheme(scheme))
|
||||
utilruntime.Must(v1.AddToScheme(scheme))
|
||||
utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion))
|
||||
}
|
133
e2e/vendor/k8s.io/apiserver/pkg/apis/audit/validation/validation.go
generated
vendored
133
e2e/vendor/k8s.io/apiserver/pkg/apis/audit/validation/validation.go
generated
vendored
@ -1,133 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 validation
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
)
|
||||
|
||||
// ValidatePolicy validates the audit policy
|
||||
func ValidatePolicy(policy *audit.Policy) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
allErrs = append(allErrs, validateOmitStages(policy.OmitStages, field.NewPath("omitStages"))...)
|
||||
rulePath := field.NewPath("rules")
|
||||
for i, rule := range policy.Rules {
|
||||
allErrs = append(allErrs, validatePolicyRule(rule, rulePath.Index(i))...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validatePolicyRule(rule audit.PolicyRule, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
allErrs = append(allErrs, validateLevel(rule.Level, fldPath.Child("level"))...)
|
||||
allErrs = append(allErrs, validateNonResourceURLs(rule.NonResourceURLs, fldPath.Child("nonResourceURLs"))...)
|
||||
allErrs = append(allErrs, validateResources(rule.Resources, fldPath.Child("resources"))...)
|
||||
allErrs = append(allErrs, validateOmitStages(rule.OmitStages, fldPath.Child("omitStages"))...)
|
||||
|
||||
if len(rule.NonResourceURLs) > 0 {
|
||||
if len(rule.Resources) > 0 || len(rule.Namespaces) > 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("nonResourceURLs"), rule.NonResourceURLs, "rules cannot apply to both regular resources and non-resource URLs"))
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
var validLevels = []string{
|
||||
string(audit.LevelNone),
|
||||
string(audit.LevelMetadata),
|
||||
string(audit.LevelRequest),
|
||||
string(audit.LevelRequestResponse),
|
||||
}
|
||||
|
||||
var validOmitStages = []string{
|
||||
string(audit.StageRequestReceived),
|
||||
string(audit.StageResponseStarted),
|
||||
string(audit.StageResponseComplete),
|
||||
string(audit.StagePanic),
|
||||
}
|
||||
|
||||
func validateLevel(level audit.Level, fldPath *field.Path) field.ErrorList {
|
||||
switch level {
|
||||
case audit.LevelNone, audit.LevelMetadata, audit.LevelRequest, audit.LevelRequestResponse:
|
||||
return nil
|
||||
case "":
|
||||
return field.ErrorList{field.Required(fldPath, "")}
|
||||
default:
|
||||
return field.ErrorList{field.NotSupported(fldPath, level, validLevels)}
|
||||
}
|
||||
}
|
||||
|
||||
func validateNonResourceURLs(urls []string, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
for i, url := range urls {
|
||||
if url == "*" {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(url, "/") {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Index(i), url, "non-resource URL rules must begin with a '/' character"))
|
||||
}
|
||||
|
||||
if url != "" && strings.ContainsRune(url[:len(url)-1], '*') {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Index(i), url, "non-resource URL wildcards '*' must be the final character of the rule"))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateResources(groupResources []audit.GroupResources, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
for _, groupResource := range groupResources {
|
||||
// The empty string represents the core API group.
|
||||
if len(groupResource.Group) != 0 {
|
||||
// Group names must be lower case and be valid DNS subdomains.
|
||||
// reference: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md
|
||||
// an error is returned for group name like rbac.authorization.k8s.io/v1beta1
|
||||
// rbac.authorization.k8s.io is the valid one
|
||||
if msgs := validation.NameIsDNSSubdomain(groupResource.Group, false); len(msgs) != 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("group"), groupResource.Group, strings.Join(msgs, ",")))
|
||||
}
|
||||
}
|
||||
|
||||
if len(groupResource.ResourceNames) > 0 && len(groupResource.Resources) == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceNames"), groupResource.ResourceNames, "using resourceNames requires at least one resource"))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateOmitStages(omitStages []audit.Stage, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
for i, stage := range omitStages {
|
||||
valid := false
|
||||
for _, validOmitStage := range validOmitStages {
|
||||
if string(stage) == validOmitStage {
|
||||
valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !valid {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Index(i), string(stage), "allowed stages are "+strings.Join(validOmitStages, ",")))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
577
e2e/vendor/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap/default.go
generated
vendored
577
e2e/vendor/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap/default.go
generated
vendored
@ -1,577 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 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 bootstrap
|
||||
|
||||
import (
|
||||
coordinationv1 "k8s.io/api/coordination/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
flowcontrol "k8s.io/api/flowcontrol/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apiserver/pkg/authentication/serviceaccount"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
// The objects that define an apiserver's initial behavior. The
|
||||
// registered defaulting procedures make no changes to these
|
||||
// particular objects (this is verified in the unit tests of the
|
||||
// internalbootstrap package; it can not be verified in this package
|
||||
// because that would require importing k8s.io/kubernetes).
|
||||
var (
|
||||
MandatoryPriorityLevelConfigurations = []*flowcontrol.PriorityLevelConfiguration{
|
||||
MandatoryPriorityLevelConfigurationCatchAll,
|
||||
MandatoryPriorityLevelConfigurationExempt,
|
||||
}
|
||||
MandatoryFlowSchemas = []*flowcontrol.FlowSchema{
|
||||
MandatoryFlowSchemaExempt,
|
||||
MandatoryFlowSchemaCatchAll,
|
||||
}
|
||||
)
|
||||
|
||||
// The objects that define the current suggested additional configuration
|
||||
var (
|
||||
SuggestedPriorityLevelConfigurations = []*flowcontrol.PriorityLevelConfiguration{
|
||||
// "system" priority-level is for the system components that affects self-maintenance of the
|
||||
// cluster and the availability of those running pods in the cluster, including kubelet and
|
||||
// kube-proxy.
|
||||
SuggestedPriorityLevelConfigurationSystem,
|
||||
// "node-high" priority-level is for the node health reporting. It is separated from "system"
|
||||
// to make sure that nodes are able to report their health even if kube-apiserver is not capable of
|
||||
// handling load caused by pod startup (fetching secrets, events etc).
|
||||
// NOTE: In large clusters 50% - 90% of all API calls use this priority-level.
|
||||
SuggestedPriorityLevelConfigurationNodeHigh,
|
||||
// "leader-election" is dedicated for controllers' leader-election, which majorly affects the
|
||||
// availability of any controller runs in the cluster.
|
||||
SuggestedPriorityLevelConfigurationLeaderElection,
|
||||
// "workload-high" is used by those workloads with higher priority but their failure won't directly
|
||||
// impact the existing running pods in the cluster, which includes kube-scheduler, and those well-known
|
||||
// built-in workloads such as "deployments", "replicasets" and other low-level custom workload which
|
||||
// is important for the cluster.
|
||||
SuggestedPriorityLevelConfigurationWorkloadHigh,
|
||||
// "workload-low" is used by those workloads with lower priority which availability only has a
|
||||
// minor impact on the cluster.
|
||||
SuggestedPriorityLevelConfigurationWorkloadLow,
|
||||
// "global-default" serves the rest traffic not handled by the other suggested flow-schemas above.
|
||||
SuggestedPriorityLevelConfigurationGlobalDefault,
|
||||
}
|
||||
SuggestedFlowSchemas = []*flowcontrol.FlowSchema{
|
||||
SuggestedFlowSchemaSystemNodes, // references "system" priority-level
|
||||
SuggestedFlowSchemaSystemNodeHigh, // references "node-high" priority-level
|
||||
SuggestedFlowSchemaProbes, // references "exempt" priority-level
|
||||
SuggestedFlowSchemaSystemLeaderElection, // references "leader-election" priority-level
|
||||
SuggestedFlowSchemaWorkloadLeaderElection, // references "leader-election" priority-level
|
||||
SuggestedFlowSchemaEndpointsController, // references "workload-high" priority-level
|
||||
SuggestedFlowSchemaKubeControllerManager, // references "workload-high" priority-level
|
||||
SuggestedFlowSchemaKubeScheduler, // references "workload-high" priority-level
|
||||
SuggestedFlowSchemaKubeSystemServiceAccounts, // references "workload-high" priority-level
|
||||
SuggestedFlowSchemaServiceAccounts, // references "workload-low" priority-level
|
||||
SuggestedFlowSchemaGlobalDefault, // references "global-default" priority-level
|
||||
}
|
||||
)
|
||||
|
||||
// Mandatory PriorityLevelConfiguration objects
|
||||
var (
|
||||
MandatoryPriorityLevelConfigurationExempt = newPriorityLevelConfiguration(
|
||||
flowcontrol.PriorityLevelConfigurationNameExempt,
|
||||
flowcontrol.PriorityLevelConfigurationSpec{
|
||||
Type: flowcontrol.PriorityLevelEnablementExempt,
|
||||
Exempt: &flowcontrol.ExemptPriorityLevelConfiguration{
|
||||
NominalConcurrencyShares: ptr.To(int32(0)),
|
||||
LendablePercent: ptr.To(int32(0)),
|
||||
},
|
||||
},
|
||||
)
|
||||
MandatoryPriorityLevelConfigurationCatchAll = newPriorityLevelConfiguration(
|
||||
flowcontrol.PriorityLevelConfigurationNameCatchAll,
|
||||
flowcontrol.PriorityLevelConfigurationSpec{
|
||||
Type: flowcontrol.PriorityLevelEnablementLimited,
|
||||
Limited: &flowcontrol.LimitedPriorityLevelConfiguration{
|
||||
NominalConcurrencyShares: ptr.To(int32(5)),
|
||||
LendablePercent: ptr.To(int32(0)),
|
||||
LimitResponse: flowcontrol.LimitResponse{
|
||||
Type: flowcontrol.LimitResponseTypeReject,
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
// Mandatory FlowSchema objects
|
||||
var (
|
||||
// "exempt" priority-level is used for preventing priority inversion and ensuring that sysadmin
|
||||
// requests are always possible.
|
||||
MandatoryFlowSchemaExempt = newFlowSchema(
|
||||
"exempt",
|
||||
flowcontrol.PriorityLevelConfigurationNameExempt,
|
||||
1, // matchingPrecedence
|
||||
"", // distinguisherMethodType
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: groups(user.SystemPrivilegedGroup),
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{
|
||||
resourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.APIGroupAll},
|
||||
[]string{flowcontrol.ResourceAll},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
true,
|
||||
),
|
||||
},
|
||||
NonResourceRules: []flowcontrol.NonResourcePolicyRule{
|
||||
nonResourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.NonResourceAll},
|
||||
),
|
||||
},
|
||||
},
|
||||
)
|
||||
// "catch-all" priority-level only gets a minimal positive share of concurrency and won't be reaching
|
||||
// ideally unless you intentionally deleted the suggested "global-default".
|
||||
MandatoryFlowSchemaCatchAll = newFlowSchema(
|
||||
flowcontrol.FlowSchemaNameCatchAll,
|
||||
flowcontrol.PriorityLevelConfigurationNameCatchAll,
|
||||
10000, // matchingPrecedence
|
||||
flowcontrol.FlowDistinguisherMethodByUserType, // distinguisherMethodType
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: groups(user.AllUnauthenticated, user.AllAuthenticated),
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{
|
||||
resourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.APIGroupAll},
|
||||
[]string{flowcontrol.ResourceAll},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
true,
|
||||
),
|
||||
},
|
||||
NonResourceRules: []flowcontrol.NonResourcePolicyRule{
|
||||
nonResourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.NonResourceAll},
|
||||
),
|
||||
},
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
// Suggested PriorityLevelConfiguration objects
|
||||
var (
|
||||
// system priority-level
|
||||
SuggestedPriorityLevelConfigurationSystem = newPriorityLevelConfiguration(
|
||||
"system",
|
||||
flowcontrol.PriorityLevelConfigurationSpec{
|
||||
Type: flowcontrol.PriorityLevelEnablementLimited,
|
||||
Limited: &flowcontrol.LimitedPriorityLevelConfiguration{
|
||||
NominalConcurrencyShares: ptr.To(int32(30)),
|
||||
LendablePercent: ptr.To(int32(33)),
|
||||
LimitResponse: flowcontrol.LimitResponse{
|
||||
Type: flowcontrol.LimitResponseTypeQueue,
|
||||
Queuing: &flowcontrol.QueuingConfiguration{
|
||||
Queues: 64,
|
||||
HandSize: 6,
|
||||
QueueLengthLimit: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
SuggestedPriorityLevelConfigurationNodeHigh = newPriorityLevelConfiguration(
|
||||
"node-high",
|
||||
flowcontrol.PriorityLevelConfigurationSpec{
|
||||
Type: flowcontrol.PriorityLevelEnablementLimited,
|
||||
Limited: &flowcontrol.LimitedPriorityLevelConfiguration{
|
||||
NominalConcurrencyShares: ptr.To(int32(40)),
|
||||
LendablePercent: ptr.To(int32(25)),
|
||||
LimitResponse: flowcontrol.LimitResponse{
|
||||
Type: flowcontrol.LimitResponseTypeQueue,
|
||||
Queuing: &flowcontrol.QueuingConfiguration{
|
||||
Queues: 64,
|
||||
HandSize: 6,
|
||||
QueueLengthLimit: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
// leader-election priority-level
|
||||
SuggestedPriorityLevelConfigurationLeaderElection = newPriorityLevelConfiguration(
|
||||
"leader-election",
|
||||
flowcontrol.PriorityLevelConfigurationSpec{
|
||||
Type: flowcontrol.PriorityLevelEnablementLimited,
|
||||
Limited: &flowcontrol.LimitedPriorityLevelConfiguration{
|
||||
NominalConcurrencyShares: ptr.To(int32(10)),
|
||||
LendablePercent: ptr.To(int32(0)),
|
||||
LimitResponse: flowcontrol.LimitResponse{
|
||||
Type: flowcontrol.LimitResponseTypeQueue,
|
||||
Queuing: &flowcontrol.QueuingConfiguration{
|
||||
Queues: 16,
|
||||
HandSize: 4,
|
||||
QueueLengthLimit: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
// workload-high priority-level
|
||||
SuggestedPriorityLevelConfigurationWorkloadHigh = newPriorityLevelConfiguration(
|
||||
"workload-high",
|
||||
flowcontrol.PriorityLevelConfigurationSpec{
|
||||
Type: flowcontrol.PriorityLevelEnablementLimited,
|
||||
Limited: &flowcontrol.LimitedPriorityLevelConfiguration{
|
||||
NominalConcurrencyShares: ptr.To(int32(40)),
|
||||
LendablePercent: ptr.To(int32(50)),
|
||||
LimitResponse: flowcontrol.LimitResponse{
|
||||
Type: flowcontrol.LimitResponseTypeQueue,
|
||||
Queuing: &flowcontrol.QueuingConfiguration{
|
||||
Queues: 128,
|
||||
HandSize: 6,
|
||||
QueueLengthLimit: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
// workload-low priority-level
|
||||
SuggestedPriorityLevelConfigurationWorkloadLow = newPriorityLevelConfiguration(
|
||||
"workload-low",
|
||||
flowcontrol.PriorityLevelConfigurationSpec{
|
||||
Type: flowcontrol.PriorityLevelEnablementLimited,
|
||||
Limited: &flowcontrol.LimitedPriorityLevelConfiguration{
|
||||
NominalConcurrencyShares: ptr.To(int32(100)),
|
||||
LendablePercent: ptr.To(int32(90)),
|
||||
LimitResponse: flowcontrol.LimitResponse{
|
||||
Type: flowcontrol.LimitResponseTypeQueue,
|
||||
Queuing: &flowcontrol.QueuingConfiguration{
|
||||
Queues: 128,
|
||||
HandSize: 6,
|
||||
QueueLengthLimit: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
// global-default priority-level
|
||||
SuggestedPriorityLevelConfigurationGlobalDefault = newPriorityLevelConfiguration(
|
||||
"global-default",
|
||||
flowcontrol.PriorityLevelConfigurationSpec{
|
||||
Type: flowcontrol.PriorityLevelEnablementLimited,
|
||||
Limited: &flowcontrol.LimitedPriorityLevelConfiguration{
|
||||
NominalConcurrencyShares: ptr.To(int32(20)),
|
||||
LendablePercent: ptr.To(int32(50)),
|
||||
LimitResponse: flowcontrol.LimitResponse{
|
||||
Type: flowcontrol.LimitResponseTypeQueue,
|
||||
Queuing: &flowcontrol.QueuingConfiguration{
|
||||
Queues: 128,
|
||||
HandSize: 6,
|
||||
QueueLengthLimit: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
// Suggested FlowSchema objects.
|
||||
// Ordered by matching precedence, so that their interactions are easier
|
||||
// to follow while reading this source.
|
||||
var (
|
||||
// the following flow schema exempts probes
|
||||
SuggestedFlowSchemaProbes = newFlowSchema(
|
||||
"probes", "exempt", 2,
|
||||
"", // distinguisherMethodType
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: groups(user.AllUnauthenticated, user.AllAuthenticated),
|
||||
NonResourceRules: []flowcontrol.NonResourcePolicyRule{
|
||||
nonResourceRule(
|
||||
[]string{"get"},
|
||||
[]string{"/healthz", "/readyz", "/livez"}),
|
||||
},
|
||||
},
|
||||
)
|
||||
SuggestedFlowSchemaSystemLeaderElection = newFlowSchema(
|
||||
"system-leader-election", "leader-election", 100,
|
||||
flowcontrol.FlowDistinguisherMethodByUserType,
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: append(
|
||||
users(user.KubeControllerManager, user.KubeScheduler),
|
||||
kubeSystemServiceAccount(flowcontrol.NameAll)...),
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{
|
||||
resourceRule(
|
||||
[]string{"get", "create", "update"},
|
||||
[]string{coordinationv1.GroupName},
|
||||
[]string{"leases"},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
false),
|
||||
},
|
||||
},
|
||||
)
|
||||
// We add an explicit rule for endpoint-controller with high precedence
|
||||
// to ensure that those calls won't get caught by the following
|
||||
// <workload-leader-election> flow-schema.
|
||||
//
|
||||
// TODO(#80289): Get rid of this rule once we get rid of support for
|
||||
// using endpoints and configmaps objects for leader election.
|
||||
SuggestedFlowSchemaEndpointsController = newFlowSchema(
|
||||
"endpoint-controller", "workload-high", 150,
|
||||
flowcontrol.FlowDistinguisherMethodByUserType,
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: append(
|
||||
users(user.KubeControllerManager),
|
||||
kubeSystemServiceAccount("endpoint-controller", "endpointslicemirroring-controller")...),
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{
|
||||
resourceRule(
|
||||
[]string{"get", "create", "update"},
|
||||
[]string{corev1.GroupName},
|
||||
[]string{"endpoints"},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
false),
|
||||
},
|
||||
},
|
||||
)
|
||||
// TODO(#80289): Get rid of this rule once we get rid of support for
|
||||
// using endpoints and configmaps objects for leader election.
|
||||
SuggestedFlowSchemaWorkloadLeaderElection = newFlowSchema(
|
||||
"workload-leader-election", "leader-election", 200,
|
||||
flowcontrol.FlowDistinguisherMethodByUserType,
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: kubeSystemServiceAccount(flowcontrol.NameAll),
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{
|
||||
resourceRule(
|
||||
[]string{"get", "create", "update"},
|
||||
[]string{corev1.GroupName},
|
||||
[]string{"endpoints", "configmaps"},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
false),
|
||||
resourceRule(
|
||||
[]string{"get", "create", "update"},
|
||||
[]string{coordinationv1.GroupName},
|
||||
[]string{"leases"},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
false),
|
||||
},
|
||||
},
|
||||
)
|
||||
SuggestedFlowSchemaSystemNodeHigh = newFlowSchema(
|
||||
"system-node-high", "node-high", 400,
|
||||
flowcontrol.FlowDistinguisherMethodByUserType,
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: groups(user.NodesGroup), // the nodes group
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{
|
||||
resourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{corev1.GroupName},
|
||||
[]string{"nodes", "nodes/status"},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
true),
|
||||
resourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{coordinationv1.GroupName},
|
||||
[]string{"leases"},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
false),
|
||||
},
|
||||
},
|
||||
)
|
||||
SuggestedFlowSchemaSystemNodes = newFlowSchema(
|
||||
"system-nodes", "system", 500,
|
||||
flowcontrol.FlowDistinguisherMethodByUserType,
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: groups(user.NodesGroup), // the nodes group
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.APIGroupAll},
|
||||
[]string{flowcontrol.ResourceAll},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
true)},
|
||||
NonResourceRules: []flowcontrol.NonResourcePolicyRule{
|
||||
nonResourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.NonResourceAll}),
|
||||
},
|
||||
},
|
||||
)
|
||||
SuggestedFlowSchemaKubeControllerManager = newFlowSchema(
|
||||
"kube-controller-manager", "workload-high", 800,
|
||||
flowcontrol.FlowDistinguisherMethodByNamespaceType,
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: users(user.KubeControllerManager),
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.APIGroupAll},
|
||||
[]string{flowcontrol.ResourceAll},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
true)},
|
||||
NonResourceRules: []flowcontrol.NonResourcePolicyRule{
|
||||
nonResourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.NonResourceAll}),
|
||||
},
|
||||
},
|
||||
)
|
||||
SuggestedFlowSchemaKubeScheduler = newFlowSchema(
|
||||
"kube-scheduler", "workload-high", 800,
|
||||
flowcontrol.FlowDistinguisherMethodByNamespaceType,
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: users(user.KubeScheduler),
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.APIGroupAll},
|
||||
[]string{flowcontrol.ResourceAll},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
true)},
|
||||
NonResourceRules: []flowcontrol.NonResourcePolicyRule{
|
||||
nonResourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.NonResourceAll}),
|
||||
},
|
||||
},
|
||||
)
|
||||
SuggestedFlowSchemaKubeSystemServiceAccounts = newFlowSchema(
|
||||
"kube-system-service-accounts", "workload-high", 900,
|
||||
flowcontrol.FlowDistinguisherMethodByNamespaceType,
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: kubeSystemServiceAccount(flowcontrol.NameAll),
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.APIGroupAll},
|
||||
[]string{flowcontrol.ResourceAll},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
true)},
|
||||
NonResourceRules: []flowcontrol.NonResourcePolicyRule{
|
||||
nonResourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.NonResourceAll}),
|
||||
},
|
||||
},
|
||||
)
|
||||
SuggestedFlowSchemaServiceAccounts = newFlowSchema(
|
||||
"service-accounts", "workload-low", 9000,
|
||||
flowcontrol.FlowDistinguisherMethodByUserType,
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: groups(serviceaccount.AllServiceAccountsGroup),
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.APIGroupAll},
|
||||
[]string{flowcontrol.ResourceAll},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
true)},
|
||||
NonResourceRules: []flowcontrol.NonResourcePolicyRule{
|
||||
nonResourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.NonResourceAll}),
|
||||
},
|
||||
},
|
||||
)
|
||||
SuggestedFlowSchemaGlobalDefault = newFlowSchema(
|
||||
"global-default", "global-default", 9900,
|
||||
flowcontrol.FlowDistinguisherMethodByUserType,
|
||||
flowcontrol.PolicyRulesWithSubjects{
|
||||
Subjects: groups(user.AllUnauthenticated, user.AllAuthenticated),
|
||||
ResourceRules: []flowcontrol.ResourcePolicyRule{resourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.APIGroupAll},
|
||||
[]string{flowcontrol.ResourceAll},
|
||||
[]string{flowcontrol.NamespaceEvery},
|
||||
true)},
|
||||
NonResourceRules: []flowcontrol.NonResourcePolicyRule{
|
||||
nonResourceRule(
|
||||
[]string{flowcontrol.VerbAll},
|
||||
[]string{flowcontrol.NonResourceAll}),
|
||||
},
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
func newPriorityLevelConfiguration(name string, spec flowcontrol.PriorityLevelConfigurationSpec) *flowcontrol.PriorityLevelConfiguration {
|
||||
return &flowcontrol.PriorityLevelConfiguration{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Annotations: map[string]string{
|
||||
flowcontrol.AutoUpdateAnnotationKey: "true",
|
||||
},
|
||||
},
|
||||
Spec: spec,
|
||||
}
|
||||
}
|
||||
|
||||
func newFlowSchema(name, plName string, matchingPrecedence int32, dmType flowcontrol.FlowDistinguisherMethodType, rules ...flowcontrol.PolicyRulesWithSubjects) *flowcontrol.FlowSchema {
|
||||
var dm *flowcontrol.FlowDistinguisherMethod
|
||||
if dmType != "" {
|
||||
dm = &flowcontrol.FlowDistinguisherMethod{Type: dmType}
|
||||
}
|
||||
return &flowcontrol.FlowSchema{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Annotations: map[string]string{
|
||||
flowcontrol.AutoUpdateAnnotationKey: "true",
|
||||
},
|
||||
},
|
||||
Spec: flowcontrol.FlowSchemaSpec{
|
||||
PriorityLevelConfiguration: flowcontrol.PriorityLevelConfigurationReference{
|
||||
Name: plName,
|
||||
},
|
||||
MatchingPrecedence: matchingPrecedence,
|
||||
DistinguisherMethod: dm,
|
||||
Rules: rules},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func groups(names ...string) []flowcontrol.Subject {
|
||||
ans := make([]flowcontrol.Subject, len(names))
|
||||
for idx, name := range names {
|
||||
ans[idx] = flowcontrol.Subject{
|
||||
Kind: flowcontrol.SubjectKindGroup,
|
||||
Group: &flowcontrol.GroupSubject{
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
}
|
||||
return ans
|
||||
}
|
||||
|
||||
func users(names ...string) []flowcontrol.Subject {
|
||||
ans := make([]flowcontrol.Subject, len(names))
|
||||
for idx, name := range names {
|
||||
ans[idx] = flowcontrol.Subject{
|
||||
Kind: flowcontrol.SubjectKindUser,
|
||||
User: &flowcontrol.UserSubject{
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
}
|
||||
return ans
|
||||
}
|
||||
|
||||
func kubeSystemServiceAccount(names ...string) []flowcontrol.Subject {
|
||||
subjects := []flowcontrol.Subject{}
|
||||
for _, name := range names {
|
||||
subjects = append(subjects, flowcontrol.Subject{
|
||||
Kind: flowcontrol.SubjectKindServiceAccount,
|
||||
ServiceAccount: &flowcontrol.ServiceAccountSubject{
|
||||
Name: name,
|
||||
Namespace: metav1.NamespaceSystem,
|
||||
},
|
||||
})
|
||||
}
|
||||
return subjects
|
||||
}
|
||||
|
||||
func resourceRule(verbs []string, groups []string, resources []string, namespaces []string, clusterScoped bool) flowcontrol.ResourcePolicyRule {
|
||||
return flowcontrol.ResourcePolicyRule{
|
||||
Verbs: verbs,
|
||||
APIGroups: groups,
|
||||
Resources: resources,
|
||||
Namespaces: namespaces,
|
||||
ClusterScope: clusterScoped,
|
||||
}
|
||||
}
|
||||
|
||||
func nonResourceRule(verbs []string, nonResourceURLs []string) flowcontrol.NonResourcePolicyRule {
|
||||
return flowcontrol.NonResourcePolicyRule{Verbs: verbs, NonResourceURLs: nonResourceURLs}
|
||||
}
|
Reference in New Issue
Block a user