mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	allowPrivilegeEscalation: modify api types & add functionality
Signed-off-by: Jess Frazelle <acidburn@google.com>
This commit is contained in:
		@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user