Skip to content

Commit

Permalink
Merge pull request #99023 from verb/1.21-securitycontext
Browse files Browse the repository at this point in the history
Allow setting securityContext in ephemeral containers
  • Loading branch information
k8s-ci-robot committed Jul 10, 2021
2 parents b2bf3d7 + babebf7 commit e799d7b
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 16 deletions.
2 changes: 1 addition & 1 deletion api/openapi-spec/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pkg/api/pod/util_test.go
Expand Up @@ -1365,12 +1365,12 @@ func TestDropEphemeralContainers(t *testing.T) {
pod func() *api.Pod
}{
{
description: "has subpaths",
description: "has ephemeral containers",
hasEphemeralContainers: true,
pod: podWithEphemeralContainers,
},
{
description: "does not have subpaths",
description: "does not have ephemeral containers",
hasEphemeralContainers: false,
pod: podWithoutEphemeralContainers,
},
Expand Down
3 changes: 2 additions & 1 deletion pkg/apis/core/types.go
Expand Up @@ -3161,7 +3161,8 @@ type EphemeralContainerCommon struct {
TerminationMessagePolicy TerminationMessagePolicy
// Required: Policy for pulling images for this container
ImagePullPolicy PullPolicy
// SecurityContext is not allowed for ephemeral containers.
// Optional: SecurityContext defines the security options the ephemeral container should be run with.
// If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.
// +optional
SecurityContext *SecurityContext

Expand Down
1 change: 1 addition & 0 deletions pkg/apis/core/validation/validation.go
Expand Up @@ -84,6 +84,7 @@ var allowedEphemeralContainerFields = map[string]bool{
"TerminationMessagePath": true,
"TerminationMessagePolicy": true,
"ImagePullPolicy": true,
"SecurityContext": true,
"Stdin": true,
"StdinOnce": true,
"TTY": true,
Expand Down
23 changes: 14 additions & 9 deletions pkg/apis/core/validation/validation_test.go
Expand Up @@ -6134,7 +6134,7 @@ func TestValidateEphemeralContainers(t *testing.T) {
TargetContainerName: "ctr",
},
},
"All Whitelisted Fields": {
"All allowed Fields": {
{
EphemeralContainerCommon: core.EphemeralContainerCommon{

Expand All @@ -6160,9 +6160,14 @@ func TestValidateEphemeralContainers(t *testing.T) {
TerminationMessagePath: "/dev/termination-log",
TerminationMessagePolicy: "File",
ImagePullPolicy: "IfNotPresent",
Stdin: true,
StdinOnce: true,
TTY: true,
SecurityContext: &core.SecurityContext{
Capabilities: &core.Capabilities{
Add: []core.Capability{"SYS_ADMIN"},
},
},
Stdin: true,
StdinOnce: true,
TTY: true,
},
},
},
Expand Down Expand Up @@ -6235,7 +6240,7 @@ func TestValidateEphemeralContainers(t *testing.T) {
field.Error{Type: field.ErrorTypeNotFound, Field: "ephemeralContainers[0].targetContainerName"},
},
{
"Container uses non-whitelisted field: Lifecycle",
"Container uses disallowed field: Lifecycle",
[]core.EphemeralContainer{
{
EphemeralContainerCommon: core.EphemeralContainerCommon{
Expand All @@ -6254,7 +6259,7 @@ func TestValidateEphemeralContainers(t *testing.T) {
field.Error{Type: field.ErrorTypeForbidden, Field: "ephemeralContainers[0].lifecycle"},
},
{
"Container uses non-whitelisted field: LivenessProbe",
"Container uses disallowed field: LivenessProbe",
[]core.EphemeralContainer{
{
EphemeralContainerCommon: core.EphemeralContainerCommon{
Expand All @@ -6274,7 +6279,7 @@ func TestValidateEphemeralContainers(t *testing.T) {
field.Error{Type: field.ErrorTypeForbidden, Field: "ephemeralContainers[0].livenessProbe"},
},
{
"Container uses non-whitelisted field: Ports",
"Container uses disallowed field: Ports",
[]core.EphemeralContainer{
{
EphemeralContainerCommon: core.EphemeralContainerCommon{
Expand All @@ -6291,7 +6296,7 @@ func TestValidateEphemeralContainers(t *testing.T) {
field.Error{Type: field.ErrorTypeForbidden, Field: "ephemeralContainers[0].ports"},
},
{
"Container uses non-whitelisted field: ReadinessProbe",
"Container uses disallowed field: ReadinessProbe",
[]core.EphemeralContainer{
{
EphemeralContainerCommon: core.EphemeralContainerCommon{
Expand All @@ -6310,7 +6315,7 @@ func TestValidateEphemeralContainers(t *testing.T) {
field.Error{Type: field.ErrorTypeForbidden, Field: "ephemeralContainers[0].readinessProbe"},
},
{
"Container uses non-whitelisted field: Resources",
"Container uses disallowed field: Resources",
[]core.EphemeralContainer{
{
EphemeralContainerCommon: core.EphemeralContainerCommon{
Expand Down
50 changes: 50 additions & 0 deletions pkg/security/podsecuritypolicy/provider_test.go
Expand Up @@ -104,6 +104,8 @@ func TestMutatePodNonmutating(t *testing.T) {
}

func TestMutateContainerNonmutating(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()

untrue := false
tests := []struct {
security *api.SecurityContext
Expand All @@ -120,6 +122,11 @@ func TestMutateContainerNonmutating(t *testing.T) {
Containers: []api.Container{{
SecurityContext: tc.security,
}},
EphemeralContainers: []api.EphemeralContainer{{
EphemeralContainerCommon: api.EphemeralContainerCommon{
SecurityContext: tc.security,
},
}},
},
}
}
Expand Down Expand Up @@ -546,6 +553,8 @@ func allowFlexVolumesPSP(allowAllFlexVolumes, allowAllVolumes bool) *policy.PodS
}

func TestValidateContainerFailures(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()

// fail user strategy
failUserPSP := defaultPSP()
uid := int64(999)
Expand Down Expand Up @@ -689,6 +698,13 @@ func TestValidateContainerFailures(t *testing.T) {
errs := provider.ValidatePod(test.pod)
require.NotEmpty(t, errs, "expected validation failure but did not receive errors")
assert.Contains(t, errs[0].Error(), test.expectedError, "unexpected error")

// We want EphemeralContainers to behave the same as regular containers, so move the
// containers to ephemeralContainers and validate again.
ecPod := moveContainersToEphemeral(test.pod)
errs = provider.ValidatePod(ecPod)
require.NotEmpty(t, errs, "expected validation failure for ephemeral containers but did not receive errors")
assert.Contains(t, errs[0].Error(), test.expectedError, "unexpected error")
})
}
}
Expand Down Expand Up @@ -1062,6 +1078,8 @@ func TestValidatePodSuccess(t *testing.T) {
}

func TestValidateContainerSuccess(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()

// success user strategy
userPSP := defaultPSP()
uid := int64(999)
Expand Down Expand Up @@ -1221,6 +1239,12 @@ func TestValidateContainerSuccess(t *testing.T) {
require.NoError(t, err, "unable to create provider")
errs := provider.ValidatePod(test.pod)
assert.Empty(t, errs, "expected validation pass but received errors")

// We want EphemeralContainers to behave the same as regular containers, so move the
// containers to ephemeralContainers and validate again.
ecPod := moveContainersToEphemeral(test.pod)
errs = provider.ValidatePod(ecPod)
assert.Empty(t, errs, "expected validation pass for ephemeral containers but received errors")
})
}
}
Expand Down Expand Up @@ -1377,6 +1401,17 @@ func defaultV1Pod() *v1.Pod {
}
}

func moveContainersToEphemeral(in *api.Pod) *api.Pod {
out := in.DeepCopy()
for _, c := range out.Spec.Containers {
out.Spec.EphemeralContainers = append(out.Spec.EphemeralContainers, api.EphemeralContainer{
EphemeralContainerCommon: api.EphemeralContainerCommon(c),
})
}
out.Spec.Containers = nil
return out
}

// TestValidateAllowedVolumes will test that for every field of VolumeSource we can create
// a pod with that type of volume and deny it, accept it explicitly, or accept it with
// the FSTypeAll wildcard.
Expand Down Expand Up @@ -1490,6 +1525,8 @@ func TestValidateProjectedVolume(t *testing.T) {
}

func TestAllowPrivilegeEscalation(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()

ptr := pointer.BoolPtr
tests := []struct {
pspAPE bool // PSP AllowPrivilegeEscalation
Expand Down Expand Up @@ -1528,6 +1565,7 @@ func TestAllowPrivilegeEscalation(t *testing.T) {
t.Run(fmt.Sprintf("pspAPE:%t_pspDAPE:%s_podAPE:%s", test.pspAPE, fmtPtr(test.pspDAPE), fmtPtr(test.podAPE)), func(t *testing.T) {
pod := defaultPod()
pod.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation = test.podAPE
ecPod := moveContainersToEphemeral(pod)

psp := defaultPSP()
psp.Spec.AllowPrivilegeEscalation = &test.pspAPE
Expand All @@ -1547,6 +1585,18 @@ func TestAllowPrivilegeEscalation(t *testing.T) {
ape := pod.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation
assert.Equal(t, test.expectAPE, ape, "expected pod AllowPrivilegeEscalation")
}

err = provider.MutatePod(ecPod)
require.NoError(t, err)

errs = provider.ValidatePod(ecPod)
if test.expectErr {
assert.NotEmpty(t, errs, "expected validation error for ephemeral containers")
} else {
assert.Empty(t, errs, "expected no validation errors for ephemeral containers")
ape := ecPod.Spec.EphemeralContainers[0].SecurityContext.AllowPrivilegeEscalation
assert.Equal(t, test.expectAPE, ape, "expected pod AllowPrivilegeEscalation for ephemeral container")
}
})
}
}
Expand Down
3 changes: 2 additions & 1 deletion staging/src/k8s.io/api/core/v1/generated.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion staging/src/k8s.io/api/core/v1/types.go
Expand Up @@ -3546,7 +3546,8 @@ type EphemeralContainerCommon struct {
// More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
// +optional
ImagePullPolicy PullPolicy `json:"imagePullPolicy,omitempty" protobuf:"bytes,14,opt,name=imagePullPolicy,casttype=PullPolicy"`
// SecurityContext is not allowed for ephemeral containers.
// Optional: SecurityContext defines the security options the ephemeral container should be run with.
// If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.
// +optional
SecurityContext *SecurityContext `json:"securityContext,omitempty" protobuf:"bytes,15,opt,name=securityContext"`

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e799d7b

Please sign in to comment.