From e7cdc595551954d6b87a859296eb09fddd01f3c9 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 28 Oct 2024 08:01:33 -0700 Subject: [PATCH] deprecate EnforceMountableSecretsAnnotation in 1.32 Signed-off-by: Rita Zhang --- api/openapi-spec/swagger.json | 2 +- api/openapi-spec/v3/api__v1_openapi.json | 2 +- pkg/apis/core/types.go | 2 + pkg/generated/openapi/zz_generated.openapi.go | 2 +- pkg/registry/core/serviceaccount/strategy.go | 23 ++++++- .../core/serviceaccount/strategy_test.go | 63 +++++++++++++++++++ .../src/k8s.io/api/core/v1/generated.proto | 2 + staging/src/k8s.io/api/core/v1/types.go | 2 + .../core/v1/types_swagger_doc_generated.go | 2 +- .../swagger-with-shared-parameters.json | 2 +- .../artifacts/openapi/swagger.json | 2 +- .../openapitest/testdata/api__v1_openapi.json | 2 +- .../kubectl/testdata/openapi/v3/api/v1.json | 2 +- test/integration/auth/svcaccttoken_test.go | 54 ++++++++++++++++ 14 files changed, 152 insertions(+), 10 deletions(-) create mode 100644 pkg/registry/core/serviceaccount/strategy_test.go diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 5f47fe88d65..5ab29ec7f4a 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -11299,7 +11299,7 @@ "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" }, "secrets": { - "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", + "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". The \"kubernetes.io/enforce-mountable-secrets\" annotation is deprecated since v1.32. Prefer separate namespaces to isolate access to mounted secrets. This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", "items": { "$ref": "#/definitions/io.k8s.api.core.v1.ObjectReference" }, diff --git a/api/openapi-spec/v3/api__v1_openapi.json b/api/openapi-spec/v3/api__v1_openapi.json index e307edc8697..a1a31343777 100644 --- a/api/openapi-spec/v3/api__v1_openapi.json +++ b/api/openapi-spec/v3/api__v1_openapi.json @@ -7432,7 +7432,7 @@ "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" }, "secrets": { - "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", + "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". The \"kubernetes.io/enforce-mountable-secrets\" annotation is deprecated since v1.32. Prefer separate namespaces to isolate access to mounted secrets. This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", "items": { "allOf": [ { diff --git a/pkg/apis/core/types.go b/pkg/apis/core/types.go index cf3879fd78b..759fe1d39e7 100644 --- a/pkg/apis/core/types.go +++ b/pkg/apis/core/types.go @@ -4780,6 +4780,8 @@ type ServiceAccount struct { // Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. // Pods are only limited to this list if this service account has a "kubernetes.io/enforce-mountable-secrets" annotation set to "true". + // The "kubernetes.io/enforce-mountable-secrets" annotation is deprecated since v1.32. + // Prefer separate namespaces to isolate access to mounted secrets. // This field should not be used to find auto-generated service account token secrets for use outside of pods. // Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. Secrets []ObjectReference diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 41e0b0fa592..b713bd1d377 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -30729,7 +30729,7 @@ func schema_k8sio_api_core_v1_ServiceAccount(ref common.ReferenceCallback) commo }, }, SchemaProps: spec.SchemaProps{ - Description: "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", + Description: "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". The \"kubernetes.io/enforce-mountable-secrets\" annotation is deprecated since v1.32. Prefer separate namespaces to isolate access to mounted secrets. This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ diff --git a/pkg/registry/core/serviceaccount/strategy.go b/pkg/registry/core/serviceaccount/strategy.go index cad6da26fb1..5f28ae74994 100644 --- a/pkg/registry/core/serviceaccount/strategy.go +++ b/pkg/registry/core/serviceaccount/strategy.go @@ -18,6 +18,7 @@ package serviceaccount import ( "context" + "fmt" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" @@ -25,6 +26,7 @@ import ( "k8s.io/kubernetes/pkg/api/legacyscheme" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/core/validation" + sa "k8s.io/kubernetes/plugin/pkg/admission/serviceaccount" ) // strategy implements behavior for ServiceAccount objects @@ -50,7 +52,9 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis } // WarningsOnCreate returns warnings for the creation of the given object. -func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil } +func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { + return warnIfHasEnforceMountableSecretsAnnotation(obj.(*api.ServiceAccount), nil) +} // Canonicalize normalizes the object after validation. func (strategy) Canonicalize(obj runtime.Object) { @@ -76,9 +80,24 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie // WarningsOnUpdate returns warnings for the given update. func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { - return nil + return warnIfHasEnforceMountableSecretsAnnotation(obj.(*api.ServiceAccount), old.(*api.ServiceAccount)) } func (strategy) AllowUnconditionalUpdate() bool { return true } + +func warnIfHasEnforceMountableSecretsAnnotation(serviceAccount, oldServiceAccount *api.ServiceAccount) []string { + if oldServiceAccount != nil { + _, ok := oldServiceAccount.Annotations[sa.EnforceMountableSecretsAnnotation] + if ok { + // skip warning if request isn't newly setting the annotation + return nil + } + } + _, ok := serviceAccount.Annotations[sa.EnforceMountableSecretsAnnotation] + if ok { + return []string{fmt.Sprintf("metadata.annotations[%s]: deprecated in v1.32+; prefer separate namespaces to isolate access to mounted secrets", sa.EnforceMountableSecretsAnnotation)} + } + return nil +} diff --git a/pkg/registry/core/serviceaccount/strategy_test.go b/pkg/registry/core/serviceaccount/strategy_test.go new file mode 100644 index 00000000000..5089eae6ca8 --- /dev/null +++ b/pkg/registry/core/serviceaccount/strategy_test.go @@ -0,0 +1,63 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package serviceaccount + +import ( + "context" + "fmt" + "testing" + + api "k8s.io/kubernetes/pkg/apis/core" + sa "k8s.io/kubernetes/plugin/pkg/admission/serviceaccount" +) + +func TestWarningsOnCreate(t *testing.T) { + ctx := context.TODO() + serviceAccount := &api.ServiceAccount{} + + warnings := Strategy.WarningsOnCreate(ctx, serviceAccount) + if len(warnings) != 0 { + t.Errorf("expected no warnings, got %v", warnings) + } + serviceAccount.Annotations = map[string]string{sa.EnforceMountableSecretsAnnotation: "true"} + warnings = Strategy.WarningsOnCreate(ctx, serviceAccount) + if len(warnings) != 1 || warnings[0] != fmt.Sprintf("metadata.annotations[%s]: deprecated in v1.32+; prefer separate namespaces to isolate access to mounted secrets", sa.EnforceMountableSecretsAnnotation) { + t.Errorf("expected warnings, got %v", warnings) + } +} + +func TestWarningsOnUpdate(t *testing.T) { + ctx := context.TODO() + serviceAccount := &api.ServiceAccount{} + oldServiceAccount := &api.ServiceAccount{} + + warnings := Strategy.WarningsOnUpdate(ctx, serviceAccount, oldServiceAccount) + if len(warnings) != 0 { + t.Errorf("expected no warnings, got %v", warnings) + } + serviceAccount.Annotations = map[string]string{sa.EnforceMountableSecretsAnnotation: "true"} + warnings = Strategy.WarningsOnUpdate(ctx, serviceAccount, oldServiceAccount) + if len(warnings) != 1 || warnings[0] != fmt.Sprintf("metadata.annotations[%s]: deprecated in v1.32+; prefer separate namespaces to isolate access to mounted secrets", sa.EnforceMountableSecretsAnnotation) { + t.Errorf("expected warnings, got %v", warnings) + } + + oldServiceAccount.Annotations = map[string]string{sa.EnforceMountableSecretsAnnotation: "true"} + warnings = Strategy.WarningsOnUpdate(ctx, serviceAccount, oldServiceAccount) + if len(warnings) != 0 { + t.Errorf("expected no warnings if request isn't newly setting the annotation, got %v", warnings) + } +} diff --git a/staging/src/k8s.io/api/core/v1/generated.proto b/staging/src/k8s.io/api/core/v1/generated.proto index acd078320c6..5825631aa05 100644 --- a/staging/src/k8s.io/api/core/v1/generated.proto +++ b/staging/src/k8s.io/api/core/v1/generated.proto @@ -5622,6 +5622,8 @@ message ServiceAccount { // Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. // Pods are only limited to this list if this service account has a "kubernetes.io/enforce-mountable-secrets" annotation set to "true". + // The "kubernetes.io/enforce-mountable-secrets" annotation is deprecated since v1.32. + // Prefer separate namespaces to isolate access to mounted secrets. // This field should not be used to find auto-generated service account token secrets for use outside of pods. // Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. // More info: https://kubernetes.io/docs/concepts/configuration/secret diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go index 66df4250867..027842cc52e 100644 --- a/staging/src/k8s.io/api/core/v1/types.go +++ b/staging/src/k8s.io/api/core/v1/types.go @@ -5694,6 +5694,8 @@ type ServiceAccount struct { // Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. // Pods are only limited to this list if this service account has a "kubernetes.io/enforce-mountable-secrets" annotation set to "true". + // The "kubernetes.io/enforce-mountable-secrets" annotation is deprecated since v1.32. + // Prefer separate namespaces to isolate access to mounted secrets. // This field should not be used to find auto-generated service account token secrets for use outside of pods. // Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. // More info: https://kubernetes.io/docs/concepts/configuration/secret diff --git a/staging/src/k8s.io/api/core/v1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/core/v1/types_swagger_doc_generated.go index fa757adf181..1cbd8789bed 100644 --- a/staging/src/k8s.io/api/core/v1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/core/v1/types_swagger_doc_generated.go @@ -2391,7 +2391,7 @@ func (Service) SwaggerDoc() map[string]string { var map_ServiceAccount = map[string]string{ "": "ServiceAccount binds together: * a name, understood by users, and perhaps by peripheral systems, for an identity * a principal that can be authenticated and authorized * a set of secrets", "metadata": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", - "secrets": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", + "secrets": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". The \"kubernetes.io/enforce-mountable-secrets\" annotation is deprecated since v1.32. Prefer separate namespaces to isolate access to mounted secrets. This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", "imagePullSecrets": "ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod", "automountServiceAccountToken": "AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. Can be overridden at the pod level.", } diff --git a/staging/src/k8s.io/cli-runtime/artifacts/openapi/swagger-with-shared-parameters.json b/staging/src/k8s.io/cli-runtime/artifacts/openapi/swagger-with-shared-parameters.json index 15d819bccdb..13877fb7a3c 100644 --- a/staging/src/k8s.io/cli-runtime/artifacts/openapi/swagger-with-shared-parameters.json +++ b/staging/src/k8s.io/cli-runtime/artifacts/openapi/swagger-with-shared-parameters.json @@ -9630,7 +9630,7 @@ "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" }, "secrets": { - "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", + "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". The \"kubernetes.io/enforce-mountable-secrets\" annotation is deprecated since v1.32. Prefer separate namespaces to isolate access to mounted secrets. This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", "items": { "$ref": "#/definitions/io.k8s.api.core.v1.ObjectReference" }, diff --git a/staging/src/k8s.io/cli-runtime/artifacts/openapi/swagger.json b/staging/src/k8s.io/cli-runtime/artifacts/openapi/swagger.json index 9ad11fe1f75..eb286e2cd2c 100644 --- a/staging/src/k8s.io/cli-runtime/artifacts/openapi/swagger.json +++ b/staging/src/k8s.io/cli-runtime/artifacts/openapi/swagger.json @@ -10019,7 +10019,7 @@ "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" }, "secrets": { - "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", + "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". The \"kubernetes.io/enforce-mountable-secrets\" annotation is deprecated since v1.32. Prefer separate namespaces to isolate access to mounted secrets. This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", "items": { "$ref": "#/definitions/io.k8s.api.core.v1.ObjectReference" }, diff --git a/staging/src/k8s.io/client-go/openapi/openapitest/testdata/api__v1_openapi.json b/staging/src/k8s.io/client-go/openapi/openapitest/testdata/api__v1_openapi.json index 4637e313d99..c71267015b8 100644 --- a/staging/src/k8s.io/client-go/openapi/openapitest/testdata/api__v1_openapi.json +++ b/staging/src/k8s.io/client-go/openapi/openapitest/testdata/api__v1_openapi.json @@ -6851,7 +6851,7 @@ "description": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata" }, "secrets": { - "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", + "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". The \"kubernetes.io/enforce-mountable-secrets\" annotation is deprecated since v1.32. Prefer separate namespaces to isolate access to mounted secrets. This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", "items": { "allOf": [ { diff --git a/staging/src/k8s.io/kubectl/testdata/openapi/v3/api/v1.json b/staging/src/k8s.io/kubectl/testdata/openapi/v3/api/v1.json index 4c5f13d8d9f..5ec9adf5da0 100644 --- a/staging/src/k8s.io/kubectl/testdata/openapi/v3/api/v1.json +++ b/staging/src/k8s.io/kubectl/testdata/openapi/v3/api/v1.json @@ -26671,7 +26671,7 @@ ] }, "secrets": { - "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", + "description": "Secrets is a list of the secrets in the same namespace that pods running using this ServiceAccount are allowed to use. Pods are only limited to this list if this service account has a \"kubernetes.io/enforce-mountable-secrets\" annotation set to \"true\". The \"kubernetes.io/enforce-mountable-secrets\" annotation is deprecated since v1.32. Prefer separate namespaces to isolate access to mounted secrets. This field should not be used to find auto-generated service account token secrets for use outside of pods. Instead, tokens can be requested directly using the TokenRequest API, or service account token secrets can be manually created. More info: https://kubernetes.io/docs/concepts/configuration/secret", "type": "array", "items": { "default": {}, diff --git a/test/integration/auth/svcaccttoken_test.go b/test/integration/auth/svcaccttoken_test.go index 0c31f285a60..ab8a6438549 100644 --- a/test/integration/auth/svcaccttoken_test.go +++ b/test/integration/auth/svcaccttoken_test.go @@ -22,6 +22,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io" "net/http" "net/url" @@ -52,6 +53,7 @@ import ( "k8s.io/kubernetes/pkg/controlplane" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/serviceaccount" + svcacct "k8s.io/kubernetes/plugin/pkg/admission/serviceaccount" "k8s.io/kubernetes/test/integration/framework" "k8s.io/kubernetes/test/utils/ktesting" "k8s.io/utils/ptr" @@ -68,6 +70,58 @@ AwEHoUQDQgAEH6cuzP8XuD5wal6wf9M6xDljTOPLX2i8uIp/C/ASqiIGUeeKQtX0 tokenExpirationSeconds = 60*60 + 7 ) +func TestServiceAccountAnnotationDeprecation(t *testing.T) { + tCtx := ktesting.Init(t) + // Start the server + kubeClient, kubeConfig, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{}) + defer tearDownFn() + + ns := framework.CreateNamespaceOrDie(kubeClient, "myns", t) + defer framework.DeleteNamespaceOrDie(kubeClient, ns, t) + + warningHandler := &recordingWarningHandler{} + + configWithWarningHandler := rest.CopyConfig(kubeConfig) + configWithWarningHandler.WarningHandler = warningHandler + cs, err := clientset.NewForConfig(configWithWarningHandler) + if err != nil { + t.Fatalf("err: %v", err) + } + var ( + saWithAnnotation = &v1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-svcacct", + Namespace: ns.Name, + }, + } + pod = &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod", + Namespace: saWithAnnotation.Namespace, + }, + Spec: v1.PodSpec{ + ServiceAccountName: saWithAnnotation.Name, + Containers: []v1.Container{{Name: "test-container", Image: "nginx"}}, + }, + } + ) + + t.Run("service account with deprecated annotation", func(t *testing.T) { + warningHandler.clear() + // test warning is emitted when the service account has this deprecated annotation + saWithAnnotation.Annotations = map[string]string{svcacct.EnforceMountableSecretsAnnotation: "true"} + _, delSvcAcct := createDeleteSvcAcct(t, cs, saWithAnnotation) + defer delSvcAcct() + warningHandler.assertEqual(t, []string{fmt.Sprintf("metadata.annotations[%s]: deprecated in v1.32+; prefer separate namespaces to isolate access to mounted secrets", svcacct.EnforceMountableSecretsAnnotation)}) + + warningHandler.clear() + // no warning when a pod is created with a service account that has this deprecated annotation + _, delPod := createDeletePod(t, cs, pod) + defer delPod() + warningHandler.assertEqual(t, nil) + }) +} + func TestServiceAccountTokenCreate(t *testing.T) { const iss = "https://foo.bar.example.com" aud := authenticator.Audiences{"api"}