From 85b5174fff713e1fe56687b5b699e04019556941 Mon Sep 17 00:00:00 2001 From: Gustav Westling Date: Mon, 25 Oct 2021 08:32:52 +0000 Subject: [PATCH 1/2] =?UTF-8?q?Remove=20the=20deprecated=20=E2=80=9CContai?= =?UTF-8?q?ner=20Security=20Context=E2=80=9D=20check.=20It=20has=20been=20?= =?UTF-8?q?deprecated=20for=20three=20releases,=20and=20disabled=20by=20de?= =?UTF-8?q?fault=20since=20the=20last=20release.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sturdy --- user_id: 847dfd0c-49bf-40c5-8870-74a12fca0d60 view_id: 72cdb3b4-8d5d-4357-aa8c-3d10e910f7af workspace_id: ec482ab3-1b84-47fc-8b77-3974d49c7dbb --- score/security/security.go | 70 ---------- score/security_test.go | 277 ------------------------------------- 2 files changed, 347 deletions(-) diff --git a/score/security/security.go b/score/security/security.go index 0195d090..4ed9252b 100644 --- a/score/security/security.go +++ b/score/security/security.go @@ -9,8 +9,6 @@ import ( ) func Register(allChecks *checks.Checks) { - allChecks.RegisterOptionalPodCheck("Container Security Context", `Makes sure that all pods have good securityContexts configured`, containerSecurityContext) - allChecks.RegisterPodCheck("Container Security Context User Group ID", `Makes sure that all pods have a security context with valid UID and GID set `, containerSecurityContextUserGroupID) allChecks.RegisterPodCheck("Container Security Context Privileged", "Makes sure that all pods have a unprivileged security context set", containerSecurityContextPrivileged) allChecks.RegisterPodCheck("Container Security Context ReadOnlyRootFilesystem", "Makes sure that all pods have a security context with read only filesystem set", containerSecurityContextReadOnlyRootFilesystem) @@ -112,74 +110,6 @@ func containerSecurityContextUserGroupID(podTemplate corev1.PodTemplateSpec, typ return } -// containerSecurityContext checks that the recommended securityPolicy options are set -// Deprecated: will be replaced with "Container Security Context User Group ID", "Container Security Context Privileged" and "Container Security Context ReadOnlyRootFilesystem" in future versions -func containerSecurityContext(podTemplate corev1.PodTemplateSpec, typeMeta metav1.TypeMeta) (score scorecard.TestScore) { - allContainers := podTemplate.Spec.InitContainers - allContainers = append(allContainers, podTemplate.Spec.Containers...) - - noContextSet := false - hasPrivileged := false - hasWritableRootFS := false - hasLowUserID := false - hasLowGroupID := false - - podSecurityContext := podTemplate.Spec.SecurityContext - - for _, container := range allContainers { - - if container.SecurityContext == nil && podSecurityContext == nil { - noContextSet = true - score.AddComment(container.Name, "Container has no configured security context", "Set securityContext to run the container in a more secure context.") - continue - } - - sec := container.SecurityContext - - if sec == nil { - sec = &corev1.SecurityContext{} - } - - // Forward values from PodSecurityContext to the (container level) SecurityContext if not set - if podSecurityContext != nil { - if sec.RunAsGroup == nil { - sec.RunAsGroup = podSecurityContext.RunAsGroup - } - if sec.RunAsUser == nil { - sec.RunAsUser = podSecurityContext.RunAsUser - } - } - - if sec.Privileged != nil && *sec.Privileged { - hasPrivileged = true - score.AddComment(container.Name, "The container is privileged", "Set securityContext.privileged to false. Privileged containers can access all devices on the host, and grants almost the same access as non-containerized processes on the host.") - } - - if sec.ReadOnlyRootFilesystem == nil || *sec.ReadOnlyRootFilesystem == false { - hasWritableRootFS = true - score.AddComment(container.Name, "The pod has a container with a writable root filesystem", "Set securityContext.readOnlyRootFilesystem to true") - } - - if sec.RunAsUser == nil || *sec.RunAsUser < 10000 { - hasLowUserID = true - score.AddComment(container.Name, "The container is running with a low user ID", "A userid above 10 000 is recommended to avoid conflicts with the host. Set securityContext.runAsUser to a value > 10000") - } - - if sec.RunAsGroup == nil || *sec.RunAsGroup < 10000 { - hasLowGroupID = true - score.AddComment(container.Name, "The container running with a low group ID", "A groupid above 10 000 is recommended to avoid conflicts with the host. Set securityContext.runAsGroup to a value > 10000") - } - } - - if noContextSet || hasPrivileged || hasWritableRootFS || hasLowUserID || hasLowGroupID { - score.Grade = scorecard.GradeCritical - } else { - score.Grade = scorecard.GradeAllOK - } - - return -} - // podSeccompProfile checks if the any Seccommp profile is configured for the pod func podSeccompProfile(podTemplate corev1.PodTemplateSpec, typeMeta metav1.TypeMeta) (score scorecard.TestScore) { metadata := podTemplate.ObjectMeta diff --git a/score/security_test.go b/score/security_test.go index 7295dec8..58060f97 100644 --- a/score/security_test.go +++ b/score/security_test.go @@ -1,291 +1,14 @@ package score import ( - "bytes" "testing" "github.com/stretchr/testify/assert" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/yaml" - "github.com/zegl/kube-score/config" ks "github.com/zegl/kube-score/domain" "github.com/zegl/kube-score/scorecard" ) -func TestPodSecurityContext(test *testing.T) { - test.Parallel() - - b := func(b bool) *bool { return &b } - i := func(i int64) *int64 { return &i } - - tests := []struct { - ctx *corev1.SecurityContext - podCtx *corev1.PodSecurityContext - expectedGrade scorecard.Grade - expectedComment *scorecard.TestScoreComment - }{ - // No security context set - { - ctx: nil, - expectedGrade: scorecard.GradeCritical, - expectedComment: &scorecard.TestScoreComment{ - Path: "foobar", - Summary: "Container has no configured security context", - Description: "Set securityContext to run the container in a more secure context.", - }, - }, - // All required variables set correctly - { - ctx: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: b(true), - RunAsGroup: i(23000), - RunAsUser: i(33000), - RunAsNonRoot: b(true), - Privileged: b(false), - }, - expectedGrade: scorecard.GradeAllOK, - }, - // Read only file system is explicitly false - { - ctx: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: b(false), - }, - expectedGrade: scorecard.GradeCritical, - expectedComment: &scorecard.TestScoreComment{ - Path: "foobar", - Summary: "The pod has a container with a writable root filesystem", - Description: "Set securityContext.readOnlyRootFilesystem to true", - }, - }, - { - ctx: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: b(false), - }, - expectedGrade: scorecard.GradeCritical, - expectedComment: &scorecard.TestScoreComment{ - Path: "foobar", - Summary: "The pod has a container with a writable root filesystem", - Description: "Set securityContext.readOnlyRootFilesystem to true", - }, - }, - - // Context is non-null, but has all null values - { - ctx: &corev1.SecurityContext{}, - expectedGrade: scorecard.GradeCritical, - expectedComment: &scorecard.TestScoreComment{ - Path: "foobar", - Summary: "The pod has a container with a writable root filesystem", - Description: "Set securityContext.readOnlyRootFilesystem to true", - }, - }, - // Context is non nul, but has all null values - { - ctx: &corev1.SecurityContext{}, - expectedGrade: scorecard.GradeCritical, - expectedComment: &scorecard.TestScoreComment{ - Path: "foobar", - Summary: "The container is running with a low user ID", - Description: "A userid above 10 000 is recommended to avoid conflicts with the host. Set securityContext.runAsUser to a value > 10000", - }, - }, - // Context is non nul, but has all null values - { - ctx: &corev1.SecurityContext{}, - expectedGrade: scorecard.GradeCritical, - expectedComment: &scorecard.TestScoreComment{ - Path: "foobar", - Summary: "The container running with a low group ID", - Description: "A groupid above 10 000 is recommended to avoid conflicts with the host. Set securityContext.runAsGroup to a value > 10000", - }, - }, - // PodSecurityContext is set, assert that the values are inherited - { - ctx: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: b(true), - RunAsNonRoot: b(true), - Privileged: b(false), - }, - podCtx: &corev1.PodSecurityContext{ - RunAsUser: i(20000), - RunAsGroup: i(20000), - }, - expectedGrade: scorecard.GradeAllOK, - }, - // PodSecurityContext is set, assert that the values are inherited - // The container ctx has invalid values - { - ctx: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: b(true), - RunAsNonRoot: b(true), - Privileged: b(false), - RunAsUser: i(4), - RunAsGroup: i(5), - }, - podCtx: &corev1.PodSecurityContext{ - RunAsUser: i(20000), - RunAsGroup: i(20000), - }, - expectedGrade: scorecard.GradeCritical, - expectedComment: &scorecard.TestScoreComment{ - Path: "foobar", - Summary: "The container running with a low group ID", - Description: "A groupid above 10 000 is recommended to avoid conflicts with the host. Set securityContext.runAsGroup to a value > 10000", - }, - }, - - // Privileged defaults to "false" - { - ctx: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: b(true), - RunAsNonRoot: b(true), - }, - podCtx: &corev1.PodSecurityContext{ - RunAsUser: i(20000), - RunAsGroup: i(20000), - }, - expectedGrade: scorecard.GradeAllOK, - }, - - // Privileged explicitly set to "false" - { - ctx: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: b(true), - RunAsNonRoot: b(true), - Privileged: b(false), - }, - podCtx: &corev1.PodSecurityContext{ - RunAsUser: i(20000), - RunAsGroup: i(20000), - }, - expectedGrade: scorecard.GradeAllOK, - }, - - // Privileged explicitly set to "true" - { - ctx: &corev1.SecurityContext{ - ReadOnlyRootFilesystem: b(true), - RunAsNonRoot: b(true), - Privileged: b(true), - }, - podCtx: &corev1.PodSecurityContext{ - RunAsUser: i(20000), - RunAsGroup: i(20000), - }, - expectedGrade: scorecard.GradeCritical, - expectedComment: &scorecard.TestScoreComment{ - Path: "foobar", - Summary: "The container is privileged", - Description: "Set securityContext.privileged to false. Privileged containers can access all devices on the host, and grants almost the same access as non-containerized processes on the host.", - }, - }, - } - - for caseID, tc := range tests { - test.Logf("Running caseID=%d", caseID) - - s := appsv1.StatefulSet{ - TypeMeta: metav1.TypeMeta{ - Kind: "StatefulSet", - APIVersion: "apps/v1", - }, - Spec: appsv1.StatefulSetSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "foo", - }, - }, - Template: corev1.PodTemplateSpec{ - Spec: corev1.PodSpec{ - SecurityContext: tc.podCtx, - Containers: []corev1.Container{ - { - Name: "foobar", - SecurityContext: tc.ctx, - }, - }, - }, - }, - }, - } - - output, err := yaml.Marshal(s) - assert.Nil(test, err, "caseID=%d", caseID) - - comments := testExpectedScoreWithConfig( - test, config.Configuration{ - AllFiles: []ks.NamedReader{unnamedReader{bytes.NewReader(output)}}, - KubernetesVersion: config.Semver{1, 18}, - EnabledOptionalTests: map[string]struct{}{ - "container-security-context": {}, - }, - }, - "Container Security Context", - tc.expectedGrade, - ) - - // comments := testExpectedScoreReader(test, bytes.NewReader(output), "Container Security Context", tc.expectedGrade) - - if tc.expectedComment != nil { - assert.Contains(test, comments, *tc.expectedComment, "caseID=%d", caseID) - } - } -} - -func TestContainerSecurityContextPrivileged(t *testing.T) { - t.Parallel() - testExpectedScoreWithConfig(t, config.Configuration{ - AllFiles: []ks.NamedReader{testFile("pod-security-context-privileged.yaml")}, - EnabledOptionalTests: map[string]struct{}{ - "container-security-context": {}, - }, - }, "Container Security Context", scorecard.GradeCritical) -} - -func TestContainerSecurityContextLowUser(t *testing.T) { - t.Parallel() - testExpectedScoreWithConfig(t, config.Configuration{ - AllFiles: []ks.NamedReader{testFile("pod-security-context-low-user-id.yaml")}, - EnabledOptionalTests: map[string]struct{}{ - "container-security-context": {}, - }, - }, "Container Security Context", scorecard.GradeCritical) -} - -func TestContainerSecurityContextLowGroup(t *testing.T) { - t.Parallel() - testExpectedScoreWithConfig(t, config.Configuration{ - AllFiles: []ks.NamedReader{testFile("pod-security-context-low-group-id.yaml")}, - EnabledOptionalTests: map[string]struct{}{ - "container-security-context": {}, - }, - }, "Container Security Context", scorecard.GradeCritical) -} - -func TestPodSecurityContextInherited(t *testing.T) { - t.Parallel() - testExpectedScoreWithConfig(t, config.Configuration{ - AllFiles: []ks.NamedReader{testFile("security-inherit-pod-security-context.yaml")}, - EnabledOptionalTests: map[string]struct{}{ - "container-security-context": {}, - }, - }, "Container Security Context", scorecard.GradeAllOK) -} - -func TestContainerSecurityContextAllGood(t *testing.T) { - t.Parallel() - c := testExpectedScoreWithConfig(t, config.Configuration{ - AllFiles: []ks.NamedReader{testFile("pod-security-context-all-good.yaml")}, - EnabledOptionalTests: map[string]struct{}{ - "container-security-context": {}, - }, - }, "Container Security Context", scorecard.GradeAllOK) - assert.Empty(t, c) -} - func TestContainerSeccompMissing(t *testing.T) { t.Parallel() From 1b5532c5edbf069f9f42dba07a733f4db1bedea6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Oct 2021 11:13:30 +0000 Subject: [PATCH 2/2] build(deps): bump k8s.io/api from 0.22.2 to 0.22.3 Bumps [k8s.io/api](https://github.com/kubernetes/api) from 0.22.2 to 0.22.3. - [Release notes](https://github.com/kubernetes/api/releases) - [Commits](https://github.com/kubernetes/api/compare/v0.22.2...v0.22.3) --- updated-dependencies: - dependency-name: k8s.io/api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index a0c185ed..c0d7e5f0 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/stretchr/testify v1.7.0 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b - k8s.io/api v0.22.2 - k8s.io/apimachinery v0.22.2 + k8s.io/api v0.22.3 + k8s.io/apimachinery v0.22.3 sigs.k8s.io/yaml v1.3.0 ) diff --git a/go.sum b/go.sum index 94151d2d..2e6ba091 100644 --- a/go.sum +++ b/go.sum @@ -219,10 +219,10 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= -k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= -k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= -k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/api v0.22.3 h1:wOoES2GoSkUsdped2RB4zYypPqWtvprGoKCENTOOjP4= +k8s.io/api v0.22.3/go.mod h1:azgiXFiXqiWyLCfI62/eYBOu19rj2LKmIhFPP4+33fs= +k8s.io/apimachinery v0.22.3 h1:mrvBG5CZnEfwgpVqWcrRKvdsYECTrhAR6cApAgdsflk= +k8s.io/apimachinery v0.22.3/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM=