Skip to content

Commit 3dd7446

Browse files
committed
Add a couple more check templates and built-in checks (#6)
1 parent f5db165 commit 3dd7446

File tree

10 files changed

+156
-1
lines changed

10 files changed

+156
-1
lines changed

.golangci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ linters-settings:
5555
- importShadow
5656
- emptyStringTest
5757
- hugeParam
58+
- rangeValCopy
5859
nolintlint:
5960
allow-leading-space: false # require machine-readable nolint directives (i.e. with no leading space)
6061
allow-unused: false # report any unused nolint directives

docs/generated/checks.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ The following table enumerates built-in checks:
22

33
| Name | Enabled by default | Description | Template | Parameters |
44
| ---- | ------------------ | ----------- | -------- | ---------- |
5-
| env-var-secret | No | Alert on objects using a secret in an environment variable | env-var |- `name`: `.*secret.*` <br />|
5+
| env-var-secret | Yes | Alert on objects using a secret in an environment variable | env-var |- `name`: `.*secret.*` <br />|
6+
| no-read-only-root-fs | Yes | Alert on containers not running with a read-only root filesystem | read-only-root-fs | none |
67
| privileged-container | Yes | Alert on deployments with containers running in privileged mode | privileged | none |
78
| required-label-owner | No | Alert on objects without the 'owner' label | required-label |- `key`: `owner` <br />|
9+
| run-as-non-root | Yes | Alert on containers not set to runAsNonRoot | run-as-non-root | none |

docs/generated/templates.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ The following table enumerates supported check templates:
44
| ---- | ----------- | ----------------- | ---------- |
55
| env-var | Flag environment variables that match the provided patterns | DeploymentLike |- `name` (required): A regex for the env var name <br />- `value`: A regex for the env var value <br />|
66
| privileged | Flag privileged containers | DeploymentLike | none |
7+
| read-only-root-fs | Flag containers without read-only root file systems | DeploymentLike | none |
78
| required-label | Flag objects not carrying at least one label matching the provided patterns | Any |- `key` (required): A regex for the key of the required label <br />- `value`: A regex for the value of the required label <br />|
9+
| run-as-non-root | Flag containers set to run as a root user | DeploymentLike | none |
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
name: "no-read-only-root-fs"
2+
description: "Alert on containers not running with a read-only root filesystem"
3+
scope:
4+
objectKinds:
5+
- DeploymentLike
6+
template: "read-only-root-fs"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
name: "run-as-non-root"
2+
description: "Alert on containers not set to runAsNonRoot"
3+
scope:
4+
objectKinds:
5+
- DeploymentLike
6+
template: "run-as-non-root"

internal/defaultchecks/default_checks.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,8 @@ var (
88
// List is the list of built-in checks that are enabled by default.
99
List = set.NewFrozenStringSet(
1010
"privileged-container",
11+
"env-var-secret",
12+
"no-read-only-root-fs",
13+
"run-as-non-root",
1114
)
1215
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package defaultchecks
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/stretchr/testify/require"
8+
"golang.stackrox.io/kube-linter/internal/builtinchecks"
9+
"golang.stackrox.io/kube-linter/internal/set"
10+
)
11+
12+
func TestListReferencesOnlyValidChecks(t *testing.T) {
13+
allChecks, err := builtinchecks.List()
14+
require.NoError(t, err)
15+
allCheckNames := set.NewStringSet()
16+
for _, check := range allChecks {
17+
allCheckNames.Add(check.Name)
18+
}
19+
for _, defaultCheck := range List.AsSlice() {
20+
assert.True(t, allCheckNames.Contains(defaultCheck), "default check %s invalid", defaultCheck)
21+
}
22+
}

internal/templates/all/all.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ import (
44
// Import all check templates.
55
_ "golang.stackrox.io/kube-linter/internal/templates/envvar"
66
_ "golang.stackrox.io/kube-linter/internal/templates/privileged"
7+
_ "golang.stackrox.io/kube-linter/internal/templates/readonlyrootfs"
78
_ "golang.stackrox.io/kube-linter/internal/templates/requiredlabel"
9+
_ "golang.stackrox.io/kube-linter/internal/templates/runasnonroot"
810
)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package readonlyrootfs
2+
3+
import (
4+
"fmt"
5+
6+
"golang.stackrox.io/kube-linter/internal/check"
7+
"golang.stackrox.io/kube-linter/internal/diagnostic"
8+
"golang.stackrox.io/kube-linter/internal/extract"
9+
"golang.stackrox.io/kube-linter/internal/lintcontext"
10+
"golang.stackrox.io/kube-linter/internal/objectkinds"
11+
"golang.stackrox.io/kube-linter/internal/templates"
12+
)
13+
14+
func init() {
15+
templates.Register(check.Template{
16+
Name: "read-only-root-fs",
17+
Description: "Flag containers without read-only root file systems",
18+
SupportedObjectKinds: check.ObjectKindsDesc{
19+
ObjectKinds: []string{objectkinds.DeploymentLike},
20+
},
21+
Parameters: nil,
22+
Instantiate: func(_ map[string]string) (check.Func, error) {
23+
return func(_ *lintcontext.LintContext, object lintcontext.Object) []diagnostic.Diagnostic {
24+
podSpec, found := extract.PodSpec(object.K8sObject)
25+
if !found {
26+
return nil
27+
}
28+
var results []diagnostic.Diagnostic
29+
for _, container := range podSpec.Containers {
30+
sc := container.SecurityContext
31+
if sc == nil || sc.ReadOnlyRootFilesystem == nil || !*sc.ReadOnlyRootFilesystem {
32+
results = append(results, diagnostic.Diagnostic{Message: fmt.Sprintf("container %q does not have a read-only root file system", container.Name)})
33+
}
34+
}
35+
return results
36+
}, nil
37+
},
38+
})
39+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package runasnonroot
2+
3+
import (
4+
"fmt"
5+
6+
"golang.stackrox.io/kube-linter/internal/check"
7+
"golang.stackrox.io/kube-linter/internal/diagnostic"
8+
"golang.stackrox.io/kube-linter/internal/extract"
9+
"golang.stackrox.io/kube-linter/internal/lintcontext"
10+
"golang.stackrox.io/kube-linter/internal/objectkinds"
11+
"golang.stackrox.io/kube-linter/internal/templates"
12+
v1 "k8s.io/api/core/v1"
13+
)
14+
15+
func effectiveRunAsNonRoot(podSC *v1.PodSecurityContext, containerSC *v1.SecurityContext) bool {
16+
if containerSC != nil && containerSC.RunAsNonRoot != nil {
17+
return *containerSC.RunAsNonRoot
18+
}
19+
if podSC != nil && podSC.RunAsNonRoot != nil {
20+
return *podSC.RunAsNonRoot
21+
}
22+
return false
23+
}
24+
25+
func effectiveRunAsUser(podSC *v1.PodSecurityContext, containerSC *v1.SecurityContext) *int64 {
26+
if containerSC != nil && containerSC.RunAsUser != nil {
27+
return containerSC.RunAsUser
28+
}
29+
if podSC != nil {
30+
return podSC.RunAsUser
31+
}
32+
return nil
33+
}
34+
35+
func init() {
36+
templates.Register(check.Template{
37+
Name: "run-as-non-root",
38+
Description: "Flag containers set to run as a root user",
39+
SupportedObjectKinds: check.ObjectKindsDesc{
40+
ObjectKinds: []string{objectkinds.DeploymentLike},
41+
},
42+
Parameters: nil,
43+
Instantiate: func(_ map[string]string) (check.Func, error) {
44+
return func(_ *lintcontext.LintContext, object lintcontext.Object) []diagnostic.Diagnostic {
45+
podSpec, found := extract.PodSpec(object.K8sObject)
46+
if !found {
47+
return nil
48+
}
49+
var results []diagnostic.Diagnostic
50+
for _, container := range podSpec.Containers {
51+
runAsUser := effectiveRunAsUser(podSpec.SecurityContext, container.SecurityContext)
52+
// runAsUser explicitly set to non-root. All good.
53+
if runAsUser != nil && *runAsUser > 0 {
54+
continue
55+
}
56+
runAsNonRoot := effectiveRunAsNonRoot(podSpec.SecurityContext, container.SecurityContext)
57+
if runAsNonRoot {
58+
// runAsNonRoot set, but runAsUser set to 0. This will result in a runtime failure.
59+
if runAsUser != nil && *runAsUser == 0 {
60+
results = append(results, diagnostic.Diagnostic{
61+
Message: fmt.Sprintf("container %q is set to runAsNonRoot, but runAsUser set to %d", container.Name, *runAsUser),
62+
})
63+
}
64+
continue
65+
}
66+
results = append(results, diagnostic.Diagnostic{Message: fmt.Sprintf("container %q is not set to runAsNonRoot", container.Name)})
67+
}
68+
return results
69+
}, nil
70+
},
71+
})
72+
}

0 commit comments

Comments
 (0)