Merge pull request #129670 from cslink/fix-ephemeral-container-secrets

Fix ephemeral container secret references
This commit is contained in:
Kubernetes Prow Robot 2025-01-23 15:53:20 -08:00 committed by GitHub
commit 2deb8af139
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 115 additions and 0 deletions

View File

@ -94,7 +94,10 @@ func (g *graphPopulator) updatePod(oldObj, obj interface{}) {
return
}
if oldPod, ok := oldObj.(*corev1.Pod); ok && oldPod != nil {
// Ephemeral containers can add new secret or config map references to the pod.
hasNewEphemeralContainers := len(pod.Spec.EphemeralContainers) > len(oldPod.Spec.EphemeralContainers)
if (pod.Spec.NodeName == oldPod.Spec.NodeName) && (pod.UID == oldPod.UID) &&
!hasNewEphemeralContainers &&
resourceclaim.PodStatusEqual(oldPod.Status.ResourceClaimStatuses, pod.Status.ResourceClaimStatuses) {
// Node and uid are unchanged, all object references in the pod spec are immutable respectively unmodified (claim statuses).
klog.V(5).Infof("updatePod %s/%s, node unchanged", pod.Namespace, pod.Name)

View File

@ -856,6 +856,118 @@ func TestNodeAuthorizerSharedResources(t *testing.T) {
}
}
func TestNodeAuthorizerAddEphemeralContainers(t *testing.T) {
g := NewGraph()
g.destinationEdgeThreshold = 1
identifier := nodeidentifier.NewDefaultNodeIdentifier()
authz := NewAuthorizer(g, identifier, bootstrappolicy.NodeRules())
node1 := &user.DefaultInfo{Name: "system:node:node1", Groups: []string{"system:nodes"}}
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "pod1-node1", Namespace: "ns1"},
Spec: corev1.PodSpec{
NodeName: "node1",
Volumes: []corev1.Volume{
{VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "node1-only"}}},
},
},
}
ecNewSecret := corev1.EphemeralContainer{
TargetContainerName: "targetContainerName",
EphemeralContainerCommon: corev1.EphemeralContainerCommon{
Image: "imageURL",
Name: "eph",
Command: []string{"command"},
EnvFrom: []corev1.EnvFromSource{
{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "new-secret",
},
Optional: nil,
},
},
},
SecurityContext: &corev1.SecurityContext{
Privileged: &[]bool{true}[0],
},
},
}
ecNewConfigMap := corev1.EphemeralContainer{
TargetContainerName: "targetContainerName",
EphemeralContainerCommon: corev1.EphemeralContainerCommon{
Image: "imageURL",
Name: "eph",
Command: []string{"command"},
EnvFrom: []corev1.EnvFromSource{
{
ConfigMapRef: &corev1.ConfigMapEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "new-config-map",
},
Optional: nil,
},
},
},
SecurityContext: &corev1.SecurityContext{
Privileged: &[]bool{true}[0],
},
},
}
p := &graphPopulator{}
p.graph = g
p.addPod(pod)
testcases := []struct {
User user.Info
Secret string
ConfigMap string
Decision authorizer.Decision
EphCont *corev1.EphemeralContainer
}{
{User: node1, Decision: authorizer.DecisionAllow, Secret: "node1-only"},
{User: node1, Decision: authorizer.DecisionNoOpinion, Secret: "new-secret"},
{User: node1, Decision: authorizer.DecisionAllow, Secret: "new-secret", EphCont: &ecNewSecret},
{User: node1, Decision: authorizer.DecisionNoOpinion, ConfigMap: "new-config-map"},
{User: node1, Decision: authorizer.DecisionAllow, ConfigMap: "new-config-map", EphCont: &ecNewConfigMap},
}
for i, tc := range testcases {
var (
decision authorizer.Decision
err error
)
if tc.EphCont != nil {
newPod := &corev1.Pod{}
pod.DeepCopyInto(newPod)
newPod.Spec.EphemeralContainers = append(newPod.Spec.EphemeralContainers, *tc.EphCont)
p.updatePod(pod, newPod)
}
if len(tc.Secret) > 0 {
decision, _, err = authz.Authorize(context.Background(), authorizer.AttributesRecord{User: tc.User, ResourceRequest: true, Verb: "get", Resource: "secrets", Namespace: "ns1", Name: tc.Secret})
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
}
} else if len(tc.ConfigMap) > 0 {
decision, _, err = authz.Authorize(context.Background(), authorizer.AttributesRecord{User: tc.User, ResourceRequest: true, Verb: "get", Resource: "configmaps", Namespace: "ns1", Name: tc.ConfigMap})
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
}
} else {
t.Fatalf("test case must include a request for a Secret")
}
if decision != tc.Decision {
t.Errorf("%d: expected %v, got %v", i, tc.Decision, decision)
}
}
}
type sampleDataOpts struct {
nodes int
namespaces int