mirror of https://github.com/k3s-io/k3s
allowPrivilegeEscalation: modify api types & add functionality
Signed-off-by: Jess Frazelle <acidburn@google.com>pull/6/head
parent
d2791d46e3
commit
0f349cc61f
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -514,6 +514,9 @@ message LinuxContainerSecurityContext {
|
|||
// * localhost/<full-path-to-profile>: the profile installed on the node.
|
||||
// <full-path-to-profile> 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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,8 @@ func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Po
|
|||
synthesized.SupplementalGroups = append(synthesized.SupplementalGroups, groups...)
|
||||
}
|
||||
|
||||
synthesized.NoNewPrivs = securitycontext.AddNoNewPrivileges(effectiveSc)
|
||||
|
||||
return synthesized
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue