Skip to content

Commit daa264e

Browse files
author
Markus Lackner
committed
score/security: added optional, splitted probes as future replacemnt for security context probe
Fixes zegl#325
1 parent d9be66a commit daa264e

9 files changed

+271
-4
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ For a full list of checks, see [README_CHECKS.md](README_CHECKS.md).
3838
* Deployments and StatefulSets should have a `PodDisruptionPolicy`
3939
* Deployments and StatefulSets should have host PodAntiAffinity configured
4040
* Container probes, a readiness should be configured, and should not be identical to the liveness probe. Read more in [README_PROBES.md](README_PROBES.md).
41-
* Container securityContext, run as high number user/group, do not run as root or with privileged root fs
41+
* Container securityContext, run as high number user/group, do not run as root or with privileged root fs. Read more in [README_SECURITYCONTEXT.md](README_SECURITYCONTEXT.md).
4242
* Stable APIs, use a stable API if available (supported: Deployments, StatefulSets, DaemonSet)
4343

4444
## Example output

README_CHECKS.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
| pod-networkpolicy | Pod | Makes sure that all Pods are targeted by a NetworkPolicy | default |
1515
| networkpolicy-targets-pod | NetworkPolicy | Makes sure that all NetworkPolicies targets at least one Pod | default |
1616
| pod-probes | Pod | Makes sure that all Pods have safe probe configurations | default |
17-
| container-security-context | Pod | Makes sure that all pods have good securityContexts configured | default |
17+
| container-security-context | Pod | Makes sure that all pods have good securityContexts configured (*deprecated*, see [README_SECURITYCONTEXT.md](README_SECURITYCONTEXT.md) | default |
18+
| container-security-context-user-group-id | Pod | Makes sure that user and group ID are set and > 10000 | optional |
19+
| container-security-context-privileged | Pod | Makes sure that no Containers run in privileged mode | optional |
20+
| container-security-context-readonlyrootfilesystem | Makes sure that all Containers have read only filesystems | optional |
1821
| container-seccomp-profile | Pod | Makes sure that all pods have at a seccomp policy configured. | optional |
1922
| service-targets-pod | Service | Makes sure that all Services targets a Pod | default |
2023
| service-type | Service | Makes sure that the Service type is not NodePort | default |

README_SECURITYCONTEXT.md

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Security Context
2+
3+
The default probe `container-security-context` checks the `SecurityContext`
4+
for
5+
6+
* Containers with writeable root filesystems
7+
* Containers that run with user ID or group ID < 10000
8+
* Privileged containers
9+
10+
If you do not want all of this checks you can disable `container-security-context`
11+
probe and enable one or more of the following optional probes:
12+
13+
* `container-security-context-user-group-id`
14+
* `container-security-context-privileged`
15+
* `container-security-context-readonlyrootfilesystem`
16+
17+
In future releases the `container-security-context` will become *optional*
18+
and replaced by the more detailed probes.

go.sum

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY=
2727
github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=
2828
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
2929
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
30+
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
3031
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
3132
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
3233
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@@ -97,12 +98,14 @@ github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx
9798
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
9899
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
99100
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
101+
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
100102
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
101103
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
102104
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
103105
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
104106
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
105107
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
108+
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
106109
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
107110
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
108111
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
@@ -287,6 +290,7 @@ k8s.io/api v0.19.1 h1:oZf4bYsBdjC49PdTwNfLmrfUFCwKUi94HY/+emXI8Qw=
287290
k8s.io/api v0.19.1/go.mod h1:+u/k4/K/7vp4vsfdT7dyl8Oxk1F26Md4g5F26Tu85PU=
288291
k8s.io/api v0.19.2 h1:q+/krnHWKsL7OBZg/rxnycsl9569Pud76UJ77MvKXms=
289292
k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI=
293+
k8s.io/api v0.19.3 h1:GN6ntFnv44Vptj/b+OnMW7FmzkpDoIDLZRvKX3XH9aU=
290294
k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs=
291295
k8s.io/apimachinery v0.0.0-20191028221656-72ed19daf4bb/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ=
292296
k8s.io/apimachinery v0.0.0-20191121015412-41065c7a8c2a h1:9V03T5lHv/iF4fSgvMCd+iB86AgEgmzLpheMqIJy7hs=
@@ -317,6 +321,7 @@ k8s.io/apimachinery v0.19.1 h1:cwsxZazM/LA9aUsBaL4bRS5ygoM6bYp8dFk22DSYQa4=
317321
k8s.io/apimachinery v0.19.1/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
318322
k8s.io/apimachinery v0.19.2 h1:5Gy9vQpAGTKHPVOh5c4plE274X8D/6cuEiTO2zve7tc=
319323
k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
324+
k8s.io/apimachinery v0.19.3 h1:bpIQXlKjB4cB/oNpnNnV+BybGPR7iP5oYpsOTEJ4hgc=
320325
k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
321326
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
322327
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=

score/security/security.go

+100
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,110 @@ import (
1010

1111
func Register(allChecks *checks.Checks) {
1212
allChecks.RegisterPodCheck("Container Security Context", `Makes sure that all pods have good securityContexts configured`, containerSecurityContext)
13+
14+
allChecks.RegisterOptionalPodCheck("Container Security Context User Group ID", `Makes sure that all pods have a security context with valid UID and GID set `, containerSecurityContextUserGroupID)
15+
allChecks.RegisterOptionalPodCheck("Container Security Context Privileged", "Makes sure that all pods have a unprivileged security context set", containerSecurityContextPrivileged)
16+
allChecks.RegisterOptionalPodCheck("Container Security Context ReadOnlyRootFilesystem", "Makes sure that all pods have a security context with read only filesystem set", containerSecurityContextReadOnlyRootFilesystem)
17+
1318
allChecks.RegisterOptionalPodCheck("Container Seccomp Profile", `Makes sure that all pods have at a seccomp policy configured.`, podSeccompProfile)
1419
}
1520

21+
// containerSecurityContextReadOnlyRootFilesystem checks for pods using writeable root filesystems
22+
func containerSecurityContextReadOnlyRootFilesystem(podTemplate corev1.PodTemplateSpec, typeMeta metav1.TypeMeta) (score scorecard.TestScore) {
23+
allContainers := podTemplate.Spec.InitContainers
24+
allContainers = append(allContainers, podTemplate.Spec.Containers...)
25+
26+
noContextSet := false
27+
hasWritableRootFS := false
28+
29+
for _, container := range allContainers {
30+
if container.SecurityContext == nil {
31+
noContextSet = true
32+
score.AddComment(container.Name, "Container has no configured security context", "Set securityContext to run the container in a more secure context.")
33+
continue
34+
}
35+
sec := container.SecurityContext
36+
if sec.ReadOnlyRootFilesystem == nil || *sec.ReadOnlyRootFilesystem == false {
37+
hasWritableRootFS = true
38+
score.AddComment(container.Name, "The pod has a container with a writable root filesystem", "Set securityContext.readOnlyRootFilesystem to true")
39+
}
40+
}
41+
42+
if noContextSet || hasWritableRootFS {
43+
score.Grade = scorecard.GradeCritical
44+
} else {
45+
score.Grade = scorecard.GradeAllOK
46+
}
47+
48+
return
49+
}
50+
51+
// containerSecurityContextPrivileged checks for privileged containers
52+
func containerSecurityContextPrivileged(podTemplate corev1.PodTemplateSpec, typeMeta metav1.TypeMeta) (score scorecard.TestScore) {
53+
allContainers := podTemplate.Spec.InitContainers
54+
allContainers = append(allContainers, podTemplate.Spec.Containers...)
55+
hasPrivileged := false
56+
for _, container := range allContainers {
57+
if container.SecurityContext != nil && container.SecurityContext.Privileged != nil && *container.SecurityContext.Privileged {
58+
hasPrivileged = true
59+
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.")
60+
}
61+
}
62+
if hasPrivileged {
63+
score.Grade = scorecard.GradeCritical
64+
} else {
65+
score.Grade = scorecard.GradeAllOK
66+
}
67+
return
68+
}
69+
70+
// containerSecurityContextUserGroupID checks that the user and group are valid ( > 10000) in the security context
71+
func containerSecurityContextUserGroupID(podTemplate corev1.PodTemplateSpec, typeMeta metav1.TypeMeta) (score scorecard.TestScore) {
72+
allContainers := podTemplate.Spec.InitContainers
73+
allContainers = append(allContainers, podTemplate.Spec.Containers...)
74+
podSecurityContext := podTemplate.Spec.SecurityContext
75+
noContextSet := false
76+
hasLowUserID := false
77+
hasLowGroupID := false
78+
for _, container := range allContainers {
79+
if container.SecurityContext == nil && podSecurityContext == nil {
80+
noContextSet = true
81+
score.AddComment(container.Name, "Container has no configured security context", "Set securityContext to run the container in a more secure context.")
82+
continue
83+
}
84+
sec := container.SecurityContext
85+
if sec == nil {
86+
sec = &corev1.SecurityContext{}
87+
}
88+
// Forward values from PodSecurityContext to the (container level) SecurityContext if not set
89+
if podSecurityContext != nil {
90+
if sec.RunAsGroup == nil {
91+
sec.RunAsGroup = podSecurityContext.RunAsGroup
92+
}
93+
if sec.RunAsUser == nil {
94+
sec.RunAsUser = podSecurityContext.RunAsUser
95+
}
96+
}
97+
if sec.RunAsUser == nil || *sec.RunAsUser < 10000 {
98+
hasLowUserID = true
99+
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")
100+
}
101+
102+
if sec.RunAsGroup == nil || *sec.RunAsGroup < 10000 {
103+
hasLowGroupID = true
104+
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")
105+
}
106+
}
107+
if noContextSet || hasLowUserID || hasLowGroupID {
108+
score.Grade = scorecard.GradeCritical
109+
} else {
110+
score.Grade = scorecard.GradeAllOK
111+
}
112+
return
113+
}
114+
16115
// containerSecurityContext checks that the recommended securityPolicy options are set
116+
// Deprecated: will be replaced with "Container Security Context User Group ID", "Container Security Context Privileged" and "Container Security Context ReadOnlyRootFilesystem" in future versions
17117
func containerSecurityContext(podTemplate corev1.PodTemplateSpec, typeMeta metav1.TypeMeta) (score scorecard.TestScore) {
18118
allContainers := podTemplate.Spec.InitContainers
19119
allContainers = append(allContainers, podTemplate.Spec.Containers...)

score/security_test.go

+125-2
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,9 @@ func TestPodSecurityContext(test *testing.T) {
217217
}
218218
}
219219

220-
func TestContainerSecurityContextPrivilegied(t *testing.T) {
220+
func TestContainerSecurityContextPrivileged(t *testing.T) {
221221
t.Parallel()
222-
testExpectedScore(t, "pod-security-context-privilegied.yaml", "Container Security Context", scorecard.GradeCritical)
222+
testExpectedScore(t, "pod-security-context-privileged.yaml", "Container Security Context", scorecard.GradeCritical)
223223
}
224224

225225
func TestContainerSecurityContextLowUser(t *testing.T) {
@@ -266,3 +266,126 @@ func TestContainerSeccompAllGood(t *testing.T) {
266266
EnabledOptionalTests: structMap,
267267
}, "Container Seccomp Profile", scorecard.GradeAllOK)
268268
}
269+
270+
func TestContainerSecurityContextUserGroupIDAllGood(t *testing.T) {
271+
t.Parallel()
272+
structMap := make(map[string]struct{})
273+
structMap["container-security-context-user-group-id"] = struct{}{}
274+
c := testExpectedScoreWithConfig(t, config.Configuration{
275+
AllFiles: []ks.NamedReader{testFile("pod-security-context-all-good.yaml")},
276+
EnabledOptionalTests: structMap,
277+
}, "Container Security Context User Group ID", scorecard.GradeAllOK)
278+
assert.Empty(t, c)
279+
}
280+
281+
func TestContainerSecurityContextUserGroupIDLowGroup(t *testing.T) {
282+
t.Parallel()
283+
optionalChecks := make(map[string]struct{})
284+
optionalChecks["container-security-context-user-group-id"] = struct{}{}
285+
comments := testExpectedScoreWithConfig(t, config.Configuration{
286+
AllFiles: []ks.NamedReader{testFile("pod-security-context-low-group-id.yaml")},
287+
EnabledOptionalTests: optionalChecks,
288+
}, "Container Security Context User Group ID", scorecard.GradeCritical)
289+
assert.Contains(t, comments, scorecard.TestScoreComment{
290+
Path: "foobar",
291+
Summary: "The container running with a low group ID",
292+
Description: "A groupid above 10 000 is recommended to avoid conflicts with the host. Set securityContext.runAsGroup to a value > 10000",
293+
})
294+
}
295+
296+
func TestContainerSecurityContextUserGroupIDLowUser(t *testing.T) {
297+
t.Parallel()
298+
optionalChecks := make(map[string]struct{})
299+
optionalChecks["container-security-context-user-group-id"] = struct{}{}
300+
comments := testExpectedScoreWithConfig(t, config.Configuration{
301+
AllFiles: []ks.NamedReader{testFile("pod-security-context-low-user-id.yaml")},
302+
EnabledOptionalTests: optionalChecks,
303+
}, "Container Security Context User Group ID", scorecard.GradeCritical)
304+
assert.Contains(t, comments, scorecard.TestScoreComment{
305+
Path: "foobar",
306+
Summary: "The container is running with a low user ID",
307+
Description: "A userid above 10 000 is recommended to avoid conflicts with the host. Set securityContext.runAsUser to a value > 10000",
308+
})
309+
}
310+
311+
func TestContainerSecurityContextUserGroupIDNoSecurityContext(t *testing.T) {
312+
t.Parallel()
313+
optionalChecks := make(map[string]struct{})
314+
optionalChecks["container-security-context-user-group-id"] = struct{}{}
315+
comments := testExpectedScoreWithConfig(t, config.Configuration{
316+
AllFiles: []ks.NamedReader{testFile("pod-security-context-nosecuritycontext.yaml")},
317+
EnabledOptionalTests: optionalChecks,
318+
}, "Container Security Context User Group ID", scorecard.GradeCritical)
319+
assert.Contains(t, comments, scorecard.TestScoreComment{
320+
Path: "foobar",
321+
Summary: "Container has no configured security context",
322+
Description: "Set securityContext to run the container in a more secure context.",
323+
})
324+
}
325+
326+
func TestContainerSecurityContextPrivilegedAllGood(t *testing.T) {
327+
t.Parallel()
328+
structMap := make(map[string]struct{})
329+
structMap["container-security-context-privileged"] = struct{}{}
330+
c := testExpectedScoreWithConfig(t, config.Configuration{
331+
AllFiles: []ks.NamedReader{testFile("pod-security-context-all-good.yaml")},
332+
EnabledOptionalTests: structMap,
333+
}, "Container Security Context Privileged", scorecard.GradeAllOK)
334+
assert.Empty(t, c)
335+
}
336+
337+
func TestContainerSecurityContextPrivilegedPrivileged(t *testing.T) {
338+
t.Parallel()
339+
optionalChecks := make(map[string]struct{})
340+
optionalChecks["container-security-context-privileged"] = struct{}{}
341+
comments := testExpectedScoreWithConfig(t, config.Configuration{
342+
AllFiles: []ks.NamedReader{testFile("pod-security-context-privileged.yaml")},
343+
EnabledOptionalTests: optionalChecks,
344+
}, "Container Security Context Privileged", scorecard.GradeCritical)
345+
assert.Contains(t, comments, scorecard.TestScoreComment{
346+
Path: "foobar",
347+
Summary: "The container is privileged",
348+
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.",
349+
})
350+
}
351+
352+
func TestContainerSecurityContextReadOnlyRootFilesystemAllGood(t *testing.T) {
353+
t.Parallel()
354+
structMap := make(map[string]struct{})
355+
structMap["container-security-context-readonlyrootfilesystem"] = struct{}{}
356+
c := testExpectedScoreWithConfig(t, config.Configuration{
357+
AllFiles: []ks.NamedReader{testFile("pod-security-context-all-good.yaml")},
358+
EnabledOptionalTests: structMap,
359+
}, "Container Security Context ReadOnlyRootFilesystem", scorecard.GradeAllOK)
360+
assert.Empty(t, c)
361+
}
362+
363+
func TestContainerSecurityContextReadOnlyRootFilesystemWriteable(t *testing.T) {
364+
t.Parallel()
365+
optionalChecks := make(map[string]struct{})
366+
optionalChecks["container-security-context-readonlyrootfilesystem"] = struct{}{}
367+
comments := testExpectedScoreWithConfig(t, config.Configuration{
368+
AllFiles: []ks.NamedReader{testFile("pod-security-context-writeablerootfilesystem.yaml")},
369+
EnabledOptionalTests: optionalChecks,
370+
}, "Container Security Context ReadOnlyRootFilesystem", scorecard.GradeCritical)
371+
assert.Contains(t, comments, scorecard.TestScoreComment{
372+
Path: "foobar",
373+
Summary: "The pod has a container with a writable root filesystem",
374+
Description: "Set securityContext.readOnlyRootFilesystem to true",
375+
})
376+
}
377+
378+
func TestContainerSecurityContextReadOnlyRootFilesystemNoSecurityContext(t *testing.T) {
379+
t.Parallel()
380+
optionalChecks := make(map[string]struct{})
381+
optionalChecks["container-security-context-readonlyrootfilesystem"] = struct{}{}
382+
comments := testExpectedScoreWithConfig(t, config.Configuration{
383+
AllFiles: []ks.NamedReader{testFile("pod-security-context-nosecuritycontext.yaml")},
384+
EnabledOptionalTests: optionalChecks,
385+
}, "Container Security Context ReadOnlyRootFilesystem", scorecard.GradeCritical)
386+
assert.Contains(t, comments, scorecard.TestScoreComment{
387+
Path: "foobar",
388+
Summary: "Container has no configured security context",
389+
Description: "Set securityContext to run the container in a more secure context.",
390+
})
391+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: v1
2+
kind: Pod
3+
metadata:
4+
name: pod-test-1
5+
spec:
6+
containers:
7+
- name: foobar
8+
image: foo/bar:latest
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
apiVersion: v1
2+
kind: Pod
3+
metadata:
4+
name: pod-test-1
5+
spec:
6+
containers:
7+
- name: foobar
8+
image: foo/bar:latest
9+
securityContext:
10+
privileged: True

0 commit comments

Comments
 (0)