CVE-2024-3177
Description
A security issue was discovered in Kubernetes where users may be able to launch containers that bypass the mountable secrets policy enforced by the ServiceAccount admission plugin when using containers, init containers, and ephemeral containers with the envFrom field populated. The policy ensures pods running with a service account may only reference secrets specified in the service account’s secrets field. Kubernetes clusters are only affected if the ServiceAccount admission plugin and the kubernetes.io/enforce-mountable-secrets annotation are used together with containers, init containers, and ephemeral containers with the envFrom field populated.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
k8s.io/kubernetesGo | < 1.27.13 | 1.27.13 |
k8s.io/kubernetesGo | >= 1.29.0, < 1.29.4 | 1.29.4 |
k8s.io/kubernetesGo | >= 1.28.0, < 1.28.9 | 1.28.9 |
Affected products
1- Range: >= 1.28.0, <= 1.28.8
Patches
3f9fb6cf52a76Merge pull request #124326 from ritazh/automated-cherry-pick-of-#124322-upstream-release-1.28
2 files changed · +132 −11
plugin/pkg/admission/serviceaccount/admission.go+21 −0 modified@@ -337,6 +337,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po } } } + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil { + if !mountableSecrets.Has(envFrom.SecretRef.Name) { + return fmt.Errorf("init container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name) + } + } + } } for _, container := range pod.Spec.Containers { @@ -347,6 +354,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po } } } + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil { + if !mountableSecrets.Has(envFrom.SecretRef.Name) { + return fmt.Errorf("container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name) + } + } + } } // limit pull secret references as well @@ -388,6 +402,13 @@ func (s *Plugin) limitEphemeralContainerSecretReferences(pod *api.Pod, a admissi } } } + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil { + if !mountableSecrets.Has(envFrom.SecretRef.Name) { + return fmt.Errorf("ephemeral container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name) + } + } + } } return nil }
plugin/pkg/admission/serviceaccount/admission_test.go+111 −11 modified@@ -520,6 +520,25 @@ func TestAllowsReferencedSecret(t *testing.T) { t.Errorf("Unexpected error: %v", err) } + pod2 = &api.Pod{ + Spec: api.PodSpec{ + Containers: []api.Container{ + { + Name: "container-1", + EnvFrom: []api.EnvFromSource{ + { + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil { + t.Errorf("Unexpected error: %v", err) + } + pod2 = &api.Pod{ Spec: api.PodSpec{ InitContainers: []api.Container{ @@ -544,6 +563,25 @@ func TestAllowsReferencedSecret(t *testing.T) { t.Errorf("Unexpected error: %v", err) } + pod2 = &api.Pod{ + Spec: api.PodSpec{ + InitContainers: []api.Container{ + { + Name: "container-1", + EnvFrom: []api.EnvFromSource{ + { + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil { + t.Errorf("Unexpected error: %v", err) + } + pod2 = &api.Pod{ Spec: api.PodSpec{ ServiceAccountName: DefaultServiceAccountName, @@ -571,6 +609,28 @@ func TestAllowsReferencedSecret(t *testing.T) { if err := admit.Validate(context.TODO(), attrs, nil); err != nil { t.Errorf("Unexpected error: %v", err) } + + pod2 = &api.Pod{ + Spec: api.PodSpec{ + ServiceAccountName: DefaultServiceAccountName, + EphemeralContainers: []api.EphemeralContainer{ + { + EphemeralContainerCommon: api.EphemeralContainerCommon{ + Name: "container-2", + EnvFrom: []api.EnvFromSource{{ + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + }, + } + // validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers" + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil) + if err := admit.Validate(context.TODO(), attrs, nil); err != nil { + t.Errorf("Unexpected error: %v", err) + } } func TestRejectsUnreferencedSecretVolumes(t *testing.T) { @@ -627,25 +687,20 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { pod2 = &api.Pod{ Spec: api.PodSpec{ - InitContainers: []api.Container{ + Containers: []api.Container{ { Name: "container-1", - Env: []api.EnvVar{ + EnvFrom: []api.EnvFromSource{ { - Name: "env-1", - ValueFrom: &api.EnvVarSource{ - SecretKeyRef: &api.SecretKeySelector{ - LocalObjectReference: api.LocalObjectReference{Name: "foo"}, - }, - }, - }, - }, + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, }, }, }, } attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) - if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") { + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") { t.Errorf("Unexpected error: %v", err) } @@ -678,6 +733,30 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err) } + pod2 = &api.Pod{ + Spec: api.PodSpec{ + ServiceAccountName: DefaultServiceAccountName, + InitContainers: []api.Container{ + { + Name: "container-1", + EnvFrom: []api.EnvFromSource{ + { + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil) + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil { + t.Errorf("admit only enforces restrictions on secret mounts when operation==create. Unexpected error: %v", err) + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) + if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") { + t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err) + } + pod2 = &api.Pod{ Spec: api.PodSpec{ ServiceAccountName: DefaultServiceAccountName, @@ -708,6 +787,27 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") { t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err) } + + pod2 = &api.Pod{ + Spec: api.PodSpec{ + ServiceAccountName: DefaultServiceAccountName, + EphemeralContainers: []api.EphemeralContainer{ + { + EphemeralContainerCommon: api.EphemeralContainerCommon{ + Name: "container-2", + EnvFrom: []api.EnvFromSource{{ + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil) + if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") { + t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err) + } } func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) {
a619ca3fd3eeMerge pull request #124327 from ritazh/automated-cherry-pick-of-#124322-upstream-release-1.29
2 files changed · +132 −11
plugin/pkg/admission/serviceaccount/admission.go+21 −0 modified@@ -337,6 +337,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po } } } + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil { + if !mountableSecrets.Has(envFrom.SecretRef.Name) { + return fmt.Errorf("init container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name) + } + } + } } for _, container := range pod.Spec.Containers { @@ -347,6 +354,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po } } } + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil { + if !mountableSecrets.Has(envFrom.SecretRef.Name) { + return fmt.Errorf("container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name) + } + } + } } // limit pull secret references as well @@ -388,6 +402,13 @@ func (s *Plugin) limitEphemeralContainerSecretReferences(pod *api.Pod, a admissi } } } + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil { + if !mountableSecrets.Has(envFrom.SecretRef.Name) { + return fmt.Errorf("ephemeral container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name) + } + } + } } return nil }
plugin/pkg/admission/serviceaccount/admission_test.go+111 −11 modified@@ -520,6 +520,25 @@ func TestAllowsReferencedSecret(t *testing.T) { t.Errorf("Unexpected error: %v", err) } + pod2 = &api.Pod{ + Spec: api.PodSpec{ + Containers: []api.Container{ + { + Name: "container-1", + EnvFrom: []api.EnvFromSource{ + { + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil { + t.Errorf("Unexpected error: %v", err) + } + pod2 = &api.Pod{ Spec: api.PodSpec{ InitContainers: []api.Container{ @@ -544,6 +563,25 @@ func TestAllowsReferencedSecret(t *testing.T) { t.Errorf("Unexpected error: %v", err) } + pod2 = &api.Pod{ + Spec: api.PodSpec{ + InitContainers: []api.Container{ + { + Name: "container-1", + EnvFrom: []api.EnvFromSource{ + { + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil { + t.Errorf("Unexpected error: %v", err) + } + pod2 = &api.Pod{ Spec: api.PodSpec{ ServiceAccountName: DefaultServiceAccountName, @@ -571,6 +609,28 @@ func TestAllowsReferencedSecret(t *testing.T) { if err := admit.Validate(context.TODO(), attrs, nil); err != nil { t.Errorf("Unexpected error: %v", err) } + + pod2 = &api.Pod{ + Spec: api.PodSpec{ + ServiceAccountName: DefaultServiceAccountName, + EphemeralContainers: []api.EphemeralContainer{ + { + EphemeralContainerCommon: api.EphemeralContainerCommon{ + Name: "container-2", + EnvFrom: []api.EnvFromSource{{ + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + }, + } + // validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers" + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil) + if err := admit.Validate(context.TODO(), attrs, nil); err != nil { + t.Errorf("Unexpected error: %v", err) + } } func TestRejectsUnreferencedSecretVolumes(t *testing.T) { @@ -627,25 +687,20 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { pod2 = &api.Pod{ Spec: api.PodSpec{ - InitContainers: []api.Container{ + Containers: []api.Container{ { Name: "container-1", - Env: []api.EnvVar{ + EnvFrom: []api.EnvFromSource{ { - Name: "env-1", - ValueFrom: &api.EnvVarSource{ - SecretKeyRef: &api.SecretKeySelector{ - LocalObjectReference: api.LocalObjectReference{Name: "foo"}, - }, - }, - }, - }, + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, }, }, }, } attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) - if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") { + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") { t.Errorf("Unexpected error: %v", err) } @@ -678,6 +733,30 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err) } + pod2 = &api.Pod{ + Spec: api.PodSpec{ + ServiceAccountName: DefaultServiceAccountName, + InitContainers: []api.Container{ + { + Name: "container-1", + EnvFrom: []api.EnvFromSource{ + { + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil) + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil { + t.Errorf("admit only enforces restrictions on secret mounts when operation==create. Unexpected error: %v", err) + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) + if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") { + t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err) + } + pod2 = &api.Pod{ Spec: api.PodSpec{ ServiceAccountName: DefaultServiceAccountName, @@ -708,6 +787,27 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") { t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err) } + + pod2 = &api.Pod{ + Spec: api.PodSpec{ + ServiceAccountName: DefaultServiceAccountName, + EphemeralContainers: []api.EphemeralContainer{ + { + EphemeralContainerCommon: api.EphemeralContainerCommon{ + Name: "container-2", + EnvFrom: []api.EnvFromSource{{ + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil) + if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") { + t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err) + } } func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) {
7c861b1ecad9Merge pull request #124325 from ritazh/automated-cherry-pick-of-#124322-upstream-release-1.27
2 files changed · +132 −11
plugin/pkg/admission/serviceaccount/admission.go+21 −0 modified@@ -337,6 +337,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po } } } + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil { + if !mountableSecrets.Has(envFrom.SecretRef.Name) { + return fmt.Errorf("init container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name) + } + } + } } for _, container := range pod.Spec.Containers { @@ -347,6 +354,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po } } } + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil { + if !mountableSecrets.Has(envFrom.SecretRef.Name) { + return fmt.Errorf("container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name) + } + } + } } // limit pull secret references as well @@ -388,6 +402,13 @@ func (s *Plugin) limitEphemeralContainerSecretReferences(pod *api.Pod, a admissi } } } + for _, envFrom := range container.EnvFrom { + if envFrom.SecretRef != nil { + if !mountableSecrets.Has(envFrom.SecretRef.Name) { + return fmt.Errorf("ephemeral container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name) + } + } + } } return nil }
plugin/pkg/admission/serviceaccount/admission_test.go+111 −11 modified@@ -521,6 +521,25 @@ func TestAllowsReferencedSecret(t *testing.T) { t.Errorf("Unexpected error: %v", err) } + pod2 = &api.Pod{ + Spec: api.PodSpec{ + Containers: []api.Container{ + { + Name: "container-1", + EnvFrom: []api.EnvFromSource{ + { + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil { + t.Errorf("Unexpected error: %v", err) + } + pod2 = &api.Pod{ Spec: api.PodSpec{ InitContainers: []api.Container{ @@ -545,6 +564,25 @@ func TestAllowsReferencedSecret(t *testing.T) { t.Errorf("Unexpected error: %v", err) } + pod2 = &api.Pod{ + Spec: api.PodSpec{ + InitContainers: []api.Container{ + { + Name: "container-1", + EnvFrom: []api.EnvFromSource{ + { + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil { + t.Errorf("Unexpected error: %v", err) + } + pod2 = &api.Pod{ Spec: api.PodSpec{ ServiceAccountName: DefaultServiceAccountName, @@ -572,6 +610,28 @@ func TestAllowsReferencedSecret(t *testing.T) { if err := admit.Validate(context.TODO(), attrs, nil); err != nil { t.Errorf("Unexpected error: %v", err) } + + pod2 = &api.Pod{ + Spec: api.PodSpec{ + ServiceAccountName: DefaultServiceAccountName, + EphemeralContainers: []api.EphemeralContainer{ + { + EphemeralContainerCommon: api.EphemeralContainerCommon{ + Name: "container-2", + EnvFrom: []api.EnvFromSource{{ + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + }, + } + // validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers" + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil) + if err := admit.Validate(context.TODO(), attrs, nil); err != nil { + t.Errorf("Unexpected error: %v", err) + } } func TestRejectsUnreferencedSecretVolumes(t *testing.T) { @@ -628,25 +688,20 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { pod2 = &api.Pod{ Spec: api.PodSpec{ - InitContainers: []api.Container{ + Containers: []api.Container{ { Name: "container-1", - Env: []api.EnvVar{ + EnvFrom: []api.EnvFromSource{ { - Name: "env-1", - ValueFrom: &api.EnvVarSource{ - SecretKeyRef: &api.SecretKeySelector{ - LocalObjectReference: api.LocalObjectReference{Name: "foo"}, - }, - }, - }, - }, + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, }, }, }, } attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) - if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") { + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") { t.Errorf("Unexpected error: %v", err) } @@ -679,6 +734,30 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err) } + pod2 = &api.Pod{ + Spec: api.PodSpec{ + ServiceAccountName: DefaultServiceAccountName, + InitContainers: []api.Container{ + { + Name: "container-1", + EnvFrom: []api.EnvFromSource{ + { + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil) + if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil { + t.Errorf("admit only enforces restrictions on secret mounts when operation==create. Unexpected error: %v", err) + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil) + if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") { + t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err) + } + pod2 = &api.Pod{ Spec: api.PodSpec{ ServiceAccountName: DefaultServiceAccountName, @@ -709,6 +788,27 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) { if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") { t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err) } + + pod2 = &api.Pod{ + Spec: api.PodSpec{ + ServiceAccountName: DefaultServiceAccountName, + EphemeralContainers: []api.EphemeralContainer{ + { + EphemeralContainerCommon: api.EphemeralContainerCommon{ + Name: "container-2", + EnvFrom: []api.EnvFromSource{{ + SecretRef: &api.SecretEnvSource{ + LocalObjectReference: api.LocalObjectReference{ + Name: "foo"}}}}, + }, + }, + }, + }, + } + attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil) + if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") { + t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err) + } } func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) {
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
13- github.com/advisories/GHSA-pxhw-596r-rwq5ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-3177ghsaADVISORY
- www.openwall.com/lists/oss-security/2024/04/16/4nvdWEB
- github.com/kubernetes/kubernetes/commit/7c861b1ecad97e1ab9332c970c9294a72065111aghsaWEB
- github.com/kubernetes/kubernetes/commit/a619ca3fd3ee3c222d9df784622020de398076d2ghsaWEB
- github.com/kubernetes/kubernetes/commit/f9fb6cf52a769a599a45e700375115c2ecc86e9bghsaWEB
- github.com/kubernetes/kubernetes/issues/124336nvdWEB
- groups.google.com/g/kubernetes-security-announce/c/JxjHf7fkVd8/m/oVCzypyOAQAJnvdWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/QRYFHIQ6XRKRYBI2F5UESH67BJBQXUPTghsaWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/WL54MTLGMTBZZO5PYGEGEBERTMADC4WCghsaWEB
- pkg.go.dev/vuln/GO-2024-2746ghsaWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/QRYFHIQ6XRKRYBI2F5UESH67BJBQXUPT/nvd
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/WL54MTLGMTBZZO5PYGEGEBERTMADC4WC/nvd
News mentions
0No linked articles in our index yet.