Skip to content

Commit

Permalink
Fix optional check for seccomp #590
Browse files Browse the repository at this point in the history
  • Loading branch information
kmarteaux authored and zegl committed Nov 25, 2024
1 parent 67cafc0 commit 3c0ad34
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 5 deletions.
4 changes: 4 additions & 0 deletions score/score.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ import (
func RegisterAllChecks(allObjects ks.AllTypes, checksConfig *checks.Config, runConfig *config.RunConfiguration) *checks.Checks {
allChecks := checks.New(checksConfig)

if runConfig == nil {
runConfig = &config.RunConfiguration{}
}

deployment.Register(allChecks, allObjects)
ingress.Register(allChecks, allObjects)
cronjob.Register(allChecks)
Expand Down
41 changes: 36 additions & 5 deletions score/security/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,20 +109,51 @@ func containerSecurityContextUserGroupID(ps ks.PodSpecer) (score scorecard.TestS
return
}

// podSeccompProfile checks that a Seccommp profile is configured for the pod
// podSeccompProfile checks that a Seccommp profile is configured. The
// seccompProfile can be specified either through annotation or securityContext.
// There are two ways to specify the seccomp profile via securityContext --
// at the pod level or container level.
// Pod level seccomp profile is preferred since it is applied to all containers.
func podSeccompProfile(ps ks.PodSpecer) (score scorecard.TestScore, err error) {
metadata := ps.GetPodTemplateSpec().ObjectMeta

seccompAnnotated := false
secured := false

// Check if the seccomp profile is set via annotation
if metadata.Annotations != nil {
if _, ok := metadata.Annotations["seccomp.security.alpha.kubernetes.io/defaultProfileName"]; ok {
seccompAnnotated = true
secured = true
}
}

//Check if seccomp is set via securityContext at Pod or Container Level
if !secured {
elements := make(map[string]bool)
if ps.GetPodTemplateSpec().Spec.SecurityContext != nil && ps.GetPodTemplateSpec().Spec.SecurityContext.SeccompProfile != nil {
secured = true
} else {
// This does not check initContainers, only Containers
for _, container := range ps.GetPodTemplateSpec().Spec.Containers {
if container.SecurityContext != nil && container.SecurityContext.SeccompProfile != nil {
elements[container.Name] = true
secured = true
} else {
score.AddComment(container.Name, "The container has not configured Seccomp", "Running containers with Seccomp is recommended to reduce the kernel attack surface")
elements[container.Name] = false
}
}
}

// one unsecured container is enough to fail the test
for _, value := range elements {
if !value {
secured = false
}
}
}

if !seccompAnnotated {
if !secured {
score.Grade = scorecard.GradeWarning
score.AddComment(metadata.Name, "The pod has not configured Seccomp for its containers", "Running containers with Seccomp is recommended to reduce the kernel attack surface")
} else {
score.Grade = scorecard.GradeAllOK
}
Expand Down
44 changes: 44 additions & 0 deletions score/security_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,50 @@ func TestContainerSeccompMissing(t *testing.T) {

}

func TestPodSecurityContextPresent(t *testing.T) {
t.Parallel()

structMap := make(map[string]struct{})
structMap["container-seccomp-profile"] = struct{}{}

testExpectedScoreWithConfig(t, []ks.NamedReader{testFile("pod-seccomp-securecontext-ok.yaml")}, nil, &config.RunConfiguration{
EnabledOptionalTests: structMap,
}, "Container Seccomp Profile", scorecard.GradeAllOK)
}

func TestContainerSecurityContextSeccompPresent(t *testing.T) {
t.Parallel()

structMap := make(map[string]struct{})
structMap["container-seccomp-profile"] = struct{}{}

testExpectedScoreWithConfig(t, []ks.NamedReader{testFile("pod-seccomp-container-securecontext-ok.yaml")}, nil, &config.RunConfiguration{
EnabledOptionalTests: structMap,
}, "Container Seccomp Profile", scorecard.GradeAllOK)
}

func TestPodSecurityContextSeccompAbsent(t *testing.T) {
t.Parallel()

structMap := make(map[string]struct{})
structMap["container-seccomp-profile"] = struct{}{}

testExpectedScoreWithConfig(t, []ks.NamedReader{testFile("pod-seccomp-securecontext-warning.yaml")}, nil, &config.RunConfiguration{
EnabledOptionalTests: structMap,
}, "Container Seccomp Profile", scorecard.GradeWarning)
}

func TestContainerSecurityContextSeccompAbsent(t *testing.T) {
t.Parallel()

structMap := make(map[string]struct{})
structMap["container-seccomp-profile"] = struct{}{}

testExpectedScoreWithConfig(t, []ks.NamedReader{testFile("pod-seccomp-container-securecontext-warning.yaml")}, nil, &config.RunConfiguration{
EnabledOptionalTests: structMap,
}, "Container Seccomp Profile", scorecard.GradeWarning)
}

func TestContainerSeccompMissingNotRunByDefault(t *testing.T) {
t.Parallel()
skipped := wasSkipped(t, []ks.NamedReader{testFile("pod-seccomp-no-annotation.yaml")}, nil, nil, "Container Seccomp Profile")
Expand Down
16 changes: 16 additions & 0 deletions score/testdata/pod-seccomp-container-securecontext-ok.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: v1
kind: Pod
metadata:
name: pod-test-1
spec:
containers:
- name: foobar
image: foo/bar:latest
securityContext:
privileged: False
runAsUser: 30000
runAsGroup: 30000
readOnlyRootFilesystem: True
seccompProfile:
type: RuntimeDefault

31 changes: 31 additions & 0 deletions score/testdata/pod-seccomp-container-securecontext-warning.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
apiVersion: v1
kind: Pod
metadata:
name: pod-test-1
spec:
containers:
- name: foobar
image: foo/bar:latest
securityContext:
privileged: False
runAsUser: 30000
runAsGroup: 30000
readOnlyRootFilesystem: True
seccompProfile:
type: RuntimeDefault
- name: foobaz
image: foo/baz:latest
securityContext:
privileged: False
runAsUser: 30000
runAsGroup: 30000
readOnlyRootFilesystem: True
- name: foozed
image: foo/zed:latest
securityContext:
privileged: False
runAsUser: 30000
runAsGroup: 30000
readOnlyRootFilesystem: True
seccompProfile:
type: RuntimeDefault
16 changes: 16 additions & 0 deletions score/testdata/pod-seccomp-securecontext-ok.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: v1
kind: Pod
metadata:
name: pod-test-1
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
containers:
- name: foobar
image: foo/bar:latest
securityContext:
privileged: False
runAsUser: 30000
runAsGroup: 30000
readOnlyRootFilesystem: True
15 changes: 15 additions & 0 deletions score/testdata/pod-seccomp-securecontext-warning.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Pod
metadata:
name: pod-test-1
spec:
securityContext:
privileged: False
runAsUser: 30000
runAsGroup: 30000
readOnlyRootFilesystem: True
containers:
- name: foobar
image: foo/bar:latest
- name: foobaz
image: foo/baz:latest

0 comments on commit 3c0ad34

Please sign in to comment.