diff --git a/pkg/api/types.go b/pkg/api/types.go index 8dcd21e158..e5d9e427af 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -4030,6 +4030,11 @@ type SecurityContext struct { // files to, ensuring the persistent data can only be written to mounts. // +optional ReadOnlyRootFilesystem *bool + // AllowPrivilegeEscalation controls whether a process can gain more + // privileges than it's parent process. This bool directly controls if + // the no_new_privs flag will be set on the container process. + // +optional + AllowPrivilegeEscalation *bool } // SELinuxOptions are the labels to be applied to the container. diff --git a/pkg/api/v1/conversion.go b/pkg/api/v1/conversion.go index 585e7c285f..72b07cffd5 100644 --- a/pkg/api/v1/conversion.go +++ b/pkg/api/v1/conversion.go @@ -675,6 +675,30 @@ func Convert_v1_Secret_To_api_Secret(in *v1.Secret, out *api.Secret, s conversio return nil } +func Convert_api_SecurityContext_To_v1_SecurityContext(in *api.SecurityContext, out *v1.SecurityContext, s conversion.Scope) error { + if in.Capabilities != nil { + out.Capabilities = new(v1.Capabilities) + if err := Convert_api_Capabilities_To_v1_Capabilities(in.Capabilities, out.Capabilities, s); err != nil { + return err + } + } else { + out.Capabilities = nil + } + out.Privileged = in.Privileged + if in.SELinuxOptions != nil { + out.SELinuxOptions = new(v1.SELinuxOptions) + if err := Convert_api_SELinuxOptions_To_v1_SELinuxOptions(in.SELinuxOptions, out.SELinuxOptions, s); err != nil { + return err + } + } else { + out.SELinuxOptions = nil + } + out.RunAsUser = in.RunAsUser + out.RunAsNonRoot = in.RunAsNonRoot + out.ReadOnlyRootFilesystem = in.ReadOnlyRootFilesystem + out.AllowPrivilegeEscalation = in.AllowPrivilegeEscalation + return nil +} func Convert_api_PodSecurityContext_To_v1_PodSecurityContext(in *api.PodSecurityContext, out *v1.PodSecurityContext, s conversion.Scope) error { out.SupplementalGroups = in.SupplementalGroups diff --git a/pkg/apis/extensions/types.go b/pkg/apis/extensions/types.go index b4ba224788..41e3a95324 100644 --- a/pkg/apis/extensions/types.go +++ b/pkg/apis/extensions/types.go @@ -922,6 +922,14 @@ type PodSecurityPolicySpec struct { // will not be forced to. // +optional ReadOnlyRootFilesystem bool + // DefaultAllowPrivilegeEscalation controls the default setting for whether a + // process can gain more privileges than its parent process. + // +optional + DefaultAllowPrivilegeEscalation *bool + // AllowPrivilegeEscalation determines if a pod can request to allow + // privilege escalation. + // +optional + AllowPrivilegeEscalation bool } // HostPortRange defines a range of host ports that will be enabled by a policy diff --git a/pkg/apis/extensions/v1beta1/conversion.go b/pkg/apis/extensions/v1beta1/conversion.go index c92d44fa26..8e8c4c08cd 100644 --- a/pkg/apis/extensions/v1beta1/conversion.go +++ b/pkg/apis/extensions/v1beta1/conversion.go @@ -59,6 +59,7 @@ func addConversionFuncs(scheme *runtime.Scheme) error { Convert_networking_NetworkPolicyPort_To_v1beta1_NetworkPolicyPort, Convert_v1beta1_NetworkPolicySpec_To_networking_NetworkPolicySpec, Convert_networking_NetworkPolicySpec_To_v1beta1_NetworkPolicySpec, + Convert_extensions_PodSecurityPolicySpec_To_v1beta1_PodSecurityPolicySpec, ) if err != nil { return err @@ -429,3 +430,7 @@ func Convert_networking_NetworkPolicyList_To_v1beta1_NetworkPolicyList(in *netwo } return nil } + +func Convert_extensions_PodSecurityPolicySpec_To_v1beta1_PodSecurityPolicySpec(in *extensions.PodSecurityPolicySpec, out *extensionsv1beta1.PodSecurityPolicySpec, s conversion.Scope) error { + return autoConvert_extensions_PodSecurityPolicySpec_To_v1beta1_PodSecurityPolicySpec(in, out, s) +} diff --git a/pkg/apis/extensions/validation/validation.go b/pkg/apis/extensions/validation/validation.go index ace36544ff..04879c9b84 100644 --- a/pkg/apis/extensions/validation/validation.go +++ b/pkg/apis/extensions/validation/validation.go @@ -661,6 +661,7 @@ func ValidatePodSecurityPolicySpec(spec *extensions.PodSecurityPolicySpec, fldPa allErrs = append(allErrs, validatePodSecurityPolicyVolumes(fldPath, spec.Volumes)...) allErrs = append(allErrs, validatePSPCapsAgainstDrops(spec.RequiredDropCapabilities, spec.DefaultAddCapabilities, field.NewPath("defaultAddCapabilities"))...) allErrs = append(allErrs, validatePSPCapsAgainstDrops(spec.RequiredDropCapabilities, spec.AllowedCapabilities, field.NewPath("allowedCapabilities"))...) + allErrs = append(allErrs, validatePSPDefaultAllowPrivilegeEscalation(fldPath.Child("defaultAllowPrivilegeEscalation"), spec.DefaultAllowPrivilegeEscalation, spec.AllowPrivilegeEscalation)...) return allErrs } @@ -786,6 +787,16 @@ func validatePodSecurityPolicyVolumes(fldPath *field.Path, volumes []extensions. return allErrs } +// validatePSPDefaultAllowPrivilegeEscalation validates the DefaultAllowPrivilegeEscalation field against the AllowPrivilegeEscalation field of a PodSecurityPolicy. +func validatePSPDefaultAllowPrivilegeEscalation(fldPath *field.Path, defaultAllowPrivilegeEscalation *bool, allowPrivilegeEscalation bool) field.ErrorList { + allErrs := field.ErrorList{} + if defaultAllowPrivilegeEscalation != nil && *defaultAllowPrivilegeEscalation && !allowPrivilegeEscalation { + allErrs = append(allErrs, field.Invalid(fldPath, defaultAllowPrivilegeEscalation, "Cannot set DefaultAllowPrivilegeEscalation to true without also setting AllowPrivilegeEscalation to true")) + } + + return allErrs +} + const sysctlPatternSegmentFmt string = "([a-z0-9][-_a-z0-9]*)?[a-z0-9*]" const SysctlPatternFmt string = "(" + apivalidation.SysctlSegmentFmt + "\\.)*" + sysctlPatternSegmentFmt diff --git a/pkg/apis/extensions/validation/validation_test.go b/pkg/apis/extensions/validation/validation_test.go index 1ec5e8b083..c19e60646e 100644 --- a/pkg/apis/extensions/validation/validation_test.go +++ b/pkg/apis/extensions/validation/validation_test.go @@ -2494,6 +2494,10 @@ func TestValidatePodSecurityPolicy(t *testing.T) { seccomp.AllowedProfilesAnnotationKey: "docker/default,not-good", } + invalidDefaultAllowPrivilegeEscalation := validPSP() + pe := true + invalidDefaultAllowPrivilegeEscalation.Spec.DefaultAllowPrivilegeEscalation = &pe + type testCase struct { psp *extensions.PodSecurityPolicy errorType field.ErrorType @@ -2600,6 +2604,11 @@ func TestValidatePodSecurityPolicy(t *testing.T) { errorType: field.ErrorTypeInvalid, errorDetail: "must be a valid seccomp profile", }, + "invalid defaultAllowPrivilegeEscalation": { + psp: invalidDefaultAllowPrivilegeEscalation, + errorType: field.ErrorTypeInvalid, + errorDetail: "Cannot set DefaultAllowPrivilegeEscalation to true without also setting AllowPrivilegeEscalation to true", + }, } for k, v := range errorCases { @@ -2674,6 +2683,11 @@ func TestValidatePodSecurityPolicy(t *testing.T) { seccomp.AllowedProfilesAnnotationKey: "docker/default,unconfined,localhost/foo", } + validDefaultAllowPrivilegeEscalation := validPSP() + pe = true + validDefaultAllowPrivilegeEscalation.Spec.DefaultAllowPrivilegeEscalation = &pe + validDefaultAllowPrivilegeEscalation.Spec.AllowPrivilegeEscalation = true + successCases := map[string]struct { psp *extensions.PodSecurityPolicy }{ @@ -2701,6 +2715,9 @@ func TestValidatePodSecurityPolicy(t *testing.T) { "valid seccomp annotations": { psp: validSeccomp, }, + "valid defaultAllowPrivilegeEscalation as true": { + psp: validDefaultAllowPrivilegeEscalation, + }, } for k, v := range successCases { diff --git a/pkg/kubelet/apis/cri/v1alpha1/runtime/api.proto b/pkg/kubelet/apis/cri/v1alpha1/runtime/api.proto index 7f461eda9f..490771ee9d 100644 --- a/pkg/kubelet/apis/cri/v1alpha1/runtime/api.proto +++ b/pkg/kubelet/apis/cri/v1alpha1/runtime/api.proto @@ -514,6 +514,9 @@ message LinuxContainerSecurityContext { // * localhost/: the profile installed on the node. // is the full path of the profile. string seccomp_profile_path = 10; + // no_new_privs defines if the flag for no_new_privs should be set on the + // container. + bool no_new_privs = 11; } // LinuxContainerConfig contains platform-specific configuration for @@ -982,7 +985,7 @@ message FilesystemUsage { // The underlying storage of the filesystem. StorageIdentifier storage_id = 2; // UsedBytes represents the bytes used for images on the filesystem. - // This may differ from the total bytes used on the filesystem and may not + // This may differ from the total bytes used on the filesystem and may not // equal CapacityBytes - AvailableBytes. UInt64Value used_bytes = 3; // InodesUsed represents the inodes used by the images. diff --git a/pkg/kubelet/dockershim/security_context.go b/pkg/kubelet/dockershim/security_context.go index 95a730dc03..34f96eff06 100644 --- a/pkg/kubelet/dockershim/security_context.go +++ b/pkg/kubelet/dockershim/security_context.go @@ -113,6 +113,10 @@ func modifyHostConfig(sc *runtimeapi.LinuxContainerSecurityContext, hostConfig * } hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, apparmorSecurityOpts...) + if sc.NoNewPrivs { + hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, "no-new-privileges") + } + return nil } diff --git a/pkg/kubelet/kuberuntime/security_context.go b/pkg/kubelet/kuberuntime/security_context.go index 4aa4118187..715b941231 100644 --- a/pkg/kubelet/kuberuntime/security_context.go +++ b/pkg/kubelet/kuberuntime/security_context.go @@ -66,6 +66,8 @@ func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Po synthesized.SupplementalGroups = append(synthesized.SupplementalGroups, groups...) } + synthesized.NoNewPrivs = securitycontext.AddNoNewPrivileges(effectiveSc) + return synthesized } diff --git a/pkg/kubelet/rkt/rkt.go b/pkg/kubelet/rkt/rkt.go index 359ad6d1de..fb42a5c652 100644 --- a/pkg/kubelet/rkt/rkt.go +++ b/pkg/kubelet/rkt/rkt.go @@ -439,6 +439,14 @@ func setIsolators(app *appctypes.App, c *v1.Container, ctx *v1.SecurityContext) } } + if ok := securitycontext.AddNoNewPrivileges(ctx); ok { + isolator, err := newNoNewPrivilegesIsolator(true) + if err != nil { + return err + } + isolators = append(isolators, *isolator) + } + mergeIsolators(app, isolators) return nil } @@ -2621,3 +2629,16 @@ func convertKubePortMappings(portMappings []kubecontainer.PortMapping) ([]appcty return containerPorts, hostPorts } + +func newNoNewPrivilegesIsolator(v bool) (*appctypes.Isolator, error) { + b := fmt.Sprintf(`{"name": "%s", "value": %t}`, appctypes.LinuxNoNewPrivilegesName, v) + + i := &appctypes.Isolator{ + Name: appctypes.LinuxNoNewPrivilegesName, + } + if err := i.UnmarshalJSON([]byte(b)); err != nil { + return nil, err + } + + return i, nil +} diff --git a/pkg/kubelet/rkt/rkt_test.go b/pkg/kubelet/rkt/rkt_test.go index 6b51e5095d..9a1a7d75b3 100644 --- a/pkg/kubelet/rkt/rkt_test.go +++ b/pkg/kubelet/rkt/rkt_test.go @@ -23,6 +23,7 @@ import ( "os" "path/filepath" "sort" + "strings" "testing" "time" @@ -48,7 +49,6 @@ import ( "k8s.io/kubernetes/pkg/kubelet/types" "k8s.io/utils/exec" fakeexec "k8s.io/utils/exec/testing" - "strings" ) func mustMarshalPodManifest(man *appcschema.PodManifest) []byte { @@ -938,6 +938,7 @@ func baseImageManifest(t *testing.T) *appcschema.ImageManifest { func baseAppWithRootUserGroup(t *testing.T) *appctypes.App { app := baseApp(t) app.User, app.Group = "0", "0" + app.Isolators = append(app.Isolators) return app } diff --git a/pkg/security/podsecuritypolicy/provider.go b/pkg/security/podsecuritypolicy/provider.go index 6587267d93..0f12241f62 100644 --- a/pkg/security/podsecuritypolicy/provider.go +++ b/pkg/security/podsecuritypolicy/provider.go @@ -183,6 +183,17 @@ func (s *simpleProvider) CreateContainerSecurityContext(pod *api.Pod, container sc.ReadOnlyRootFilesystem = &readOnlyRootFS } + // if the PSP sets DefaultAllowPrivilegeEscalation and the container security context + // allowPrivilegeEscalation is not set, then default to that set by the PSP. + if s.psp.Spec.DefaultAllowPrivilegeEscalation != nil && sc.AllowPrivilegeEscalation == nil { + sc.AllowPrivilegeEscalation = s.psp.Spec.DefaultAllowPrivilegeEscalation + } + + // if the PSP sets psp.AllowPrivilegeEscalation to false set that as the default + if !s.psp.Spec.AllowPrivilegeEscalation && sc.AllowPrivilegeEscalation == nil { + sc.AllowPrivilegeEscalation = &s.psp.Spec.AllowPrivilegeEscalation + } + return sc, annotations, nil } @@ -301,6 +312,15 @@ func (s *simpleProvider) ValidateContainerSecurityContext(pod *api.Pod, containe } } + if !s.psp.Spec.AllowPrivilegeEscalation && sc.AllowPrivilegeEscalation == nil { + allErrs = append(allErrs, field.Invalid(fldPath.Child("allowPrivilegeEscalation"), sc.AllowPrivilegeEscalation, "Allowing privilege escalation for containers is not allowed")) + + } + + if !s.psp.Spec.AllowPrivilegeEscalation && sc.AllowPrivilegeEscalation != nil && *sc.AllowPrivilegeEscalation { + allErrs = append(allErrs, field.Invalid(fldPath.Child("allowPrivilegeEscalation"), *sc.AllowPrivilegeEscalation, "Allowing privilege escalation for containers is not allowed")) + } + return allErrs } diff --git a/pkg/security/podsecuritypolicy/provider_test.go b/pkg/security/podsecuritypolicy/provider_test.go index 767172ed51..b1f34b39d8 100644 --- a/pkg/security/podsecuritypolicy/provider_test.go +++ b/pkg/security/podsecuritypolicy/provider_test.go @@ -920,6 +920,7 @@ func defaultPSP() *extensions.PodSecurityPolicy { SupplementalGroups: extensions.SupplementalGroupsStrategyOptions{ Rule: extensions.SupplementalGroupsStrategyRunAsAny, }, + AllowPrivilegeEscalation: true, }, } } @@ -1033,3 +1034,111 @@ func TestValidateAllowedVolumes(t *testing.T) { } } } + +// TestValidateAllowPrivilegeEscalation will test that when the podSecurityPolicy +// AllowPrivilegeEscalation is false we cannot set a container's securityContext +// to allowPrivilegeEscalation, but when it is true we can. +func TestValidateAllowPrivilegeEscalation(t *testing.T) { + pod := defaultPod() + pe := true + pod.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation = &pe + + // create a PSP that does not allow privilege escalation + psp := defaultPSP() + psp.Spec.AllowPrivilegeEscalation = false + + provider, err := NewSimpleProvider(psp, "namespace", NewSimpleStrategyFactory()) + if err != nil { + t.Errorf("error creating provider: %v", err.Error()) + } + + // expect a denial for this PSP and test the error message to ensure it's related to allowPrivilegeEscalation + errs := provider.ValidateContainerSecurityContext(pod, &pod.Spec.Containers[0], field.NewPath("")) + if len(errs) != 1 { + t.Errorf("expected exactly 1 error but got %v", errs) + } else { + if !strings.Contains(errs.ToAggregate().Error(), "Allowing privilege escalation for containers is not allowed") { + t.Errorf("did not find the expected error, received: %v", errs) + } + } + + // now add allowPrivilegeEscalation to the podSecurityPolicy + psp.Spec.AllowPrivilegeEscalation = true + errs = provider.ValidateContainerSecurityContext(pod, &pod.Spec.Containers[0], field.NewPath("")) + if len(errs) != 0 { + t.Errorf("directly allowing privilege escalation expected no errors but got %v", errs) + } +} + +// TestValidateDefaultAllowPrivilegeEscalation will test that when the podSecurityPolicy +// DefaultAllowPrivilegeEscalation is false we cannot set a container's +// securityContext to allowPrivilegeEscalation but when it is true we can. +func TestValidateDefaultAllowPrivilegeEscalation(t *testing.T) { + pod := defaultPod() + pe := true + pod.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation = &pe + + // create a PSP that does not allow privilege escalation + psp := defaultPSP() + dpe := false + psp.Spec.DefaultAllowPrivilegeEscalation = &dpe + psp.Spec.AllowPrivilegeEscalation = false + + provider, err := NewSimpleProvider(psp, "namespace", NewSimpleStrategyFactory()) + if err != nil { + t.Errorf("error creating provider: %v", err.Error()) + } + + // expect a denial for this PSP and test the error message to ensure it's related to allowPrivilegeEscalation + errs := provider.ValidateContainerSecurityContext(pod, &pod.Spec.Containers[0], field.NewPath("")) + if len(errs) != 1 { + t.Errorf("expected exactly 1 error but got %v", errs) + } else { + if !strings.Contains(errs.ToAggregate().Error(), "Allowing privilege escalation for containers is not allowed") { + t.Errorf("did not find the expected error, received: %v", errs) + } + } + + // now add DefaultAllowPrivilegeEscalation to the podSecurityPolicy + dpe = true + psp.Spec.DefaultAllowPrivilegeEscalation = &dpe + psp.Spec.AllowPrivilegeEscalation = false + + // expect a denial for this PSP because we did not allowPrivilege Escalation via the PodSecurityPolicy + // and test the error message to ensure it's related to allowPrivilegeEscalation + errs = provider.ValidateContainerSecurityContext(pod, &pod.Spec.Containers[0], field.NewPath("")) + if len(errs) != 1 { + t.Errorf("expected exactly 1 error but got %v", errs) + } else { + if !strings.Contains(errs.ToAggregate().Error(), "Allowing privilege escalation for containers is not allowed") { + t.Errorf("did not find the expected error, received: %v", errs) + } + } + + // Now set AllowPrivilegeEscalation + psp.Spec.AllowPrivilegeEscalation = true + errs = provider.ValidateContainerSecurityContext(pod, &pod.Spec.Containers[0], field.NewPath("")) + if len(errs) != 0 { + t.Errorf("directly allowing privilege escalation expected no errors but got %v", errs) + } + + // Now set the psp spec to false and reset AllowPrivilegeEscalation + psp.Spec.AllowPrivilegeEscalation = false + pod.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation = nil + errs = provider.ValidateContainerSecurityContext(pod, &pod.Spec.Containers[0], field.NewPath("")) + if len(errs) != 1 { + t.Errorf("expected exactly 1 error but got %v", errs) + } else { + if !strings.Contains(errs.ToAggregate().Error(), "Allowing privilege escalation for containers is not allowed") { + t.Errorf("did not find the expected error, received: %v", errs) + } + } + + // Now unset both AllowPrivilegeEscalation + psp.Spec.AllowPrivilegeEscalation = true + pod.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation = nil + errs = provider.ValidateContainerSecurityContext(pod, &pod.Spec.Containers[0], field.NewPath("")) + if len(errs) != 0 { + t.Errorf("resetting allowing privilege escalation expected no errors but got %v", errs) + } +} diff --git a/pkg/securitycontext/util.go b/pkg/securitycontext/util.go index d64e1b1d93..60ea8dd544 100644 --- a/pkg/securitycontext/util.go +++ b/pkg/securitycontext/util.go @@ -133,6 +133,11 @@ func DetermineEffectiveSecurityContext(pod *v1.Pod, container *v1.Container) *v1 *effectiveSc.ReadOnlyRootFilesystem = *containerSc.ReadOnlyRootFilesystem } + if containerSc.AllowPrivilegeEscalation != nil { + effectiveSc.AllowPrivilegeEscalation = new(bool) + *effectiveSc.AllowPrivilegeEscalation = *containerSc.AllowPrivilegeEscalation + } + return effectiveSc } @@ -205,6 +210,11 @@ func InternalDetermineEffectiveSecurityContext(pod *api.Pod, container *api.Cont *effectiveSc.ReadOnlyRootFilesystem = *containerSc.ReadOnlyRootFilesystem } + if containerSc.AllowPrivilegeEscalation != nil { + effectiveSc.AllowPrivilegeEscalation = new(bool) + *effectiveSc.AllowPrivilegeEscalation = *containerSc.AllowPrivilegeEscalation + } + return effectiveSc } @@ -231,3 +241,38 @@ func internalSecurityContextFromPodSecurityContext(pod *api.Pod) *api.SecurityCo return synthesized } + +// AddNoNewPrivileges returns if we should add the no_new_privs option. This will return true if: +// 1) the container is not privileged +// 2) CAP_SYS_ADMIN is not being added +// 3) if podSecurityPolicy.DefaultAllowPrivilegeEscalation is: +// - nil, then return false +// - true, then return false +// - false, then return true +func AddNoNewPrivileges(sc *v1.SecurityContext) bool { + if sc == nil { + return false + } + + // handle the case where the container is privileged + if sc.Privileged != nil && *sc.Privileged { + return false + } + + // handle the case where we are adding CAP_SYS_ADMIN + if sc.Capabilities != nil { + for _, cap := range sc.Capabilities.Add { + if string(cap) == "CAP_SYS_ADMIN" { + return false + } + } + } + + // handle the case where the user did not set the default and did not explicitly set allowPrivilegeEscalation + if sc.AllowPrivilegeEscalation == nil { + return false + } + + // handle the case where defaultAllowPrivilegeEscalation is false or the user explicitly set allowPrivilegeEscalation to true/false + return !*sc.AllowPrivilegeEscalation +} diff --git a/pkg/securitycontext/util_test.go b/pkg/securitycontext/util_test.go index a2fd1c6350..91cf64054f 100644 --- a/pkg/securitycontext/util_test.go +++ b/pkg/securitycontext/util_test.go @@ -176,3 +176,100 @@ func TestHasRootRunAsUser(t *testing.T) { } } } + +func TestAddNoNewPrivileges(t *testing.T) { + var nonRoot int64 = 1000 + var root int64 = 0 + pfalse := false + ptrue := true + + tests := map[string]struct { + sc v1.SecurityContext + expect bool + }{ + "allowPrivilegeEscalation nil security context nil": {}, + "allowPrivilegeEscalation nil capAddSysadmin": { + sc: v1.SecurityContext{ + Capabilities: &v1.Capabilities{ + Add: []v1.Capability{"CAP_SYS_ADMIN"}, + }, + }, + }, + "allowPrivilegeEscalation nil privileged": { + sc: v1.SecurityContext{ + Privileged: &ptrue, + }, + }, + "allowPrivilegeEscalation nil nonRoot": { + sc: v1.SecurityContext{ + RunAsUser: &nonRoot, + }, + }, + "allowPrivilegeEscalation nil root": { + sc: v1.SecurityContext{ + RunAsUser: &root, + }, + }, + "allowPrivilegeEscalation false capAddSysadmin": { + sc: v1.SecurityContext{ + Capabilities: &v1.Capabilities{ + Add: []v1.Capability{"CAP_SYS_ADMIN"}, + }, + AllowPrivilegeEscalation: &pfalse, + }, + }, + "allowPrivilegeEscalation false privileged": { + sc: v1.SecurityContext{ + Privileged: &ptrue, + AllowPrivilegeEscalation: &pfalse, + }, + }, + "allowPrivilegeEscalation false nonRoot": { + sc: v1.SecurityContext{ + RunAsUser: &nonRoot, + AllowPrivilegeEscalation: &pfalse, + }, + expect: true, + }, + "allowPrivilegeEscalation false root": { + sc: v1.SecurityContext{ + RunAsUser: &root, + AllowPrivilegeEscalation: &pfalse, + }, + expect: true, + }, + "allowPrivilegeEscalation true capAddSysadmin": { + sc: v1.SecurityContext{ + Capabilities: &v1.Capabilities{ + Add: []v1.Capability{"CAP_SYS_ADMIN"}, + }, + AllowPrivilegeEscalation: &ptrue, + }, + }, + "allowPrivilegeEscalation true privileged": { + sc: v1.SecurityContext{ + Privileged: &ptrue, + AllowPrivilegeEscalation: &ptrue, + }, + }, + "allowPrivilegeEscalation true nonRoot": { + sc: v1.SecurityContext{ + RunAsUser: &nonRoot, + AllowPrivilegeEscalation: &ptrue, + }, + }, + "allowPrivilegeEscalation true root": { + sc: v1.SecurityContext{ + RunAsUser: &root, + AllowPrivilegeEscalation: &ptrue, + }, + }, + } + + for k, v := range tests { + actual := AddNoNewPrivileges(&v.sc) + if actual != v.expect { + t.Errorf("%s failed, expected %t but received %t", k, v.expect, actual) + } + } +}