Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(query): Extend containers_running_as_root k8s rule to work if no securityContext is defined #4886

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"queryName": "Container Running As Root",
"severity": "MEDIUM",
"category": "Best Practices",
"descriptionText": "Check if containers are running as root unduly.",
"descriptionText": "Containers should only run as non-root user. This limits the exploitability of security misconfigurations and restricts an attacker's possibilities in case of compromise",
"descriptionUrl": "https://kubernetes.io/docs/tasks/configure-pod-container/security-context/",
"platform": "Kubernetes",
"descriptionID": "9d5b1d16"
Expand Down
174 changes: 46 additions & 128 deletions assets/queries/k8s/containers_running_as_root/query.rego
Original file line number Diff line number Diff line change
Expand Up @@ -4,155 +4,73 @@ import data.generic.k8s as k8sLib
import data.generic.common as common_lib

types := {"initContainers", "containers"}
options := {"runAsUser", "runAsNonRoot"}

# if the node is Pod type
CxPolicy[result] {
document := input.document[i]
document.kind == "Pod"

spec := document.spec

metadata := document.metadata
result := checkRootParent(spec.securityContext, types[x], spec[types[x]][_],"spec", metadata,input.document[i].id)
}

# if the node is CronJob type
CxPolicy[result] {
document := input.document[i]
document.kind == "CronJob"

spec := document.spec.jobTemplate.spec.template.spec

metadata := document.metadata
result := checkRootParent(spec.securityContext, types[x], spec[types[x]][_], "spec.jobTemplate.spec.template.spec", metadata,input.document[i].id)
}

CxPolicy[result] {
document := input.document[i]
kind := document.kind
listKinds := ["Deployment", "DaemonSet", "StatefulSet", "ReplicaSet", "ReplicationController", "Job", "Service", "Secret", "ServiceAccount", "Role", "RoleBinding", "ConfigMap", "Ingress"]
k8sLib.checkKind(kind, listKinds)

spec := document.spec.template.spec

metadata := document.metadata
result := checkRootParent(spec.securityContext, types[x], spec[types[x]][_], "spec.template.spec", metadata,input.document[i].id)
}

