From 5b7b03912e060f0f3ce0f318378d0b6de6fc8927 Mon Sep 17 00:00:00 2001 From: Robert Brennan Date: Mon, 11 Nov 2019 16:31:01 +0000 Subject: [PATCH] pass RunAsNonRoot if RunAsUser > 0 --- pkg/validator/container.go | 19 ++--- pkg/validator/container_test.go | 130 ++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 11 deletions(-) diff --git a/pkg/validator/container.go b/pkg/validator/container.go index b2697ffdd..a05fd8ef5 100644 --- a/pkg/validator/container.go +++ b/pkg/validator/container.go @@ -235,19 +235,16 @@ func (cv *ContainerValidation) validateSecurity(conf *config.Configuration, cont name := "RunAsRootAllowed" if conf.IsActionable(conf.Security, name, controllerName) { id := config.GetIDFromField(conf.Security, name) - if getBoolValue(securityContext.RunAsNonRoot) { + runAsRootSuccess := false + if getBoolValue(securityContext.RunAsNonRoot) || (securityContext.RunAsUser != nil && *securityContext.RunAsUser > 0) { // Check if the container is explicitly set to True (pass) + runAsRootSuccess = true + } else if securityContext.RunAsNonRoot == nil && securityContext.RunAsUser == nil { + // Or if the container values are unset, check the pod values + runAsRootSuccess = getBoolValue(podSecurityContext.RunAsNonRoot) || (podSecurityContext.RunAsUser != nil && *podSecurityContext.RunAsUser > 0) + } + if runAsRootSuccess { cv.addSuccess(messages.RunAsRootSuccess, category, id) - } else if securityContext.RunAsNonRoot == nil { - // Check if the value in the container spec if nil (thus defaulting to the podspec) - // Check if the container value is not set - if getBoolValue(podSecurityContext.RunAsNonRoot) { - // if the pod spec default for containers is true, then pass - cv.addSuccess(messages.RunAsRootSuccess, category, id) - } else { - // else fail as RunAsNonRoot defaults to false - cv.addFailure(messages.RunAsRootFailure, conf.Security.RunAsRootAllowed, category, id) - } } else { cv.addFailure(messages.RunAsRootFailure, conf.Security.RunAsRootAllowed, category, id) } diff --git a/pkg/validator/container_test.go b/pkg/validator/container_test.go index 4eb56a46a..b1c3e9aa2 100644 --- a/pkg/validator/container_test.go +++ b/pkg/validator/container_test.go @@ -15,6 +15,7 @@ package validator import ( + "fmt" "testing" conf "github.com/fairwindsops/polaris/pkg/config" @@ -1075,6 +1076,135 @@ func TestValidateSecurity(t *testing.T) { } } +func TestValidateRunAsRoot(t *testing.T) { + falseVar := false + trueVar := true + nonRootUser := int64(1000) + rootUser := int64(0) + config := conf.Configuration{ + Security: conf.Security{ + RunAsRootAllowed: conf.SeverityWarning, + }, + } + testCases := []struct { + cv ContainerValidation + message ResultMessage + }{ + { + cv: ContainerValidation{ + ResourceValidation: &ResourceValidation{}, + Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{ + RunAsNonRoot: nil, + }}, + parentPodSpec: corev1.PodSpec{ + SecurityContext: &corev1.PodSecurityContext{ + RunAsNonRoot: &falseVar, + }, + }, + }, + message: ResultMessage{ + ID: "runAsRootAllowed", + Message: "Should not be allowed to run as root", + Type: "warning", + Category: "Security", + }, + }, + { + cv: ContainerValidation{ + ResourceValidation: &ResourceValidation{}, + Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{ + RunAsNonRoot: &trueVar, + }}, + parentPodSpec: corev1.PodSpec{ + SecurityContext: &corev1.PodSecurityContext{ + RunAsNonRoot: &falseVar, + }, + }, + }, + message: ResultMessage{ + ID: "runAsRootAllowed", + Message: "Is not allowed to run as root", + Type: "success", + Category: "Security", + }, + }, + { + cv: ContainerValidation{ + ResourceValidation: &ResourceValidation{}, + Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{ + RunAsUser: &nonRootUser, + }}, + }, + message: ResultMessage{ + ID: "runAsRootAllowed", + Message: "Is not allowed to run as root", + Type: "success", + Category: "Security", + }, + }, + { + cv: ContainerValidation{ + ResourceValidation: &ResourceValidation{}, + Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{}}, + parentPodSpec: corev1.PodSpec{ + SecurityContext: &corev1.PodSecurityContext{ + RunAsUser: &nonRootUser, + }, + }, + }, + message: ResultMessage{ + ID: "runAsRootAllowed", + Message: "Is not allowed to run as root", + Type: "success", + Category: "Security", + }, + }, + { + cv: ContainerValidation{ + ResourceValidation: &ResourceValidation{}, + Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{ + RunAsUser: &rootUser, + }}, + parentPodSpec: corev1.PodSpec{ + SecurityContext: &corev1.PodSecurityContext{ + RunAsUser: &nonRootUser, + }, + }, + }, + message: ResultMessage{ + ID: "runAsRootAllowed", + Message: "Should not be allowed to run as root", + Type: "warning", + Category: "Security", + }, + }, + { + cv: ContainerValidation{ + ResourceValidation: &ResourceValidation{}, + Container: &corev1.Container{Name: "", SecurityContext: &corev1.SecurityContext{ + RunAsNonRoot: &falseVar, + }}, + parentPodSpec: corev1.PodSpec{ + SecurityContext: &corev1.PodSecurityContext{ + RunAsUser: &nonRootUser, + }, + }, + }, + message: ResultMessage{ + ID: "runAsRootAllowed", + Message: "Should not be allowed to run as root", + Type: "warning", + Category: "Security", + }, + }, + } + for idx, tt := range testCases { + tt.cv.validateSecurity(&config, "") + assert.Len(t, tt.cv.messages(), 1) + assert.Equal(t, &tt.message, tt.cv.messages()[0], fmt.Sprintf("Test case %d failed", idx)) + } +} + func TestValidateResourcesExemption(t *testing.T) { container := corev1.Container{ Name: "Empty",