From c84eb5b7a79c852afd484b41bdf3b4f123c9a570 Mon Sep 17 00:00:00 2001 From: Navraj Singh Chhina Date: Tue, 22 Jan 2019 14:53:57 -0500 Subject: [PATCH 1/6] add podHostName for Occur. object and split RunAsNonRoot t RANR PSC/CSC --- cmd/k8sruntime_util.go | 10 ++++++++ cmd/occurrence.go | 1 + cmd/runAsNonRoot.go | 55 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/cmd/k8sruntime_util.go b/cmd/k8sruntime_util.go index c14f1571..21db327c 100644 --- a/cmd/k8sruntime_util.go +++ b/cmd/k8sruntime_util.go @@ -199,6 +199,16 @@ func getContainers(resource Resource) (container []ContainerV1) { return container } +// Get PodSpec from the PodV1 resource type to check for PSC + +func getPodSpecs(resource Resource) (podSpec PodSpecV1) { + switch kubeType := resource.(type) { + case *PodV1: + podSpec = kubeType.Spec + } + return podSpec +} + func getPodAnnotations(resource Resource) (annotations map[string]string) { switch kubeType := resource.(type) { case *CronJobV1Beta1: diff --git a/cmd/occurrence.go b/cmd/occurrence.go index 91588a2e..222cc55f 100644 --- a/cmd/occurrence.go +++ b/cmd/occurrence.go @@ -7,4 +7,5 @@ type Occurrence struct { message string // just the message container string // name of the container metadata Metadata + podHost string // Hostname of the pod } diff --git a/cmd/runAsNonRoot.go b/cmd/runAsNonRoot.go index 7b0b6a08..7347184d 100644 --- a/cmd/runAsNonRoot.go +++ b/cmd/runAsNonRoot.go @@ -5,7 +5,8 @@ import ( "github.com/spf13/cobra" ) -func checkRunAsNonRoot(container ContainerV1, result *Result) { +// Checks the CSC for RANR +func checkRunAsNonRootCSC(container ContainerV1, result *Result) { if reason := result.Labels["audit.kubernetes.io/allow-run-as-root"]; reason != "" { if container.SecurityContext == nil || container.SecurityContext.RunAsNonRoot == nil || *container.SecurityContext.RunAsNonRoot == false { occ := Occurrence{ @@ -46,7 +47,52 @@ func checkRunAsNonRoot(container ContainerV1, result *Result) { return } +// Checks the PSC for RANR + +func checkRunAsNonRootPSC(podSpec PodSpecV1, result *Result) { + if reason := result.Labels["audit.kubernetes.io/allow-run-as-root"]; reason != "" { + if podSpec.SecurityContext == nil || podSpec.SecurityContext.RunAsNonRoot == nil || *podSpec.SecurityContext.RunAsNonRoot == false { + occ := Occurrence{ + podHost: podSpec.Hostname, + id: ErrorRunAsNonRootFalseAllowed, + kind: Warn, + message: "Allowed setting RunAsNonRoot to false", + metadata: Metadata{"Reason": prettifyReason(reason)}, + } + result.Occurrences = append(result.Occurrences, occ) + } else { + occ := Occurrence{ + podHost: podSpec.Hostname, + id: ErrorMisconfiguredKubeauditAllow, + kind: Warn, + message: "Allowed setting RunAsNonRoot to false, but it is set to true", + metadata: Metadata{"Reason": prettifyReason(reason)}, + } + result.Occurrences = append(result.Occurrences, occ) + } + } else if podSpec.SecurityContext == nil || podSpec.SecurityContext.RunAsNonRoot == nil { + occ := Occurrence{ + podHost: podSpec.Hostname, + id: ErrorRunAsNonRootNil, + kind: Error, + message: "RunAsNonRoot is not set, which results in root user being allowed!", + } + result.Occurrences = append(result.Occurrences, occ) + } else if *podSpec.SecurityContext.RunAsNonRoot == false { + occ := Occurrence{ + podHost: podSpec.Hostname, + id: ErrorRunAsNonRootFalse, + kind: Error, + message: "RunAsNonRoot is set to false (root user allowed), please set to true!", + } + result.Occurrences = append(result.Occurrences, occ) + } + return +} + func auditRunAsNonRoot(resource Resource) (results []Result) { + // get PodSpec for PSC + podSpec := getPodSpecs(resource) for _, container := range getContainers(resource) { result, err := newResultFromResource(resource) if err != nil { @@ -54,7 +100,12 @@ func auditRunAsNonRoot(resource Resource) (results []Result) { return } - checkRunAsNonRoot(container, result) + // check if Container Security Context is defined, else audit the Pod Security Context + if (container.SecurityContext == nil && podSpec.SecurityContext != nil) || (container.SecurityContext.RunAsNonRoot == nil && container.SecurityContext.RunAsNonRoot != nil) { + checkRunAsNonRootCSC(container, result) + } else { + checkRunAsNonRootPSC(podSpec, result) + } if len(result.Occurrences) > 0 { results = append(results, *result) } From 014f332bfa53afee41fa8f60a520d915e0baedc4 Mon Sep 17 00:00:00 2001 From: Navraj Singh Chhina Date: Tue, 22 Jan 2019 15:38:07 -0500 Subject: [PATCH 2/6] fixed check for CSC definition and order of function calls --- cmd/runAsNonRoot.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/runAsNonRoot.go b/cmd/runAsNonRoot.go index 7347184d..2a9a1bc4 100644 --- a/cmd/runAsNonRoot.go +++ b/cmd/runAsNonRoot.go @@ -100,11 +100,11 @@ func auditRunAsNonRoot(resource Resource) (results []Result) { return } - // check if Container Security Context is defined, else audit the Pod Security Context - if (container.SecurityContext == nil && podSpec.SecurityContext != nil) || (container.SecurityContext.RunAsNonRoot == nil && container.SecurityContext.RunAsNonRoot != nil) { - checkRunAsNonRootCSC(container, result) - } else { + // check if Container Security Context is defined properly, else audit the Pod Security Context + if (container.SecurityContext == nil && podSpec.SecurityContext != nil) || ((container.SecurityContext != nil && container.SecurityContext.RunAsNonRoot == nil) && (podSpec.SecurityContext != nil && podSpec.SecurityContext.RunAsNonRoot != nil)) { checkRunAsNonRootPSC(podSpec, result) + } else { + checkRunAsNonRootCSC(container, result) } if len(result.Occurrences) > 0 { results = append(results, *result) From 79077d99ee3fdf80ce539448f92b977ad777b4ff Mon Sep 17 00:00:00 2001 From: Navraj Singh Chhina Date: Wed, 23 Jan 2019 14:16:07 -0500 Subject: [PATCH 3/6] add RANRPSC tests, add Pod field to RANRFalse error, refactor PSC test --- cmd/result.go | 5 +++++ cmd/runAsNonRoot.go | 2 +- cmd/runAsNonRoot_test.go | 15 +++++++++++++++ cmd/util.go | 12 ++++++++++++ .../run_as_non_root_psc_false_allowed_v1.yml | 17 +++++++++++++++++ .../run_as_non_root_psc_false_csc_false_v1.yml | 15 +++++++++++++++ fixtures/run_as_non_root_psc_false_v1.yml | 17 +++++++++++++++++ .../run_as_non_root_psc_true_csc_false_v1.yml | 15 +++++++++++++++ 8 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 fixtures/run_as_non_root_psc_false_allowed_v1.yml create mode 100644 fixtures/run_as_non_root_psc_false_csc_false_v1.yml create mode 100644 fixtures/run_as_non_root_psc_false_v1.yml create mode 100644 fixtures/run_as_non_root_psc_true_csc_false_v1.yml diff --git a/cmd/result.go b/cmd/result.go index 4392e473..eeefb39d 100644 --- a/cmd/result.go +++ b/cmd/result.go @@ -59,6 +59,11 @@ func createFields(res Result, occ Occurrence) (fields log.Fields) { fields[k] = v } fields["Container"] = occ.container + + if occ.id == ErrorRunAsNonRootFalse { + fields["Pod"] = occ.podHost + } + return } diff --git a/cmd/runAsNonRoot.go b/cmd/runAsNonRoot.go index 2a9a1bc4..c4cff7a1 100644 --- a/cmd/runAsNonRoot.go +++ b/cmd/runAsNonRoot.go @@ -101,7 +101,7 @@ func auditRunAsNonRoot(resource Resource) (results []Result) { } // check if Container Security Context is defined properly, else audit the Pod Security Context - if (container.SecurityContext == nil && podSpec.SecurityContext != nil) || ((container.SecurityContext != nil && container.SecurityContext.RunAsNonRoot == nil) && (podSpec.SecurityContext != nil && podSpec.SecurityContext.RunAsNonRoot != nil)) { + if isPSCDefinedCSCUndefined(podSpec, container) { checkRunAsNonRootPSC(podSpec, result) } else { checkRunAsNonRootCSC(container, result) diff --git a/cmd/runAsNonRoot_test.go b/cmd/runAsNonRoot_test.go index 7d771660..ea9cc68b 100644 --- a/cmd/runAsNonRoot_test.go +++ b/cmd/runAsNonRoot_test.go @@ -23,3 +23,18 @@ func TestRunAsRootFalseAllowedV1(t *testing.T) { func TestRunAsNonRootMisconfiguredAllowV1(t *testing.T) { runAuditTest(t, "run_as_non_root_misconfigured_allow_v1.yml", auditRunAsNonRoot, []int{ErrorMisconfiguredKubeauditAllow}) } + +func TestPSCRunAsNonRootFalseV1(t *testing.T) { + runAuditTest(t, "run_as_non_root_psc_false_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootFalse}) +} + +func TestPSCTrueCSCFalseRunAsNonRootFalseV1(t *testing.T) { + runAuditTest(t, "run_as_non_root_psc_true_csc_false_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootFalse}) +} + +func TestPSCFalseCSCFalseRunAsNonRootFalseV1(t *testing.T) { + runAuditTest(t, "run_as_non_root_psc_false_csc_false_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootFalse}) +} +func TestPSCRunAsRootFalseAllowedV1(t *testing.T) { + runAuditTest(t, "run_as_non_root_psc_false_allowed_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootFalseAllowed}) +} diff --git a/cmd/util.go b/cmd/util.go index 2bd27319..f906a61d 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -360,3 +360,15 @@ func prettifyReason(reason string) string { } return reason } + +func isPSCDefinedCSCUndefined(podSpec PodSpecV1, container ContainerV1) bool { + if container.SecurityContext == nil && podSpec.SecurityContext != nil { + return true + } + if container.SecurityContext != nil && container.SecurityContext.RunAsNonRoot == nil { + if podSpec.SecurityContext != nil && podSpec.SecurityContext.RunAsNonRoot != nil { + return true + } + } + return false +} diff --git a/fixtures/run_as_non_root_psc_false_allowed_v1.yml b/fixtures/run_as_non_root_psc_false_allowed_v1.yml new file mode 100644 index 00000000..eab064d7 --- /dev/null +++ b/fixtures/run_as_non_root_psc_false_allowed_v1.yml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: run_as_non_root_false_allowed + labels: + apps: fakeSecurityContext + audit.kubernetes.io/allow-run-as-root: "Superuser privileges needed" + namespace: fakeDeploymentRANR +spec: + securityContext: + runAsNonRoot: false + containers: + - name: fakeContainerRANR + resources: {} + securityContext: {} +status: {} \ No newline at end of file diff --git a/fixtures/run_as_non_root_psc_false_csc_false_v1.yml b/fixtures/run_as_non_root_psc_false_csc_false_v1.yml new file mode 100644 index 00000000..4c1a63ba --- /dev/null +++ b/fixtures/run_as_non_root_psc_false_csc_false_v1.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: run_as_non_root_psc_false_csc_false + namespace: fakeDeploymentRANR +spec: + securityContext: + runAsNonRoot: false + containers: + - name: fakeContainerRANR + resources: {} + securityContext: + runAsNonRoot: false +status: {} \ No newline at end of file diff --git a/fixtures/run_as_non_root_psc_false_v1.yml b/fixtures/run_as_non_root_psc_false_v1.yml new file mode 100644 index 00000000..ef1c8491 --- /dev/null +++ b/fixtures/run_as_non_root_psc_false_v1.yml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: run_as_non_root_false + labels: + apps: fakeSecurityContext + namespace: fakeDeploymentRANR +spec: + hostname: fakeRANR + securityContext: + runAsNonRoot: false + containers: + - name: fakeContainerRANR + resources: {} + securityContext: {} +status: {} diff --git a/fixtures/run_as_non_root_psc_true_csc_false_v1.yml b/fixtures/run_as_non_root_psc_true_csc_false_v1.yml new file mode 100644 index 00000000..9469077d --- /dev/null +++ b/fixtures/run_as_non_root_psc_true_csc_false_v1.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: run_as_non_root_psc_true_csc_false + namespace: fakeDeploymentRANR +spec: + securityContext: + runAsNonRoot: true + containers: + - name: fakeContainerRANR + resources: {} + securityContext: + runAsNonRoot: false +status: {} From 8a6ef46f0f0ac563493206742e754f48852ded14 Mon Sep 17 00:00:00 2001 From: Navraj Singh Chhina Date: Thu, 24 Jan 2019 11:02:39 -0500 Subject: [PATCH 4/6] add more tests for PSC, change error ID's and messages, reformat code --- cmd/all_test.go | 4 +-- cmd/autofix.go | 4 +-- cmd/errors.go | 10 ++++--- cmd/result.go | 6 ++-- cmd/runAsNonRoot.go | 28 +++++++------------ cmd/runAsNonRoot_test.go | 26 ++++++++++++----- cmd/util.go | 10 +++---- .../run_as_non_root_psc_false_allowed_v1.yml | 2 +- ...run_as_non_root_psc_false_csc_false_v1.yml | 2 +- ...oot_psc_false_csc_nil_multiple_cont_v1.yml | 19 +++++++++++++ ...ot_psc_false_csc_true_multiple_cont_v1.yml | 20 +++++++++++++ .../run_as_non_root_psc_false_csc_true_v1.yml | 15 ++++++++++ 12 files changed, 103 insertions(+), 43 deletions(-) create mode 100644 fixtures/run_as_non_root_psc_false_csc_nil_multiple_cont_v1.yml create mode 100644 fixtures/run_as_non_root_psc_false_csc_true_multiple_cont_v1.yml create mode 100644 fixtures/run_as_non_root_psc_false_csc_true_v1.yml diff --git a/cmd/all_test.go b/cmd/all_test.go index c42b26e9..22ccb0d6 100644 --- a/cmd/all_test.go +++ b/cmd/all_test.go @@ -8,7 +8,7 @@ func TestAuditAllV1(t *testing.T) { requiredErrors := []int{ ErrorAllowPrivilegeEscalationNil, ErrorAutomountServiceAccountTokenNilAndNoName, ErrorCapabilityNotDropped, ErrorImageTagMissing, ErrorPrivilegedNil, ErrorReadOnlyRootFilesystemNil, ErrorResourcesLimitsNil, - ErrorRunAsNonRootNil, ErrorAppArmorAnnotationMissing, ErrorSeccompAnnotationMissing, + ErrorRunAsNonRootPSCNilCSCNil, ErrorAppArmorAnnotationMissing, ErrorSeccompAnnotationMissing, } runAuditTest(t, "audit_all_v1.yml", mergeAuditFunctions(allAuditFunctions), requiredErrors) } @@ -17,7 +17,7 @@ func TestAuditAllV1beta1(t *testing.T) { requiredErrors := []int{ ErrorAllowPrivilegeEscalationNil, ErrorAutomountServiceAccountTokenNilAndNoName, ErrorCapabilityNotDropped, ErrorImageTagMissing, ErrorPrivilegedNil, ErrorReadOnlyRootFilesystemNil, ErrorResourcesLimitsNil, - ErrorRunAsNonRootNil, ErrorAppArmorAnnotationMissing, ErrorSeccompAnnotationMissing, + ErrorRunAsNonRootPSCNilCSCNil, ErrorAppArmorAnnotationMissing, ErrorSeccompAnnotationMissing, } runAuditTest(t, "audit_all_v1beta1.yml", mergeAuditFunctions(allAuditFunctions), requiredErrors) } diff --git a/cmd/autofix.go b/cmd/autofix.go index 06bcc521..362c2ee5 100644 --- a/cmd/autofix.go +++ b/cmd/autofix.go @@ -27,7 +27,7 @@ func fixPotentialSecurityIssue(resource Resource, result Result) Resource { resource = fixPrivileged(resource, occurrence) case ErrorReadOnlyRootFilesystemFalse, ErrorReadOnlyRootFilesystemNil: resource = fixReadOnlyRootFilesystem(resource, occurrence) - case ErrorRunAsNonRootFalse, ErrorRunAsNonRootNil: + case ErrorRunAsNonRootPSCTrueFalseCSCFalse, ErrorRunAsNonRootPSCNilCSCNil: resource = fixRunAsNonRoot(resource, occurrence) case ErrorServiceAccountTokenDeprecated: resource = fixDeprecatedServiceAccount(resource) @@ -46,7 +46,7 @@ func fixPotentialSecurityIssue(resource Resource, result Result) Resource { func prepareResourceForFix(resource Resource, result Result) Resource { needSecurityContextDefined := []int{ErrorAllowPrivilegeEscalationNil, ErrorAllowPrivilegeEscalationTrue, ErrorPrivilegedNil, ErrorPrivilegedTrue, ErrorReadOnlyRootFilesystemFalse, ErrorReadOnlyRootFilesystemNil, - ErrorRunAsNonRootFalse, ErrorRunAsNonRootNil, ErrorServiceAccountTokenDeprecated, + ErrorRunAsNonRootPSCTrueFalseCSCFalse, ErrorRunAsNonRootPSCNilCSCNil, ErrorServiceAccountTokenDeprecated, ErrorAutomountServiceAccountTokenTrueAndNoName, ErrorAutomountServiceAccountTokenNilAndNoName, ErrorCapabilityNotDropped, ErrorCapabilityAdded, ErrorMisconfiguredKubeauditAllow} needCapabilitiesDefined := []int{ErrorCapabilityNotDropped, ErrorCapabilityAdded, ErrorMisconfiguredKubeauditAllow} diff --git a/cmd/errors.go b/cmd/errors.go index c538433c..a124381c 100644 --- a/cmd/errors.go +++ b/cmd/errors.go @@ -56,12 +56,14 @@ const ( ErrorResourcesLimitsMemoryNil // ErrorResourcesLimitsNil occurs when the resource limit is set to nil. ErrorResourcesLimitsNil - // ErrorRunAsNonRootFalse occurs when RunAsNonRoot is set to false. - ErrorRunAsNonRootFalse + // ErrorRunAsNonRootPSCTrueCSCFalse occurs when RunAsNonRoot is set to false in the Container SC and to true/false in Pod SC. + ErrorRunAsNonRootPSCTrueFalseCSCFalse + // ErrorRunAsNonRootPSCFalseCSCNil occurs when RunAsNonRoot is Nil in the Container SC and to false in Pod SC. + ErrorRunAsNonRootPSCFalseCSCNil // ErrorRunAsNonRootFalseAllowed occurs when RunAsNonRoot is allowed to be set to false. ErrorRunAsNonRootFalseAllowed - // ErrorRunAsNonRootNil occurs when RunAsNonRoot is not set. - ErrorRunAsNonRootNil + // ErrorRunAsNonRootNil occurs when RunAsNonRoot is not set in either Pod SC or Container SC. + ErrorRunAsNonRootPSCNilCSCNil // ErrorServiceAccountTokenDeprecated occurs when serviceAccount is used. ServiceAccount is a deprecated alias // for ServiceAccountName. ErrorServiceAccountTokenDeprecated diff --git a/cmd/result.go b/cmd/result.go index eeefb39d..cea09109 100644 --- a/cmd/result.go +++ b/cmd/result.go @@ -58,9 +58,11 @@ func createFields(res Result, occ Occurrence) (fields log.Fields) { for k, v := range occ.metadata { fields[k] = v } - fields["Container"] = occ.container + if len(occ.container) != 0 { + fields["Container"] = occ.container + } - if occ.id == ErrorRunAsNonRootFalse { + if occ.id == ErrorRunAsNonRootPSCFalseCSCNil && len(occ.podHost) != 0 { fields["Pod"] = occ.podHost } diff --git a/cmd/runAsNonRoot.go b/cmd/runAsNonRoot.go index c4cff7a1..28566834 100644 --- a/cmd/runAsNonRoot.go +++ b/cmd/runAsNonRoot.go @@ -13,7 +13,7 @@ func checkRunAsNonRootCSC(container ContainerV1, result *Result) { container: container.Name, id: ErrorRunAsNonRootFalseAllowed, kind: Warn, - message: "Allowed setting RunAsNonRoot to false", + message: "Allowed setting RunAsNonRoot to false in Container's Security Context", metadata: Metadata{"Reason": prettifyReason(reason)}, } result.Occurrences = append(result.Occurrences, occ) @@ -30,17 +30,17 @@ func checkRunAsNonRootCSC(container ContainerV1, result *Result) { } else if container.SecurityContext == nil || container.SecurityContext.RunAsNonRoot == nil { occ := Occurrence{ container: container.Name, - id: ErrorRunAsNonRootNil, + id: ErrorRunAsNonRootPSCNilCSCNil, kind: Error, - message: "RunAsNonRoot is not set, which results in root user being allowed!", + message: "RunAsNonRoot is not set in Container/Pod's Security Context, which results in root user being allowed!", } result.Occurrences = append(result.Occurrences, occ) } else if *container.SecurityContext.RunAsNonRoot == false { occ := Occurrence{ container: container.Name, - id: ErrorRunAsNonRootFalse, + id: ErrorRunAsNonRootPSCTrueFalseCSCFalse, kind: Error, - message: "RunAsNonRoot is set to false (root user allowed), please set to true!", + message: "RunAsNonRoot is set to false (root user allowed) in Container's Security Context, please set to true!", } result.Occurrences = append(result.Occurrences, occ) } @@ -70,20 +70,12 @@ func checkRunAsNonRootPSC(podSpec PodSpecV1, result *Result) { } result.Occurrences = append(result.Occurrences, occ) } - } else if podSpec.SecurityContext == nil || podSpec.SecurityContext.RunAsNonRoot == nil { - occ := Occurrence{ - podHost: podSpec.Hostname, - id: ErrorRunAsNonRootNil, - kind: Error, - message: "RunAsNonRoot is not set, which results in root user being allowed!", - } - result.Occurrences = append(result.Occurrences, occ) } else if *podSpec.SecurityContext.RunAsNonRoot == false { occ := Occurrence{ podHost: podSpec.Hostname, - id: ErrorRunAsNonRootFalse, + id: ErrorRunAsNonRootPSCFalseCSCNil, kind: Error, - message: "RunAsNonRoot is set to false (root user allowed), please set to true!", + message: "RunAsNonRoot is set to false (root user allowed) in Pods's Security Context and not set in Container's Security Context, please set to true!", } result.Occurrences = append(result.Occurrences, occ) } @@ -101,10 +93,10 @@ func auditRunAsNonRoot(resource Resource) (results []Result) { } // check if Container Security Context is defined properly, else audit the Pod Security Context - if isPSCDefinedCSCUndefined(podSpec, container) { - checkRunAsNonRootPSC(podSpec, result) - } else { + if isCSCWellDefined(podSpec, container) { checkRunAsNonRootCSC(container, result) + } else { + checkRunAsNonRootPSC(podSpec, result) } if len(result.Occurrences) > 0 { results = append(results, *result) diff --git a/cmd/runAsNonRoot_test.go b/cmd/runAsNonRoot_test.go index ea9cc68b..518d94b2 100644 --- a/cmd/runAsNonRoot_test.go +++ b/cmd/runAsNonRoot_test.go @@ -5,15 +5,15 @@ import ( ) func TestSecurityContextNilV1(t *testing.T) { - runAuditTest(t, "security_context_nil_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootNil}) + runAuditTest(t, "security_context_nil_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootPSCNilCSCNil}) } func TestRunAsNonRootNilV1(t *testing.T) { - runAuditTest(t, "run_as_non_root_nil_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootNil}) + runAuditTest(t, "run_as_non_root_nil_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootPSCNilCSCNil}) } func TestRunAsNonRootFalseV1(t *testing.T) { - runAuditTest(t, "run_as_non_root_false_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootFalse}) + runAuditTest(t, "run_as_non_root_false_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootPSCTrueFalseCSCFalse}) } func TestRunAsRootFalseAllowedV1(t *testing.T) { @@ -24,17 +24,29 @@ func TestRunAsNonRootMisconfiguredAllowV1(t *testing.T) { runAuditTest(t, "run_as_non_root_misconfigured_allow_v1.yml", auditRunAsNonRoot, []int{ErrorMisconfiguredKubeauditAllow}) } -func TestPSCRunAsNonRootFalseV1(t *testing.T) { - runAuditTest(t, "run_as_non_root_psc_false_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootFalse}) +func TestPSCFalseCSCNilRunAsNonRootV1(t *testing.T) { + runAuditTest(t, "run_as_non_root_psc_false_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootPSCFalseCSCNil}) } func TestPSCTrueCSCFalseRunAsNonRootFalseV1(t *testing.T) { - runAuditTest(t, "run_as_non_root_psc_true_csc_false_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootFalse}) + runAuditTest(t, "run_as_non_root_psc_true_csc_false_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootPSCTrueFalseCSCFalse}) } func TestPSCFalseCSCFalseRunAsNonRootFalseV1(t *testing.T) { - runAuditTest(t, "run_as_non_root_psc_false_csc_false_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootFalse}) + runAuditTest(t, "run_as_non_root_psc_false_csc_false_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootPSCTrueFalseCSCFalse}) } func TestPSCRunAsRootFalseAllowedV1(t *testing.T) { runAuditTest(t, "run_as_non_root_psc_false_allowed_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootFalseAllowed}) } + +func TestPSCFalseCSCTrueRunAsNonRootFalseV1(t *testing.T) { + runAuditTest(t, "run_as_non_root_psc_false_csc_true_v1.yml", auditRunAsNonRoot, []int{}) +} + +func TestPSCFalseCSCNilMultipleRunAsNonRootFalseV1(t *testing.T) { + runAuditTest(t, "run_as_non_root_psc_false_csc_nil_multiple_cont_v1.yml", auditRunAsNonRoot, []int{ErrorRunAsNonRootPSCFalseCSCNil}) +} + +func TestPSCFalseCSCTrueMultipleRunAsNonRootFalseV1(t *testing.T) { + runAuditTest(t, "run_as_non_root_psc_false_csc_true_multiple_cont_v1.yml", auditRunAsNonRoot, []int{}) +} diff --git a/cmd/util.go b/cmd/util.go index f906a61d..f22ee792 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -361,14 +361,12 @@ func prettifyReason(reason string) string { return reason } -func isPSCDefinedCSCUndefined(podSpec PodSpecV1, container ContainerV1) bool { - if container.SecurityContext == nil && podSpec.SecurityContext != nil { +func isCSCWellDefined(podSpec PodSpecV1, container ContainerV1) bool { + if container.SecurityContext != nil && container.SecurityContext.RunAsNonRoot != nil { return true } - if container.SecurityContext != nil && container.SecurityContext.RunAsNonRoot == nil { - if podSpec.SecurityContext != nil && podSpec.SecurityContext.RunAsNonRoot != nil { - return true - } + if podSpec.SecurityContext == nil || podSpec.SecurityContext.RunAsNonRoot == nil { + return true } return false } diff --git a/fixtures/run_as_non_root_psc_false_allowed_v1.yml b/fixtures/run_as_non_root_psc_false_allowed_v1.yml index eab064d7..5b351df1 100644 --- a/fixtures/run_as_non_root_psc_false_allowed_v1.yml +++ b/fixtures/run_as_non_root_psc_false_allowed_v1.yml @@ -14,4 +14,4 @@ spec: - name: fakeContainerRANR resources: {} securityContext: {} -status: {} \ No newline at end of file +status: {} diff --git a/fixtures/run_as_non_root_psc_false_csc_false_v1.yml b/fixtures/run_as_non_root_psc_false_csc_false_v1.yml index 4c1a63ba..c90231db 100644 --- a/fixtures/run_as_non_root_psc_false_csc_false_v1.yml +++ b/fixtures/run_as_non_root_psc_false_csc_false_v1.yml @@ -12,4 +12,4 @@ spec: resources: {} securityContext: runAsNonRoot: false -status: {} \ No newline at end of file +status: {} diff --git a/fixtures/run_as_non_root_psc_false_csc_nil_multiple_cont_v1.yml b/fixtures/run_as_non_root_psc_false_csc_nil_multiple_cont_v1.yml new file mode 100644 index 00000000..30a5c8f2 --- /dev/null +++ b/fixtures/run_as_non_root_psc_false_csc_nil_multiple_cont_v1.yml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: run_as_non_root_psc_false_csc_nil_multiple + namespace: fakeDeploymentRANR +spec: + hostname: multiple_containers + securityContext: + runAsNonRoot: false + containers: + - name: fakeContainerRANR1 + resources: {} + securityContext: + runAsNonRoot: true + - name: fakeContainerRANR2 + resources: {} + securityContext: {} +status: {} diff --git a/fixtures/run_as_non_root_psc_false_csc_true_multiple_cont_v1.yml b/fixtures/run_as_non_root_psc_false_csc_true_multiple_cont_v1.yml new file mode 100644 index 00000000..5a87d013 --- /dev/null +++ b/fixtures/run_as_non_root_psc_false_csc_true_multiple_cont_v1.yml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: run_as_non_root_psc_false_csc_true_multiple + namespace: fakeDeploymentRANR +spec: + hostname: multiple_containers + securityContext: + runAsNonRoot: false + containers: + - name: fakeContainerRANR1 + resources: {} + securityContext: + runAsNonRoot: true + - name: fakeContainerRANR2 + resources: {} + securityContext: + runAsNonRoot: true +status: {} diff --git a/fixtures/run_as_non_root_psc_false_csc_true_v1.yml b/fixtures/run_as_non_root_psc_false_csc_true_v1.yml new file mode 100644 index 00000000..7d6040fa --- /dev/null +++ b/fixtures/run_as_non_root_psc_false_csc_true_v1.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + name: run_as_non_root_psc_false_csc_false + namespace: fakeDeploymentRANR +spec: + securityContext: + runAsNonRoot: false + containers: + - name: fakeContainerRANR + resources: {} + securityContext: + runAsNonRoot: true +status: {} From e0a26369cc445ca07bf4fd7d917ae6190f2ef590 Mon Sep 17 00:00:00 2001 From: Navraj Singh Chhina Date: Thu, 24 Jan 2019 13:03:06 -0500 Subject: [PATCH 5/6] add containerName field to occ in PSC Error and fix function name --- cmd/runAsNonRoot.go | 39 +++++++++++++++++++++------------------ cmd/util.go | 2 +- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/cmd/runAsNonRoot.go b/cmd/runAsNonRoot.go index 28566834..a847fb95 100644 --- a/cmd/runAsNonRoot.go +++ b/cmd/runAsNonRoot.go @@ -32,7 +32,7 @@ func checkRunAsNonRootCSC(container ContainerV1, result *Result) { container: container.Name, id: ErrorRunAsNonRootPSCNilCSCNil, kind: Error, - message: "RunAsNonRoot is not set in Container/Pod's Security Context, which results in root user being allowed!", + message: "RunAsNonRoot is not set in Container's Security Context, which results in root user being allowed!", } result.Occurrences = append(result.Occurrences, occ) } else if *container.SecurityContext.RunAsNonRoot == false { @@ -49,33 +49,36 @@ func checkRunAsNonRootCSC(container ContainerV1, result *Result) { // Checks the PSC for RANR -func checkRunAsNonRootPSC(podSpec PodSpecV1, result *Result) { +func checkRunAsNonRootPSC(podSpec PodSpecV1, result *Result, containerName string) { if reason := result.Labels["audit.kubernetes.io/allow-run-as-root"]; reason != "" { if podSpec.SecurityContext == nil || podSpec.SecurityContext.RunAsNonRoot == nil || *podSpec.SecurityContext.RunAsNonRoot == false { occ := Occurrence{ - podHost: podSpec.Hostname, - id: ErrorRunAsNonRootFalseAllowed, - kind: Warn, - message: "Allowed setting RunAsNonRoot to false", - metadata: Metadata{"Reason": prettifyReason(reason)}, + container: containerName, + podHost: podSpec.Hostname, + id: ErrorRunAsNonRootFalseAllowed, + kind: Warn, + message: "Allowed setting RunAsNonRoot to false", + metadata: Metadata{"Reason": prettifyReason(reason)}, } result.Occurrences = append(result.Occurrences, occ) } else { occ := Occurrence{ - podHost: podSpec.Hostname, - id: ErrorMisconfiguredKubeauditAllow, - kind: Warn, - message: "Allowed setting RunAsNonRoot to false, but it is set to true", - metadata: Metadata{"Reason": prettifyReason(reason)}, + container: containerName, + podHost: podSpec.Hostname, + id: ErrorMisconfiguredKubeauditAllow, + kind: Warn, + message: "Allowed setting RunAsNonRoot to false, but it is set to true", + metadata: Metadata{"Reason": prettifyReason(reason)}, } result.Occurrences = append(result.Occurrences, occ) } } else if *podSpec.SecurityContext.RunAsNonRoot == false { occ := Occurrence{ - podHost: podSpec.Hostname, - id: ErrorRunAsNonRootPSCFalseCSCNil, - kind: Error, - message: "RunAsNonRoot is set to false (root user allowed) in Pods's Security Context and not set in Container's Security Context, please set to true!", + container: containerName, + podHost: podSpec.Hostname, + id: ErrorRunAsNonRootPSCFalseCSCNil, + kind: Error, + message: "RunAsNonRoot is set to false (root user allowed) in Pods's Security Context and not set in Container's Security Context, please set to true!", } result.Occurrences = append(result.Occurrences, occ) } @@ -93,10 +96,10 @@ func auditRunAsNonRoot(resource Resource) (results []Result) { } // check if Container Security Context is defined properly, else audit the Pod Security Context - if isCSCWellDefined(podSpec, container) { + if shouldAuditCSC(podSpec, container) { checkRunAsNonRootCSC(container, result) } else { - checkRunAsNonRootPSC(podSpec, result) + checkRunAsNonRootPSC(podSpec, result, container.Name) } if len(result.Occurrences) > 0 { results = append(results, *result) diff --git a/cmd/util.go b/cmd/util.go index f22ee792..d0a0dbb2 100644 --- a/cmd/util.go +++ b/cmd/util.go @@ -361,7 +361,7 @@ func prettifyReason(reason string) string { return reason } -func isCSCWellDefined(podSpec PodSpecV1, container ContainerV1) bool { +func shouldAuditCSC(podSpec PodSpecV1, container ContainerV1) bool { if container.SecurityContext != nil && container.SecurityContext.RunAsNonRoot != nil { return true } From a3dd038ff708ebe95636d25ba1f1ff3520e58636 Mon Sep 17 00:00:00 2001 From: Navraj Singh Chhina Date: Thu, 24 Jan 2019 17:35:15 -0500 Subject: [PATCH 6/6] limit use of acronyms --- cmd/errors.go | 6 +++--- cmd/runAsNonRoot.go | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cmd/errors.go b/cmd/errors.go index a124381c..fec8df9b 100644 --- a/cmd/errors.go +++ b/cmd/errors.go @@ -56,13 +56,13 @@ const ( ErrorResourcesLimitsMemoryNil // ErrorResourcesLimitsNil occurs when the resource limit is set to nil. ErrorResourcesLimitsNil - // ErrorRunAsNonRootPSCTrueCSCFalse occurs when RunAsNonRoot is set to false in the Container SC and to true/false in Pod SC. + // ErrorRunAsNonRootPSCTrueCSCFalse occurs when RunAsNonRoot is set to false in the ContainerSecurityContext and to true/false in PodSecurityContext. ErrorRunAsNonRootPSCTrueFalseCSCFalse - // ErrorRunAsNonRootPSCFalseCSCNil occurs when RunAsNonRoot is Nil in the Container SC and to false in Pod SC. + // ErrorRunAsNonRootPSCFalseCSCNil occurs when RunAsNonRoot is Nil in the ContainerSecurityContext and to false in Pod ecurityContext. ErrorRunAsNonRootPSCFalseCSCNil // ErrorRunAsNonRootFalseAllowed occurs when RunAsNonRoot is allowed to be set to false. ErrorRunAsNonRootFalseAllowed - // ErrorRunAsNonRootNil occurs when RunAsNonRoot is not set in either Pod SC or Container SC. + // ErrorRunAsNonRootNil occurs when RunAsNonRoot is not set in either PodSecurityContext or ContainerSecurityContext. ErrorRunAsNonRootPSCNilCSCNil // ErrorServiceAccountTokenDeprecated occurs when serviceAccount is used. ServiceAccount is a deprecated alias // for ServiceAccountName. diff --git a/cmd/runAsNonRoot.go b/cmd/runAsNonRoot.go index a847fb95..994ae809 100644 --- a/cmd/runAsNonRoot.go +++ b/cmd/runAsNonRoot.go @@ -13,7 +13,7 @@ func checkRunAsNonRootCSC(container ContainerV1, result *Result) { container: container.Name, id: ErrorRunAsNonRootFalseAllowed, kind: Warn, - message: "Allowed setting RunAsNonRoot to false in Container's Security Context", + message: "Allowed setting RunAsNonRoot to false in ContainerSecurityContext", metadata: Metadata{"Reason": prettifyReason(reason)}, } result.Occurrences = append(result.Occurrences, occ) @@ -32,7 +32,7 @@ func checkRunAsNonRootCSC(container ContainerV1, result *Result) { container: container.Name, id: ErrorRunAsNonRootPSCNilCSCNil, kind: Error, - message: "RunAsNonRoot is not set in Container's Security Context, which results in root user being allowed!", + message: "RunAsNonRoot is not set in ContainerSecurityContext, which results in root user being allowed!", } result.Occurrences = append(result.Occurrences, occ) } else if *container.SecurityContext.RunAsNonRoot == false { @@ -40,14 +40,14 @@ func checkRunAsNonRootCSC(container ContainerV1, result *Result) { container: container.Name, id: ErrorRunAsNonRootPSCTrueFalseCSCFalse, kind: Error, - message: "RunAsNonRoot is set to false (root user allowed) in Container's Security Context, please set to true!", + message: "RunAsNonRoot is set to false (root user allowed) in ContainerSecurityContext, please set to true!", } result.Occurrences = append(result.Occurrences, occ) } return } -// Checks the PSC for RANR +// Checks the PodSecurityContext for RANR func checkRunAsNonRootPSC(podSpec PodSpecV1, result *Result, containerName string) { if reason := result.Labels["audit.kubernetes.io/allow-run-as-root"]; reason != "" { @@ -78,7 +78,7 @@ func checkRunAsNonRootPSC(podSpec PodSpecV1, result *Result, containerName strin podHost: podSpec.Hostname, id: ErrorRunAsNonRootPSCFalseCSCNil, kind: Error, - message: "RunAsNonRoot is set to false (root user allowed) in Pods's Security Context and not set in Container's Security Context, please set to true!", + message: "RunAsNonRoot is set to false (root user allowed) in PodsSecurityContext and not set in ContainerSecurityContext, please set to true!", } result.Occurrences = append(result.Occurrences, occ) } @@ -86,7 +86,7 @@ func checkRunAsNonRootPSC(podSpec PodSpecV1, result *Result, containerName strin } func auditRunAsNonRoot(resource Resource) (results []Result) { - // get PodSpec for PSC + // get PodSpec for PodSecurityContext podSpec := getPodSpecs(resource) for _, container := range getContainers(resource) { result, err := newResultFromResource(resource) @@ -95,7 +95,7 @@ func auditRunAsNonRoot(resource Resource) (results []Result) { return } - // check if Container Security Context is defined properly, else audit the Pod Security Context + // check if ContainerSecurityContext is defined properly, else audit the PodSecurityContext if shouldAuditCSC(podSpec, container) { checkRunAsNonRootCSC(container, result) } else {