#if pod runAsNonRoot==true and container runAsNonRoot==true (container not runs as root)
#if pod runAsNonRoot==true and container runAsNonRoot==false
#if container runAsUser>0 (container not runs as root)
#if container runAsUser<=0 (container runs as root)
checkRootParent(rootSecurityContext, containerType, container, path, metadata,id) = result {
nonRootParent := object.get(rootSecurityContext, "runAsNonRoot", "undefined")
is_boolean(nonRootParent)
runsAsRoot(ctx) {
runAsNonRoot := object.get(ctx, "runAsNonRoot", false)
runAsUser := object.get(ctx, "runAsUser", 0)

nonRootParent == true

result := checkRootContainer(rootSecurityContext, containerType, container, path, metadata,id)
runAsNonRoot == false
to_number(runAsUser) == 0
}

#if pod runAsNonRoot==false and pod runAsUser>0
#if container runAsUser>0
#if container runAsNonRoot==false (container runs as non root)
#if container runAsNonRoot==true (container runs as non root)
#if container runAsUser<=0
#if container runAsNonRoot==false (container runs as root)
#if container runAsNonRoot==true (container runs as root)
checkRootParent(rootSecurityContext, containerType, container, path, metadata,id) = result {
nonRootParent := object.get(rootSecurityContext, "runAsNonRoot", "undefined")
is_boolean(nonRootParent)

nonRootParent == false

userParent := object.get(rootSecurityContext, "runAsUser", "undefined")
is_number(userParent)
# container defines runAsNonRoot or runAsUser
checkRoot(specInfo, container, containerType, containerId, document, metadata) = result {
common_lib.valid_key(container.securityContext, options[_])
runsAsRoot(container.securityContext)

userParent > 0

result := checkUserContainer(rootSecurityContext, containerType, container, path, metadata,id)
}
#if pod runAsNonRoot==false and pod runAsUser<=0
#if container runAsUser>0
#if container runAsNonRoot==false (container runs as non root)
#if container runAsNonRoot==true (container runs as non root)
#if container runAsUser<=0
#if container runAsNonRoot==false (container runs as root)
#if container runAsNonRoot==true (container runs as non root)
checkRootParent(rootSecurityContext, containerType, container, path, metadata,id) = result {
nonRootParent := object.get(rootSecurityContext, "runAsNonRoot", "undefined")
is_boolean(nonRootParent)

nonRootParent == false

userParent := object.get(rootSecurityContext, "runAsUser", "undefined")
is_number(userParent)

userParent <= 0

result := checkRootContainer(rootSecurityContext, containerType, container, path, metadata,id)
result := {
"documentId": document.id,
"searchKey": sprintf("metadata.name={{%s}}.%s.%s.name={{%s}}.securityContext.runAsUser", [metadata.name, specInfo.path, containerType, container.name]),
"issueType": "IncorrectValue",
"keyExpectedValue": sprintf("metadata.name={{%s}}.%s.%s.name={{%s}}.securityContext.runAsUser is higher than 0 and/or 'runAsNonRoot' is true", [metadata.name, specInfo.path, containerType, container.name]),
"keyActualValue": sprintf("metadata.name={{%s}}.%s.%s.name={{%s}}.securityContext.runAsUser is 0 and 'runAsNonRoot' is false", [metadata.name, specInfo.path, containerType, container.name]),
}
}

# container inherits setting from pod
checkRoot(specInfo, container, containerType, containerId, document, metadata) = result {
containerCtx := object.get(container, "securityContext", {})
not common_lib.valid_key(containerCtx, "runAsUser")
not common_lib.valid_key(containerCtx, "runAsNonRoot")

checkRootParent(rootSecurityContext, containerType, container, path, metadata,id) = result {
not common_lib.valid_key(rootSecurityContext, "runAsNonRoot")
not common_lib.valid_key(rootSecurityContext, "runAsUser")

result := checkRootContainer(rootSecurityContext, containerType, container, path, metadata,id)
}

checkRootContainer(rootSecurityContext, containerType, container, path, metadata,id) = result {

not container.securityContext.runAsNonRoot
uid := container.securityContext.runAsUser
to_number(uid) <= 0
common_lib.valid_key(specInfo.spec.securityContext, options[_])
runsAsRoot(specInfo.spec.securityContext)

result := {
"documentId": id,
"searchKey": sprintf("metadata.name={{%s}}.%s.%s.%s", [metadata.name, path, containerType, container.name]),
"documentId": document.id,
"searchKey": sprintf("metadata.name={{%s}}.%s.securityContext.runAsUser", [metadata.name, specInfo.path]),
"issueType": "IncorrectValue",
"keyExpectedValue": sprintf("'%s.%s.securityContext.runAsUser' is higher than 0 and/or 'runAsNonRoot' is true", [path, containerType]),
"keyActualValue": sprintf("'%s.%s.securityContext.runAsUser' is 0 and 'runAsNonRoot' is not set to true", [path, containerType]),
"keyExpectedValue": sprintf("metadata.name={{%s}}.%s.securityContext.runAsUser is higher than 0 and/or 'runAsNonRoot' is true", [metadata.name, specInfo.path]),
"keyActualValue": sprintf("metadata.name={{%s}}.%s.securityContext.runAsUser is 0 and 'runAsNonRoot' is false", [metadata.name, specInfo.path]),
}
}

checkRootContainer(rootSecurityContext, containerType, container, path, metadata,id) = result {
# neither pod nor container define runAsNonRoot or runAsUser
checkRoot(specInfo, container, containerType, containerId, document, metadata) = result {
specCtx := object.get(specInfo.spec, "securityContext", {})
not common_lib.valid_key(specCtx, "runAsUser")
not common_lib.valid_key(specCtx, "runAsNonRoot")

not container.securityContext.runAsNonRoot
not common_lib.valid_key(container.securityContext, "runAsUser")
containerCtx := object.get(container, "securityContext", {})
not common_lib.valid_key(containerCtx, "runAsUser")
not common_lib.valid_key(containerCtx, "runAsNonRoot")

result := {
"documentId": id,
"searchKey": sprintf("metadata.name={{%s}}.%s.%s.{{%s}}.securityContext", [metadata.name, path, containerType, container.name]),
"documentId": document.id,
"searchKey": sprintf("metadata.name={{%s}}.%s.%s.name={{%s}}", [metadata.name, specInfo.path, containerType, container.name]),
"issueType": "MissingAttribute",
"keyExpectedValue": sprintf("'%s.%s.securityContext.runAsUser' is defined", [path, containerType]),
"keyActualValue": sprintf("'%s.%s.securityContext.runAsUser' is undefined", [path, containerType]),
"keyExpectedValue": sprintf("metadata.name={{%s}}.%s.%s.name={{%s}}.securityContext.runAsUser is higher than 0 and/or 'runAsNonRoot' is true", [metadata.name, specInfo.path, containerType, container.name]),
"keyActualValue": sprintf("metadata.name={{%s}}.%s.%s.name={{%s}}.securityContext.runAsUser is 0 and 'runAsNonRoot' is false", [metadata.name, specInfo.path, containerType, container.name]),
"searchLine": common_lib.build_search_line(split(specInfo.path, "."), [containerType, containerId, "securityContext"])
}
}

checkUserContainer(rootSecurityContext, containerType, container, path, metadata,id) = result {
uid := container.securityContext.runAsUser
to_number(uid) <= 0

result := {
"documentId": id,
"searchKey": sprintf("metadata.name={{%s}}.%s.%s.%s", [metadata.name, path, containerType, container.name]),
"issueType": "IncorrectValue",
"keyExpectedValue": sprintf("'%s.%s.securityContext.runAsUser' is higher than 0 and/or 'runAsNonRoot' is true", [path, containerType]),
"keyActualValue": sprintf("'%s.%s.securityContext.runAsUser' is 0 and 'runAsNonRoot' is not set to true", [path, containerType]),
}
}
CxPolicy[result] {
document := input.document[i]
metadata := document.metadata

checkUserContainer(rootSecurityContext, containerType, container, path, metadata,id) = result {
not container.securityContext.runAsNonRoot
not common_lib.valid_key(container.securityContext, "runAsUser")
specInfo := k8sLib.getSpecInfo(document)

result := {
"documentId": id,
"searchKey": sprintf("metadata.name={{%s}}.%s.%s.{{%s}}.securityContext", [metadata.name, path, containerType, container.name]),
"issueType": "MissingAttribute",
"keyExpectedValue": sprintf("'%s.%s.securityContext.runAsUser' is defined", [path, containerType]),
"keyActualValue": sprintf("'%s.%s.securityContext.runAsUser' is undefined", [path, containerType]),
}

result := checkRoot(specInfo, specInfo.spec[types[x]][c], types[x], c, document, metadata)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo-2
spec:
containers:
- name: sec-ctx-demo-1
image: gcr.io/google-samples/node-hello:1.0
- name: sec-ctx-demo-2
image: gcr.io/google-samples/node-hello:1.0
securityContext:
runAsUser: 0
allowPrivilegeEscalation: false
runAsNonRoot: false
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,49 @@
{
"queryName": "Container Running As Root",
"severity": "MEDIUM",
"line": 10,
"line": 13,
"fileName": "positive1.yaml"
},
{
"queryName": "Container Running As Root",
"severity": "MEDIUM",
"line": 28,
"line": 38,
"fileName": "positive1.yaml"
},
{
"queryName": "Container Running As Root",
"severity": "MEDIUM",
"line": 41,
"line": 44,
"fileName": "positive1.yaml"
},
{
"queryName": "Container Running As Root",
"severity": "MEDIUM",
"line": 10,
"line": 13,
"fileName": "positive2.yaml"
},
{
"queryName": "Container Running As Root",
"severity": "MEDIUM",
"line": 15,
"line": 18,
"fileName": "positive2.yaml"
},
{
"queryName": "Container Running As Root",
"severity": "MEDIUM",
"line": 10,
"line": 13,
"fileName": "positive3.yaml"
},
{
"queryName": "Container Running As Root",
"severity": "MEDIUM",
"line": 7,
"fileName": "positive4.yaml"
},
{
"queryName": "Container Running As Root",
"severity": "MEDIUM",
"line": 12,
"fileName": "positive4.yaml"
}
]