From de506ce7ac9981c8253b2f818478bb4093fb7bb6 Mon Sep 17 00:00:00 2001 From: cici37 Date: Tue, 23 Jan 2024 22:10:40 +0000 Subject: [PATCH] Promote ValidatingAdmissionPolicy to GA. --- cmd/kube-apiserver/app/server.go | 5 +- .../app/validatingadmissionpolicystatus.go | 4 +- pkg/api/testing/defaulting_test.go | 4 + pkg/apis/admissionregistration/v1/defaults.go | 24 + .../admissionregistration/v1/defaults_test.go | 88 +++ .../controller.go | 28 +- .../controller_test.go | 51 +- .../storageversionhashdata/data.go | 62 +- pkg/features/kube_features.go | 2 +- pkg/kubeapiserver/admission/config.go | 23 +- pkg/kubeapiserver/admission/initializer.go | 8 - .../admission/initializer_test.go | 50 +- .../rest/storage_apiserver.go | 28 + .../validatingadmissionpolicy/strategy.go | 7 + plugin/pkg/admission/gc/gc_admission_test.go | 6 +- .../admission/limitranger/admission_test.go | 2 +- .../namespace/autoprovision/admission_test.go | 2 +- .../namespace/exists/admission_test.go | 2 +- .../podnodeselector/admission_test.go | 2 +- .../admission_test.go | 2 +- .../admission/resourcequota/admission_test.go | 4 +- .../testdata/controller-role-bindings.yaml | 17 + .../testdata/controller-roles.yaml | 35 ++ .../api/admissionregistration/v1/register.go | 4 + .../api/admissionregistration/v1/types.go | 590 ++++++++++++++++++ .../test/integration/fixtures/server.go | 2 +- .../pkg/admission/initializer/initializer.go | 7 + .../admission/initializer/initializer_test.go | 66 +- .../namespace/lifecycle/admission_test.go | 2 +- .../plugin/policy/generic/accessor.go | 10 +- .../policy/generic/policy_dispatcher.go | 8 +- .../plugin/policy/generic/policy_matcher.go | 6 +- .../policy/generic/policy_source_test.go | 14 +- .../policy/generic/policy_test_context.go | 1 + .../plugin/policy/matching/matching.go | 7 +- .../plugin/policy/matching/matching_test.go | 229 ++++--- .../plugin/policy/validating/accessor.go | 18 +- .../policy/validating/admission_test.go | 104 +-- .../plugin/policy/validating/dispatcher.go | 34 +- .../plugin/policy/validating/plugin.go | 39 +- .../plugin/policy/validating/typechecking.go | 24 +- .../policy/validating/typechecking_test.go | 152 ++--- .../apiserver/pkg/features/kube_features.go | 5 +- .../apiserver/pkg/server/options/admission.go | 19 +- test/e2e/apimachinery/health_handlers.go | 6 +- .../apimachinery/validatingadmissionpolicy.go | 107 ++-- .../admissionwebhook/admission_test.go | 3 + .../apiserver/apply/reset_fields_test.go | 2 + .../apiserver/apply/status_test.go | 1 + .../apiserver/cel/admission_test_util.go | 3 + .../cel/validatingadmissionpolicy_test.go | 397 ++++++------ test/integration/etcd/data.go | 18 +- 52 files changed, 1568 insertions(+), 766 deletions(-) diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index f8eefb7c7dd..3370d38889b 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -299,7 +299,7 @@ func CreateKubeAPIServerConfig(opts options.CompletedOptions) ( CloudConfigFile: opts.CloudProvider.CloudConfigFile, } serviceResolver := buildServiceResolver(opts.EnableAggregatorRouting, genericConfig.LoopbackClientConfig.Host, versionedInformers) - pluginInitializers, admissionPostStartHook, err := admissionConfig.New(proxyTransport, genericConfig.EgressSelector, serviceResolver, genericConfig.TracerProvider) + pluginInitializers, err := admissionConfig.New(proxyTransport, genericConfig.EgressSelector, serviceResolver, genericConfig.TracerProvider) if err != nil { return nil, nil, nil, fmt.Errorf("failed to create admission plugin initializer: %v", err) } @@ -321,9 +321,6 @@ func CreateKubeAPIServerConfig(opts options.CompletedOptions) ( if err != nil { return nil, nil, nil, fmt.Errorf("failed to apply admission: %w", err) } - if err := config.GenericConfig.AddPostStartHook("start-kube-apiserver-admission-initializer", admissionPostStartHook); err != nil { - return nil, nil, nil, err - } if config.GenericConfig.EgressSelector != nil { // Use the config.GenericConfig.EgressSelector lookup to find the dialer to connect to the kubelet diff --git a/cmd/kube-controller-manager/app/validatingadmissionpolicystatus.go b/cmd/kube-controller-manager/app/validatingadmissionpolicystatus.go index a685a94cdb1..2c143ef623f 100644 --- a/cmd/kube-controller-manager/app/validatingadmissionpolicystatus.go +++ b/cmd/kube-controller-manager/app/validatingadmissionpolicystatus.go @@ -52,8 +52,8 @@ func startValidatingAdmissionPolicyStatusController(ctx context.Context, control RestMapper: controllerContext.RESTMapper, } c, err := validatingadmissionpolicystatus.NewController( - controllerContext.InformerFactory.Admissionregistration().V1beta1().ValidatingAdmissionPolicies(), - controllerContext.ClientBuilder.ClientOrDie(names.ValidatingAdmissionPolicyStatusController).AdmissionregistrationV1beta1().ValidatingAdmissionPolicies(), + controllerContext.InformerFactory.Admissionregistration().V1().ValidatingAdmissionPolicies(), + controllerContext.ClientBuilder.ClientOrDie(names.ValidatingAdmissionPolicyStatusController).AdmissionregistrationV1().ValidatingAdmissionPolicies(), typeChecker, ) diff --git a/pkg/api/testing/defaulting_test.go b/pkg/api/testing/defaulting_test.go index 6253eadaed1..07c63b4c008 100644 --- a/pkg/api/testing/defaulting_test.go +++ b/pkg/api/testing/defaulting_test.go @@ -151,6 +151,10 @@ func TestDefaulting(t *testing.T) { {Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyList"}: {}, {Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyBinding"}: {}, {Group: "admissionregistration.k8s.io", Version: "v1beta1", Kind: "ValidatingAdmissionPolicyBindingList"}: {}, + {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicy"}: {}, + {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicyList"}: {}, + {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicyBinding"}: {}, + {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingAdmissionPolicyBindingList"}: {}, {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfiguration"}: {}, {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "ValidatingWebhookConfigurationList"}: {}, {Group: "admissionregistration.k8s.io", Version: "v1", Kind: "MutatingWebhookConfiguration"}: {}, diff --git a/pkg/apis/admissionregistration/v1/defaults.go b/pkg/apis/admissionregistration/v1/defaults.go index 2bb62e8ad7e..484a481b194 100644 --- a/pkg/apis/admissionregistration/v1/defaults.go +++ b/pkg/apis/admissionregistration/v1/defaults.go @@ -93,3 +93,27 @@ func SetDefaults_ServiceReference(obj *admissionregistrationv1.ServiceReference) obj.Port = utilpointer.Int32(443) } } + +// SetDefaults_ValidatingAdmissionPolicySpec sets defaults for ValidatingAdmissionPolicySpec +func SetDefaults_ValidatingAdmissionPolicySpec(obj *admissionregistrationv1.ValidatingAdmissionPolicySpec) { + if obj.FailurePolicy == nil { + policy := admissionregistrationv1.Fail + obj.FailurePolicy = &policy + } +} + +// SetDefaults_MatchResources sets defaults for MatchResources +func SetDefaults_MatchResources(obj *admissionregistrationv1.MatchResources) { + if obj.MatchPolicy == nil { + policy := admissionregistrationv1.Equivalent + obj.MatchPolicy = &policy + } + if obj.NamespaceSelector == nil { + selector := metav1.LabelSelector{} + obj.NamespaceSelector = &selector + } + if obj.ObjectSelector == nil { + selector := metav1.LabelSelector{} + obj.ObjectSelector = &selector + } +} diff --git a/pkg/apis/admissionregistration/v1/defaults_test.go b/pkg/apis/admissionregistration/v1/defaults_test.go index 5f9f9f5b6e5..1aad1f0031b 100644 --- a/pkg/apis/admissionregistration/v1/defaults_test.go +++ b/pkg/apis/admissionregistration/v1/defaults_test.go @@ -132,3 +132,91 @@ func TestDefaultAdmissionWebhook(t *testing.T) { }) } } + +func TestDefaultAdmissionPolicy(t *testing.T) { + fail := v1.Fail + equivalent := v1.Equivalent + allScopes := v1.AllScopes + + tests := []struct { + name string + original runtime.Object + expected runtime.Object + }{ + { + name: "ValidatingAdmissionPolicy", + original: &v1.ValidatingAdmissionPolicy{ + Spec: v1.ValidatingAdmissionPolicySpec{ + MatchConstraints: &v1.MatchResources{}, + }, + }, + expected: &v1.ValidatingAdmissionPolicy{ + Spec: v1.ValidatingAdmissionPolicySpec{ + MatchConstraints: &v1.MatchResources{ + MatchPolicy: &equivalent, + NamespaceSelector: &metav1.LabelSelector{}, + ObjectSelector: &metav1.LabelSelector{}, + }, + FailurePolicy: &fail, + }, + }, + }, + { + name: "ValidatingAdmissionPolicyBinding", + original: &v1.ValidatingAdmissionPolicyBinding{ + Spec: v1.ValidatingAdmissionPolicyBindingSpec{ + MatchResources: &v1.MatchResources{}, + }, + }, + expected: &v1.ValidatingAdmissionPolicyBinding{ + Spec: v1.ValidatingAdmissionPolicyBindingSpec{ + MatchResources: &v1.MatchResources{ + MatchPolicy: &equivalent, + NamespaceSelector: &metav1.LabelSelector{}, + ObjectSelector: &metav1.LabelSelector{}, + }, + }, + }, + }, + { + name: "scope=*", + original: &v1.ValidatingAdmissionPolicy{ + Spec: v1.ValidatingAdmissionPolicySpec{ + MatchConstraints: &v1.MatchResources{ + ResourceRules: []v1.NamedRuleWithOperations{{}}, + }, + }, + }, + expected: &v1.ValidatingAdmissionPolicy{ + Spec: v1.ValidatingAdmissionPolicySpec{ + MatchConstraints: &v1.MatchResources{ + MatchPolicy: &equivalent, + NamespaceSelector: &metav1.LabelSelector{}, + ObjectSelector: &metav1.LabelSelector{}, + ResourceRules: []v1.NamedRuleWithOperations{ + { + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ + Scope: &allScopes, // defaulted + }, + }, + }, + }, + }, + FailurePolicy: &fail, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + original := test.original + expected := test.expected + legacyscheme.Scheme.Default(original) + if !apiequality.Semantic.DeepEqual(original, expected) { + t.Error(cmp.Diff(expected, original)) + } + }) + } +} diff --git a/pkg/controller/validatingadmissionpolicystatus/controller.go b/pkg/controller/validatingadmissionpolicystatus/controller.go index a1d7f40fc53..776d2cdf476 100644 --- a/pkg/controller/validatingadmissionpolicystatus/controller.go +++ b/pkg/controller/validatingadmissionpolicystatus/controller.go @@ -21,15 +21,15 @@ import ( "fmt" "time" - "k8s.io/api/admissionregistration/v1beta1" + "k8s.io/api/admissionregistration/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" validatingadmissionpolicy "k8s.io/apiserver/pkg/admission/plugin/policy/validating" - admissionregistrationv1beta1apply "k8s.io/client-go/applyconfigurations/admissionregistration/v1beta1" - informerv1beta1 "k8s.io/client-go/informers/admissionregistration/v1beta1" - admissionregistrationv1beta1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1" + admissionregistrationv1apply "k8s.io/client-go/applyconfigurations/admissionregistration/v1" + informerv1 "k8s.io/client-go/informers/admissionregistration/v1" + admissionregistrationv1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" ) @@ -40,10 +40,10 @@ const ControllerName = "validatingadmissionpolicy-status" // Controller is the ValidatingAdmissionPolicy Status controller that reconciles the Status field of each policy object. // This controller runs type checks against referred types for each policy definition. type Controller struct { - policyInformer informerv1beta1.ValidatingAdmissionPolicyInformer + policyInformer informerv1.ValidatingAdmissionPolicyInformer policyQueue workqueue.RateLimitingInterface policySynced cache.InformerSynced - policyClient admissionregistrationv1beta1.ValidatingAdmissionPolicyInterface + policyClient admissionregistrationv1.ValidatingAdmissionPolicyInterface // typeChecker checks the policy's expressions for type errors. // Type of params is defined in policy.Spec.ParamsKind @@ -66,7 +66,7 @@ func (c *Controller) Run(ctx context.Context, workers int) { <-ctx.Done() } -func NewController(policyInformer informerv1beta1.ValidatingAdmissionPolicyInformer, policyClient admissionregistrationv1beta1.ValidatingAdmissionPolicyInterface, typeChecker *validatingadmissionpolicy.TypeChecker) (*Controller, error) { +func NewController(policyInformer informerv1.ValidatingAdmissionPolicyInformer, policyClient admissionregistrationv1.ValidatingAdmissionPolicyInterface, typeChecker *validatingadmissionpolicy.TypeChecker) (*Controller, error) { c := &Controller{ policyInformer: policyInformer, policyQueue: workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{Name: ControllerName}), @@ -89,7 +89,7 @@ func NewController(policyInformer informerv1beta1.ValidatingAdmissionPolicyInfor } func (c *Controller) enqueuePolicy(policy any) { - if policy, ok := policy.(*v1beta1.ValidatingAdmissionPolicy); ok { + if policy, ok := policy.(*v1.ValidatingAdmissionPolicy); ok { // policy objects are cluster-scoped, no point include its namespace. key := policy.ObjectMeta.Name if key == "" { @@ -138,7 +138,7 @@ func (c *Controller) processNextWorkItem(ctx context.Context) bool { return true } -func (c *Controller) reconcile(ctx context.Context, policy *v1beta1.ValidatingAdmissionPolicy) error { +func (c *Controller) reconcile(ctx context.Context, policy *v1.ValidatingAdmissionPolicy) error { if policy == nil { return nil } @@ -146,16 +146,16 @@ func (c *Controller) reconcile(ctx context.Context, policy *v1beta1.ValidatingAd return nil } warnings := c.typeChecker.Check(policy) - warningsConfig := make([]*admissionregistrationv1beta1apply.ExpressionWarningApplyConfiguration, 0, len(warnings)) + warningsConfig := make([]*admissionregistrationv1apply.ExpressionWarningApplyConfiguration, 0, len(warnings)) for _, warning := range warnings { - warningsConfig = append(warningsConfig, admissionregistrationv1beta1apply.ExpressionWarning(). + warningsConfig = append(warningsConfig, admissionregistrationv1apply.ExpressionWarning(). WithFieldRef(warning.FieldRef). WithWarning(warning.Warning)) } - applyConfig := admissionregistrationv1beta1apply.ValidatingAdmissionPolicy(policy.Name). - WithStatus(admissionregistrationv1beta1apply.ValidatingAdmissionPolicyStatus(). + applyConfig := admissionregistrationv1apply.ValidatingAdmissionPolicy(policy.Name). + WithStatus(admissionregistrationv1apply.ValidatingAdmissionPolicyStatus(). WithObservedGeneration(policy.Generation). - WithTypeChecking(admissionregistrationv1beta1apply.TypeChecking(). + WithTypeChecking(admissionregistrationv1apply.TypeChecking(). WithExpressionWarnings(warningsConfig...))) _, err := c.policyClient.ApplyStatus(ctx, applyConfig, metav1.ApplyOptions{FieldManager: ControllerName, Force: true}) return err diff --git a/pkg/controller/validatingadmissionpolicystatus/controller_test.go b/pkg/controller/validatingadmissionpolicystatus/controller_test.go index 005fa204c3c..17056cbb47b 100644 --- a/pkg/controller/validatingadmissionpolicystatus/controller_test.go +++ b/pkg/controller/validatingadmissionpolicystatus/controller_test.go @@ -23,7 +23,6 @@ import ( "time" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" "k8s.io/apimachinery/pkg/api/meta/testrestmapper" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" @@ -38,13 +37,13 @@ import ( func TestTypeChecking(t *testing.T) { for _, tc := range []struct { name string - policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy - assertFieldRef func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) // warning.fieldRef - assertWarnings func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) // warning.warning + policy *admissionregistrationv1.ValidatingAdmissionPolicy + assertFieldRef func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) // warning.fieldRef + assertWarnings func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) // warning.warning }{ { name: "deployment with correct expression", - policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1beta1.Validation{ + policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1.Validation{ { Expression: "object.spec.replicas > 1", }, @@ -54,7 +53,7 @@ func TestTypeChecking(t *testing.T) { }, { name: "deployment with type confusion", - policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1beta1.Validation{ + policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1.Validation{ { Expression: "object.spec.replicas < 100", // this one passes }, @@ -67,7 +66,7 @@ func TestTypeChecking(t *testing.T) { }, { name: "two expressions different type checking errors", - policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1beta1.Validation{ + policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1.Validation{ { Expression: "object.spec.nonExistingFirst > 1", }, @@ -83,7 +82,7 @@ func TestTypeChecking(t *testing.T) { }, { name: "one expression, two warnings", - policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1beta1.Validation{ + policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1.Validation{ { Expression: "object.spec.replicas < 100", // this one passes }, @@ -107,8 +106,8 @@ func TestTypeChecking(t *testing.T) { RestMapper: testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme), } controller, err := NewController( - informerFactory.Admissionregistration().V1beta1().ValidatingAdmissionPolicies(), - client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies(), + informerFactory.Admissionregistration().V1().ValidatingAdmissionPolicies(), + client.AdmissionregistrationV1().ValidatingAdmissionPolicies(), typeChecker, ) if err != nil { @@ -120,7 +119,7 @@ func TestTypeChecking(t *testing.T) { name := policy.Name // wait until the typeChecking is set, which means the type checking // is complete. - updated, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(ctx, name, metav1.GetOptions{}) + updated, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(ctx, name, metav1.GetOptions{}) if err != nil { return false, err } @@ -143,8 +142,8 @@ func TestTypeChecking(t *testing.T) { } -func toBe(expected ...string) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { - return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { +func toBe(expected ...string) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { + return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { if len(expected) != len(warnings) { t.Fatalf("mismatched length, expect %d, got %d", len(expected), len(warnings)) } @@ -156,8 +155,8 @@ func toBe(expected ...string) func(warnings []admissionregistrationv1beta1.Expre } } -func toHaveSubstring(substrings ...string) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { - return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { +func toHaveSubstring(substrings ...string) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { + return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { if len(substrings) != len(warnings) { t.Fatalf("mismatched length, expect %d, got %d", len(substrings), len(warnings)) } @@ -169,8 +168,8 @@ func toHaveSubstring(substrings ...string) func(warnings []admissionregistration } } -func toHaveMultipleSubstrings(substrings ...[]string) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { - return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { +func toHaveMultipleSubstrings(substrings ...[]string) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { + return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { if len(substrings) != len(warnings) { t.Fatalf("mismatched length, expect %d, got %d", len(substrings), len(warnings)) } @@ -184,19 +183,19 @@ func toHaveMultipleSubstrings(substrings ...[]string) func(warnings []admissionr } } -func toHaveLengthOf(n int) func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { - return func(warnings []admissionregistrationv1beta1.ExpressionWarning, t *testing.T) { +func toHaveLengthOf(n int) func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { + return func(warnings []admissionregistrationv1.ExpressionWarning, t *testing.T) { if n != len(warnings) { t.Fatalf("mismatched length, expect %d, got %d", n, len(warnings)) } } } -func withGVRMatch(groups []string, versions []string, resources []string, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { - policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{ - ResourceRules: []admissionregistrationv1beta1.NamedRuleWithOperations{ +func withGVRMatch(groups []string, versions []string, resources []string, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { + policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{ + ResourceRules: []admissionregistrationv1.NamedRuleWithOperations{ { - RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ + RuleWithOperations: admissionregistrationv1.RuleWithOperations{ Operations: []admissionregistrationv1.OperationType{ "*", }, @@ -212,13 +211,13 @@ func withGVRMatch(groups []string, versions []string, resources []string, policy return policy } -func withValidations(validations []admissionregistrationv1beta1.Validation, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func withValidations(validations []admissionregistrationv1.Validation, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { policy.Spec.Validations = validations return policy } -func makePolicy(name string) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { - return &admissionregistrationv1beta1.ValidatingAdmissionPolicy{ +func makePolicy(name string) *admissionregistrationv1.ValidatingAdmissionPolicy { + return &admissionregistrationv1.ValidatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: name}, } } diff --git a/pkg/controlplane/storageversionhashdata/data.go b/pkg/controlplane/storageversionhashdata/data.go index 7391f9b56bc..98852c9dc37 100644 --- a/pkg/controlplane/storageversionhashdata/data.go +++ b/pkg/controlplane/storageversionhashdata/data.go @@ -56,34 +56,36 @@ var GVRToStorageVersionHash = map[string]string{ "autoscaling/v2/horizontalpodautoscalers": "qwQve8ut294=", "batch/v1/jobs": "mudhfqk/qZY=", "batch/v1/cronjobs": "sd5LIXh4Fjs=", - "certificates.k8s.io/v1/certificatesigningrequests": "95fRKMXA+00=", - "coordination.k8s.io/v1/leases": "gqkMMb/YqFM=", - "discovery.k8s.io/v1/endpointslices": "Nx3SIv6I0mE=", - "networking.k8s.io/v1/networkpolicies": "YpfwF18m1G8=", - "networking.k8s.io/v1/ingresses": "39NQlfNR+bo=", - "networking.k8s.io/v1/ingressclasses": "l/iqIbDgFyQ=", - "node.k8s.io/v1/runtimeclasses": "WQTu1GL3T2Q=", - "policy/v1/poddisruptionbudgets": "EVWiDmWqyJw=", - "rbac.authorization.k8s.io/v1/clusterrolebindings": "48tpQ8gZHFc=", - "rbac.authorization.k8s.io/v1/clusterroles": "bYE5ZWDrJ44=", - "rbac.authorization.k8s.io/v1/rolebindings": "eGsCzGH6b1g=", - "rbac.authorization.k8s.io/v1/roles": "7FuwZcIIItM=", - "scheduling.k8s.io/v1/priorityclasses": "1QwjyaZjj3Y=", - "storage.k8s.io/v1/csidrivers": "hL6j/rwBV5w=", - "storage.k8s.io/v1/csinodes": "Pe62DkZtjuo=", - "storage.k8s.io/v1/storageclasses": "K+m6uJwbjGY=", - "storage.k8s.io/v1/csistoragecapacities": "xeVl+2Ly1kE=", - "storage.k8s.io/v1/volumeattachments": "tJx/ezt6UDU=", - "apps/v1/controllerrevisions": "85nkx63pcBU=", - "apps/v1/daemonsets": "dd7pWHUlMKQ=", - "apps/v1/deployments": "8aSe+NMegvE=", - "apps/v1/replicasets": "P1RzHs8/mWQ=", - "apps/v1/statefulsets": "H+vl74LkKdo=", - "admissionregistration.k8s.io/v1/mutatingwebhookconfigurations": "Sqi0GUgDaX0=", - "admissionregistration.k8s.io/v1/validatingwebhookconfigurations": "B0wHjQmsGNk=", - "events.k8s.io/v1/events": "r2yiGXH7wu8=", - "flowcontrol.apiserver.k8s.io/v1beta3/flowschemas": "GJVAJZSZBIw=", - "flowcontrol.apiserver.k8s.io/v1beta3/prioritylevelconfigurations": "Kir5PVfvNeI=", - "flowcontrol.apiserver.k8s.io/v1/flowschemas": "GJVAJZSZBIw=", - "flowcontrol.apiserver.k8s.io/v1/prioritylevelconfigurations": "Kir5PVfvNeI=", + "certificates.k8s.io/v1/certificatesigningrequests": "95fRKMXA+00=", + "coordination.k8s.io/v1/leases": "gqkMMb/YqFM=", + "discovery.k8s.io/v1/endpointslices": "Nx3SIv6I0mE=", + "networking.k8s.io/v1/networkpolicies": "YpfwF18m1G8=", + "networking.k8s.io/v1/ingresses": "39NQlfNR+bo=", + "networking.k8s.io/v1/ingressclasses": "l/iqIbDgFyQ=", + "node.k8s.io/v1/runtimeclasses": "WQTu1GL3T2Q=", + "policy/v1/poddisruptionbudgets": "EVWiDmWqyJw=", + "rbac.authorization.k8s.io/v1/clusterrolebindings": "48tpQ8gZHFc=", + "rbac.authorization.k8s.io/v1/clusterroles": "bYE5ZWDrJ44=", + "rbac.authorization.k8s.io/v1/rolebindings": "eGsCzGH6b1g=", + "rbac.authorization.k8s.io/v1/roles": "7FuwZcIIItM=", + "scheduling.k8s.io/v1/priorityclasses": "1QwjyaZjj3Y=", + "storage.k8s.io/v1/csidrivers": "hL6j/rwBV5w=", + "storage.k8s.io/v1/csinodes": "Pe62DkZtjuo=", + "storage.k8s.io/v1/storageclasses": "K+m6uJwbjGY=", + "storage.k8s.io/v1/csistoragecapacities": "xeVl+2Ly1kE=", + "storage.k8s.io/v1/volumeattachments": "tJx/ezt6UDU=", + "apps/v1/controllerrevisions": "85nkx63pcBU=", + "apps/v1/daemonsets": "dd7pWHUlMKQ=", + "apps/v1/deployments": "8aSe+NMegvE=", + "apps/v1/replicasets": "P1RzHs8/mWQ=", + "apps/v1/statefulsets": "H+vl74LkKdo=", + "admissionregistration.k8s.io/v1/mutatingwebhookconfigurations": "Sqi0GUgDaX0=", + "admissionregistration.k8s.io/v1/validatingwebhookconfigurations": "B0wHjQmsGNk=", + "admissionregistration.k8s.io/v1/validatingadmissionpolicies": "P/h9c6yIbaY=", + "admissionregistration.k8s.io/v1/validatingadmissionpolicybindings": "XYju31JKYek=", + "events.k8s.io/v1/events": "r2yiGXH7wu8=", + "flowcontrol.apiserver.k8s.io/v1beta3/flowschemas": "GJVAJZSZBIw=", + "flowcontrol.apiserver.k8s.io/v1beta3/prioritylevelconfigurations": "Kir5PVfvNeI=", + "flowcontrol.apiserver.k8s.io/v1/flowschemas": "GJVAJZSZBIw=", + "flowcontrol.apiserver.k8s.io/v1/prioritylevelconfigurations": "Kir5PVfvNeI=", } diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index c22193519c3..67be23a8a9e 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -1258,7 +1258,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS genericfeatures.UnauthenticatedHTTP2DOSMitigation: {Default: true, PreRelease: featuregate.Beta}, - genericfeatures.ValidatingAdmissionPolicy: {Default: false, PreRelease: featuregate.Beta}, + genericfeatures.ValidatingAdmissionPolicy: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32 genericfeatures.WatchBookmark: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, diff --git a/pkg/kubeapiserver/admission/config.go b/pkg/kubeapiserver/admission/config.go index 24e565bcffa..249013611fa 100644 --- a/pkg/kubeapiserver/admission/config.go +++ b/pkg/kubeapiserver/admission/config.go @@ -19,23 +19,17 @@ package admission import ( "net/http" "os" - "time" "k8s.io/klog/v2" "go.opentelemetry.io/otel/trace" - utilwait "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/admission" webhookinit "k8s.io/apiserver/pkg/admission/plugin/webhook/initializer" - genericapiserver "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/pkg/server/egressselector" "k8s.io/apiserver/pkg/util/webhook" - cacheddiscovery "k8s.io/client-go/discovery/cached/memory" externalinformers "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" - "k8s.io/client-go/restmapper" "k8s.io/kubernetes/pkg/kubeapiserver/admission/exclusion" quotainstall "k8s.io/kubernetes/pkg/quota/v1/install" ) @@ -48,7 +42,7 @@ type Config struct { } // New sets up the plugins and admission start hooks needed for admission -func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselector.EgressSelector, serviceResolver webhook.ServiceResolver, tp trace.TracerProvider) ([]admission.PluginInitializer, genericapiserver.PostStartHookFunc, error) { +func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselector.EgressSelector, serviceResolver webhook.ServiceResolver, tp trace.TracerProvider) ([]admission.PluginInitializer, error) { webhookAuthResolverWrapper := webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, egressSelector, c.LoopbackClientConfig, tp) webhookPluginInitializer := webhookinit.NewPluginInitializer(webhookAuthResolverWrapper, serviceResolver) @@ -60,24 +54,11 @@ func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselec klog.Fatalf("Error reading from cloud configuration file %s: %#v", c.CloudConfigFile, err) } } - clientset, err := kubernetes.NewForConfig(c.LoopbackClientConfig) - if err != nil { - return nil, nil, err - } - discoveryClient := cacheddiscovery.NewMemCacheClient(clientset.Discovery()) - discoveryRESTMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) kubePluginInitializer := NewPluginInitializer( cloudConfig, - discoveryRESTMapper, quotainstall.NewQuotaConfigurationForAdmission(), exclusion.Excluded(), ) - admissionPostStartHook := func(context genericapiserver.PostStartHookContext) error { - discoveryRESTMapper.Reset() - go utilwait.Until(discoveryRESTMapper.Reset, 30*time.Second, context.StopCh) - return nil - } - - return []admission.PluginInitializer{webhookPluginInitializer, kubePluginInitializer}, admissionPostStartHook, nil + return []admission.PluginInitializer{webhookPluginInitializer, kubePluginInitializer}, nil } diff --git a/pkg/kubeapiserver/admission/initializer.go b/pkg/kubeapiserver/admission/initializer.go index d3ef1ad33a5..aa295aecc29 100644 --- a/pkg/kubeapiserver/admission/initializer.go +++ b/pkg/kubeapiserver/admission/initializer.go @@ -17,7 +17,6 @@ limitations under the License. package admission import ( - "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/initializer" @@ -34,7 +33,6 @@ type WantsCloudConfig interface { // PluginInitializer is used for initialization of the Kubernetes specific admission plugins. type PluginInitializer struct { cloudConfig []byte - restMapper meta.RESTMapper quotaConfiguration quota.Configuration excludedAdmissionResources []schema.GroupResource } @@ -46,13 +44,11 @@ var _ admission.PluginInitializer = &PluginInitializer{} // all public, this construction method is pointless boilerplate. func NewPluginInitializer( cloudConfig []byte, - restMapper meta.RESTMapper, quotaConfiguration quota.Configuration, excludedAdmissionResources []schema.GroupResource, ) *PluginInitializer { return &PluginInitializer{ cloudConfig: cloudConfig, - restMapper: restMapper, quotaConfiguration: quotaConfiguration, excludedAdmissionResources: excludedAdmissionResources, } @@ -65,10 +61,6 @@ func (i *PluginInitializer) Initialize(plugin admission.Interface) { wants.SetCloudConfig(i.cloudConfig) } - if wants, ok := plugin.(initializer.WantsRESTMapper); ok { - wants.SetRESTMapper(i.restMapper) - } - if wants, ok := plugin.(initializer.WantsQuotaConfiguration); ok { wants.SetQuotaConfiguration(i.quotaConfiguration) } diff --git a/pkg/kubeapiserver/admission/initializer_test.go b/pkg/kubeapiserver/admission/initializer_test.go index f4fa85e812c..53d4eb1db01 100644 --- a/pkg/kubeapiserver/admission/initializer_test.go +++ b/pkg/kubeapiserver/admission/initializer_test.go @@ -20,7 +20,6 @@ import ( "context" "testing" - "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" quota "k8s.io/apiserver/pkg/quota/v1" @@ -49,7 +48,7 @@ func (p *WantsCloudConfigAdmissionPlugin) SetCloudConfig(cloudConfig []byte) { func TestCloudConfigAdmissionPlugin(t *testing.T) { cloudConfig := []byte("cloud-configuration") - initializer := NewPluginInitializer(cloudConfig, nil, nil, nil) + initializer := NewPluginInitializer(cloudConfig, nil, nil) wantsCloudConfigAdmission := &WantsCloudConfigAdmissionPlugin{} initializer.Initialize(wantsCloudConfigAdmission) @@ -58,51 +57,6 @@ func TestCloudConfigAdmissionPlugin(t *testing.T) { } } -type doNothingRESTMapper struct{} - -func (doNothingRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { - return schema.GroupVersionKind{}, nil -} -func (doNothingRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) { - return nil, nil -} -func (doNothingRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) { - return schema.GroupVersionResource{}, nil -} -func (doNothingRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { - return nil, nil -} -func (doNothingRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) { - return nil, nil -} -func (doNothingRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) { - return nil, nil -} -func (doNothingRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { - return "", nil -} - -type WantsRESTMapperAdmissionPlugin struct { - doNothingAdmission - doNothingPluginInitialization - mapper meta.RESTMapper -} - -func (p *WantsRESTMapperAdmissionPlugin) SetRESTMapper(mapper meta.RESTMapper) { - p.mapper = mapper -} - -func TestRESTMapperAdmissionPlugin(t *testing.T) { - mapper := doNothingRESTMapper{} - initializer := NewPluginInitializer(nil, mapper, nil, nil) - wantsRESTMapperAdmission := &WantsRESTMapperAdmissionPlugin{} - initializer.Initialize(wantsRESTMapperAdmission) - - if wantsRESTMapperAdmission.mapper == nil { - t.Errorf("Expected REST mapper to be initialized but found nil") - } -} - type doNothingQuotaConfiguration struct{} func (doNothingQuotaConfiguration) IgnoredResources() map[schema.GroupResource]struct{} { return nil } @@ -121,7 +75,7 @@ func (p *WantsQuotaConfigurationAdmissionPlugin) SetQuotaConfiguration(config qu func TestQuotaConfigurationAdmissionPlugin(t *testing.T) { config := doNothingQuotaConfiguration{} - initializer := NewPluginInitializer(nil, nil, config, nil) + initializer := NewPluginInitializer(nil, config, nil) wantsQuotaConfigurationAdmission := &WantsQuotaConfigurationAdmissionPlugin{} initializer.Initialize(wantsQuotaConfigurationAdmission) diff --git a/pkg/registry/admissionregistration/rest/storage_apiserver.go b/pkg/registry/admissionregistration/rest/storage_apiserver.go index 5b60b25cae3..57922cda656 100644 --- a/pkg/registry/admissionregistration/rest/storage_apiserver.go +++ b/pkg/registry/admissionregistration/rest/storage_apiserver.go @@ -68,6 +68,14 @@ func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorag func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) { storage := map[string]rest.Storage{} + // use a simple wrapper so that initialization order won't cause a nil getter + var policyGetter rest.Getter + + r, err := resolver.NewDiscoveryResourceResolver(p.DiscoveryClient) + if err != nil { + return storage, err + } + // validatingwebhookconfigurations if resource := "validatingwebhookconfigurations"; apiResourceConfigSource.ResourceEnabled(admissionregistrationv1.SchemeGroupVersion.WithResource(resource)) { validatingStorage, err := validatingwebhookconfigurationstorage.NewREST(restOptionsGetter) @@ -86,6 +94,26 @@ func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.API storage[resource] = mutatingStorage } + // validatingadmissionpolicies + if resource := "validatingadmissionpolicies"; apiResourceConfigSource.ResourceEnabled(admissionregistrationv1.SchemeGroupVersion.WithResource(resource)) { + policyStorage, policyStatusStorage, err := validatingadmissionpolicystorage.NewREST(restOptionsGetter, p.Authorizer, r) + if err != nil { + return storage, err + } + policyGetter = policyStorage + storage[resource] = policyStorage + storage[resource+"/status"] = policyStatusStorage + } + + // validatingadmissionpolicybindings + if resource := "validatingadmissionpolicybindings"; apiResourceConfigSource.ResourceEnabled(admissionregistrationv1.SchemeGroupVersion.WithResource(resource)) { + policyBindingStorage, err := policybindingstorage.NewREST(restOptionsGetter, p.Authorizer, &policybindingstorage.DefaultPolicyGetter{Getter: policyGetter}, r) + if err != nil { + return storage, err + } + storage[resource] = policyBindingStorage + } + return storage, nil } diff --git a/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go b/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go index b1d926c1107..5579a97d7f0 100644 --- a/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go +++ b/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go @@ -138,6 +138,9 @@ func (v *validatingAdmissionPolicyStrategy) GetResetFields() map[fieldpath.APIVe "admissionregistration.k8s.io/v1beta1": fieldpath.NewSet( fieldpath.MakePathOrDie("status"), ), + "admissionregistration.k8s.io/v1": fieldpath.NewSet( + fieldpath.MakePathOrDie("status"), + ), } return fields @@ -177,6 +180,10 @@ func (s *validatingAdmissionPolicyStatusStrategy) GetResetFields() map[fieldpath fieldpath.MakePathOrDie("spec"), fieldpath.MakePathOrDie("metadata"), ), + "admissionregistration.k8s.io/v1": fieldpath.NewSet( + fieldpath.MakePathOrDie("spec"), + fieldpath.MakePathOrDie("metadata"), + ), } } diff --git a/plugin/pkg/admission/gc/gc_admission_test.go b/plugin/pkg/admission/gc/gc_admission_test.go index 889162e29f0..4dc1e3b02e5 100644 --- a/plugin/pkg/admission/gc/gc_admission_test.go +++ b/plugin/pkg/admission/gc/gc_admission_test.go @@ -115,7 +115,6 @@ func newGCPermissionsEnforcement() (*gcPermissionsEnforcement, error) { whiteList: whiteList, } - genericPluginInitializer := initializer.New(nil, nil, nil, fakeAuthorizer{}, nil, nil) fakeDiscoveryClient := &fakediscovery.FakeDiscovery{Fake: &coretesting.Fake{}} fakeDiscoveryClient.Resources = []*metav1.APIResourceList{ { @@ -133,13 +132,14 @@ func newGCPermissionsEnforcement() (*gcPermissionsEnforcement, error) { }, }, } - restMapperRes, err := restmapper.GetAPIGroupResources(fakeDiscoveryClient) if err != nil { return nil, fmt.Errorf("unexpected error while constructing resource list from fake discovery client: %v", err) } restMapper := restmapper.NewDiscoveryRESTMapper(restMapperRes) - pluginInitializer := kubeadmission.NewPluginInitializer(nil, restMapper, nil, nil) + genericPluginInitializer := initializer.New(nil, nil, nil, fakeAuthorizer{}, nil, nil, restMapper) + + pluginInitializer := kubeadmission.NewPluginInitializer(nil, nil, nil) initializersChain := admission.PluginInitializers{} initializersChain = append(initializersChain, genericPluginInitializer) initializersChain = append(initializersChain, pluginInitializer) diff --git a/plugin/pkg/admission/limitranger/admission_test.go b/plugin/pkg/admission/limitranger/admission_test.go index cec598e788b..d28b9d1cecc 100644 --- a/plugin/pkg/admission/limitranger/admission_test.go +++ b/plugin/pkg/admission/limitranger/admission_test.go @@ -817,7 +817,7 @@ func newHandlerForTest(c clientset.Interface) (*LimitRanger, informers.SharedInf if err != nil { return nil, f, err } - pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil) + pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil) pluginInitializer.Initialize(handler) err = admission.ValidateInitialization(handler) return handler, f, err diff --git a/plugin/pkg/admission/namespace/autoprovision/admission_test.go b/plugin/pkg/admission/namespace/autoprovision/admission_test.go index 57c8fa0ace6..935a1357677 100644 --- a/plugin/pkg/admission/namespace/autoprovision/admission_test.go +++ b/plugin/pkg/admission/namespace/autoprovision/admission_test.go @@ -41,7 +41,7 @@ import ( func newHandlerForTest(c clientset.Interface) (admission.MutationInterface, informers.SharedInformerFactory, error) { f := informers.NewSharedInformerFactory(c, 5*time.Minute) handler := NewProvision() - pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil) + pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil) pluginInitializer.Initialize(handler) err := admission.ValidateInitialization(handler) return handler, f, err diff --git a/plugin/pkg/admission/namespace/exists/admission_test.go b/plugin/pkg/admission/namespace/exists/admission_test.go index 999bb7b0a92..2937cb3948e 100644 --- a/plugin/pkg/admission/namespace/exists/admission_test.go +++ b/plugin/pkg/admission/namespace/exists/admission_test.go @@ -39,7 +39,7 @@ import ( func newHandlerForTest(c kubernetes.Interface) (admission.ValidationInterface, informers.SharedInformerFactory, error) { f := informers.NewSharedInformerFactory(c, 5*time.Minute) handler := NewExists() - pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil) + pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil) pluginInitializer.Initialize(handler) err := admission.ValidateInitialization(handler) return handler, f, err diff --git a/plugin/pkg/admission/podnodeselector/admission_test.go b/plugin/pkg/admission/podnodeselector/admission_test.go index f7de6357165..b1e191622ef 100644 --- a/plugin/pkg/admission/podnodeselector/admission_test.go +++ b/plugin/pkg/admission/podnodeselector/admission_test.go @@ -198,7 +198,7 @@ func TestHandles(t *testing.T) { func newHandlerForTest(c kubernetes.Interface) (*Plugin, informers.SharedInformerFactory, error) { f := informers.NewSharedInformerFactory(c, 5*time.Minute) handler := NewPodNodeSelector(nil) - pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil) + pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil) pluginInitializer.Initialize(handler) err := admission.ValidateInitialization(handler) return handler, f, err diff --git a/plugin/pkg/admission/podtolerationrestriction/admission_test.go b/plugin/pkg/admission/podtolerationrestriction/admission_test.go index 6c127321c25..9a23c035462 100644 --- a/plugin/pkg/admission/podtolerationrestriction/admission_test.go +++ b/plugin/pkg/admission/podtolerationrestriction/admission_test.go @@ -355,7 +355,7 @@ func newHandlerForTest(c kubernetes.Interface) (*Plugin, informers.SharedInforme return nil, nil, err } handler := NewPodTolerationsPlugin(pluginConfig) - pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil) + pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil) pluginInitializer.Initialize(handler) err = admission.ValidateInitialization(handler) return handler, f, err diff --git a/plugin/pkg/admission/resourcequota/admission_test.go b/plugin/pkg/admission/resourcequota/admission_test.go index 23cdc4df239..03763d3d7c5 100644 --- a/plugin/pkg/admission/resourcequota/admission_test.go +++ b/plugin/pkg/admission/resourcequota/admission_test.go @@ -114,8 +114,8 @@ func createHandlerWithConfig(kubeClient kubernetes.Interface, informerFactory in } initializers := admission.PluginInitializers{ - genericadmissioninitializer.New(kubeClient, nil, informerFactory, nil, nil, stopCh), - kubeapiserveradmission.NewPluginInitializer(nil, nil, quotaConfiguration, nil), + genericadmissioninitializer.New(kubeClient, nil, informerFactory, nil, nil, stopCh, nil), + kubeapiserveradmission.NewPluginInitializer(nil, quotaConfiguration, nil), } initializers.Initialize(handler) diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-role-bindings.yaml b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-role-bindings.yaml index 595e95df8ec..5b7cf3d4644 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-role-bindings.yaml +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-role-bindings.yaml @@ -544,5 +544,22 @@ items: - kind: ServiceAccount name: ttl-controller namespace: kube-system +- apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + creationTimestamp: null + labels: + kubernetes.io/bootstrapping: rbac-defaults + name: system:controller:validatingadmissionpolicy-status-controller + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:controller:validatingadmissionpolicy-status-controller + subjects: + - kind: ServiceAccount + name: validatingadmissionpolicy-status-controller + namespace: kube-system kind: List metadata: {} diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-roles.yaml b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-roles.yaml index ea2295ccfe2..f17fc954f88 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-roles.yaml +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-roles.yaml @@ -1543,5 +1543,40 @@ items: - create - patch - update +- apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + creationTimestamp: null + labels: + kubernetes.io/bootstrapping: rbac-defaults + name: system:controller:validatingadmissionpolicy-status-controller + rules: + - apiGroups: + - admissionregistration.k8s.io + resources: + - validatingadmissionpolicies + verbs: + - get + - list + - watch + - apiGroups: + - admissionregistration.k8s.io + resources: + - validatingadmissionpolicies/status + verbs: + - get + - patch + - update + - apiGroups: + - "" + - events.k8s.io + resources: + - events + verbs: + - create + - patch + - update kind: List metadata: {} diff --git a/staging/src/k8s.io/api/admissionregistration/v1/register.go b/staging/src/k8s.io/api/admissionregistration/v1/register.go index e42a8bce3be..da74379ce2e 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1/register.go +++ b/staging/src/k8s.io/api/admissionregistration/v1/register.go @@ -50,6 +50,10 @@ func addKnownTypes(scheme *runtime.Scheme) error { &ValidatingWebhookConfigurationList{}, &MutatingWebhookConfiguration{}, &MutatingWebhookConfigurationList{}, + &ValidatingAdmissionPolicy{}, + &ValidatingAdmissionPolicyList{}, + &ValidatingAdmissionPolicyBinding{}, + &ValidatingAdmissionPolicyBindingList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/staging/src/k8s.io/api/admissionregistration/v1/types.go b/staging/src/k8s.io/api/admissionregistration/v1/types.go index 87f63009f93..0510712b246 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1/types.go +++ b/staging/src/k8s.io/api/admissionregistration/v1/types.go @@ -91,6 +91,18 @@ const ( Fail FailurePolicyType = "Fail" ) +// ParameterNotFoundActionType specifies a failure policy that defines how a binding +// is evaluated when the param referred by its perNamespaceParamRef is not found. +type ParameterNotFoundActionType string + +const ( + // Allow means all requests will be admitted if no param resources + // could be found. + AllowAction ParameterNotFoundActionType = "Allow" + // Deny means all requests will be denied if no param resources are found. + DenyAction ParameterNotFoundActionType = "Deny" +) + // MatchPolicyType specifies the type of match policy. // +enum type MatchPolicyType string @@ -120,6 +132,584 @@ const ( SideEffectClassNoneOnDryRun SideEffectClass = "NoneOnDryRun" ) +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.30 +// ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it. +type ValidatingAdmissionPolicy struct { + metav1.TypeMeta `json:",inline"` + // Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. + // +optional + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + // Specification of the desired behavior of the ValidatingAdmissionPolicy. + Spec ValidatingAdmissionPolicySpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` + // The status of the ValidatingAdmissionPolicy, including warnings that are useful to determine if the policy + // behaves in the expected way. + // Populated by the system. + // Read-only. + // +optional + Status ValidatingAdmissionPolicyStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` +} + +// ValidatingAdmissionPolicyStatus represents the status of an admission validation policy. +type ValidatingAdmissionPolicyStatus struct { + // The generation observed by the controller. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty" protobuf:"varint,1,opt,name=observedGeneration"` + // The results of type checking for each expression. + // Presence of this field indicates the completion of the type checking. + // +optional + TypeChecking *TypeChecking `json:"typeChecking,omitempty" protobuf:"bytes,2,opt,name=typeChecking"` + // The conditions represent the latest available observations of a policy's current state. + // +optional + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty" protobuf:"bytes,3,rep,name=conditions"` +} + +// ValidatingAdmissionPolicyConditionType is the condition type of admission validation policy. +type ValidatingAdmissionPolicyConditionType string + +// TypeChecking contains results of type checking the expressions in the +// ValidatingAdmissionPolicy +type TypeChecking struct { + // The type checking warnings for each expression. + // +optional + // +listType=atomic + ExpressionWarnings []ExpressionWarning `json:"expressionWarnings,omitempty" protobuf:"bytes,1,rep,name=expressionWarnings"` +} + +// ExpressionWarning is a warning information that targets a specific expression. +type ExpressionWarning struct { + // The path to the field that refers the expression. + // For example, the reference to the expression of the first item of + // validations is "spec.validations[0].expression" + FieldRef string `json:"fieldRef" protobuf:"bytes,2,opt,name=fieldRef"` + // The content of type checking information in a human-readable form. + // Each line of the warning contains the type that the expression is checked + // against, followed by the type check error from the compiler. + Warning string `json:"warning" protobuf:"bytes,3,opt,name=warning"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.30 +// ValidatingAdmissionPolicyList is a list of ValidatingAdmissionPolicy. +type ValidatingAdmissionPolicyList struct { + metav1.TypeMeta `json:",inline"` + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + // +optional + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + // List of ValidatingAdmissionPolicy. + Items []ValidatingAdmissionPolicy `json:"items,omitempty" protobuf:"bytes,2,rep,name=items"` +} + +// ValidatingAdmissionPolicySpec is the specification of the desired behavior of the AdmissionPolicy. +type ValidatingAdmissionPolicySpec struct { + // ParamKind specifies the kind of resources used to parameterize this policy. + // If absent, there are no parameters for this policy and the param CEL variable will not be provided to validation expressions. + // If ParamKind refers to a non-existent kind, this policy definition is mis-configured and the FailurePolicy is applied. + // If paramKind is specified but paramRef is unset in ValidatingAdmissionPolicyBinding, the params variable will be null. + // +optional + ParamKind *ParamKind `json:"paramKind,omitempty" protobuf:"bytes,1,rep,name=paramKind"` + + // MatchConstraints specifies what resources this policy is designed to validate. + // The AdmissionPolicy cares about a request if it matches _all_ Constraints. + // However, in order to prevent clusters from being put into an unstable state that cannot be recovered from via the API + // ValidatingAdmissionPolicy cannot match ValidatingAdmissionPolicy and ValidatingAdmissionPolicyBinding. + // Required. + MatchConstraints *MatchResources `json:"matchConstraints,omitempty" protobuf:"bytes,2,rep,name=matchConstraints"` + + // Validations contain CEL expressions which is used to apply the validation. + // Validations and AuditAnnotations may not both be empty; a minimum of one Validations or AuditAnnotations is + // required. + // +listType=atomic + // +optional + Validations []Validation `json:"validations,omitempty" protobuf:"bytes,3,rep,name=validations"` + + // failurePolicy defines how to handle failures for the admission policy. Failures can + // occur from CEL expression parse errors, type check errors, runtime errors and invalid + // or mis-configured policy definitions or bindings. + // + // A policy is invalid if spec.paramKind refers to a non-existent Kind. + // A binding is invalid if spec.paramRef.name refers to a non-existent resource. + // + // failurePolicy does not define how validations that evaluate to false are handled. + // + // When failurePolicy is set to Fail, ValidatingAdmissionPolicyBinding validationActions + // define how failures are enforced. + // + // Allowed values are Ignore or Fail. Defaults to Fail. + // +optional + FailurePolicy *FailurePolicyType `json:"failurePolicy,omitempty" protobuf:"bytes,4,opt,name=failurePolicy,casttype=FailurePolicyType"` + + // auditAnnotations contains CEL expressions which are used to produce audit + // annotations for the audit event of the API request. + // validations and auditAnnotations may not both be empty; a least one of validations or auditAnnotations is + // required. + // +listType=atomic + // +optional + AuditAnnotations []AuditAnnotation `json:"auditAnnotations,omitempty" protobuf:"bytes,5,rep,name=auditAnnotations"` + + // MatchConditions is a list of conditions that must be met for a request to be validated. + // Match conditions filter requests that have already been matched by the rules, + // namespaceSelector, and objectSelector. An empty list of matchConditions matches all requests. + // There are a maximum of 64 match conditions allowed. + // + // If a parameter object is provided, it can be accessed via the `params` handle in the same + // manner as validation expressions. + // + // The exact matching logic is (in order): + // 1. If ANY matchCondition evaluates to FALSE, the policy is skipped. + // 2. If ALL matchConditions evaluate to TRUE, the policy is evaluated. + // 3. If any matchCondition evaluates to an error (but none are FALSE): + // - If failurePolicy=Fail, reject the request + // - If failurePolicy=Ignore, the policy is skipped + // + // +patchMergeKey=name + // +patchStrategy=merge + // +listType=map + // +listMapKey=name + // +optional + MatchConditions []MatchCondition `json:"matchConditions,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,6,rep,name=matchConditions"` + + // Variables contain definitions of variables that can be used in composition of other expressions. + // Each variable is defined as a named CEL expression. + // The variables defined here will be available under `variables` in other expressions of the policy + // except MatchConditions because MatchConditions are evaluated before the rest of the policy. + // + // The expression of a variable can refer to other variables defined earlier in the list but not those after. + // Thus, Variables must be sorted by the order of first appearance and acyclic. + // +patchMergeKey=name + // +patchStrategy=merge + // +listType=map + // +listMapKey=name + // +optional + Variables []Variable `json:"variables,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,7,rep,name=variables"` +} + +// ParamKind is a tuple of Group Kind and Version. +// +structType=atomic +type ParamKind struct { + // APIVersion is the API group version the resources belong to. + // In format of "group/version". + // Required. + APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,1,rep,name=apiVersion"` + + // Kind is the API kind the resources belong to. + // Required. + Kind string `json:"kind,omitempty" protobuf:"bytes,2,rep,name=kind"` +} + +// Validation specifies the CEL expression which is used to apply the validation. +type Validation struct { + // Expression represents the expression which will be evaluated by CEL. + // ref: https://github.com/google/cel-spec + // CEL expressions have access to the contents of the API request/response, organized into CEL variables as well as some other useful variables: + // + // - 'object' - The object from the incoming request. The value is null for DELETE requests. + // - 'oldObject' - The existing object. The value is null for CREATE requests. + // - 'request' - Attributes of the API request([ref](/pkg/apis/admission/types.go#AdmissionRequest)). + // - 'params' - Parameter resource referred to by the policy binding being evaluated. Only populated if the policy has a ParamKind. + // - 'namespaceObject' - The namespace object that the incoming object belongs to. The value is null for cluster-scoped resources. + // - 'variables' - Map of composited variables, from its name to its lazily evaluated value. + // For example, a variable named 'foo' can be accessed as 'variables.foo'. + // - 'authorizer' - A CEL Authorizer. May be used to perform authorization checks for the principal (user or service account) of the request. + // See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz + // - 'authorizer.requestResource' - A CEL ResourceCheck constructed from the 'authorizer' and configured with the + // request resource. + // + // The `apiVersion`, `kind`, `metadata.name` and `metadata.generateName` are always accessible from the root of the + // object. No other metadata properties are accessible. + // + // Only property names of the form `[a-zA-Z_.-/][a-zA-Z0-9_.-/]*` are accessible. + // Accessible property names are escaped according to the following rules when accessed in the expression: + // - '__' escapes to '__underscores__' + // - '.' escapes to '__dot__' + // - '-' escapes to '__dash__' + // - '/' escapes to '__slash__' + // - Property names that exactly match a CEL RESERVED keyword escape to '__{keyword}__'. The keywords are: + // "true", "false", "null", "in", "as", "break", "const", "continue", "else", "for", "function", "if", + // "import", "let", "loop", "package", "namespace", "return". + // Examples: + // - Expression accessing a property named "namespace": {"Expression": "object.__namespace__ > 0"} + // - Expression accessing a property named "x-prop": {"Expression": "object.x__dash__prop > 0"} + // - Expression accessing a property named "redact__d": {"Expression": "object.redact__underscores__d > 0"} + // + // Equality on arrays with list type of 'set' or 'map' ignores element order, i.e. [1, 2] == [2, 1]. + // Concatenation on arrays with x-kubernetes-list-type use the semantics of the list type: + // - 'set': `X + Y` performs a union where the array positions of all elements in `X` are preserved and + // non-intersecting elements in `Y` are appended, retaining their partial order. + // - 'map': `X + Y` performs a merge where the array positions of all keys in `X` are preserved but the values + // are overwritten by values in `Y` when the key sets of `X` and `Y` intersect. Elements in `Y` with + // non-intersecting keys are appended, retaining their partial order. + // Required. + Expression string `json:"expression" protobuf:"bytes,1,opt,name=Expression"` + // Message represents the message displayed when validation fails. The message is required if the Expression contains + // line breaks. The message must not contain line breaks. + // If unset, the message is "failed rule: {Rule}". + // e.g. "must be a URL with the host matching spec.host" + // If the Expression contains line breaks. Message is required. + // The message must not contain line breaks. + // If unset, the message is "failed Expression: {Expression}". + // +optional + Message string `json:"message,omitempty" protobuf:"bytes,2,opt,name=message"` + // Reason represents a machine-readable description of why this validation failed. + // If this is the first validation in the list to fail, this reason, as well as the + // corresponding HTTP response code, are used in the + // HTTP response to the client. + // The currently supported reasons are: "Unauthorized", "Forbidden", "Invalid", "RequestEntityTooLarge". + // If not set, StatusReasonInvalid is used in the response to the client. + // +optional + Reason *metav1.StatusReason `json:"reason,omitempty" protobuf:"bytes,3,opt,name=reason"` + // messageExpression declares a CEL expression that evaluates to the validation failure message that is returned when this rule fails. + // Since messageExpression is used as a failure message, it must evaluate to a string. + // If both message and messageExpression are present on a validation, then messageExpression will be used if validation fails. + // If messageExpression results in a runtime error, the runtime error is logged, and the validation failure message is produced + // as if the messageExpression field were unset. If messageExpression evaluates to an empty string, a string with only spaces, or a string + // that contains line breaks, then the validation failure message will also be produced as if the messageExpression field were unset, and + // the fact that messageExpression produced an empty string/string with only spaces/string with line breaks will be logged. + // messageExpression has access to all the same variables as the `expression` except for 'authorizer' and 'authorizer.requestResource'. + // Example: + // "object.x must be less than max ("+string(params.max)+")" + // +optional + MessageExpression string `json:"messageExpression,omitempty" protobuf:"bytes,4,opt,name=messageExpression"` +} + +// Variable is the definition of a variable that is used for composition. A variable is defined as a named expression. +// +structType=atomic +type Variable struct { + // Name is the name of the variable. The name must be a valid CEL identifier and unique among all variables. + // The variable can be accessed in other expressions through `variables` + // For example, if name is "foo", the variable will be available as `variables.foo` + Name string `json:"name" protobuf:"bytes,1,opt,name=Name"` + + // Expression is the expression that will be evaluated as the value of the variable. + // The CEL expression has access to the same identifiers as the CEL expressions in Validation. + Expression string `json:"expression" protobuf:"bytes,2,opt,name=Expression"` +} + +// AuditAnnotation describes how to produce an audit annotation for an API request. +type AuditAnnotation struct { + // key specifies the audit annotation key. The audit annotation keys of + // a ValidatingAdmissionPolicy must be unique. The key must be a qualified + // name ([A-Za-z0-9][-A-Za-z0-9_.]*) no more than 63 bytes in length. + // + // The key is combined with the resource name of the + // ValidatingAdmissionPolicy to construct an audit annotation key: + // "{ValidatingAdmissionPolicy name}/{key}". + // + // If an admission webhook uses the same resource name as this ValidatingAdmissionPolicy + // and the same audit annotation key, the annotation key will be identical. + // In this case, the first annotation written with the key will be included + // in the audit event and all subsequent annotations with the same key + // will be discarded. + // + // Required. + Key string `json:"key" protobuf:"bytes,1,opt,name=key"` + + // valueExpression represents the expression which is evaluated by CEL to + // produce an audit annotation value. The expression must evaluate to either + // a string or null value. If the expression evaluates to a string, the + // audit annotation is included with the string value. If the expression + // evaluates to null or empty string the audit annotation will be omitted. + // The valueExpression may be no longer than 5kb in length. + // If the result of the valueExpression is more than 10kb in length, it + // will be truncated to 10kb. + // + // If multiple ValidatingAdmissionPolicyBinding resources match an + // API request, then the valueExpression will be evaluated for + // each binding. All unique values produced by the valueExpressions + // will be joined together in a comma-separated list. + // + // Required. + ValueExpression string `json:"valueExpression" protobuf:"bytes,2,opt,name=valueExpression"` +} + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.30 + +// ValidatingAdmissionPolicyBinding binds the ValidatingAdmissionPolicy with paramerized resources. +// ValidatingAdmissionPolicyBinding and parameter CRDs together define how cluster administrators configure policies for clusters. +// +// For a given admission request, each binding will cause its policy to be +// evaluated N times, where N is 1 for policies/bindings that don't use +// params, otherwise N is the number of parameters selected by the binding. +// +// The CEL expressions of a policy must have a computed CEL cost below the maximum +// CEL budget. Each evaluation of the policy is given an independent CEL cost budget. +// Adding/removing policies, bindings, or params can not affect whether a +// given (policy, binding, param) combination is within its own CEL budget. +type ValidatingAdmissionPolicyBinding struct { + metav1.TypeMeta `json:",inline"` + // Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata. + // +optional + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + // Specification of the desired behavior of the ValidatingAdmissionPolicyBinding. + Spec ValidatingAdmissionPolicyBindingSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.30 + +// ValidatingAdmissionPolicyBindingList is a list of ValidatingAdmissionPolicyBinding. +type ValidatingAdmissionPolicyBindingList struct { + metav1.TypeMeta `json:",inline"` + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + // +optional + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + // List of PolicyBinding. + Items []ValidatingAdmissionPolicyBinding `json:"items,omitempty" protobuf:"bytes,2,rep,name=items"` +} + +// ValidatingAdmissionPolicyBindingSpec is the specification of the ValidatingAdmissionPolicyBinding. +type ValidatingAdmissionPolicyBindingSpec struct { + // PolicyName references a ValidatingAdmissionPolicy name which the ValidatingAdmissionPolicyBinding binds to. + // If the referenced resource does not exist, this binding is considered invalid and will be ignored + // Required. + PolicyName string `json:"policyName,omitempty" protobuf:"bytes,1,rep,name=policyName"` + + // paramRef specifies the parameter resource used to configure the admission control policy. + // It should point to a resource of the type specified in ParamKind of the bound ValidatingAdmissionPolicy. + // If the policy specifies a ParamKind and the resource referred to by ParamRef does not exist, this binding is considered mis-configured and the FailurePolicy of the ValidatingAdmissionPolicy applied. + // If the policy does not specify a ParamKind then this field is ignored, and the rules are evaluated without a param. + // +optional + ParamRef *ParamRef `json:"paramRef,omitempty" protobuf:"bytes,2,rep,name=paramRef"` + + // MatchResources declares what resources match this binding and will be validated by it. + // Note that this is intersected with the policy's matchConstraints, so only requests that are matched by the policy can be selected by this. + // If this is unset, all resources matched by the policy are validated by this binding + // When resourceRules is unset, it does not constrain resource matching. If a resource is matched by the other fields of this object, it will be validated. + // Note that this is differs from ValidatingAdmissionPolicy matchConstraints, where resourceRules are required. + // +optional + MatchResources *MatchResources `json:"matchResources,omitempty" protobuf:"bytes,3,rep,name=matchResources"` + + // validationActions declares how Validations of the referenced ValidatingAdmissionPolicy are enforced. + // If a validation evaluates to false it is always enforced according to these actions. + // + // Failures defined by the ValidatingAdmissionPolicy's FailurePolicy are enforced according + // to these actions only if the FailurePolicy is set to Fail, otherwise the failures are + // ignored. This includes compilation errors, runtime errors and misconfigurations of the policy. + // + // validationActions is declared as a set of action values. Order does + // not matter. validationActions may not contain duplicates of the same action. + // + // The supported actions values are: + // + // "Deny" specifies that a validation failure results in a denied request. + // + // "Warn" specifies that a validation failure is reported to the request client + // in HTTP Warning headers, with a warning code of 299. Warnings can be sent + // both for allowed or denied admission responses. + // + // "Audit" specifies that a validation failure is included in the published + // audit event for the request. The audit event will contain a + // `validation.policy.admission.k8s.io/validation_failure` audit annotation + // with a value containing the details of the validation failures, formatted as + // a JSON list of objects, each with the following fields: + // - message: The validation failure message string + // - policy: The resource name of the ValidatingAdmissionPolicy + // - binding: The resource name of the ValidatingAdmissionPolicyBinding + // - expressionIndex: The index of the failed validations in the ValidatingAdmissionPolicy + // - validationActions: The enforcement actions enacted for the validation failure + // Example audit annotation: + // `"validation.policy.admission.k8s.io/validation_failure": "[{\"message\": \"Invalid value\", {\"policy\": \"policy.example.com\", {\"binding\": \"policybinding.example.com\", {\"expressionIndex\": \"1\", {\"validationActions\": [\"Audit\"]}]"` + // + // Clients should expect to handle additional values by ignoring + // any values not recognized. + // + // "Deny" and "Warn" may not be used together since this combination + // needlessly duplicates the validation failure both in the + // API response body and the HTTP warning headers. + // + // Required. + // +listType=set + ValidationActions []ValidationAction `json:"validationActions,omitempty" protobuf:"bytes,4,rep,name=validationActions"` +} + +// ParamRef describes how to locate the params to be used as input to +// expressions of rules applied by a policy binding. +// +structType=atomic +type ParamRef struct { + // name is the name of the resource being referenced. + // + // One of `name` or `selector` must be set, but `name` and `selector` are + // mutually exclusive properties. If one is set, the other must be unset. + // + // A single parameter used for all admission requests can be configured + // by setting the `name` field, leaving `selector` blank, and setting namespace + // if `paramKind` is namespace-scoped. + // + Name string `json:"name,omitempty" protobuf:"bytes,1,rep,name=name"` + + // namespace is the namespace of the referenced resource. Allows limiting + // the search for params to a specific namespace. Applies to both `name` and + // `selector` fields. + // + // A per-namespace parameter may be used by specifying a namespace-scoped + // `paramKind` in the policy and leaving this field empty. + // + // - If `paramKind` is cluster-scoped, this field MUST be unset. Setting this + // field results in a configuration error. + // + // - If `paramKind` is namespace-scoped, the namespace of the object being + // evaluated for admission will be used when this field is left unset. Take + // care that if this is left empty the binding must not match any cluster-scoped + // resources, which will result in an error. + // + // +optional + Namespace string `json:"namespace,omitempty" protobuf:"bytes,2,rep,name=namespace"` + + // selector can be used to match multiple param objects based on their labels. + // Supply selector: {} to match all resources of the ParamKind. + // + // If multiple params are found, they are all evaluated with the policy expressions + // and the results are ANDed together. + // + // One of `name` or `selector` must be set, but `name` and `selector` are + // mutually exclusive properties. If one is set, the other must be unset. + // + // +optional + Selector *metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,3,rep,name=selector"` + + // `parameterNotFoundAction` controls the behavior of the binding when the resource + // exists, and name or selector is valid, but there are no parameters + // matched by the binding. If the value is set to `Allow`, then no + // matched parameters will be treated as successful validation by the binding. + // If set to `Deny`, then no matched parameters will be subject to the + // `failurePolicy` of the policy. + // + // Allowed values are `Allow` or `Deny` + // + // Required + ParameterNotFoundAction *ParameterNotFoundActionType `json:"parameterNotFoundAction,omitempty" protobuf:"bytes,4,rep,name=parameterNotFoundAction"` +} + +// MatchResources decides whether to run the admission control policy on an object based +// on whether it meets the match criteria. +// The exclude rules take precedence over include rules (if a resource matches both, it is excluded) +// +structType=atomic +type MatchResources struct { + // NamespaceSelector decides whether to run the admission control policy on an object based + // on whether the namespace for that object matches the selector. If the + // object itself is a namespace, the matching is performed on + // object.metadata.labels. If the object is another cluster scoped resource, + // it never skips the policy. + // + // For example, to run the webhook on any objects whose namespace is not + // associated with "runlevel" of "0" or "1"; you will set the selector as + // follows: + // "namespaceSelector": { + // "matchExpressions": [ + // { + // "key": "runlevel", + // "operator": "NotIn", + // "values": [ + // "0", + // "1" + // ] + // } + // ] + // } + // + // If instead you want to only run the policy on any objects whose + // namespace is associated with the "environment" of "prod" or "staging"; + // you will set the selector as follows: + // "namespaceSelector": { + // "matchExpressions": [ + // { + // "key": "environment", + // "operator": "In", + // "values": [ + // "prod", + // "staging" + // ] + // } + // ] + // } + // + // See + // https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + // for more examples of label selectors. + // + // Default to the empty LabelSelector, which matches everything. + // +optional + NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty" protobuf:"bytes,1,opt,name=namespaceSelector"` + // ObjectSelector decides whether to run the validation based on if the + // object has matching labels. objectSelector is evaluated against both + // the oldObject and newObject that would be sent to the cel validation, and + // is considered to match if either object matches the selector. A null + // object (oldObject in the case of create, or newObject in the case of + // delete) or an object that cannot have labels (like a + // DeploymentRollback or a PodProxyOptions object) is not considered to + // match. + // Use the object selector only if the webhook is opt-in, because end + // users may skip the admission webhook by setting the labels. + // Default to the empty LabelSelector, which matches everything. + // +optional + ObjectSelector *metav1.LabelSelector `json:"objectSelector,omitempty" protobuf:"bytes,2,opt,name=objectSelector"` + // ResourceRules describes what operations on what resources/subresources the ValidatingAdmissionPolicy matches. + // The policy cares about an operation if it matches _any_ Rule. + // +listType=atomic + // +optional + ResourceRules []NamedRuleWithOperations `json:"resourceRules,omitempty" protobuf:"bytes,3,rep,name=resourceRules"` + // ExcludeResourceRules describes what operations on what resources/subresources the ValidatingAdmissionPolicy should not care about. + // The exclude rules take precedence over include rules (if a resource matches both, it is excluded) + // +listType=atomic + // +optional + ExcludeResourceRules []NamedRuleWithOperations `json:"excludeResourceRules,omitempty" protobuf:"bytes,4,rep,name=excludeResourceRules"` + // matchPolicy defines how the "MatchResources" list is used to match incoming requests. + // Allowed values are "Exact" or "Equivalent". + // + // - Exact: match a request only if it exactly matches a specified rule. + // For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, + // but "rules" only included `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]`, + // a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the ValidatingAdmissionPolicy. + // + // - Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. + // For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, + // and "rules" only included `apiGroups:["apps"], apiVersions:["v1"], resources: ["deployments"]`, + // a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the ValidatingAdmissionPolicy. + // + // Defaults to "Equivalent" + // +optional + MatchPolicy *MatchPolicyType `json:"matchPolicy,omitempty" protobuf:"bytes,7,opt,name=matchPolicy,casttype=MatchPolicyType"` +} + +// ValidationAction specifies a policy enforcement action. +// +enum +type ValidationAction string + +const ( + // Deny specifies that a validation failure results in a denied request. + Deny ValidationAction = "Deny" + // Warn specifies that a validation failure is reported to the request client + // in HTTP Warning headers, with a warning code of 299. Warnings can be sent + // both for allowed or denied admission responses. + Warn ValidationAction = "Warn" + // Audit specifies that a validation failure is included in the published + // audit event for the request. The audit event will contain a + // `validation.policy.admission.k8s.io/validation_failure` audit annotation + // with a value containing the details of the validation failure. + Audit ValidationAction = "Audit" +) + +// NamedRuleWithOperations is a tuple of Operations and Resources with ResourceNames. +// +structType=atomic +type NamedRuleWithOperations struct { + // ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. + // +listType=atomic + // +optional + ResourceNames []string `json:"resourceNames,omitempty" protobuf:"bytes,1,rep,name=resourceNames"` + // RuleWithOperations is a tuple of Operations and Resources. + RuleWithOperations `json:",inline" protobuf:"bytes,2,opt,name=ruleWithOperations"` +} + // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/staging/src/k8s.io/apiextensions-apiserver/test/integration/fixtures/server.go b/staging/src/k8s.io/apiextensions-apiserver/test/integration/fixtures/server.go index fb35029fc3e..8be6a88e54c 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/test/integration/fixtures/server.go +++ b/staging/src/k8s.io/apiextensions-apiserver/test/integration/fixtures/server.go @@ -90,7 +90,7 @@ users: "--kubeconfig", fakeKubeConfig.Name(), // disable admission and filters that require talking to kube-apiserver "--enable-priority-and-fairness=false", - "--disable-admission-plugins", "NamespaceLifecycle,MutatingAdmissionWebhook,ValidatingAdmissionWebhook"}, + "--disable-admission-plugins", "NamespaceLifecycle,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ValidatingAdmissionPolicy"}, flags..., ), nil) if err != nil { diff --git a/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer.go b/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer.go index 2d293d79ac6..21ee8c80121 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer.go @@ -17,6 +17,7 @@ limitations under the License. package initializer import ( + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/client-go/dynamic" @@ -32,6 +33,7 @@ type pluginInitializer struct { authorizer authorizer.Authorizer featureGates featuregate.FeatureGate stopCh <-chan struct{} + restMapper meta.RESTMapper } // New creates an instance of admission plugins initializer. @@ -44,6 +46,7 @@ func New( authz authorizer.Authorizer, featureGates featuregate.FeatureGate, stopCh <-chan struct{}, + restMapper meta.RESTMapper, ) pluginInitializer { return pluginInitializer{ externalClient: extClientset, @@ -52,6 +55,7 @@ func New( authorizer: authz, featureGates: featureGates, stopCh: stopCh, + restMapper: restMapper, } } @@ -83,6 +87,9 @@ func (i pluginInitializer) Initialize(plugin admission.Interface) { if wants, ok := plugin.(WantsAuthorizer); ok { wants.SetAuthorizer(i.authorizer) } + if wants, ok := plugin.(WantsRESTMapper); ok { + wants.SetRESTMapper(i.restMapper) + } } var _ admission.PluginInitializer = pluginInitializer{} diff --git a/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go b/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go index 872178b4bda..d80ce6dd431 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go @@ -21,6 +21,8 @@ import ( "testing" "time" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/initializer" "k8s.io/apiserver/pkg/authorization/authorizer" @@ -32,7 +34,7 @@ import ( // TestWantsAuthorizer ensures that the authorizer is injected // when the WantsAuthorizer interface is implemented by a plugin. func TestWantsAuthorizer(t *testing.T) { - target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, nil) + target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, nil, nil) wantAuthorizerAdmission := &WantAuthorizerAdmission{} target.Initialize(wantAuthorizerAdmission) if wantAuthorizerAdmission.auth == nil { @@ -44,7 +46,7 @@ func TestWantsAuthorizer(t *testing.T) { // when the WantsExternalKubeClientSet interface is implemented by a plugin. func TestWantsExternalKubeClientSet(t *testing.T) { cs := &fake.Clientset{} - target := initializer.New(cs, nil, nil, &TestAuthorizer{}, nil, nil) + target := initializer.New(cs, nil, nil, &TestAuthorizer{}, nil, nil, nil) wantExternalKubeClientSet := &WantExternalKubeClientSet{} target.Initialize(wantExternalKubeClientSet) if wantExternalKubeClientSet.cs != cs { @@ -57,7 +59,7 @@ func TestWantsExternalKubeClientSet(t *testing.T) { func TestWantsExternalKubeInformerFactory(t *testing.T) { cs := &fake.Clientset{} sf := informers.NewSharedInformerFactory(cs, time.Duration(1)*time.Second) - target := initializer.New(cs, nil, sf, &TestAuthorizer{}, nil, nil) + target := initializer.New(cs, nil, sf, &TestAuthorizer{}, nil, nil, nil) wantExternalKubeInformerFactory := &WantExternalKubeInformerFactory{} target.Initialize(wantExternalKubeInformerFactory) if wantExternalKubeInformerFactory.sf != sf { @@ -69,7 +71,7 @@ func TestWantsExternalKubeInformerFactory(t *testing.T) { // when the WantsShutdownSignal interface is implemented by a plugin. func TestWantsShutdownNotification(t *testing.T) { stopCh := make(chan struct{}) - target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, stopCh) + target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, stopCh, nil) wantDrainedNotification := &WantDrainedNotification{} target.Initialize(wantDrainedNotification) if wantDrainedNotification.stopCh == nil { @@ -149,3 +151,59 @@ type TestAuthorizer struct{} func (t *TestAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { return authorizer.DecisionNoOpinion, "", nil } + +func TestRESTMapperAdmissionPlugin(t *testing.T) { + initializer := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, nil, &doNothingRESTMapper{}) + wantsRESTMapperAdmission := &WantsRESTMapperAdmissionPlugin{} + initializer.Initialize(wantsRESTMapperAdmission) + + if wantsRESTMapperAdmission.mapper == nil { + t.Errorf("Expected REST mapper to be initialized but found nil") + } +} + +type WantsRESTMapperAdmissionPlugin struct { + doNothingAdmission + doNothingPluginInitialization + mapper meta.RESTMapper +} + +func (p *WantsRESTMapperAdmissionPlugin) SetRESTMapper(mapper meta.RESTMapper) { + p.mapper = mapper +} + +type doNothingRESTMapper struct{} + +func (doNothingRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) { + return schema.GroupVersionKind{}, nil +} +func (doNothingRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) { + return nil, nil +} +func (doNothingRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) { + return schema.GroupVersionResource{}, nil +} +func (doNothingRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) { + return nil, nil +} +func (doNothingRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) { + return nil, nil +} +func (doNothingRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) { + return nil, nil +} +func (doNothingRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { + return "", nil +} + +type doNothingAdmission struct{} + +func (doNothingAdmission) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { + return nil +} +func (doNothingAdmission) Handles(o admission.Operation) bool { return false } +func (doNothingAdmission) Validate() error { return nil } + +type doNothingPluginInitialization struct{} + +func (doNothingPluginInitialization) ValidateInitialization() error { return nil } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go index bc4ff7b1af0..22c693d2dd1 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go @@ -53,7 +53,7 @@ func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) ( if err != nil { return nil, f, err } - pluginInitializer := kubeadmission.New(c, nil, f, nil, nil, nil) + pluginInitializer := kubeadmission.New(c, nil, f, nil, nil, nil, nil) pluginInitializer.Initialize(handler) err = admission.ValidateInitialization(handler) return handler, f, err diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/accessor.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/accessor.go index ae6d069a35c..85b18612f87 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/accessor.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/accessor.go @@ -17,15 +17,15 @@ limitations under the License. package generic import ( - "k8s.io/api/admissionregistration/v1beta1" + "k8s.io/api/admissionregistration/v1" "k8s.io/apimachinery/pkg/types" ) type PolicyAccessor interface { GetName() string GetNamespace() string - GetParamKind() *v1beta1.ParamKind - GetMatchConstraints() *v1beta1.MatchResources + GetParamKind() *v1.ParamKind + GetMatchConstraints() *v1.MatchResources } type BindingAccessor interface { @@ -36,7 +36,7 @@ type BindingAccessor interface { // which is cluster-scoped, so namespace is usually left blank. // But we leave the door open to add a namespaced vesion in the future GetPolicyName() types.NamespacedName - GetParamRef() *v1beta1.ParamRef + GetParamRef() *v1.ParamRef - GetMatchResources() *v1beta1.MatchResources + GetMatchResources() *v1.MatchResources } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_dispatcher.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_dispatcher.go index a3d21235f3d..62ed7bc6c69 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_dispatcher.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_dispatcher.go @@ -22,7 +22,7 @@ import ( "fmt" "time" - "k8s.io/api/admissionregistration/v1beta1" + "k8s.io/api/admissionregistration/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -217,10 +217,10 @@ func (d *policyDispatcher[P, B, E]) Dispatch(ctx context.Context, a admission.At // configuration. If the policy-binding has no param configuration, it // returns a single-element list with a nil param. func CollectParams( - paramKind *v1beta1.ParamKind, + paramKind *v1.ParamKind, paramInformer informers.GenericInformer, paramScope meta.RESTScope, - paramRef *v1beta1.ParamRef, + paramRef *v1.ParamRef, namespace string, ) ([]runtime.Object, error) { // If definition has paramKind, paramRef is required in binding. @@ -326,7 +326,7 @@ func CollectParams( } // Apply fail action for params not found case - if len(params) == 0 && paramRef.ParameterNotFoundAction != nil && *paramRef.ParameterNotFoundAction == v1beta1.DenyAction { + if len(params) == 0 && paramRef.ParameterNotFoundAction != nil && *paramRef.ParameterNotFoundAction == v1.DenyAction { return nil, errors.New("no params found for policy binding with `Deny` parameterNotFoundAction") } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_matcher.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_matcher.go index 9f8b6b432f6..d243b0710bc 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_matcher.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_matcher.go @@ -19,7 +19,7 @@ package generic import ( "fmt" - "k8s.io/api/admissionregistration/v1beta1" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -89,7 +89,7 @@ func (c *matcher) GetNamespace(name string) (*corev1.Namespace, error) { var _ matching.MatchCriteria = &matchCriteria{} type matchCriteria struct { - constraints *v1beta1.MatchResources + constraints *admissionregistrationv1.MatchResources } // GetParsedNamespaceSelector returns the converted LabelSelector which implements labels.Selector @@ -103,6 +103,6 @@ func (m *matchCriteria) GetParsedObjectSelector() (labels.Selector, error) { } // GetMatchResources returns the matchConstraints -func (m *matchCriteria) GetMatchResources() v1beta1.MatchResources { +func (m *matchCriteria) GetMatchResources() admissionregistrationv1.MatchResources { return *m.constraints } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_source_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_source_test.go index 7aae1be052a..218b0861100 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_source_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_source_test.go @@ -20,7 +20,7 @@ import ( "testing" "github.com/stretchr/testify/require" - "k8s.io/api/admissionregistration/v1beta1" + "k8s.io/api/admissionregistration/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -110,7 +110,7 @@ func TestPolicySourceHasSyncedInitialList(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "policy2", }, - ParamKind: &v1beta1.ParamKind{ + ParamKind: &v1.ParamKind{ APIVersion: "policy.example.com/v1", Kind: "FakeParam", }, @@ -177,7 +177,7 @@ type FakePolicy struct { metav1.TypeMeta metav1.ObjectMeta - ParamKind *v1beta1.ParamKind + ParamKind *v1.ParamKind } var _ generic.PolicyAccessor = &FakePolicy{} @@ -199,11 +199,11 @@ func (fp *FakePolicy) GetNamespace() string { return fp.Namespace } -func (fp *FakePolicy) GetParamKind() *v1beta1.ParamKind { +func (fp *FakePolicy) GetParamKind() *v1.ParamKind { return fp.ParamKind } -func (fb *FakePolicy) GetMatchConstraints() *v1beta1.MatchResources { +func (fb *FakePolicy) GetMatchConstraints() *v1.MatchResources { return nil } @@ -221,11 +221,11 @@ func (fb *FakeBinding) GetPolicyName() types.NamespacedName { } } -func (fb *FakeBinding) GetMatchResources() *v1beta1.MatchResources { +func (fb *FakeBinding) GetMatchResources() *v1.MatchResources { return nil } -func (fb *FakeBinding) GetParamRef() *v1beta1.ParamRef { +func (fb *FakeBinding) GetParamRef() *v1.ParamRef { return nil } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_test_context.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_test_context.go index 0d5fee3e2f3..69b19fb2aa6 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_test_context.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/generic/policy_test_context.go @@ -216,6 +216,7 @@ func NewPolicyTestContext[P, B runtime.Object, E Evaluator]( fakeAuthorizer{}, featureGate, testContext.Done(), + fakeRestMapper, ) genericInitializer.Initialize(plugin) plugin.SetRESTMapper(fakeRestMapper) diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/matching/matching.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/matching/matching.go index ebdb61db889..eebe7694340 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/matching/matching.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/matching/matching.go @@ -20,7 +20,6 @@ import ( "fmt" v1 "k8s.io/api/admissionregistration/v1" - "k8s.io/api/admissionregistration/v1beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" @@ -36,7 +35,7 @@ type MatchCriteria interface { namespace.NamespaceSelectorProvider object.ObjectSelectorProvider - GetMatchResources() v1beta1.MatchResources + GetMatchResources() v1.MatchResources } // Matcher decides if a request matches against matchCriteria @@ -121,7 +120,7 @@ func (m *Matcher) Matches(attr admission.Attributes, o admission.ObjectInterface return true, matchResource, matchKind, nil } -func matchesResourceRules(namedRules []v1beta1.NamedRuleWithOperations, matchPolicy *v1beta1.MatchPolicyType, attr admission.Attributes, o admission.ObjectInterfaces) (bool, schema.GroupVersionResource, schema.GroupVersionKind, error) { +func matchesResourceRules(namedRules []v1.NamedRuleWithOperations, matchPolicy *v1.MatchPolicyType, attr admission.Attributes, o admission.ObjectInterfaces) (bool, schema.GroupVersionResource, schema.GroupVersionKind, error) { matchKind := attr.GetKind() matchResource := attr.GetResource() @@ -150,7 +149,7 @@ func matchesResourceRules(namedRules []v1beta1.NamedRuleWithOperations, matchPol // if match policy is undefined or exact, don't perform fuzzy matching // note that defaulting to fuzzy matching is set by the API - if matchPolicy == nil || *matchPolicy == v1beta1.Exact { + if matchPolicy == nil || *matchPolicy == v1.Exact { return false, schema.GroupVersionResource{}, schema.GroupVersionKind{}, nil } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/matching/matching_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/matching/matching_test.go index e763eb3d86b..c15db2f479d 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/matching/matching_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/matching/matching_test.go @@ -22,7 +22,6 @@ import ( "testing" v1 "k8s.io/api/admissionregistration/v1" - "k8s.io/api/admissionregistration/v1beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -38,10 +37,10 @@ import ( var _ MatchCriteria = &fakeCriteria{} type fakeCriteria struct { - matchResources v1beta1.MatchResources + matchResources v1.MatchResources } -func (fc *fakeCriteria) GetMatchResources() v1beta1.MatchResources { +func (fc *fakeCriteria) GetMatchResources() v1.MatchResources { return fc.matchResources } @@ -65,8 +64,8 @@ func TestMatcher(t *testing.T) { a := &Matcher{namespaceMatcher: &namespace.Matcher{}, objectMatcher: &object.Matcher{}} allScopes := v1.AllScopes - exactMatch := v1beta1.Exact - equivalentMatch := v1beta1.Equivalent + exactMatch := v1.Exact + equivalentMatch := v1.Equivalent mapper := runtime.NewEquivalentResourceRegistryWithIdentity(func(resource schema.GroupResource) string { if resource.Resource == "deployments" { @@ -95,7 +94,7 @@ func TestMatcher(t *testing.T) { testcases := []struct { name string - criteria *v1beta1.MatchResources + criteria *v1.MatchResources attrs admission.Attributes expectMatches bool @@ -105,17 +104,17 @@ func TestMatcher(t *testing.T) { }{ { name: "no rules (just write)", - criteria: &v1beta1.MatchResources{NamespaceSelector: &metav1.LabelSelector{}, ResourceRules: []v1beta1.NamedRuleWithOperations{}}, + criteria: &v1.MatchResources{NamespaceSelector: &metav1.LabelSelector{}, ResourceRules: []v1.NamedRuleWithOperations{}}, attrs: admission.NewAttributesRecord(nil, nil, gvk("apps", "v1", "Deployment"), "ns", "name", gvr("apps", "v1", "deployments"), "", admission.Create, &metav1.CreateOptions{}, false, nil), expectMatches: false, }, { name: "wildcard rule, match as requested", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}, Scope: &allScopes}, }, @@ -126,21 +125,21 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, prefer exact match", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, - Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, + Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, @@ -151,16 +150,16 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, match miss", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, @@ -170,17 +169,17 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, exact match miss", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ MatchPolicy: &exactMatch, NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, @@ -190,17 +189,17 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, equivalent match, prefer extensions", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ MatchPolicy: &equivalentMatch, NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, @@ -212,17 +211,17 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, equivalent match, prefer apps", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ MatchPolicy: &equivalentMatch, NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, @@ -235,21 +234,21 @@ func TestMatcher(t *testing.T) { { name: "specific rules, subresource prefer exact match", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, @@ -260,16 +259,16 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, subresource match miss", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, @@ -279,17 +278,17 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, subresource exact match miss", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ MatchPolicy: &exactMatch, NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, @@ -299,17 +298,17 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, subresource equivalent match, prefer extensions", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ MatchPolicy: &equivalentMatch, NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, @@ -321,17 +320,17 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, subresource equivalent match, prefer apps", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ MatchPolicy: &equivalentMatch, NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, @@ -343,12 +342,12 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, prefer exact match and name match", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ + ResourceRules: []v1.NamedRuleWithOperations{{ ResourceNames: []string{"name"}, - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, @@ -359,12 +358,12 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, prefer exact match and name match miss", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ + ResourceRules: []v1.NamedRuleWithOperations{{ ResourceNames: []string{"wrong-name"}, - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, @@ -374,13 +373,13 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, subresource equivalent match, prefer extensions and name match", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ MatchPolicy: &equivalentMatch, NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ + ResourceRules: []v1.NamedRuleWithOperations{{ ResourceNames: []string{"name"}, - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, @@ -392,13 +391,13 @@ func TestMatcher(t *testing.T) { }, { name: "specific rules, subresource equivalent match, prefer extensions and name match miss", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ MatchPolicy: &equivalentMatch, NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ + ResourceRules: []v1.NamedRuleWithOperations{{ ResourceNames: []string{"wrong-name"}, - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, @@ -408,17 +407,17 @@ func TestMatcher(t *testing.T) { }, { name: "exclude resource match on miss", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}, Scope: &allScopes}, }, }}, - ExcludeResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ExcludeResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, @@ -430,17 +429,17 @@ func TestMatcher(t *testing.T) { }, { name: "exclude resource miss on match", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}, Scope: &allScopes}, }, }}, - ExcludeResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ExcludeResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, @@ -451,11 +450,11 @@ func TestMatcher(t *testing.T) { }, { name: "treat empty ResourceRules as match", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ExcludeResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ + ExcludeResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments"}, Scope: &allScopes}, }, @@ -466,23 +465,23 @@ func TestMatcher(t *testing.T) { }, { name: "treat non-empty ResourceRules as no match", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{}}, + ResourceRules: []v1.NamedRuleWithOperations{{}}, }, attrs: admission.NewAttributesRecord(nil, nil, gvk("autoscaling", "v1", "Scale"), "ns", "name", gvr("apps", "v1", "deployments"), "", admission.Create, &metav1.CreateOptions{}, false, nil), expectMatches: false, }, { name: "erroring namespace selector on otherwise non-matching rule doesn't error", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key ", Operator: "In", Values: []string{"bad value"}}}}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"deployments"}}, - Operations: []v1beta1.OperationType{"*"}, + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"deployments"}}, + Operations: []v1.OperationType{"*"}, }, }}, }, @@ -492,13 +491,13 @@ func TestMatcher(t *testing.T) { }, { name: "erroring namespace selector on otherwise matching rule errors", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key", Operator: "In", Values: []string{"bad value"}}}}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"pods"}}, - Operations: []v1beta1.OperationType{"*"}, + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"pods"}}, + Operations: []v1.OperationType{"*"}, }, }}, }, @@ -508,13 +507,13 @@ func TestMatcher(t *testing.T) { }, { name: "erroring object selector on otherwise non-matching rule doesn't error", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key", Operator: "In", Values: []string{"bad value"}}}}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"deployments"}}, - Operations: []v1beta1.OperationType{"*"}, + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"deployments"}}, + Operations: []v1.OperationType{"*"}, }, }}, }, @@ -524,13 +523,13 @@ func TestMatcher(t *testing.T) { }, { name: "erroring object selector on otherwise matching rule errors", - criteria: &v1beta1.MatchResources{ + criteria: &v1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{}, ObjectSelector: &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{{Key: "key", Operator: "In", Values: []string{"bad value"}}}}, - ResourceRules: []v1beta1.NamedRuleWithOperations{{ - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"pods"}}, - Operations: []v1beta1.OperationType{"*"}, + ResourceRules: []v1.NamedRuleWithOperations{{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"pods"}}, + Operations: []v1.OperationType{"*"}, }, }}, }, @@ -601,7 +600,7 @@ func (f fakeNamespaceLister) Get(name string) (*corev1.Namespace, error) { func BenchmarkMatcher(b *testing.B) { allScopes := v1.AllScopes - equivalentMatch := v1beta1.Equivalent + equivalentMatch := v1.Equivalent namespace1Labels := map[string]string{"ns": "ns1"} namespace1 := corev1.Namespace{ @@ -642,19 +641,19 @@ func BenchmarkMatcher(b *testing.B) { nsSelector[fmt.Sprintf("key-%d", i)] = fmt.Sprintf("val-%d", i) } - mr := v1beta1.MatchResources{ + mr := v1.MatchResources{ MatchPolicy: &equivalentMatch, NamespaceSelector: &metav1.LabelSelector{MatchLabels: nsSelector}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{ + ResourceRules: []v1.NamedRuleWithOperations{ { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"apps"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{APIGroups: []string{"extensions"}, APIVersions: []string{"v1beta1"}, Resources: []string{"deployments", "deployments/scale"}, Scope: &allScopes}, }, @@ -674,7 +673,7 @@ func BenchmarkMatcher(b *testing.B) { func BenchmarkShouldCallHookWithComplexRule(b *testing.B) { allScopes := v1.AllScopes - equivalentMatch := v1beta1.Equivalent + equivalentMatch := v1.Equivalent namespace1Labels := map[string]string{"ns": "ns1"} namespace1 := corev1.Namespace{ @@ -710,16 +709,16 @@ func BenchmarkShouldCallHookWithComplexRule(b *testing.B) { mapper.RegisterKindFor(gvr("apps", "v1beta1", "statefulset"), "scale", gvk("apps", "v1beta1", "Scale")) mapper.RegisterKindFor(gvr("apps", "v1alpha2", "statefulset"), "scale", gvk("apps", "v1beta2", "Scale")) - mr := v1beta1.MatchResources{ + mr := v1.MatchResources{ MatchPolicy: &equivalentMatch, NamespaceSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{}, + ResourceRules: []v1.NamedRuleWithOperations{}, } for i := 0; i < 100; i++ { - rule := v1beta1.NamedRuleWithOperations{ - RuleWithOperations: v1beta1.RuleWithOperations{ + rule := v1.NamedRuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{ APIGroups: []string{fmt.Sprintf("app-%d", i)}, @@ -744,7 +743,7 @@ func BenchmarkShouldCallHookWithComplexRule(b *testing.B) { func BenchmarkShouldCallHookWithComplexSelectorAndRule(b *testing.B) { allScopes := v1.AllScopes - equivalentMatch := v1beta1.Equivalent + equivalentMatch := v1.Equivalent namespace1Labels := map[string]string{"ns": "ns1"} namespace1 := corev1.Namespace{ @@ -785,16 +784,16 @@ func BenchmarkShouldCallHookWithComplexSelectorAndRule(b *testing.B) { nsSelector[fmt.Sprintf("key-%d", i)] = fmt.Sprintf("val-%d", i) } - mr := v1beta1.MatchResources{ + mr := v1.MatchResources{ MatchPolicy: &equivalentMatch, NamespaceSelector: &metav1.LabelSelector{MatchLabels: nsSelector}, ObjectSelector: &metav1.LabelSelector{}, - ResourceRules: []v1beta1.NamedRuleWithOperations{}, + ResourceRules: []v1.NamedRuleWithOperations{}, } for i := 0; i < 100; i++ { - rule := v1beta1.NamedRuleWithOperations{ - RuleWithOperations: v1beta1.RuleWithOperations{ + rule := v1.NamedRuleWithOperations{ + RuleWithOperations: v1.RuleWithOperations{ Operations: []v1.OperationType{"*"}, Rule: v1.Rule{ APIGroups: []string{fmt.Sprintf("app-%d", i)}, diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/accessor.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/accessor.go index 6af2857598d..97cef091480 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/accessor.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/accessor.go @@ -17,25 +17,25 @@ limitations under the License. package validating import ( - "k8s.io/api/admissionregistration/v1beta1" + "k8s.io/api/admissionregistration/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apiserver/pkg/admission/plugin/policy/generic" ) -func NewValidatingAdmissionPolicyAccessor(obj *v1beta1.ValidatingAdmissionPolicy) generic.PolicyAccessor { +func NewValidatingAdmissionPolicyAccessor(obj *v1.ValidatingAdmissionPolicy) generic.PolicyAccessor { return &validatingAdmissionPolicyAccessor{ ValidatingAdmissionPolicy: obj, } } -func NewValidatingAdmissionPolicyBindingAccessor(obj *v1beta1.ValidatingAdmissionPolicyBinding) generic.BindingAccessor { +func NewValidatingAdmissionPolicyBindingAccessor(obj *v1.ValidatingAdmissionPolicyBinding) generic.BindingAccessor { return &validatingAdmissionPolicyBindingAccessor{ ValidatingAdmissionPolicyBinding: obj, } } type validatingAdmissionPolicyAccessor struct { - *v1beta1.ValidatingAdmissionPolicy + *v1.ValidatingAdmissionPolicy } func (v *validatingAdmissionPolicyAccessor) GetNamespace() string { @@ -46,16 +46,16 @@ func (v *validatingAdmissionPolicyAccessor) GetName() string { return v.Name } -func (v *validatingAdmissionPolicyAccessor) GetParamKind() *v1beta1.ParamKind { +func (v *validatingAdmissionPolicyAccessor) GetParamKind() *v1.ParamKind { return v.Spec.ParamKind } -func (v *validatingAdmissionPolicyAccessor) GetMatchConstraints() *v1beta1.MatchResources { +func (v *validatingAdmissionPolicyAccessor) GetMatchConstraints() *v1.MatchResources { return v.Spec.MatchConstraints } type validatingAdmissionPolicyBindingAccessor struct { - *v1beta1.ValidatingAdmissionPolicyBinding + *v1.ValidatingAdmissionPolicyBinding } func (v *validatingAdmissionPolicyBindingAccessor) GetNamespace() string { @@ -73,10 +73,10 @@ func (v *validatingAdmissionPolicyBindingAccessor) GetPolicyName() types.Namespa } } -func (v *validatingAdmissionPolicyBindingAccessor) GetMatchResources() *v1beta1.MatchResources { +func (v *validatingAdmissionPolicyBindingAccessor) GetMatchResources() *v1.MatchResources { return v.Spec.MatchResources } -func (v *validatingAdmissionPolicyBindingAccessor) GetParamRef() *v1beta1.ParamRef { +func (v *validatingAdmissionPolicyBindingAccessor) GetParamRef() *v1.ParamRef { return v.Spec.ParamRef } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/admission_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/admission_test.go index 6831d9053a0..661d162b914 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/admission_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/admission_test.go @@ -27,7 +27,7 @@ import ( "github.com/stretchr/testify/require" - "k8s.io/api/admissionregistration/v1beta1" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -61,18 +61,18 @@ var ( } // Common objects - denyPolicy *v1beta1.ValidatingAdmissionPolicy = &v1beta1.ValidatingAdmissionPolicy{ + denyPolicy *admissionregistrationv1.ValidatingAdmissionPolicy = &admissionregistrationv1.ValidatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "denypolicy.example.com", ResourceVersion: "1", }, - Spec: v1beta1.ValidatingAdmissionPolicySpec{ - ParamKind: &v1beta1.ParamKind{ + Spec: admissionregistrationv1.ValidatingAdmissionPolicySpec{ + ParamKind: &admissionregistrationv1.ParamKind{ APIVersion: paramsGVK.GroupVersion().String(), Kind: paramsGVK.Kind, }, - FailurePolicy: ptrTo(v1beta1.Fail), - Validations: []v1beta1.Validation{ + FailurePolicy: ptrTo(admissionregistrationv1.Fail), + Validations: []admissionregistrationv1.Validation{ { Expression: "messageId for deny policy", }, @@ -93,61 +93,61 @@ var ( }, } - denyBinding *v1beta1.ValidatingAdmissionPolicyBinding = &v1beta1.ValidatingAdmissionPolicyBinding{ + denyBinding *admissionregistrationv1.ValidatingAdmissionPolicyBinding = &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ ObjectMeta: metav1.ObjectMeta{ Name: "denybinding.example.com", ResourceVersion: "1", }, - Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ + Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ PolicyName: denyPolicy.Name, - ParamRef: &v1beta1.ParamRef{ + ParamRef: &admissionregistrationv1.ParamRef{ Name: fakeParams.GetName(), Namespace: fakeParams.GetNamespace(), // fake object tracker does not populate defaults - ParameterNotFoundAction: ptrTo(v1beta1.DenyAction), + ParameterNotFoundAction: ptrTo(admissionregistrationv1.DenyAction), }, - ValidationActions: []v1beta1.ValidationAction{v1beta1.Deny}, + ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny}, }, } - denyBindingWithNoParamRef *v1beta1.ValidatingAdmissionPolicyBinding = &v1beta1.ValidatingAdmissionPolicyBinding{ + denyBindingWithNoParamRef *admissionregistrationv1.ValidatingAdmissionPolicyBinding = &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ ObjectMeta: metav1.ObjectMeta{ Name: "denybinding.example.com", ResourceVersion: "1", }, - Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ + Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ PolicyName: denyPolicy.Name, - ValidationActions: []v1beta1.ValidationAction{v1beta1.Deny}, + ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny}, }, } - denyBindingWithAudit = &v1beta1.ValidatingAdmissionPolicyBinding{ + denyBindingWithAudit = &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ ObjectMeta: metav1.ObjectMeta{ Name: "denybinding.example.com", ResourceVersion: "1", }, - Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ + Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ PolicyName: denyPolicy.Name, - ValidationActions: []v1beta1.ValidationAction{v1beta1.Audit}, + ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Audit}, }, } - denyBindingWithWarn = &v1beta1.ValidatingAdmissionPolicyBinding{ + denyBindingWithWarn = &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ ObjectMeta: metav1.ObjectMeta{ Name: "denybinding.example.com", ResourceVersion: "1", }, - Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ + Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ PolicyName: denyPolicy.Name, - ValidationActions: []v1beta1.ValidationAction{v1beta1.Warn}, + ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Warn}, }, } - denyBindingWithAll = &v1beta1.ValidatingAdmissionPolicyBinding{ + denyBindingWithAll = &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ ObjectMeta: metav1.ObjectMeta{ Name: "denybinding.example.com", ResourceVersion: "1", }, - Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ + Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ PolicyName: denyPolicy.Name, - ValidationActions: []v1beta1.ValidationAction{v1beta1.Deny, v1beta1.Warn, v1beta1.Audit}, + ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny, admissionregistrationv1.Warn, admissionregistrationv1.Audit}, }, } ) @@ -277,7 +277,7 @@ type fakeMatcher struct { BindingMatchFuncs map[types.NamespacedName]func(generic.BindingAccessor, admission.Attributes) bool } -func (f *fakeMatcher) RegisterDefinition(definition *v1beta1.ValidatingAdmissionPolicy, matchFunc func(generic.PolicyAccessor, admission.Attributes) bool) { +func (f *fakeMatcher) RegisterDefinition(definition *admissionregistrationv1.ValidatingAdmissionPolicy, matchFunc func(generic.PolicyAccessor, admission.Attributes) bool) { namespace, name := definition.Namespace, definition.Name key := types.NamespacedName{ Name: name, @@ -292,7 +292,7 @@ func (f *fakeMatcher) RegisterDefinition(definition *v1beta1.ValidatingAdmission } } -func (f *fakeMatcher) RegisterBinding(binding *v1beta1.ValidatingAdmissionPolicyBinding, matchFunc func(generic.BindingAccessor, admission.Attributes) bool) { +func (f *fakeMatcher) RegisterBinding(binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding, matchFunc func(generic.BindingAccessor, admission.Attributes) bool) { namespace, name := binding.Namespace, binding.Name key := types.NamespacedName{ Name: name, @@ -644,19 +644,19 @@ func TestReconfigureBinding(t *testing.T) { } }) - denyBinding2 := &v1beta1.ValidatingAdmissionPolicyBinding{ + denyBinding2 := &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ ObjectMeta: metav1.ObjectMeta{ Name: "denybinding.example.com", ResourceVersion: "2", }, - Spec: v1beta1.ValidatingAdmissionPolicyBindingSpec{ + Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ PolicyName: denyPolicy.Name, - ParamRef: &v1beta1.ParamRef{ + ParamRef: &admissionregistrationv1.ParamRef{ Name: fakeParams2.GetName(), Namespace: fakeParams2.GetNamespace(), - ParameterNotFoundAction: ptrTo(v1beta1.DenyAction), + ParameterNotFoundAction: ptrTo(admissionregistrationv1.DenyAction), }, - ValidationActions: []v1beta1.ValidationAction{v1beta1.Deny}, + ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny}, }, } @@ -805,7 +805,7 @@ func TestInvalidParamSourceGVK(t *testing.T) { passedParams := make(chan *unstructured.Unstructured) badPolicy := *denyPolicy - badPolicy.Spec.ParamKind = &v1beta1.ParamKind{ + badPolicy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ APIVersion: paramsGVK.GroupVersion().String(), Kind: "BadParamKind", } @@ -985,13 +985,13 @@ func TestMultiplePoliciesSharedParamType(t *testing.T) { // Use ConfigMap native-typed param policy1 := *denyPolicy policy1.Name = "denypolicy1.example.com" - policy1.Spec = v1beta1.ValidatingAdmissionPolicySpec{ - ParamKind: &v1beta1.ParamKind{ + policy1.Spec = admissionregistrationv1.ValidatingAdmissionPolicySpec{ + ParamKind: &admissionregistrationv1.ParamKind{ APIVersion: paramsGVK.GroupVersion().String(), Kind: paramsGVK.Kind, }, - FailurePolicy: ptrTo(v1beta1.Fail), - Validations: []v1beta1.Validation{ + FailurePolicy: ptrTo(admissionregistrationv1.Fail), + Validations: []admissionregistrationv1.Validation{ { Expression: "policy1", }, @@ -1000,13 +1000,13 @@ func TestMultiplePoliciesSharedParamType(t *testing.T) { policy2 := *denyPolicy policy2.Name = "denypolicy2.example.com" - policy2.Spec = v1beta1.ValidatingAdmissionPolicySpec{ - ParamKind: &v1beta1.ParamKind{ + policy2.Spec = admissionregistrationv1.ValidatingAdmissionPolicySpec{ + ParamKind: &admissionregistrationv1.ParamKind{ APIVersion: paramsGVK.GroupVersion().String(), Kind: paramsGVK.Kind, }, - FailurePolicy: ptrTo(v1beta1.Fail), - Validations: []v1beta1.Validation{ + FailurePolicy: ptrTo(admissionregistrationv1.Fail), + Validations: []admissionregistrationv1.Validation{ { Expression: "policy2", }, @@ -1106,7 +1106,7 @@ func TestNativeTypeParam(t *testing.T) { // Use ConfigMap native-typed param nativeTypeParamPolicy := *denyPolicy - nativeTypeParamPolicy.Spec.ParamKind = &v1beta1.ParamKind{ + nativeTypeParamPolicy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ APIVersion: "v1", Kind: "ConfigMap", } @@ -1208,7 +1208,7 @@ func TestAuditValidationAction(t *testing.T) { expected := []validating.ValidationFailureValue{{ ExpressionIndex: 0, Message: "I'm sorry Dave", - ValidationActions: []v1beta1.ValidationAction{v1beta1.Audit}, + ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Audit}, Binding: "denybinding.example.com", Policy: noParamSourcePolicy.Name, }} @@ -1305,7 +1305,7 @@ func TestAllValidationActions(t *testing.T) { expected := []validating.ValidationFailureValue{{ ExpressionIndex: 0, Message: "I'm sorry Dave", - ValidationActions: []v1beta1.ValidationAction{v1beta1.Deny, v1beta1.Warn, v1beta1.Audit}, + ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny, admissionregistrationv1.Warn, admissionregistrationv1.Audit}, Binding: "denybinding.example.com", Policy: noParamSourcePolicy.Name, }} @@ -1325,13 +1325,13 @@ func TestNamespaceParamRefName(t *testing.T) { // Use ConfigMap native-typed param nativeTypeParamPolicy := *denyPolicy - nativeTypeParamPolicy.Spec.ParamKind = &v1beta1.ParamKind{ + nativeTypeParamPolicy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ APIVersion: "v1", Kind: "ConfigMap", } namespaceParamBinding := *denyBinding - namespaceParamBinding.Spec.ParamRef = &v1beta1.ParamRef{ + namespaceParamBinding.Spec.ParamRef = &admissionregistrationv1.ParamRef{ Name: "replicas-test.example.com", } lock := sync.Mutex{} @@ -1543,7 +1543,7 @@ func testParamRefCase(t *testing.T, paramIsClusterScoped, nameIsSet, namespaceIs // Create a cluster scoped and a namespace scoped CRD policy := *denyPolicy binding := *denyBinding - binding.Spec.ParamRef = &v1beta1.ParamRef{} + binding.Spec.ParamRef = &admissionregistrationv1.ParamRef{} paramRef := binding.Spec.ParamRef shouldErrorOnClusterScopedRequests := !namespaceIsSet && !paramIsClusterScoped @@ -1557,12 +1557,12 @@ func testParamRefCase(t *testing.T, paramIsClusterScoped, nameIsSet, namespaceIs otherNonmatchingLabels := labels.Set{"notaffiliated": "no"} if paramIsClusterScoped { - policy.Spec.ParamKind = &v1beta1.ParamKind{ + policy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ APIVersion: clusterScopedParamsGVK.GroupVersion().String(), Kind: clusterScopedParamsGVK.Kind, } } else { - policy.Spec.ParamKind = &v1beta1.ParamKind{ + policy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ APIVersion: paramsGVK.GroupVersion().String(), Kind: paramsGVK.Kind, } @@ -1581,9 +1581,9 @@ func testParamRefCase(t *testing.T, paramIsClusterScoped, nameIsSet, namespaceIs } if denyNotFound { - paramRef.ParameterNotFoundAction = ptrTo(v1beta1.DenyAction) + paramRef.ParameterNotFoundAction = ptrTo(admissionregistrationv1.DenyAction) } else { - paramRef.ParameterNotFoundAction = ptrTo(v1beta1.AllowAction) + paramRef.ParameterNotFoundAction = ptrTo(admissionregistrationv1.AllowAction) } compiler := &fakeCompiler{} @@ -1815,20 +1815,20 @@ func TestNamespaceParamRefClusterScopedParamError(t *testing.T) { // Use ValidatingAdmissionPolicy for param type since it is cluster-scoped nativeTypeParamPolicy := *denyPolicy - nativeTypeParamPolicy.Spec.ParamKind = &v1beta1.ParamKind{ + nativeTypeParamPolicy.Spec.ParamKind = &admissionregistrationv1.ParamKind{ APIVersion: "admissionregistration.k8s.io/v1beta1", Kind: "ValidatingAdmissionPolicy", } namespaceParamBinding := *denyBinding - namespaceParamBinding.Spec.ParamRef = &v1beta1.ParamRef{ + namespaceParamBinding.Spec.ParamRef = &admissionregistrationv1.ParamRef{ Name: "other-param-to-use-with-no-label.example.com", Namespace: "mynamespace", } compiler.RegisterDefinition(&nativeTypeParamPolicy, func(ctx context.Context, matchedResource schema.GroupVersionResource, versionedAttr *admission.VersionedAttributes, versionedParams runtime.Object, namespace *v1.Namespace, runtimeCELCostBudget int64, authz authorizer.Authorizer) validating.ValidateResult { evaluations.Add(1) - if _, ok := versionedParams.(*v1beta1.ValidatingAdmissionPolicy); ok { + if _, ok := versionedParams.(*admissionregistrationv1.ValidatingAdmissionPolicy); ok { return validating.ValidateResult{ Decisions: []validating.PolicyDecision{ { diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/dispatcher.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/dispatcher.go index 3fc67a4c6ab..edf5a788673 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/dispatcher.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/dispatcher.go @@ -22,7 +22,7 @@ import ( "fmt" "strings" - "k8s.io/api/admissionregistration/v1beta1" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" v1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -59,8 +59,8 @@ func NewDispatcher( // that determined the decision type policyDecisionWithMetadata struct { PolicyDecision - Definition *v1beta1.ValidatingAdmissionPolicy - Binding *v1beta1.ValidatingAdmissionPolicyBinding + Definition *admissionregistrationv1.ValidatingAdmissionPolicy + Binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding } // Dispatch implements generic.Dispatcher. @@ -68,21 +68,21 @@ func (c *dispatcher) Dispatch(ctx context.Context, a admission.Attributes, o adm var deniedDecisions []policyDecisionWithMetadata - addConfigError := func(err error, definition *v1beta1.ValidatingAdmissionPolicy, binding *v1beta1.ValidatingAdmissionPolicyBinding) { + addConfigError := func(err error, definition *admissionregistrationv1.ValidatingAdmissionPolicy, binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding) { // we always default the FailurePolicy if it is unset and validate it in API level - var policy v1beta1.FailurePolicyType + var policy admissionregistrationv1.FailurePolicyType if definition.Spec.FailurePolicy == nil { - policy = v1beta1.Fail + policy = admissionregistrationv1.Fail } else { policy = *definition.Spec.FailurePolicy } // apply FailurePolicy specified in ValidatingAdmissionPolicy, the default would be Fail switch policy { - case v1beta1.Ignore: + case admissionregistrationv1.Ignore: // TODO: add metrics for ignored error here return - case v1beta1.Fail: + case admissionregistrationv1.Fail: var message string if binding == nil { message = fmt.Errorf("failed to configure policy: %w", err).Error() @@ -228,17 +228,17 @@ func (c *dispatcher) Dispatch(ctx context.Context, a admission.Attributes, o adm case ActionDeny: for _, action := range binding.Spec.ValidationActions { switch action { - case v1beta1.Deny: + case admissionregistrationv1.Deny: deniedDecisions = append(deniedDecisions, policyDecisionWithMetadata{ Definition: definition, Binding: binding, PolicyDecision: decision, }) celmetrics.Metrics.ObserveRejection(ctx, decision.Elapsed, definition.Name, binding.Name, "active") - case v1beta1.Audit: + case admissionregistrationv1.Audit: publishValidationFailureAnnotation(binding, i, decision, versionedAttr) celmetrics.Metrics.ObserveAudit(ctx, decision.Elapsed, definition.Name, binding.Name, "active") - case v1beta1.Warn: + case admissionregistrationv1.Warn: warning.AddWarning(ctx, "", fmt.Sprintf("Validation failed for ValidatingAdmissionPolicy '%s' with binding '%s': %s", definition.Name, binding.Name, decision.Message)) celmetrics.Metrics.ObserveWarn(ctx, decision.Elapsed, definition.Name, binding.Name, "active") } @@ -302,7 +302,7 @@ func (c *dispatcher) Dispatch(ctx context.Context, a admission.Attributes, o adm return nil } -func publishValidationFailureAnnotation(binding *v1beta1.ValidatingAdmissionPolicyBinding, expressionIndex int, decision PolicyDecision, attributes admission.Attributes) { +func publishValidationFailureAnnotation(binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding, expressionIndex int, decision PolicyDecision, attributes admission.Attributes) { key := "validation.policy.admission.k8s.io/validation_failure" // Marshal to a list of failures since, in the future, we may need to support multiple failures valueJSON, err := utiljson.Marshal([]ValidationFailureValue{{ @@ -326,11 +326,11 @@ const maxAuditAnnotationValueLength = 10 * 1024 // validationFailureValue defines the JSON format of a "validation.policy.admission.k8s.io/validation_failure" audit // annotation value. type ValidationFailureValue struct { - Message string `json:"message"` - Policy string `json:"policy"` - Binding string `json:"binding"` - ExpressionIndex int `json:"expressionIndex"` - ValidationActions []v1beta1.ValidationAction `json:"validationActions"` + Message string `json:"message"` + Policy string `json:"policy"` + Binding string `json:"binding"` + ExpressionIndex int `json:"expressionIndex"` + ValidationActions []admissionregistrationv1.ValidationAction `json:"validationActions"` } type auditAnnotationCollector struct { diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/plugin.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/plugin.go index 2fae52d197d..c286cffbdc8 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/plugin.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/plugin.go @@ -21,7 +21,6 @@ import ( "io" v1 "k8s.io/api/admissionregistration/v1" - "k8s.io/api/admissionregistration/v1beta1" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/initializer" @@ -62,8 +61,8 @@ func Register(plugins *admission.Plugins) { } // Plugin is an implementation of admission.Interface. -type Policy = v1beta1.ValidatingAdmissionPolicy -type PolicyBinding = v1beta1.ValidatingAdmissionPolicyBinding +type Policy = v1.ValidatingAdmissionPolicy +type PolicyBinding = v1.ValidatingAdmissionPolicyBinding type PolicyEvaluator = Validator type PolicyHook = generic.PolicyHook[*Policy, *PolicyBinding, PolicyEvaluator] @@ -84,8 +83,8 @@ func NewPlugin(_ io.Reader) *Plugin { handler, func(f informers.SharedInformerFactory, client kubernetes.Interface, dynamicClient dynamic.Interface, restMapper meta.RESTMapper) generic.Source[PolicyHook] { return generic.NewPolicySource( - f.Admissionregistration().V1beta1().ValidatingAdmissionPolicies().Informer(), - f.Admissionregistration().V1beta1().ValidatingAdmissionPolicyBindings().Informer(), + f.Admissionregistration().V1().ValidatingAdmissionPolicies().Informer(), + f.Admissionregistration().V1().ValidatingAdmissionPolicyBindings().Informer(), NewValidatingAdmissionPolicyAccessor, NewValidatingAdmissionPolicyBindingAccessor, compilePolicy, @@ -117,7 +116,7 @@ func compilePolicy(policy *Policy) Validator { } optionalVars := cel.OptionalVariableDeclarations{HasParams: hasParam, HasAuthorizer: true} expressionOptionalVars := cel.OptionalVariableDeclarations{HasParams: hasParam, HasAuthorizer: false} - failurePolicy := convertv1beta1FailurePolicyTypeTov1FailurePolicyType(policy.Spec.FailurePolicy) + failurePolicy := policy.Spec.FailurePolicy var matcher matchconditions.Matcher = nil matchConditions := policy.Spec.MatchConditions @@ -132,31 +131,17 @@ func compilePolicy(policy *Policy) Validator { matcher = matchconditions.NewMatcher(filterCompiler.Compile(matchExpressionAccessors, optionalVars, environment.StoredExpressions), failurePolicy, "policy", "validate", policy.Name) } res := NewValidator( - filterCompiler.Compile(convertv1beta1Validations(policy.Spec.Validations), optionalVars, environment.StoredExpressions), + filterCompiler.Compile(convertv1Validations(policy.Spec.Validations), optionalVars, environment.StoredExpressions), matcher, - filterCompiler.Compile(convertv1beta1AuditAnnotations(policy.Spec.AuditAnnotations), optionalVars, environment.StoredExpressions), - filterCompiler.Compile(convertv1beta1MessageExpressions(policy.Spec.Validations), expressionOptionalVars, environment.StoredExpressions), + filterCompiler.Compile(convertv1AuditAnnotations(policy.Spec.AuditAnnotations), optionalVars, environment.StoredExpressions), + filterCompiler.Compile(convertv1MessageExpressions(policy.Spec.Validations), expressionOptionalVars, environment.StoredExpressions), failurePolicy, ) return res } -func convertv1beta1FailurePolicyTypeTov1FailurePolicyType(policyType *v1beta1.FailurePolicyType) *v1.FailurePolicyType { - if policyType == nil { - return nil - } - - var v1FailPolicy v1.FailurePolicyType - if *policyType == v1beta1.Fail { - v1FailPolicy = v1.Fail - } else if *policyType == v1beta1.Ignore { - v1FailPolicy = v1.Ignore - } - return &v1FailPolicy -} - -func convertv1beta1Validations(inputValidations []v1beta1.Validation) []cel.ExpressionAccessor { +func convertv1Validations(inputValidations []v1.Validation) []cel.ExpressionAccessor { celExpressionAccessor := make([]cel.ExpressionAccessor, len(inputValidations)) for i, validation := range inputValidations { validation := ValidationCondition{ @@ -169,7 +154,7 @@ func convertv1beta1Validations(inputValidations []v1beta1.Validation) []cel.Expr return celExpressionAccessor } -func convertv1beta1MessageExpressions(inputValidations []v1beta1.Validation) []cel.ExpressionAccessor { +func convertv1MessageExpressions(inputValidations []v1.Validation) []cel.ExpressionAccessor { celExpressionAccessor := make([]cel.ExpressionAccessor, len(inputValidations)) for i, validation := range inputValidations { if validation.MessageExpression != "" { @@ -182,7 +167,7 @@ func convertv1beta1MessageExpressions(inputValidations []v1beta1.Validation) []c return celExpressionAccessor } -func convertv1beta1AuditAnnotations(inputValidations []v1beta1.AuditAnnotation) []cel.ExpressionAccessor { +func convertv1AuditAnnotations(inputValidations []v1.AuditAnnotation) []cel.ExpressionAccessor { celExpressionAccessor := make([]cel.ExpressionAccessor, len(inputValidations)) for i, validation := range inputValidations { validation := AuditAnnotationCondition{ @@ -194,7 +179,7 @@ func convertv1beta1AuditAnnotations(inputValidations []v1beta1.AuditAnnotation) return celExpressionAccessor } -func convertv1beta1Variables(variables []v1beta1.Variable) []cel.NamedExpressionAccessor { +func convertv1beta1Variables(variables []v1.Variable) []cel.NamedExpressionAccessor { namedExpressions := make([]cel.NamedExpressionAccessor, len(variables)) for i, variable := range variables { namedExpressions[i] = &Variable{Name: variable.Name, Expression: variable.Expression} diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/typechecking.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/typechecking.go index d54d3b667ab..16184b4badd 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/typechecking.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/typechecking.go @@ -25,7 +25,7 @@ import ( "github.com/google/cel-go/cel" - "k8s.io/api/admissionregistration/v1beta1" + "k8s.io/api/admissionregistration/v1" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -57,7 +57,7 @@ type TypeCheckingContext struct { paramGVK schema.GroupVersionKind paramDeclType *apiservercel.DeclType - variables []v1beta1.Variable + variables []v1.Variable } type typeOverwrite struct { @@ -105,18 +105,18 @@ func (r *TypeCheckingResult) String() string { // as []ExpressionWarning that is ready to be set in policy.Status // The result is nil if type checking returns no warning. // The policy object is NOT mutated. The caller should update Status accordingly -func (c *TypeChecker) Check(policy *v1beta1.ValidatingAdmissionPolicy) []v1beta1.ExpressionWarning { +func (c *TypeChecker) Check(policy *v1.ValidatingAdmissionPolicy) []v1.ExpressionWarning { ctx := c.CreateContext(policy) // warnings to return, note that the capacity is optimistically set to zero - var warnings []v1beta1.ExpressionWarning // intentionally not setting capacity + var warnings []v1.ExpressionWarning // intentionally not setting capacity // check main validation expressions and their message expressions, located in spec.validations[*] fieldRef := field.NewPath("spec", "validations") for i, v := range policy.Spec.Validations { results := c.CheckExpression(ctx, v.Expression) if len(results) != 0 { - warnings = append(warnings, v1beta1.ExpressionWarning{ + warnings = append(warnings, v1.ExpressionWarning{ FieldRef: fieldRef.Index(i).Child("expression").String(), Warning: results.String(), }) @@ -127,7 +127,7 @@ func (c *TypeChecker) Check(policy *v1beta1.ValidatingAdmissionPolicy) []v1beta1 } results = c.CheckExpression(ctx, v.MessageExpression) if len(results) != 0 { - warnings = append(warnings, v1beta1.ExpressionWarning{ + warnings = append(warnings, v1.ExpressionWarning{ FieldRef: fieldRef.Index(i).Child("messageExpression").String(), Warning: results.String(), }) @@ -138,7 +138,7 @@ func (c *TypeChecker) Check(policy *v1beta1.ValidatingAdmissionPolicy) []v1beta1 } // CreateContext resolves all types and their schemas from a policy definition and creates the context. -func (c *TypeChecker) CreateContext(policy *v1beta1.ValidatingAdmissionPolicy) *TypeCheckingContext { +func (c *TypeChecker) CreateContext(policy *v1.ValidatingAdmissionPolicy) *TypeCheckingContext { ctx := new(TypeCheckingContext) allGvks := c.typesToCheck(policy) gvks := make([]schema.GroupVersionKind, 0, len(allGvks)) @@ -250,7 +250,7 @@ func (c *TypeChecker) declType(gvk schema.GroupVersionKind) (*apiservercel.DeclT return common.SchemaDeclType(&openapi.Schema{Schema: s}, true).MaybeAssignTypeName(generateUniqueTypeName(gvk.Kind)), nil } -func (c *TypeChecker) paramsGVK(policy *v1beta1.ValidatingAdmissionPolicy) schema.GroupVersionKind { +func (c *TypeChecker) paramsGVK(policy *v1.ValidatingAdmissionPolicy) schema.GroupVersionKind { if policy.Spec.ParamKind == nil { return schema.GroupVersionKind{} } @@ -263,7 +263,7 @@ func (c *TypeChecker) paramsGVK(policy *v1beta1.ValidatingAdmissionPolicy) schem // typesToCheck extracts a list of GVKs that needs type checking from the policy // the result is sorted in the order of Group, Version, and Kind -func (c *TypeChecker) typesToCheck(p *v1beta1.ValidatingAdmissionPolicy) []schema.GroupVersionKind { +func (c *TypeChecker) typesToCheck(p *v1.ValidatingAdmissionPolicy) []schema.GroupVersionKind { gvks := sets.New[schema.GroupVersionKind]() if p.Spec.MatchConstraints == nil || len(p.Spec.MatchConstraints.ResourceRules) == 0 { return nil @@ -333,7 +333,7 @@ func (c *TypeChecker) typesToCheck(p *v1beta1.ValidatingAdmissionPolicy) []schem return sortGVKList(gvks.UnsortedList()) } -func extractGroups(rule *v1beta1.Rule) []string { +func extractGroups(rule *v1.Rule) []string { groups := make([]string, 0, len(rule.APIGroups)) for _, group := range rule.APIGroups { // give up if wildcard @@ -345,7 +345,7 @@ func extractGroups(rule *v1beta1.Rule) []string { return groups } -func extractVersions(rule *v1beta1.Rule) []string { +func extractVersions(rule *v1.Rule) []string { versions := make([]string, 0, len(rule.APIVersions)) for _, version := range rule.APIVersions { if strings.ContainsAny(version, "*") { @@ -356,7 +356,7 @@ func extractVersions(rule *v1beta1.Rule) []string { return versions } -func extractResources(rule *v1beta1.Rule) []string { +func extractResources(rule *v1.Rule) []string { resources := make([]string, 0, len(rule.Resources)) for _, resource := range rule.Resources { // skip wildcard and subresources diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/typechecking_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/typechecking_test.go index 31e9a129909..4da14b92912 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/typechecking_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/policy/validating/typechecking_test.go @@ -22,7 +22,7 @@ import ( "strings" "testing" - "k8s.io/api/admissionregistration/v1beta1" + "k8s.io/api/admissionregistration/v1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" @@ -36,7 +36,7 @@ import ( var ( scheme *runtime.Scheme = func() *runtime.Scheme { res := runtime.NewScheme() - if err := v1beta1.AddToScheme(res); err != nil { + if err := v1.AddToScheme(res); err != nil { panic(err) } @@ -58,21 +58,21 @@ func must3[T any, I any](val T, _ I, err error) T { func TestExtractTypeNames(t *testing.T) { for _, tc := range []struct { name string - policy *v1beta1.ValidatingAdmissionPolicy + policy *v1.ValidatingAdmissionPolicy expected []schema.GroupVersionKind // must be sorted }{ { name: "empty", - policy: &v1beta1.ValidatingAdmissionPolicy{}, + policy: &v1.ValidatingAdmissionPolicy{}, expected: nil, }, { name: "specific", - policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ + policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, @@ -89,19 +89,19 @@ func TestExtractTypeNames(t *testing.T) { }, { name: "multiple", - policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ + policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, }, }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{""}, APIVersions: []string{"v1"}, Resources: []string{"pods"}, @@ -122,11 +122,11 @@ func TestExtractTypeNames(t *testing.T) { }, { name: "all resources", - policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ + policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"*"}, @@ -139,11 +139,11 @@ func TestExtractTypeNames(t *testing.T) { }, { name: "sub resources", - policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ + policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"pods/*"}, @@ -156,11 +156,11 @@ func TestExtractTypeNames(t *testing.T) { }, { name: "mixtures", - policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ + policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, @@ -168,8 +168,8 @@ func TestExtractTypeNames(t *testing.T) { }, }, { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"*"}, Resources: []string{"deployments"}, @@ -196,16 +196,16 @@ func TestExtractTypeNames(t *testing.T) { } func TestTypeCheck(t *testing.T) { - deploymentPolicy := &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - Validations: []v1beta1.Validation{ + deploymentPolicy := &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + Validations: []v1.Validation{ { Expression: "object.foo == 'bar'", }, }, - MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ + MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, @@ -218,8 +218,8 @@ func TestTypeCheck(t *testing.T) { deploymentPolicyWithBadMessageExpression := deploymentPolicy.DeepCopy() deploymentPolicyWithBadMessageExpression.Spec.Validations[0].MessageExpression = "object.foo + 114514" // confusion - multiExpressionPolicy := &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - Validations: []v1beta1.Validation{ + multiExpressionPolicy := &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + Validations: []v1.Validation{ { Expression: "object.foo == 'bar'", }, @@ -227,10 +227,10 @@ func TestTypeCheck(t *testing.T) { Expression: "object.bar == 'foo'", }, }, - MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ + MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, @@ -239,20 +239,20 @@ func TestTypeCheck(t *testing.T) { }, }}, }} - paramsRefPolicy := &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - ParamKind: &v1beta1.ParamKind{ + paramsRefPolicy := &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + ParamKind: &v1.ParamKind{ APIVersion: "v1", Kind: "DoesNotMatter", }, - Validations: []v1beta1.Validation{ + Validations: []v1.Validation{ { Expression: "object.foo == params.bar", }, }, - MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ + MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, @@ -261,16 +261,16 @@ func TestTypeCheck(t *testing.T) { }, }}, }} - authorizerPolicy := &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - Validations: []v1beta1.Validation{ + authorizerPolicy := &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + Validations: []v1.Validation{ { Expression: "authorizer.group('').resource('endpoints').check('create').allowed()", }, }, - MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ + MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, @@ -279,16 +279,16 @@ func TestTypeCheck(t *testing.T) { }, }}, }} - authorizerInvalidPolicy := &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - Validations: []v1beta1.Validation{ + authorizerInvalidPolicy := &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + Validations: []v1.Validation{ { Expression: "authorizer.allowed()", }, }, - MatchConstraints: &v1beta1.MatchResources{ResourceRules: []v1beta1.NamedRuleWithOperations{ + MatchConstraints: &v1.MatchResources{ResourceRules: []v1.NamedRuleWithOperations{ { - RuleWithOperations: v1beta1.RuleWithOperations{ - Rule: v1beta1.Rule{ + RuleWithOperations: v1.RuleWithOperations{ + Rule: v1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, @@ -300,12 +300,12 @@ func TestTypeCheck(t *testing.T) { for _, tc := range []struct { name string schemaToReturn *spec.Schema - policy *v1beta1.ValidatingAdmissionPolicy + policy *v1.ValidatingAdmissionPolicy assertions []assertionFunc }{ { name: "empty", - policy: &v1beta1.ValidatingAdmissionPolicy{}, + policy: &v1.ValidatingAdmissionPolicy{}, assertions: []assertionFunc{toBeEmpty}, }, { @@ -439,14 +439,14 @@ func TestTypeCheck(t *testing.T) { }, { name: "variables valid", - policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - Variables: []v1beta1.Variable{ + policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + Variables: []v1.Variable{ { Name: "works", Expression: "true", }, }, - Validations: []v1beta1.Validation{ + Validations: []v1.Validation{ { Expression: "variables.works", }, @@ -466,14 +466,14 @@ func TestTypeCheck(t *testing.T) { }, { name: "variables missing field", - policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - Variables: []v1beta1.Variable{ + policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + Variables: []v1.Variable{ { Name: "works", Expression: "true", }, }, - Validations: []v1beta1.Validation{ + Validations: []v1.Validation{ { Expression: "variables.nonExisting", }, @@ -497,14 +497,14 @@ func TestTypeCheck(t *testing.T) { }, { name: "variables field wrong type", - policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - Variables: []v1beta1.Variable{ + policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + Variables: []v1.Variable{ { Name: "name", Expression: "'something'", }, }, - Validations: []v1beta1.Validation{ + Validations: []v1.Validation{ { Expression: "variables.name == object.foo", // foo is int64 }, @@ -528,14 +528,14 @@ func TestTypeCheck(t *testing.T) { }, { name: "error in variables, not reported during type checking.", - policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{ - Variables: []v1beta1.Variable{ + policy: &v1.ValidatingAdmissionPolicy{Spec: v1.ValidatingAdmissionPolicySpec{ + Variables: []v1.Variable{ { Name: "name", Expression: "object.foo == 'str'", }, }, - Validations: []v1beta1.Validation{ + Validations: []v1.Validation{ { Expression: "variables.name == object.foo", // foo is int64 }, @@ -593,14 +593,14 @@ func (r *fakeSchemaResolver) ResolveSchema(gvk schema.GroupVersionKind) (*spec.S return r.schemaToReturn, nil } -func toBeEmpty(warnings []v1beta1.ExpressionWarning, t *testing.T) { +func toBeEmpty(warnings []v1.ExpressionWarning, t *testing.T) { if len(warnings) != 0 { t.Fatalf("expected empty but got %v", warnings) } } -func toContain(substring string) func(warnings []v1beta1.ExpressionWarning, t *testing.T) { - return func(warnings []v1beta1.ExpressionWarning, t *testing.T) { +func toContain(substring string) func(warnings []v1.ExpressionWarning, t *testing.T) { + return func(warnings []v1.ExpressionWarning, t *testing.T) { if len(warnings) == 0 { t.Errorf("expected containing %q but got empty", substring) } @@ -612,8 +612,8 @@ func toContain(substring string) func(warnings []v1beta1.ExpressionWarning, t *t } } -func toHaveLengthOf(expected int) func(warnings []v1beta1.ExpressionWarning, t *testing.T) { - return func(warnings []v1beta1.ExpressionWarning, t *testing.T) { +func toHaveLengthOf(expected int) func(warnings []v1.ExpressionWarning, t *testing.T) { + return func(warnings []v1.ExpressionWarning, t *testing.T) { got := len(warnings) if expected != got { t.Errorf("expect warnings to have length of %d, but got %d", expected, got) @@ -621,8 +621,8 @@ func toHaveLengthOf(expected int) func(warnings []v1beta1.ExpressionWarning, t * } } -func toHaveFieldRef(paths ...string) func(warnings []v1beta1.ExpressionWarning, t *testing.T) { - return func(warnings []v1beta1.ExpressionWarning, t *testing.T) { +func toHaveFieldRef(paths ...string) func(warnings []v1.ExpressionWarning, t *testing.T) { + return func(warnings []v1.ExpressionWarning, t *testing.T) { if len(paths) != len(warnings) { t.Errorf("expect warnings to have length of %d, but got %d", len(paths), len(warnings)) } @@ -634,4 +634,4 @@ func toHaveFieldRef(paths ...string) func(warnings []v1beta1.ExpressionWarning, } } -type assertionFunc func(warnings []v1beta1.ExpressionWarning, t *testing.T) +type assertionFunc func(warnings []v1.ExpressionWarning, t *testing.T) diff --git a/staging/src/k8s.io/apiserver/pkg/features/kube_features.go b/staging/src/k8s.io/apiserver/pkg/features/kube_features.go index 0c1ad42c7a9..d40412cb9c2 100644 --- a/staging/src/k8s.io/apiserver/pkg/features/kube_features.go +++ b/staging/src/k8s.io/apiserver/pkg/features/kube_features.go @@ -101,7 +101,10 @@ const ( // owner: @cici37 @jpbetz // kep: http://kep.k8s.io/3488 // alpha: v1.26 + // beta: v1.28 + // stable: v1.30 // + // Note: the feature gate can be removed in 1.32 // Enables expression validation in Admission Control ValidatingAdmissionPolicy featuregate.Feature = "ValidatingAdmissionPolicy" @@ -309,7 +312,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS APIServingWithRoutine: {Default: true, PreRelease: featuregate.Beta}, - ValidatingAdmissionPolicy: {Default: false, PreRelease: featuregate.Beta}, + ValidatingAdmissionPolicy: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.32 CustomResourceValidationExpressions: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.31 diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/admission.go b/staging/src/k8s.io/apiserver/pkg/server/options/admission.go index 3f65a0d1f3f..542c81a8691 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/admission.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/admission.go @@ -19,12 +19,14 @@ package options import ( "fmt" "strings" + "time" "github.com/spf13/pflag" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" + utilwait "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/initializer" admissionmetrics "k8s.io/apiserver/pkg/admission/metrics" @@ -36,9 +38,11 @@ import ( apiserverapiv1 "k8s.io/apiserver/pkg/apis/apiserver/v1" apiserverapiv1alpha1 "k8s.io/apiserver/pkg/apis/apiserver/v1alpha1" "k8s.io/apiserver/pkg/server" + cacheddiscovery "k8s.io/client-go/discovery/cached/memory" "k8s.io/client-go/dynamic" "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" + "k8s.io/client-go/restmapper" "k8s.io/component-base/featuregate" ) @@ -143,11 +147,24 @@ func (a *AdmissionOptions) ApplyTo( return fmt.Errorf("failed to read plugin config: %v", err) } + discoveryClient := cacheddiscovery.NewMemCacheClient(kubeClient.Discovery()) + discoveryRESTMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) genericInitializer := initializer.New(kubeClient, dynamicClient, informers, c.Authorization.Authorizer, features, - c.DrainedNotify()) + c.DrainedNotify(), discoveryRESTMapper) initializersChain := admission.PluginInitializers{genericInitializer} initializersChain = append(initializersChain, pluginInitializers...) + admissionPostStartHook := func(context server.PostStartHookContext) error { + discoveryRESTMapper.Reset() + go utilwait.Until(discoveryRESTMapper.Reset, 30*time.Second, context.StopCh) + return nil + } + + err = c.AddPostStartHook("start-apiserver-admission-initializer", admissionPostStartHook) + if err != nil { + return fmt.Errorf("failed to add post start hook for policy admission: %w", err) + } + admissionChain, err := a.Plugins.NewFromPlugins(pluginNames, pluginsConfigProvider, initializersChain, a.Decorators) if err != nil { return err diff --git a/test/e2e/apimachinery/health_handlers.go b/test/e2e/apimachinery/health_handlers.go index 2c6190c0c86..ca64adb337e 100644 --- a/test/e2e/apimachinery/health_handlers.go +++ b/test/e2e/apimachinery/health_handlers.go @@ -37,7 +37,7 @@ var ( "[+]ping ok", "[+]log ok", "[+]etcd ok", - "[+]poststarthook/start-kube-apiserver-admission-initializer ok", + "[+]poststarthook/start-apiserver-admission-initializer ok", "[+]poststarthook/generic-apiserver-start-informers ok", "[+]poststarthook/start-apiextensions-informers ok", "[+]poststarthook/start-apiextensions-controllers ok", @@ -58,7 +58,7 @@ var ( "[+]ping ok", "[+]log ok", "[+]etcd ok", - "[+]poststarthook/start-kube-apiserver-admission-initializer ok", + "[+]poststarthook/start-apiserver-admission-initializer ok", "[+]poststarthook/generic-apiserver-start-informers ok", "[+]poststarthook/start-apiextensions-informers ok", "[+]poststarthook/start-apiextensions-controllers ok", @@ -80,7 +80,7 @@ var ( "[+]log ok", "[+]etcd ok", "[+]informer-sync ok", - "[+]poststarthook/start-kube-apiserver-admission-initializer ok", + "[+]poststarthook/start-apiserver-admission-initializer ok", "[+]poststarthook/generic-apiserver-start-informers ok", "[+]poststarthook/start-apiextensions-informers ok", "[+]poststarthook/start-apiextensions-controllers ok", diff --git a/test/e2e/apimachinery/validatingadmissionpolicy.go b/test/e2e/apimachinery/validatingadmissionpolicy.go index d7fdea3ea64..68e99221ec8 100644 --- a/test/e2e/apimachinery/validatingadmissionpolicy.go +++ b/test/e2e/apimachinery/validatingadmissionpolicy.go @@ -18,14 +18,12 @@ package apimachinery import ( "context" - "fmt" "time" "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -52,11 +50,6 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame var err error client, err = clientset.NewForConfig(f.ClientConfig()) framework.ExpectNoError(err, "initializing client") - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().List(context.Background(), metav1.ListOptions{}) - if apierrors.IsNotFound(err) { - // TODO: feature check should fail after GA graduation - ginkgo.Skip(fmt.Sprintf("server does not support ValidatingAdmissionPolicy v1beta1: %v, feature gate not enabled?", err)) - } extensionsClient, err = apiextensionsclientset.NewForConfig(f.ClientConfig()) framework.ExpectNoError(err, "initializing api-extensions client") }) @@ -76,25 +69,25 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame StartResourceRule(). MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). EndResourceRule(). - WithValidation(admissionregistrationv1beta1.Validation{ + WithValidation(admissionregistrationv1.Validation{ Expression: "object.spec.replicas > 1", MessageExpression: "'wants replicas > 1, got ' + object.spec.replicas", }). - WithValidation(admissionregistrationv1beta1.Validation{ + WithValidation(admissionregistrationv1.Validation{ Expression: "namespaceObject.metadata.name == '" + f.UniqueName + "'", Message: "Internal error! Other namespace should not be allowed.", }). Build() - policy, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) + policy, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) framework.ExpectNoError(err, "create policy") ginkgo.DeferCleanup(func(ctx context.Context, name string) error { - return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) + return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) }, policy.Name) binding := createBinding(f.UniqueName+".binding.example.com", f.UniqueName, policy.Name) - binding, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Create(ctx, binding, metav1.CreateOptions{}) + binding, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Create(ctx, binding, metav1.CreateOptions{}) framework.ExpectNoError(err, "create policy binding") ginkgo.DeferCleanup(func(ctx context.Context, name string) error { - return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Delete(ctx, name, metav1.DeleteOptions{}) + return client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Delete(ctx, name, metav1.DeleteOptions{}) }, binding.Name) }) ginkgo.By("waiting until the marker is denied", func() { @@ -127,27 +120,27 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame }) ginkgo.It("should type check validation expressions", func(ctx context.Context) { - var policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy + var policy *admissionregistrationv1.ValidatingAdmissionPolicy ginkgo.By("creating the policy with correct types", func() { policy = newValidatingAdmissionPolicyBuilder(f.UniqueName+".correct-policy.example.com"). MatchUniqueNamespace(f.UniqueName). StartResourceRule(). MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). EndResourceRule(). - WithValidation(admissionregistrationv1beta1.Validation{ + WithValidation(admissionregistrationv1.Validation{ Expression: "object.spec.replicas > 1", }). Build() var err error - policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) + policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) framework.ExpectNoError(err, "create policy") ginkgo.DeferCleanup(func(ctx context.Context, name string) error { - return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) + return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) }, policy.Name) }) ginkgo.By("waiting for the type check to finish without any warnings", func() { err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { - policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) + policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) if err != nil { return false, err } @@ -165,21 +158,21 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame StartResourceRule(). MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). EndResourceRule(). - WithValidation(admissionregistrationv1beta1.Validation{ + WithValidation(admissionregistrationv1.Validation{ Expression: "object.spec.replicas > '1'", // confusion: int > string MessageExpression: "'wants replicas > 1, got ' + object.spec.replicas", // confusion: string + int }). Build() var err error - policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) + policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) framework.ExpectNoError(err, "create policy") ginkgo.DeferCleanup(func(ctx context.Context, name string) error { - return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) + return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) }, policy.Name) }) ginkgo.By("waiting for the type check to finish with warnings", func() { err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { - policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) + policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) if err != nil { return false, err } @@ -208,31 +201,31 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame StartResourceRule(). MatchResource([]string{"apps"}, []string{"v1"}, []string{"deployments"}). EndResourceRule(). - WithVariable(admissionregistrationv1beta1.Variable{ + WithVariable(admissionregistrationv1.Variable{ Name: "replicas", Expression: "object.spec.replicas", }). - WithVariable(admissionregistrationv1beta1.Variable{ + WithVariable(admissionregistrationv1.Variable{ Name: "oddReplicas", Expression: "variables.replicas % 2 == 1", }). - WithValidation(admissionregistrationv1beta1.Validation{ + WithValidation(admissionregistrationv1.Validation{ Expression: "variables.replicas > 1", }). - WithValidation(admissionregistrationv1beta1.Validation{ + WithValidation(admissionregistrationv1.Validation{ Expression: "variables.oddReplicas", }). Build() - policy, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) + policy, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) framework.ExpectNoError(err, "create policy") ginkgo.DeferCleanup(func(ctx context.Context, name string) error { - return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) + return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) }, policy.Name) binding := createBinding(f.UniqueName+".binding.example.com", f.UniqueName, policy.Name) - binding, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Create(ctx, binding, metav1.CreateOptions{}) + binding, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Create(ctx, binding, metav1.CreateOptions{}) framework.ExpectNoError(err, "create policy binding") ginkgo.DeferCleanup(func(ctx context.Context, name string) error { - return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Delete(ctx, name, metav1.DeleteOptions{}) + return client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Delete(ctx, name, metav1.DeleteOptions{}) }, binding.Name) }) ginkgo.By("waiting until the marker is denied", func() { @@ -268,7 +261,7 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame crd := crontabExampleCRD() crd.Spec.Group = "stable." + f.UniqueName crd.Name = crd.Spec.Names.Plural + "." + crd.Spec.Group - var policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy + var policy *admissionregistrationv1.ValidatingAdmissionPolicy ginkgo.By("creating the CRD", func() { var err error crd, err = extensionsClient.ApiextensionsV1().CustomResourceDefinitions().Create(ctx, crd, metav1.CreateOptions{}) @@ -290,19 +283,19 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame StartResourceRule(). MatchResource([]string{crd.Spec.Group}, []string{"v1"}, []string{"crontabs"}). EndResourceRule(). - WithValidation(admissionregistrationv1beta1.Validation{ + WithValidation(admissionregistrationv1.Validation{ Expression: "object.spec.replicas > 1", }). Build() - policy, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) + policy, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) framework.ExpectNoError(err, "create policy") ginkgo.DeferCleanup(func(ctx context.Context, name string) error { - return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) + return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) }, policy.Name) }) ginkgo.By("waiting for the type check to finish without warnings", func() { err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { - policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) + policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) if err != nil { return false, err } @@ -320,22 +313,22 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame StartResourceRule(). MatchResource([]string{crd.Spec.Group}, []string{"v1"}, []string{"crontabs"}). EndResourceRule(). - WithValidation(admissionregistrationv1beta1.Validation{ + WithValidation(admissionregistrationv1.Validation{ Expression: "object.spec.replicas > '1'", // type confusion }). - WithValidation(admissionregistrationv1beta1.Validation{ + WithValidation(admissionregistrationv1.Validation{ Expression: "object.spec.maxRetries < 10", // not yet existing field }). Build() - policy, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) + policy, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, policy, metav1.CreateOptions{}) framework.ExpectNoError(err, "create policy") ginkgo.DeferCleanup(func(ctx context.Context, name string) error { - return client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) + return client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(ctx, name, metav1.DeleteOptions{}) }, policy.Name) }) ginkgo.By("waiting for the type check to finish with warnings", func() { err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (done bool, err error) { - policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) + policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(ctx, policy.Name, metav1.GetOptions{}) if err != nil { return false, err } @@ -357,17 +350,17 @@ var _ = SIGDescribe("ValidatingAdmissionPolicy [Privileged:ClusterAdmin]", frame }) }) -func createBinding(bindingName string, uniqueLabel string, policyName string) *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding { - return &admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding{ +func createBinding(bindingName string, uniqueLabel string, policyName string) *admissionregistrationv1.ValidatingAdmissionPolicyBinding { + return &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ ObjectMeta: metav1.ObjectMeta{Name: bindingName}, - Spec: admissionregistrationv1beta1.ValidatingAdmissionPolicyBindingSpec{ + Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ PolicyName: policyName, - MatchResources: &admissionregistrationv1beta1.MatchResources{ + MatchResources: &admissionregistrationv1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{uniqueLabel: "true"}, }, }, - ValidationActions: []admissionregistrationv1beta1.ValidationAction{admissionregistrationv1beta1.Deny}, + ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny}, }, } } @@ -427,17 +420,17 @@ func basicReplicaSet(name string, replicas int32) *appsv1.ReplicaSet { } type validatingAdmissionPolicyBuilder struct { - policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy + policy *admissionregistrationv1.ValidatingAdmissionPolicy } type resourceRuleBuilder struct { policyBuilder *validatingAdmissionPolicyBuilder - resourceRule *admissionregistrationv1beta1.NamedRuleWithOperations + resourceRule *admissionregistrationv1.NamedRuleWithOperations } func newValidatingAdmissionPolicyBuilder(policyName string) *validatingAdmissionPolicyBuilder { return &validatingAdmissionPolicyBuilder{ - policy: &admissionregistrationv1beta1.ValidatingAdmissionPolicy{ + policy: &admissionregistrationv1.ValidatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: policyName}, }, } @@ -445,7 +438,7 @@ func newValidatingAdmissionPolicyBuilder(policyName string) *validatingAdmission func (b *validatingAdmissionPolicyBuilder) MatchUniqueNamespace(uniqueLabel string) *validatingAdmissionPolicyBuilder { if b.policy.Spec.MatchConstraints == nil { - b.policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{} + b.policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{} } b.policy.Spec.MatchConstraints.NamespaceSelector = &metav1.LabelSelector{ MatchLabels: map[string]string{ @@ -458,10 +451,10 @@ func (b *validatingAdmissionPolicyBuilder) MatchUniqueNamespace(uniqueLabel stri func (b *validatingAdmissionPolicyBuilder) StartResourceRule() *resourceRuleBuilder { return &resourceRuleBuilder{ policyBuilder: b, - resourceRule: &admissionregistrationv1beta1.NamedRuleWithOperations{ - RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ + resourceRule: &admissionregistrationv1.NamedRuleWithOperations{ + RuleWithOperations: admissionregistrationv1.RuleWithOperations{ Operations: []admissionregistrationv1.OperationType{admissionregistrationv1.Create, admissionregistrationv1.Update}, - Rule: admissionregistrationv1beta1.Rule{ + Rule: admissionregistrationv1.Rule{ APIGroups: []string{"apps"}, APIVersions: []string{"v1"}, Resources: []string{"deployments"}, @@ -477,7 +470,7 @@ func (rb *resourceRuleBuilder) CreateAndUpdate() *resourceRuleBuilder { } func (rb *resourceRuleBuilder) MatchResource(groups []string, versions []string, resources []string) *resourceRuleBuilder { - rb.resourceRule.Rule = admissionregistrationv1beta1.Rule{ + rb.resourceRule.Rule = admissionregistrationv1.Rule{ APIGroups: groups, APIVersions: versions, Resources: resources, @@ -488,23 +481,23 @@ func (rb *resourceRuleBuilder) MatchResource(groups []string, versions []string, func (rb *resourceRuleBuilder) EndResourceRule() *validatingAdmissionPolicyBuilder { b := rb.policyBuilder if b.policy.Spec.MatchConstraints == nil { - b.policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{} + b.policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{} } b.policy.Spec.MatchConstraints.ResourceRules = append(b.policy.Spec.MatchConstraints.ResourceRules, *rb.resourceRule) return b } -func (b *validatingAdmissionPolicyBuilder) WithValidation(validation admissionregistrationv1beta1.Validation) *validatingAdmissionPolicyBuilder { +func (b *validatingAdmissionPolicyBuilder) WithValidation(validation admissionregistrationv1.Validation) *validatingAdmissionPolicyBuilder { b.policy.Spec.Validations = append(b.policy.Spec.Validations, validation) return b } -func (b *validatingAdmissionPolicyBuilder) WithVariable(variable admissionregistrationv1beta1.Variable) *validatingAdmissionPolicyBuilder { +func (b *validatingAdmissionPolicyBuilder) WithVariable(variable admissionregistrationv1.Variable) *validatingAdmissionPolicyBuilder { b.policy.Spec.Variables = append(b.policy.Spec.Variables, variable) return b } -func (b *validatingAdmissionPolicyBuilder) Build() *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func (b *validatingAdmissionPolicyBuilder) Build() *admissionregistrationv1.ValidatingAdmissionPolicy { return b.policy } diff --git a/test/integration/apiserver/admissionwebhook/admission_test.go b/test/integration/apiserver/admissionwebhook/admission_test.go index bd3d113117c..3ab0e8f5916 100644 --- a/test/integration/apiserver/admissionwebhook/admission_test.go +++ b/test/integration/apiserver/admissionwebhook/admission_test.go @@ -145,6 +145,9 @@ var ( gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"): true, gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies/status"): true, gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicybindings"): true, + gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"): true, + gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies/status"): true, + gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicybindings"): true, } parentResources = map[schema.GroupVersionResource]schema.GroupVersionResource{ diff --git a/test/integration/apiserver/apply/reset_fields_test.go b/test/integration/apiserver/apply/reset_fields_test.go index c80e4847ca3..35aa16d56fb 100644 --- a/test/integration/apiserver/apply/reset_fields_test.go +++ b/test/integration/apiserver/apply/reset_fields_test.go @@ -65,6 +65,7 @@ var resetFieldsStatusData = map[schema.GroupVersionResource]string{ // standard for []metav1.Condition gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, + gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, gvr("networking.k8s.io", "v1alpha1", "servicecidrs"): `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, } @@ -156,6 +157,7 @@ var resetFieldsSpecData = map[schema.GroupVersionResource]string{ gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): `{}`, gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"metadata": {"labels": {"a":"c"}}, "spec": {"paramKind": {"apiVersion": "apps/v1", "kind": "Deployment"}}}`, gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"): `{"metadata": {"labels": {"a":"c"}}, "spec": {"paramKind": {"apiVersion": "apps/v1", "kind": "Deployment"}}}`, + gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"): `{"metadata": {"labels": {"a":"c"}}, "spec": {"paramKind": {"apiVersion": "apps/v1", "kind": "Deployment"}}}`, } // TestResetFields makes sure that fieldManager does not own fields reset by the storage strategy. diff --git a/test/integration/apiserver/apply/status_test.go b/test/integration/apiserver/apply/status_test.go index 4bfb625a9bc..efae4a5cfa9 100644 --- a/test/integration/apiserver/apply/status_test.go +++ b/test/integration/apiserver/apply/status_test.go @@ -58,6 +58,7 @@ var statusData = map[schema.GroupVersionResource]string{ // standard for []metav1.Condition gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, + gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`, } const statusDefault = `{"status": {"conditions": [{"type": "MyStatus", "status":"True"}]}}` diff --git a/test/integration/apiserver/cel/admission_test_util.go b/test/integration/apiserver/cel/admission_test_util.go index 4e281d02739..9917c61b0bb 100644 --- a/test/integration/apiserver/cel/admission_test_util.go +++ b/test/integration/apiserver/cel/admission_test_util.go @@ -143,6 +143,9 @@ var ( gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies"): true, gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicies/status"): true, gvr("admissionregistration.k8s.io", "v1beta1", "validatingadmissionpolicybindings"): true, + gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"): true, + gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies/status"): true, + gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicybindings"): true, // transient resource exemption gvr("authentication.k8s.io", "v1", "selfsubjectreviews"): true, gvr("authentication.k8s.io", "v1beta1", "selfsubjectreviews"): true, diff --git a/test/integration/apiserver/cel/validatingadmissionpolicy_test.go b/test/integration/apiserver/cel/validatingadmissionpolicy_test.go index 9ee7594a3d1..4daedd8b901 100644 --- a/test/integration/apiserver/cel/validatingadmissionpolicy_test.go +++ b/test/integration/apiserver/cel/validatingadmissionpolicy_test.go @@ -61,7 +61,6 @@ import ( clientset "k8s.io/client-go/kubernetes" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" - admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" authorizationv1 "k8s.io/api/authorization/v1" v1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -73,19 +72,19 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { testcases := []struct { name string - policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy - policyBinding *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding + policy *admissionregistrationv1.ValidatingAdmissionPolicy + policyBinding *admissionregistrationv1.ValidatingAdmissionPolicyBinding namespace *v1.Namespace err string failureReason metav1.StatusReason }{ { name: "namespace name contains suffix enforced by validating admission policy, using object metadata fields", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.endsWith('k8s')", }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), + }, withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -96,11 +95,11 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "namespace name does NOT contain suffix enforced by validating admission policyusing, object metadata fields", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.endsWith('k8s')", }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), + }, withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -112,12 +111,12 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "namespace name does NOT contain suffix enforced by validating admission policy using object metadata fields, AND validating expression returns StatusReasonForbidden", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.endsWith('k8s')", Reason: &forbiddenReason, }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), + }, withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -129,11 +128,11 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "namespace name contains suffix enforced by validating admission policy, using request field", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "request.name.endsWith('k8s')", }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), + }, withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -144,11 +143,11 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "namespace name does NOT contains suffix enforced by validating admission policy, using request field", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "request.name.endsWith('k8s')", }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), + }, withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -159,11 +158,11 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "runtime error when validating namespace, but failurePolicy=Ignore", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "object.nonExistentProperty == 'someval'", }, - }, withFailurePolicy(admissionregistrationv1beta1.Ignore, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), + }, withFailurePolicy(admissionregistrationv1.Ignore, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -174,11 +173,11 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "runtime error when validating namespace, but failurePolicy=Fail", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "object.nonExistentProperty == 'someval'", }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), + }, withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix")))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -190,11 +189,11 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "runtime error due to unguarded params", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.startsWith(params.metadata.name)", }, - }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), + }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -206,11 +205,11 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "with check against unguarded params using has()", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "has(params.metadata) && has(params.metadata.name) && object.metadata.name.endsWith(params.metadata.name)", }, - }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), + }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -222,11 +221,11 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "with check against null params", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "(params != null && object.metadata.name.endsWith(params.metadata.name))", }, - }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), + }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -238,11 +237,11 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "with check against unguarded params using has() and default check", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "(has(params.metadata) && has(params.metadata.name) && object.metadata.name.startsWith(params.metadata.name)) || object.metadata.name.endsWith('k8s')", }, - }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), + }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -253,11 +252,11 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "with check against null params and default check", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "(params != null && object.metadata.name.startsWith(params.metadata.name)) || object.metadata.name.endsWith('k8s')", }, - }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), + }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -268,11 +267,11 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { }, { name: "with check against namespaceObject", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "namespaceObject == null", // because namespace itself is cluster-scoped. }, - }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), + }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", ""), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -301,7 +300,7 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { t.Fatal(err) } policy := withWaitReadyConstraintAndExpression(testcase.policy) - if _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { + if _, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { t.Fatal(err) } if err := createAndWaitReady(t, client, testcase.policyBinding, nil); err != nil { @@ -318,8 +317,8 @@ func Test_ValidateNamespace_NoParams(t *testing.T) { func Test_ValidateAnnotationsAndWarnings(t *testing.T) { testcases := []struct { name string - policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy - policyBinding *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding + policy *admissionregistrationv1.ValidatingAdmissionPolicy + policyBinding *admissionregistrationv1.ValidatingAdmissionPolicyBinding object *v1.ConfigMap err string failureReason metav1.StatusReason @@ -328,7 +327,7 @@ func Test_ValidateAnnotationsAndWarnings(t *testing.T) { }{ { name: "with audit annotations", - policy: withAuditAnnotations([]admissionregistrationv1beta1.AuditAnnotation{ + policy: withAuditAnnotations([]admissionregistrationv1.AuditAnnotation{ { Key: "example-key", ValueExpression: "'object name: ' + object.metadata.name", @@ -337,7 +336,7 @@ func Test_ValidateAnnotationsAndWarnings(t *testing.T) { Key: "exclude-key", ValueExpression: "null", }, - }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1beta1.Fail, withConfigMapMatch(makePolicy("validate-audit-annotations"))))), + }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1.Fail, withConfigMapMatch(makePolicy("validate-audit-annotations"))))), policyBinding: makeBinding("validate-audit-annotations-binding", "validate-audit-annotations", ""), object: &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -351,12 +350,12 @@ func Test_ValidateAnnotationsAndWarnings(t *testing.T) { }, { name: "with audit annotations with invalid expression", - policy: withAuditAnnotations([]admissionregistrationv1beta1.AuditAnnotation{ + policy: withAuditAnnotations([]admissionregistrationv1.AuditAnnotation{ { Key: "example-key", ValueExpression: "string(params.metadata.name)", // runtime error, params is null }, - }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1beta1.Fail, withConfigMapMatch(makePolicy("validate-audit-annotations-invalid"))))), + }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1.Fail, withConfigMapMatch(makePolicy("validate-audit-annotations-invalid"))))), policyBinding: makeBinding("validate-audit-annotations-invalid-binding", "validate-audit-annotations-invalid", ""), object: &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -368,12 +367,12 @@ func Test_ValidateAnnotationsAndWarnings(t *testing.T) { }, { name: "with audit annotations with invalid expression and ignore failure policy", - policy: withAuditAnnotations([]admissionregistrationv1beta1.AuditAnnotation{ + policy: withAuditAnnotations([]admissionregistrationv1.AuditAnnotation{ { Key: "example-key", ValueExpression: "string(params.metadata.name)", // runtime error, params is null }, - }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1beta1.Ignore, withConfigMapMatch(makePolicy("validate-audit-annotations-invalid-ignore"))))), + }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1.Ignore, withConfigMapMatch(makePolicy("validate-audit-annotations-invalid-ignore"))))), policyBinding: makeBinding("validate-audit-annotations-invalid-ignore-binding", "validate-audit-annotations-invalid-ignore", ""), object: &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -384,12 +383,12 @@ func Test_ValidateAnnotationsAndWarnings(t *testing.T) { }, { name: "with warn validationActions", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.endsWith('k8s')", }, - }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1beta1.Fail, withConfigMapMatch(makePolicy("validate-actions-warn"))))), - policyBinding: withValidationActions([]admissionregistrationv1beta1.ValidationAction{admissionregistrationv1beta1.Warn}, makeBinding("validate-actions-warn-binding", "validate-actions-warn", "")), + }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1.Fail, withConfigMapMatch(makePolicy("validate-actions-warn"))))), + policyBinding: withValidationActions([]admissionregistrationv1.ValidationAction{admissionregistrationv1.Warn}, makeBinding("validate-actions-warn-binding", "validate-actions-warn", "")), object: &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: "test4-nope", @@ -399,12 +398,12 @@ func Test_ValidateAnnotationsAndWarnings(t *testing.T) { }, { name: "with audit validationActions", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.endsWith('k8s')", }, - }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1beta1.Fail, withConfigMapMatch(makePolicy("validate-actions-audit"))))), - policyBinding: withValidationActions([]admissionregistrationv1beta1.ValidationAction{admissionregistrationv1beta1.Deny, admissionregistrationv1beta1.Audit}, makeBinding("validate-actions-audit-binding", "validate-actions-audit", "")), + }, withParams(configParamKind(), withFailurePolicy(admissionregistrationv1.Fail, withConfigMapMatch(makePolicy("validate-actions-audit"))))), + policyBinding: withValidationActions([]admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny, admissionregistrationv1.Audit}, makeBinding("validate-actions-audit-binding", "validate-actions-audit", "")), object: &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: "test5-nope", @@ -471,7 +470,7 @@ func Test_ValidateAnnotationsAndWarnings(t *testing.T) { } policy := withWaitReadyConstraintAndExpression(testcase.policy) - if _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { + if _, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { t.Fatal(err) } @@ -505,8 +504,8 @@ func Test_ValidateAnnotationsAndWarnings(t *testing.T) { func Test_ValidateNamespace_WithConfigMapParams(t *testing.T) { testcases := []struct { name string - policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy - policyBinding *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding + policy *admissionregistrationv1.ValidatingAdmissionPolicy + policyBinding *admissionregistrationv1.ValidatingAdmissionPolicyBinding configMap *v1.ConfigMap namespace *v1.Namespace err string @@ -514,11 +513,11 @@ func Test_ValidateNamespace_WithConfigMapParams(t *testing.T) { }{ { name: "namespace name contains suffix enforced by validating admission policy", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.endsWith(params.data.namespaceSuffix)", }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, withParams(configParamKind(), withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), + }, withFailurePolicy(admissionregistrationv1.Fail, withParams(configParamKind(), withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", "validate-namespace-suffix-param"), configMap: makeConfigParams("validate-namespace-suffix-param", map[string]string{ "namespaceSuffix": "k8s", @@ -532,11 +531,11 @@ func Test_ValidateNamespace_WithConfigMapParams(t *testing.T) { }, { name: "namespace name does NOT contain suffix enforced by validating admission policy", - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.endsWith(params.data.namespaceSuffix)", }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, withParams(configParamKind(), withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), + }, withFailurePolicy(admissionregistrationv1.Fail, withParams(configParamKind(), withNamespaceMatch(makePolicy("validate-namespace-suffix"))))), policyBinding: makeBinding("validate-namespace-suffix-binding", "validate-namespace-suffix", "validate-namespace-suffix-param"), configMap: makeConfigParams("validate-namespace-suffix-param", map[string]string{ "namespaceSuffix": "k8s", @@ -574,7 +573,7 @@ func Test_ValidateNamespace_WithConfigMapParams(t *testing.T) { } policy := withWaitReadyConstraintAndExpression(testcase.policy) - if _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { + if _, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { t.Fatal(err) } if err := createAndWaitReady(t, client, testcase.policyBinding, nil); err != nil { @@ -604,18 +603,18 @@ func TestMultiplePolicyBindings(t *testing.T) { t.Fatal(err) } - paramKind := &admissionregistrationv1beta1.ParamKind{ + paramKind := &admissionregistrationv1.ParamKind{ APIVersion: "v1", Kind: "ConfigMap", } - policy := withPolicyExistsLabels([]string{"paramIdent"}, withParams(paramKind, withPolicyMatch("secrets", withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("test-policy"))))) - policy.Spec.Validations = []admissionregistrationv1beta1.Validation{ + policy := withPolicyExistsLabels([]string{"paramIdent"}, withParams(paramKind, withPolicyMatch("secrets", withFailurePolicy(admissionregistrationv1.Fail, makePolicy("test-policy"))))) + policy.Spec.Validations = []admissionregistrationv1.Validation{ { Expression: "params.data.autofail != 'true' && (params.data.conditional == 'false' || object.metadata.name.startsWith(params.data.check))", }, } policy = withWaitReadyConstraintAndExpression(policy) - if _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { + if _, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { t.Fatal(err) } @@ -734,10 +733,10 @@ func Test_PolicyExemption(t *testing.T) { } policy := makePolicy("test-policy") - policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{ - ResourceRules: []admissionregistrationv1beta1.NamedRuleWithOperations{ + policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{ + ResourceRules: []admissionregistrationv1.NamedRuleWithOperations{ { - RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ + RuleWithOperations: admissionregistrationv1.RuleWithOperations{ Operations: []admissionregistrationv1.OperationType{ "*", }, @@ -757,12 +756,12 @@ func Test_PolicyExemption(t *testing.T) { }, } - policy.Spec.Validations = []admissionregistrationv1beta1.Validation{{ + policy.Spec.Validations = []admissionregistrationv1.Validation{{ Expression: "false", Message: "marker denied; policy is ready", }} - policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -773,18 +772,18 @@ func Test_PolicyExemption(t *testing.T) { } // validate that operations to ValidatingAdmissionPolicy are exempt from an existing policy that catches all resources - policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(context.TODO(), policy.Name, metav1.GetOptions{}) + policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(context.TODO(), policy.Name, metav1.GetOptions{}) if err != nil { t.Fatal(err) } - ignoreFailurePolicy := admissionregistrationv1beta1.Ignore + ignoreFailurePolicy := admissionregistrationv1.Ignore policy.Spec.FailurePolicy = &ignoreFailurePolicy - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Update(context.TODO(), policy, metav1.UpdateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Update(context.TODO(), policy, metav1.UpdateOptions{}) if err != nil { t.Error(err) } - policyBinding, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Get(context.TODO(), policyBinding.Name, metav1.GetOptions{}) + policyBinding, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Get(context.TODO(), policyBinding.Name, metav1.GetOptions{}) if err != nil { t.Fatal(err) } @@ -792,7 +791,7 @@ func Test_PolicyExemption(t *testing.T) { // validate that operations to ValidatingAdmissionPolicyBindings are exempt from an existing policy that catches all resources policyBindingCopy := policyBinding.DeepCopy() policyBindingCopy.Spec.PolicyName = "different-binding" - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Update(context.TODO(), policyBindingCopy, metav1.UpdateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Update(context.TODO(), policyBindingCopy, metav1.UpdateOptions{}) if err != nil { t.Error(err) } @@ -838,19 +837,19 @@ func Test_ValidatingAdmissionPolicy_UpdateParamKind(t *testing.T) { t.Fatal(err) } - paramKind := &admissionregistrationv1beta1.ParamKind{ + paramKind := &admissionregistrationv1.ParamKind{ APIVersion: "v1", Kind: "ConfigMap", } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.startsWith(params.kind.lowerAscii())", Message: "wrong paramKind", }, - }, withParams(paramKind, withNamespaceMatch(withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("allowed-prefixes"))))) + }, withParams(paramKind, withNamespaceMatch(withFailurePolicy(admissionregistrationv1.Fail, makePolicy("allowed-prefixes"))))) policy = withWaitReadyConstraintAndExpression(policy) - policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -887,16 +886,16 @@ func Test_ValidatingAdmissionPolicy_UpdateParamKind(t *testing.T) { checkFailureReason(t, err, metav1.StatusReasonInvalid) // update the policy ParamKind to reference a Secret - paramKind = &admissionregistrationv1beta1.ParamKind{ + paramKind = &admissionregistrationv1.ParamKind{ APIVersion: "v1", Kind: "Secret", } - policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Get(context.TODO(), policy.Name, metav1.GetOptions{}) + policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Get(context.TODO(), policy.Name, metav1.GetOptions{}) if err != nil { t.Error(err) } policy.Spec.ParamKind = paramKind - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Update(context.TODO(), policy, metav1.UpdateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Update(context.TODO(), policy, metav1.UpdateOptions{}) if err != nil { t.Error(err) } @@ -981,14 +980,14 @@ func Test_ValidatingAdmissionPolicy_UpdateParamRef(t *testing.T) { t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.startsWith(params.metadata.name)", Message: "wrong paramRef", }, - }, withParams(configParamKind(), withNamespaceMatch(withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("allowed-prefixes"))))) + }, withParams(configParamKind(), withNamespaceMatch(withFailurePolicy(admissionregistrationv1.Fail, makePolicy("allowed-prefixes"))))) policy = withWaitReadyConstraintAndExpression(policy) - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -1036,19 +1035,19 @@ func Test_ValidatingAdmissionPolicy_UpdateParamRef(t *testing.T) { } // Update the paramRef in the policy binding to use the test-2 ConfigMap - policyBinding, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Get(context.TODO(), allowedPrefixesBinding.Name, metav1.GetOptions{}) + policyBinding, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Get(context.TODO(), allowedPrefixesBinding.Name, metav1.GetOptions{}) if err != nil { t.Fatal(err) } - denyAction := admissionregistrationv1beta1.DenyAction + denyAction := admissionregistrationv1.DenyAction policyBindingCopy := policyBinding.DeepCopy() - policyBindingCopy.Spec.ParamRef = &admissionregistrationv1beta1.ParamRef{ + policyBindingCopy.Spec.ParamRef = &admissionregistrationv1.ParamRef{ Name: "test-2", Namespace: "default", ParameterNotFoundAction: &denyAction, } - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Update(context.TODO(), policyBindingCopy, metav1.UpdateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Update(context.TODO(), policyBindingCopy, metav1.UpdateOptions{}) if err != nil { t.Error(err) } @@ -1123,14 +1122,14 @@ func Test_ValidatingAdmissionPolicy_UpdateParamResource(t *testing.T) { t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.startsWith(params.data['prefix'])", Message: "wrong prefix", }, - }, withParams(configParamKind(), withNamespaceMatch(withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("allowed-prefixes"))))) + }, withParams(configParamKind(), withNamespaceMatch(withFailurePolicy(admissionregistrationv1.Fail, makePolicy("allowed-prefixes"))))) policy = withWaitReadyConstraintAndExpression(policy) - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -1248,15 +1247,15 @@ func Test_ValidatingAdmissionPolicy_MatchByObjectSelector(t *testing.T) { }, } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "false", Message: "matched by object selector!", }, - }, withConfigMapMatch(withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("match-by-object-selector")))) + }, withConfigMapMatch(withFailurePolicy(admissionregistrationv1.Fail, makePolicy("match-by-object-selector")))) policy = withObjectSelector(labelSelector, policy) policy = withWaitReadyConstraintAndExpression(policy) - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -1321,21 +1320,21 @@ func Test_ValidatingAdmissionPolicy_MatchByNamespaceSelector(t *testing.T) { }, } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "false", Message: "matched by namespace selector!", }, - }, withConfigMapMatch(withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("match-by-namespace-selector")))) + }, withConfigMapMatch(withFailurePolicy(admissionregistrationv1.Fail, makePolicy("match-by-namespace-selector")))) policy = withNamespaceSelector(labelSelector, policy) policy = withWaitReadyConstraintAndExpression(policy) - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } policyBinding := makeBinding("match-by-namespace-selector-binding", "match-by-namespace-selector", "") - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Create(context.TODO(), policyBinding, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Create(context.TODO(), policyBinding, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -1402,15 +1401,15 @@ func Test_ValidatingAdmissionPolicy_MatchByResourceNames(t *testing.T) { t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "false", Message: "matched by resource names!", }, - }, withConfigMapMatch(withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("match-by-resource-names")))) + }, withConfigMapMatch(withFailurePolicy(admissionregistrationv1.Fail, makePolicy("match-by-resource-names")))) policy.Spec.MatchConstraints.ResourceRules[0].ResourceNames = []string{"matched-by-resource-name"} policy = withWaitReadyConstraintAndExpression(policy) - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -1461,21 +1460,21 @@ func Test_ValidatingAdmissionPolicy_MatchWithExcludeResources(t *testing.T) { t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "false", Message: "not matched by exclude resources!", }, - }, withPolicyMatch("*", withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("match-by-resource-names")))) + }, withPolicyMatch("*", withFailurePolicy(admissionregistrationv1.Fail, makePolicy("match-by-resource-names")))) policy = withExcludePolicyMatch("configmaps", policy) - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } policyBinding := makeBinding("match-by-resource-names-binding", "match-by-resource-names", "") - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Create(context.TODO(), policyBinding, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Create(context.TODO(), policyBinding, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -1534,16 +1533,16 @@ func Test_ValidatingAdmissionPolicy_MatchWithMatchPolicyEquivalent(t *testing.T) t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "false", Message: "matched by equivalent match policy!", }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("match-by-match-policy-equivalent"))) - policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{ - ResourceRules: []admissionregistrationv1beta1.NamedRuleWithOperations{ + }, withFailurePolicy(admissionregistrationv1.Fail, makePolicy("match-by-match-policy-equivalent"))) + policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{ + ResourceRules: []admissionregistrationv1.NamedRuleWithOperations{ { - RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ + RuleWithOperations: admissionregistrationv1.RuleWithOperations{ Operations: []admissionregistrationv1.OperationType{ "*", }, @@ -1563,7 +1562,7 @@ func Test_ValidatingAdmissionPolicy_MatchWithMatchPolicyEquivalent(t *testing.T) }, } policy = withWaitReadyConstraintAndExpression(policy) - if _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { + if _, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { t.Fatal(err) } @@ -1626,18 +1625,18 @@ func Test_ValidatingAdmissionPolicy_MatchWithMatchPolicyExact(t *testing.T) { t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "false", Message: "matched by exact match policy!", }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("match-by-match-policy-exact"))) - matchPolicyExact := admissionregistrationv1beta1.Exact - policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{ + }, withFailurePolicy(admissionregistrationv1.Fail, makePolicy("match-by-match-policy-exact"))) + matchPolicyExact := admissionregistrationv1.Exact + policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{ MatchPolicy: &matchPolicyExact, - ResourceRules: []admissionregistrationv1beta1.NamedRuleWithOperations{ + ResourceRules: []admissionregistrationv1.NamedRuleWithOperations{ { - RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ + RuleWithOperations: admissionregistrationv1.RuleWithOperations{ Operations: []admissionregistrationv1.OperationType{ "*", }, @@ -1657,7 +1656,7 @@ func Test_ValidatingAdmissionPolicy_MatchWithMatchPolicyExact(t *testing.T) { }, } policy = withWaitReadyConstraintAndExpression(policy) - if _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { + if _, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { t.Fatal(err) } @@ -1720,17 +1719,17 @@ func Test_ValidatingAdmissionPolicy_MatchExcludedResource(t *testing.T) { t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "false", Message: "try to deny SelfSubjectReview", }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("match-excluded-resources"))) - policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{ - MatchPolicy: ptr.To(admissionregistrationv1beta1.Exact), - ResourceRules: []admissionregistrationv1beta1.NamedRuleWithOperations{ + }, withFailurePolicy(admissionregistrationv1.Fail, makePolicy("match-excluded-resources"))) + policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{ + MatchPolicy: ptr.To(admissionregistrationv1.Exact), + ResourceRules: []admissionregistrationv1.NamedRuleWithOperations{ { - RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ + RuleWithOperations: admissionregistrationv1.RuleWithOperations{ Operations: []admissionregistrationv1.OperationType{ "*", }, @@ -1750,7 +1749,7 @@ func Test_ValidatingAdmissionPolicy_MatchExcludedResource(t *testing.T) { }, } policy = withWaitReadyConstraintAndExpression(policy) - if _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.Background(), policy, metav1.CreateOptions{}); err != nil { + if _, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.Background(), policy, metav1.CreateOptions{}); err != nil { t.Fatalf("fail to create policy: %v", err) } @@ -1787,14 +1786,14 @@ func Test_ValidatingAdmissionPolicy_PolicyDeletedThenRecreated(t *testing.T) { t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.startsWith('test')", Message: "wrong prefix", }, - }, withParams(configParamKind(), withNamespaceMatch(withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("allowed-prefixes"))))) + }, withParams(configParamKind(), withNamespaceMatch(withFailurePolicy(admissionregistrationv1.Fail, makePolicy("allowed-prefixes"))))) policy = withWaitReadyConstraintAndExpression(policy) - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -1831,7 +1830,7 @@ func Test_ValidatingAdmissionPolicy_PolicyDeletedThenRecreated(t *testing.T) { } // delete the binding object and validate that policy is not enforced - if err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Delete(context.TODO(), "allowed-prefixes", metav1.DeleteOptions{}); err != nil { + if err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Delete(context.TODO(), "allowed-prefixes", metav1.DeleteOptions{}); err != nil { t.Fatal(err) } @@ -1856,7 +1855,7 @@ func Test_ValidatingAdmissionPolicy_PolicyDeletedThenRecreated(t *testing.T) { t.Errorf("timed out waiting: %v", err) } - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -1905,14 +1904,14 @@ func Test_ValidatingAdmissionPolicy_BindingDeletedThenRecreated(t *testing.T) { t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.startsWith('test')", Message: "wrong prefix", }, - }, withParams(configParamKind(), withNamespaceMatch(withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("allowed-prefixes"))))) + }, withParams(configParamKind(), withNamespaceMatch(withFailurePolicy(admissionregistrationv1.Fail, makePolicy("allowed-prefixes"))))) policy = withWaitReadyConstraintAndExpression(policy) - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -1949,7 +1948,7 @@ func Test_ValidatingAdmissionPolicy_BindingDeletedThenRecreated(t *testing.T) { } // delete the binding object and validate that policy is not enforced - if err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Delete(context.TODO(), "allowed-prefixes-binding", metav1.DeleteOptions{}); err != nil { + if err := client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Delete(context.TODO(), "allowed-prefixes-binding", metav1.DeleteOptions{}); err != nil { t.Fatal(err) } @@ -1975,7 +1974,7 @@ func Test_ValidatingAdmissionPolicy_BindingDeletedThenRecreated(t *testing.T) { } // recreate the policy binding and test that policy is enforced again - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Create(context.TODO(), policyBinding, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Create(context.TODO(), policyBinding, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -2034,14 +2033,14 @@ func Test_ValidatingAdmissionPolicy_ParamResourceDeletedThenRecreated(t *testing t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.startsWith(params.metadata.name)", Message: "wrong prefix", }, - }, withParams(configParamKind(), withNamespaceMatch(withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("allowed-prefixes"))))) + }, withParams(configParamKind(), withNamespaceMatch(withFailurePolicy(admissionregistrationv1.Fail, makePolicy("allowed-prefixes"))))) policy = withWaitReadyConstraintAndExpression(policy) - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -2137,8 +2136,8 @@ func TestCRDParams(t *testing.T) { testcases := []struct { name string resource *unstructured.Unstructured - policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy - policyBinding *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding + policy *admissionregistrationv1.ValidatingAdmissionPolicy + policyBinding *admissionregistrationv1.ValidatingAdmissionPolicyBinding namespace *v1.Namespace err string failureReason metav1.StatusReason @@ -2155,11 +2154,11 @@ func TestCRDParams(t *testing.T) { "nameCheck": "crd-test-k8s", }, }}, - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "params.spec.nameCheck == object.metadata.name", }, - }, withNamespaceMatch(withParams(withCRDParamKind("Panda", "awesome.bears.com", "v1"), withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("test-policy"))))), + }, withNamespaceMatch(withParams(withCRDParamKind("Panda", "awesome.bears.com", "v1"), withFailurePolicy(admissionregistrationv1.Fail, makePolicy("test-policy"))))), policyBinding: makeBinding("crd-policy-binding", "test-policy", "config-obj"), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -2181,11 +2180,11 @@ func TestCRDParams(t *testing.T) { "nameCheck": "crd-test-k8s", }, }}, - policy: withValidations([]admissionregistrationv1beta1.Validation{ + policy: withValidations([]admissionregistrationv1.Validation{ { Expression: "params.spec.nameCheck == object.metadata.name", }, - }, withNamespaceMatch(withParams(withCRDParamKind("Panda", "awesome.bears.com", "v1"), withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("test-policy"))))), + }, withNamespaceMatch(withParams(withCRDParamKind("Panda", "awesome.bears.com", "v1"), withFailurePolicy(admissionregistrationv1.Fail, makePolicy("test-policy"))))), policyBinding: makeBinding("crd-policy-binding", "test-policy", "config-obj"), namespace: &v1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -2232,7 +2231,7 @@ func TestCRDParams(t *testing.T) { } policy := withWaitReadyConstraintAndExpression(testcase.policy) - if _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { + if _, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { t.Fatal(err) } // remove default namespace since the CRD is cluster-scoped @@ -2266,14 +2265,14 @@ func TestBindingRemoval(t *testing.T) { t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "false", Message: "policy still in effect", }, - }, withNamespaceMatch(withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("test-policy")))) + }, withNamespaceMatch(withFailurePolicy(admissionregistrationv1.Fail, makePolicy("test-policy")))) policy = withWaitReadyConstraintAndExpression(policy) - if _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { + if _, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { t.Fatal(err) } @@ -2301,14 +2300,14 @@ func TestBindingRemoval(t *testing.T) { }); waitErr != nil { t.Errorf("timed out waiting: %v", waitErr) } - if err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Delete(context.TODO(), "test-binding", metav1.DeleteOptions{}); err != nil { + if err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Delete(context.TODO(), "test-binding", metav1.DeleteOptions{}); err != nil { t.Fatal(err) } // wait for binding to be deleted if waitErr := wait.PollImmediate(time.Millisecond*10, wait.ForeverTestTimeout, func() (bool, error) { - _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Get(context.TODO(), "test-binding", metav1.GetOptions{}) + _, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Get(context.TODO(), "test-binding", metav1.GetOptions{}) if err != nil { if apierrors.IsNotFound(err) { return true, nil @@ -2440,12 +2439,12 @@ func Test_ValidateSecondaryAuthorization(t *testing.T) { testcase.extraAccountFn(t, adminClient, server.ClientConfig, extraRules) } - policy := withWaitReadyConstraintAndExpression(withValidations([]admissionregistrationv1beta1.Validation{ + policy := withWaitReadyConstraintAndExpression(withValidations([]admissionregistrationv1.Validation{ { Expression: testcase.expression, }, - }, withFailurePolicy(admissionregistrationv1beta1.Fail, withNamespaceMatch(makePolicy("validate-authz"))))) - if _, err := adminClient.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { + }, withFailurePolicy(admissionregistrationv1.Fail, withNamespaceMatch(makePolicy("validate-authz"))))) + if _, err := adminClient.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}); err != nil { t.Fatal(err) } if err := createAndWaitReady(t, adminClient, makeBinding("validate-authz-binding", "validate-authz", ""), nil); err != nil { @@ -2543,14 +2542,14 @@ func TestCRDsOnStartup(t *testing.T) { t.Fatal(err) } - policy := withValidations([]admissionregistrationv1beta1.Validation{ + policy := withValidations([]admissionregistrationv1.Validation{ { Expression: "object.metadata.name.startsWith(params.metadata.name)", Message: "wrong prefix", }, - }, withParams(withCRDParamKind(crdGVK.Kind, crdGVK.Group, crdGVK.Version), withNamespaceMatch(withFailurePolicy(admissionregistrationv1beta1.Fail, makePolicy("allowed-prefixes"))))) + }, withParams(withCRDParamKind(crdGVK.Kind, crdGVK.Group, crdGVK.Version), withNamespaceMatch(withFailurePolicy(admissionregistrationv1.Fail, makePolicy("allowed-prefixes"))))) policy = withWaitReadyConstraintAndExpression(policy) - _, err := client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) + _, err := client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(context.TODO(), policy, metav1.CreateOptions{}) if err != nil { t.Fatal(err) } @@ -2658,11 +2657,11 @@ func serviceAccountClient(namespace, name string) clientFn { } } -func withWaitReadyConstraintAndExpression(policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func withWaitReadyConstraintAndExpression(policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { policy = policy.DeepCopy() - policy.Spec.MatchConstraints.ResourceRules = append(policy.Spec.MatchConstraints.ResourceRules, admissionregistrationv1beta1.NamedRuleWithOperations{ + policy.Spec.MatchConstraints.ResourceRules = append(policy.Spec.MatchConstraints.ResourceRules, admissionregistrationv1.NamedRuleWithOperations{ ResourceNames: []string{"test-marker"}, - RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ + RuleWithOperations: admissionregistrationv1.RuleWithOperations{ Operations: []admissionregistrationv1.OperationType{ "UPDATE", }, @@ -2679,22 +2678,22 @@ func withWaitReadyConstraintAndExpression(policy *admissionregistrationv1beta1.V }, }, }) - policy.Spec.Validations = append([]admissionregistrationv1beta1.Validation{{ + policy.Spec.Validations = append([]admissionregistrationv1.Validation{{ Expression: "object.metadata.name != 'test-marker'", Message: "marker denied; policy is ready", }}, policy.Spec.Validations...) return policy } -func createAndWaitReady(t *testing.T, client clientset.Interface, binding *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding, matchLabels map[string]string) error { +func createAndWaitReady(t *testing.T, client clientset.Interface, binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding, matchLabels map[string]string) error { return createAndWaitReadyNamespaced(t, client, binding, matchLabels, "default") } -func createAndWaitReadyNamespaced(t *testing.T, client clientset.Interface, binding *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding, matchLabels map[string]string, ns string) error { +func createAndWaitReadyNamespaced(t *testing.T, client clientset.Interface, binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding, matchLabels map[string]string, ns string) error { return createAndWaitReadyNamespacedWithWarnHandler(t, client, binding, matchLabels, ns, newWarningHandler()) } -func createAndWaitReadyNamespacedWithWarnHandler(t *testing.T, client clientset.Interface, binding *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding, matchLabels map[string]string, ns string, handler *warningHandler) error { +func createAndWaitReadyNamespacedWithWarnHandler(t *testing.T, client clientset.Interface, binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding, matchLabels map[string]string, ns string, handler *warningHandler) error { marker := &v1.Endpoints{ObjectMeta: metav1.ObjectMeta{Name: "test-marker", Namespace: ns, Labels: matchLabels}} defer func() { err := client.CoreV1().Endpoints(ns).Delete(context.TODO(), marker.Name, metav1.DeleteOptions{}) @@ -2707,7 +2706,7 @@ func createAndWaitReadyNamespacedWithWarnHandler(t *testing.T, client clientset. return err } - _, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicyBindings().Create(context.TODO(), binding, metav1.CreateOptions{}) + _, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicyBindings().Create(context.TODO(), binding, metav1.CreateOptions{}) if err != nil { return err } @@ -2735,8 +2734,8 @@ func createAndWaitReadyNamespacedWithWarnHandler(t *testing.T, client clientset. return nil } -func withMatchNamespace(binding *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding, ns string) *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding { - binding.Spec.MatchResources = &admissionregistrationv1beta1.MatchResources{ +func withMatchNamespace(binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding, ns string) *admissionregistrationv1.ValidatingAdmissionPolicyBinding { + binding.Spec.MatchResources = &admissionregistrationv1.MatchResources{ NamespaceSelector: &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ { @@ -2750,52 +2749,52 @@ func withMatchNamespace(binding *admissionregistrationv1beta1.ValidatingAdmissio return binding } -func makePolicy(name string) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { - return &admissionregistrationv1beta1.ValidatingAdmissionPolicy{ +func makePolicy(name string) *admissionregistrationv1.ValidatingAdmissionPolicy { + return &admissionregistrationv1.ValidatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: name}, } } -func withParams(params *admissionregistrationv1beta1.ParamKind, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func withParams(params *admissionregistrationv1.ParamKind, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { policy.Spec.ParamKind = params return policy } -func configParamKind() *admissionregistrationv1beta1.ParamKind { - return &admissionregistrationv1beta1.ParamKind{ +func configParamKind() *admissionregistrationv1.ParamKind { + return &admissionregistrationv1.ParamKind{ APIVersion: "v1", Kind: "ConfigMap", } } -func withFailurePolicy(failure admissionregistrationv1beta1.FailurePolicyType, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func withFailurePolicy(failure admissionregistrationv1.FailurePolicyType, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { policy.Spec.FailurePolicy = &failure return policy } -func withNamespaceMatch(policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func withNamespaceMatch(policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { return withPolicyMatch("namespaces", policy) } -func withConfigMapMatch(policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func withConfigMapMatch(policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { return withPolicyMatch("configmaps", policy) } -func withObjectSelector(labelSelector *metav1.LabelSelector, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func withObjectSelector(labelSelector *metav1.LabelSelector, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { policy.Spec.MatchConstraints.ObjectSelector = labelSelector return policy } -func withNamespaceSelector(labelSelector *metav1.LabelSelector, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func withNamespaceSelector(labelSelector *metav1.LabelSelector, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { policy.Spec.MatchConstraints.NamespaceSelector = labelSelector return policy } -func withPolicyMatch(resource string, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { - policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{ - ResourceRules: []admissionregistrationv1beta1.NamedRuleWithOperations{ +func withPolicyMatch(resource string, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { + policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{ + ResourceRules: []admissionregistrationv1.NamedRuleWithOperations{ { - RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ + RuleWithOperations: admissionregistrationv1.RuleWithOperations{ Operations: []admissionregistrationv1.OperationType{ "*", }, @@ -2817,10 +2816,10 @@ func withPolicyMatch(resource string, policy *admissionregistrationv1beta1.Valid return policy } -func withExcludePolicyMatch(resource string, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { - policy.Spec.MatchConstraints.ExcludeResourceRules = []admissionregistrationv1beta1.NamedRuleWithOperations{ +func withExcludePolicyMatch(resource string, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { + policy.Spec.MatchConstraints.ExcludeResourceRules = []admissionregistrationv1.NamedRuleWithOperations{ { - RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ + RuleWithOperations: admissionregistrationv1.RuleWithOperations{ Operations: []admissionregistrationv1.OperationType{ "*", }, @@ -2841,9 +2840,9 @@ func withExcludePolicyMatch(resource string, policy *admissionregistrationv1beta return policy } -func withPolicyExistsLabels(labels []string, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func withPolicyExistsLabels(labels []string, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { if policy.Spec.MatchConstraints == nil { - policy.Spec.MatchConstraints = &admissionregistrationv1beta1.MatchResources{} + policy.Spec.MatchConstraints = &admissionregistrationv1.MatchResources{} } matchExprs := buildExistsSelector(labels) policy.Spec.MatchConstraints.ObjectSelector = &metav1.LabelSelector{ @@ -2852,42 +2851,42 @@ func withPolicyExistsLabels(labels []string, policy *admissionregistrationv1beta return policy } -func withValidations(validations []admissionregistrationv1beta1.Validation, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func withValidations(validations []admissionregistrationv1.Validation, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { policy.Spec.Validations = validations return policy } -func withAuditAnnotations(auditAnnotations []admissionregistrationv1beta1.AuditAnnotation, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy) *admissionregistrationv1beta1.ValidatingAdmissionPolicy { +func withAuditAnnotations(auditAnnotations []admissionregistrationv1.AuditAnnotation, policy *admissionregistrationv1.ValidatingAdmissionPolicy) *admissionregistrationv1.ValidatingAdmissionPolicy { policy.Spec.AuditAnnotations = auditAnnotations return policy } -func makeBinding(name, policyName, paramName string) *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding { - var paramRef *admissionregistrationv1beta1.ParamRef +func makeBinding(name, policyName, paramName string) *admissionregistrationv1.ValidatingAdmissionPolicyBinding { + var paramRef *admissionregistrationv1.ParamRef if paramName != "" { - denyAction := admissionregistrationv1beta1.DenyAction - paramRef = &admissionregistrationv1beta1.ParamRef{ + denyAction := admissionregistrationv1.DenyAction + paramRef = &admissionregistrationv1.ParamRef{ Name: paramName, Namespace: "default", ParameterNotFoundAction: &denyAction, } } - return &admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding{ + return &admissionregistrationv1.ValidatingAdmissionPolicyBinding{ ObjectMeta: metav1.ObjectMeta{Name: name}, - Spec: admissionregistrationv1beta1.ValidatingAdmissionPolicyBindingSpec{ + Spec: admissionregistrationv1.ValidatingAdmissionPolicyBindingSpec{ PolicyName: policyName, ParamRef: paramRef, - ValidationActions: []admissionregistrationv1beta1.ValidationAction{admissionregistrationv1beta1.Deny}, + ValidationActions: []admissionregistrationv1.ValidationAction{admissionregistrationv1.Deny}, }, } } -func withValidationActions(validationActions []admissionregistrationv1beta1.ValidationAction, binding *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding) *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding { +func withValidationActions(validationActions []admissionregistrationv1.ValidationAction, binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding) *admissionregistrationv1.ValidatingAdmissionPolicyBinding { binding.Spec.ValidationActions = validationActions return binding } -func withBindingExistsLabels(labels []string, policy *admissionregistrationv1beta1.ValidatingAdmissionPolicy, binding *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding) *admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding { +func withBindingExistsLabels(labels []string, policy *admissionregistrationv1.ValidatingAdmissionPolicy, binding *admissionregistrationv1.ValidatingAdmissionPolicyBinding) *admissionregistrationv1.ValidatingAdmissionPolicyBinding { if policy != nil { // shallow copy constraintsCopy := *policy.Spec.MatchConstraints @@ -2973,8 +2972,8 @@ func checkAuditEvents(t *testing.T, logFile *os.File, auditEvents []utils.AuditE } } -func withCRDParamKind(kind, crdGroup, crdVersion string) *admissionregistrationv1beta1.ParamKind { - return &admissionregistrationv1beta1.ParamKind{ +func withCRDParamKind(kind, crdGroup, crdVersion string) *admissionregistrationv1.ParamKind { + return &admissionregistrationv1.ParamKind{ APIVersion: crdGroup + "/" + crdVersion, Kind: kind, } @@ -3132,11 +3131,11 @@ rules: func TestAuthorizationDecisionCaching(t *testing.T) { for _, tc := range []struct { name string - validations []admissionregistrationv1beta1.Validation + validations []admissionregistrationv1.Validation }{ { name: "hit", - validations: []admissionregistrationv1beta1.Validation{ + validations: []admissionregistrationv1.Validation{ { Expression: "authorizer.requestResource.check('test').reason() == authorizer.requestResource.check('test').reason()", }, @@ -3144,7 +3143,7 @@ func TestAuthorizationDecisionCaching(t *testing.T) { }, { name: "miss", - validations: []admissionregistrationv1beta1.Validation{ + validations: []admissionregistrationv1.Validation{ { Expression: "authorizer.requestResource.subresource('a').check('test').reason() == '1'", }, @@ -3233,16 +3232,16 @@ contexts: }) defer teardown() - policy := &admissionregistrationv1beta1.ValidatingAdmissionPolicy{ + policy := &admissionregistrationv1.ValidatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-authorization-decision-caching-policy", }, - Spec: admissionregistrationv1beta1.ValidatingAdmissionPolicySpec{ - MatchConstraints: &admissionregistrationv1beta1.MatchResources{ - ResourceRules: []admissionregistrationv1beta1.NamedRuleWithOperations{ + Spec: admissionregistrationv1.ValidatingAdmissionPolicySpec{ + MatchConstraints: &admissionregistrationv1.MatchResources{ + ResourceRules: []admissionregistrationv1.NamedRuleWithOperations{ { ResourceNames: []string{"test-authorization-decision-caching-namespace"}, - RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ + RuleWithOperations: admissionregistrationv1.RuleWithOperations{ Operations: []admissionregistrationv1.OperationType{ admissionregistrationv1.Create, }, @@ -3259,7 +3258,7 @@ contexts: }, } - policy, err = client.AdmissionregistrationV1beta1().ValidatingAdmissionPolicies().Create(ctx, withWaitReadyConstraintAndExpression(policy), metav1.CreateOptions{}) + policy, err = client.AdmissionregistrationV1().ValidatingAdmissionPolicies().Create(ctx, withWaitReadyConstraintAndExpression(policy), metav1.CreateOptions{}) if err != nil { t.Fatal(err) } diff --git a/test/integration/etcd/data.go b/test/integration/etcd/data.go index ab39820a291..9148909da6e 100644 --- a/test/integration/etcd/data.go +++ b/test/integration/etcd/data.go @@ -339,6 +339,16 @@ func GetEtcdStorageDataForNamespace(namespace string) map[schema.GroupVersionRes Stub: `{"metadata":{"name":"hook2","creationTimestamp":null},"webhooks":[{"name":"externaladmissionhook.k8s.io","clientConfig":{"service":{"namespace":"ns","name":"n"},"caBundle":null},"rules":[{"operations":["CREATE"],"apiGroups":["group"],"apiVersions":["version"],"resources":["resource"]}],"failurePolicy":"Ignore","sideEffects":"None","admissionReviewVersions":["v1beta1"]}]}`, ExpectedEtcdPath: "/registry/mutatingwebhookconfigurations/hook2", }, + gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicies"): { + Stub: `{"metadata":{"name":"vap1","creationTimestamp":null},"spec":{"paramKind":{"apiVersion":"test.example.com/v1","kind":"Example"},"matchConstraints":{"resourceRules": [{"resourceNames": ["fakeName"], "apiGroups":["apps"],"apiVersions":["v1"],"operations":["CREATE", "UPDATE"], "resources":["deployments"]}]},"validations":[{"expression":"object.spec.replicas <= params.maxReplicas","message":"Too many replicas"}]}}`, + ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1", + ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicy"), + }, + gvr("admissionregistration.k8s.io", "v1", "validatingadmissionpolicybindings"): { + Stub: `{"metadata":{"name":"pb1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com","parameterNotFoundAction":"Deny"},"validationActions":["Deny"]}}`, + ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1", + ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicyBinding"), + }, // -- // k8s.io/kubernetes/pkg/apis/admissionregistration/v1beta1 @@ -354,13 +364,13 @@ func GetEtcdStorageDataForNamespace(namespace string) map[schema.GroupVersionRes // k8s.io/kubernetes/pkg/apis/admissionregistration/v1alpha1 gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): { - Stub: `{"metadata":{"name":"vap1","creationTimestamp":null},"spec":{"paramKind":{"apiVersion":"test.example.com/v1","kind":"Example"},"matchConstraints":{"resourceRules": [{"resourceNames": ["fakeName"], "apiGroups":["apps"],"apiVersions":["v1"],"operations":["CREATE", "UPDATE"], "resources":["deployments"]}]},"validations":[{"expression":"object.spec.replicas <= params.maxReplicas","message":"Too many replicas"}]}}`, - ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1", + Stub: `{"metadata":{"name":"vap1a1","creationTimestamp":null},"spec":{"paramKind":{"apiVersion":"test.example.com/v1","kind":"Example"},"matchConstraints":{"resourceRules": [{"resourceNames": ["fakeName"], "apiGroups":["apps"],"apiVersions":["v1"],"operations":["CREATE", "UPDATE"], "resources":["deployments"]}]},"validations":[{"expression":"object.spec.replicas <= params.maxReplicas","message":"Too many replicas"}]}}`, + ExpectedEtcdPath: "/registry/validatingadmissionpolicies/vap1a1", ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicy"), }, gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicybindings"): { - Stub: `{"metadata":{"name":"pb1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com"},"validationActions":["Deny"]}}`, - ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1", + Stub: `{"metadata":{"name":"pb1a1","creationTimestamp":null},"spec":{"policyName":"replicalimit-policy.example.com","paramRef":{"name":"replica-limit-test.example.com"},"validationActions":["Deny"]}}`, + ExpectedEtcdPath: "/registry/validatingadmissionpolicybindings/pb1a1", ExpectedGVK: gvkP("admissionregistration.k8s.io", "v1beta1", "ValidatingAdmissionPolicyBinding"), }, // --