diff --git a/assets/queries/k8s/containers_running_as_root/query.rego b/assets/queries/k8s/containers_running_as_root/query.rego index 0eda309ed59..5485d1c6b1f 100644 --- a/assets/queries/k8s/containers_running_as_root/query.rego +++ b/assets/queries/k8s/containers_running_as_root/query.rego @@ -2,6 +2,9 @@ package Cx import data.generic.k8s as k8sLib +types := {"initContainers", "containers"} + +# if the node is Pod type CxPolicy[result] { document := input.document[i] document.kind == "Pod" @@ -9,9 +12,10 @@ CxPolicy[result] { spec := document.spec metadata := document.metadata - result := checkRootParent(spec, "spec", metadata, input.document[i].id) + 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" @@ -19,7 +23,7 @@ CxPolicy[result] { spec := document.spec.jobTemplate.spec.template.spec metadata := document.metadata - result := checkRootParent(spec, "spec.jobTemplate.spec.template.spec", metadata, input.document[i].id) + result := checkRootParent(spec.securityContext, types[x], spec[types[x]][_], "spec.jobTemplate.spec.template.spec", metadata,input.document[i].id) } CxPolicy[result] { @@ -31,98 +35,123 @@ CxPolicy[result] { spec := document.spec.template.spec metadata := document.metadata - result := checkRootParent(spec, "spec.template.spec", metadata, input.document[i].id) + result := checkRootParent(spec.securityContext, types[x], spec[types[x]][_], "spec.template.spec", metadata,input.document[i].id) } -checkRootParent(spec, path, metadata, id) = result { - nonRootParent := object.get(spec.securityContext, "runAsNonRoot", "undefined") +#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) nonRootParent == true - result := checkRootContainer(spec, path, metadata, id) + result := checkRootContainer(rootSecurityContext, containerType, container, path, metadata,id) } -checkRootParent(spec, path, metadata, id) = result { - nonRootParent := object.get(spec.securityContext, "runAsNonRoot", "undefined") +#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(spec.securityContext, "runAsUser", "undefined") + userParent := object.get(rootSecurityContext, "runAsUser", "undefined") is_number(userParent) userParent > 0 - result := checkUserContainer(spec, path, metadata, id) + 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) -checkRootParent(spec, path, metadata, id) = result { - object.get(spec.securityContext, "runAsNonRoot", "undefined") == "undefined" - object.get(spec.securityContext, "runAsUser", "undefined") == "undefined" + userParent <= 0 - result := checkRootContainer(spec, path, metadata, id) + result := checkRootContainer(rootSecurityContext, containerType, container, path, metadata,id) } -types := {"initContainers", "containers"} -checkRootContainer(spec, path, metadata, id) = result { - some j - container := spec[types[x]][j] +checkRootParent(rootSecurityContext, containerType, container, path, metadata,id) = result { + object.get(rootSecurityContext, "runAsNonRoot", "undefined") == "undefined" + object.get(rootSecurityContext, "runAsUser", "undefined") == "undefined" + + 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 result := { "documentId": id, - "searchKey": sprintf("metadata.name={{%s}}.%s.%s.%s", [metadata.name, path, types[x], container.name]), + "searchKey": sprintf("metadata.name={{%s}}.%s.%s.%s", [metadata.name, path, containerType, container.name]), "issueType": "IncorrectValue", - "keyExpectedValue": sprintf("'%s.%s[%d].securityContext.runAsUser' is higher than 0 and/or 'runAsNonRoot' is true", [path, types[x], j]), - "keyActualValue": sprintf("'%s.%s[%d].securityContext.runAsUser' is 0 and 'runAsNonRoot' is not set to true", [path, types[x], j]), + "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]), } } -checkRootContainer(spec, path, metadata, id) = result { - some j - container := spec[types[x]][j] +checkRootContainer(rootSecurityContext, containerType, container, path, metadata,id) = result { + not container.securityContext.runAsNonRoot object.get(container.securityContext, "runAsUser", "undefined") == "undefined" result := { "documentId": id, - "searchKey": sprintf("metadata.name={{%s}}.%s.%s.{{%s}}.securityContext", [metadata.name, path, types[x], container.name]), + "searchKey": sprintf("metadata.name={{%s}}.%s.%s.{{%s}}.securityContext", [metadata.name, path, containerType, container.name]), "issueType": "MissingAttribute", - "keyExpectedValue": sprintf("'%s.%s[%d].securityContext.runAsUser' is defined", [path, types[x], j]), - "keyActualValue": sprintf("'%s.%s[%d].securityContext.runAsUser' is undefined", [path, types[x], j]), + "keyExpectedValue": sprintf("'%s.%s.securityContext.runAsUser' is defined", [path, containerType]), + "keyActualValue": sprintf("'%s.%s.securityContext.runAsUser' is undefined", [path, containerType]), } } -checkUserContainer(spec, path, metadata, id) = result { - some j - container := spec[types[x]][j] +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, types[x], container.name]), + "searchKey": sprintf("metadata.name={{%s}}.%s.%s.%s", [metadata.name, path, containerType, container.name]), "issueType": "IncorrectValue", - "keyExpectedValue": sprintf("'%s.%s[%d].securityContext.runAsUser' is higher than 0 and/or 'runAsNonRoot' is true", [path, types[x], j]), - "keyActualValue": sprintf("'%s.%s[%d].securityContext.runAsUser' is 0 and 'runAsNonRoot' is not set to true", [path, types[x], j]), + "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]), } } -checkUserContainer(spec, path, metadata, id) = result { - some j - container := spec[types[x]][j] +checkUserContainer(rootSecurityContext, containerType, container, path, metadata,id) = result { not container.securityContext.runAsNonRoot object.get(container.securityContext, "runAsUser", "undefined") == "undefined" result := { "documentId": id, - "searchKey": sprintf("metadata.name={{%s}}.%s.%s.{{%s}}.securityContext", [metadata.name, path, types[x], container.name]), + "searchKey": sprintf("metadata.name={{%s}}.%s.%s.{{%s}}.securityContext", [metadata.name, path, containerType, container.name]), "issueType": "MissingAttribute", - "keyExpectedValue": sprintf("'%s.%s[%d].securityContext.runAsUser' is defined", [path, types[x], j]), - "keyActualValue": sprintf("'%s.%s[%d].securityContext.runAsUser' is undefined", [path, types[x], j]), + "keyExpectedValue": sprintf("'%s.%s.securityContext.runAsUser' is defined", [path, containerType]), + "keyActualValue": sprintf("'%s.%s.securityContext.runAsUser' is undefined", [path, containerType]), } + } diff --git a/assets/queries/k8s/containers_running_as_root/test/negative.yaml b/assets/queries/k8s/containers_running_as_root/test/negative1.yaml similarity index 100% rename from assets/queries/k8s/containers_running_as_root/test/negative.yaml rename to assets/queries/k8s/containers_running_as_root/test/negative1.yaml diff --git a/assets/queries/k8s/containers_running_as_root/test/negative2.yaml b/assets/queries/k8s/containers_running_as_root/test/negative2.yaml new file mode 100644 index 00000000000..ae10f897568 --- /dev/null +++ b/assets/queries/k8s/containers_running_as_root/test/negative2.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Pod +metadata: + name: security-context-demo-1 +spec: + securityContext: + runAsUser: 1000 + runAsNonRoot: true + containers: + - name: sec-ctx-demo-100 + image: gcr.io/google-samples/node-hello:1.0 + securityContext: + runAsUser: 1000 + runAsNonRoot: false + - name: sec-ctx-demo-200 + image: gcr.io/google-samples/node-hedwfwllo:1.0 + securityContext: + runAsUser: 2000 + runAsNonRoot: true + \ No newline at end of file diff --git a/assets/queries/k8s/containers_running_as_root/test/negative3.yaml b/assets/queries/k8s/containers_running_as_root/test/negative3.yaml new file mode 100644 index 00000000000..93b6009f037 --- /dev/null +++ b/assets/queries/k8s/containers_running_as_root/test/negative3.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: containers-runs-as-root +spec: + securityContext: + runAsUser: 0 + runAsNonRoot: false + containers: + - name: sec-ctx-demo-100 + image: gcr.io/google-samples/node-hello:1.0 + securityContext: + runAsUser: 1000 + runAsNonRoot: false + \ No newline at end of file diff --git a/assets/queries/k8s/containers_running_as_root/test/positive.yaml b/assets/queries/k8s/containers_running_as_root/test/positive1.yaml similarity index 100% rename from assets/queries/k8s/containers_running_as_root/test/positive.yaml rename to assets/queries/k8s/containers_running_as_root/test/positive1.yaml diff --git a/assets/queries/k8s/containers_running_as_root/test/positive2.yaml b/assets/queries/k8s/containers_running_as_root/test/positive2.yaml new file mode 100644 index 00000000000..a16fcfd1bae --- /dev/null +++ b/assets/queries/k8s/containers_running_as_root/test/positive2.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Pod +metadata: + name: security-context-demo-2 +spec: + securityContext: + runAsUser: 10 + runAsNonRoot: false + containers: + - name: sec-ctx-demo-100 + image: gcr.io/google-samples/node-hello:1.0 + securityContext: + runAsUser: 0 + runAsNonRoot: false + - name: sec-ctx-demo-200 + image: gcr.io/google-samples/node-hedwfwllo:1.0 + securityContext: + runAsUser: 0 + runAsNonRoot: false + \ No newline at end of file diff --git a/assets/queries/k8s/containers_running_as_root/test/positive3.yaml b/assets/queries/k8s/containers_running_as_root/test/positive3.yaml new file mode 100644 index 00000000000..ef09d55f875 --- /dev/null +++ b/assets/queries/k8s/containers_running_as_root/test/positive3.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: containers-runs-as-root +spec: + securityContext: + runAsUser: 0 + runAsNonRoot: false + containers: + - name: sec-ctx-demo-100 + image: gcr.io/google-samples/node-hello:1.0 + securityContext: + runAsUser: 0 + runAsNonRoot: false + + \ No newline at end of file diff --git a/assets/queries/k8s/containers_running_as_root/test/positive_expected_result.json b/assets/queries/k8s/containers_running_as_root/test/positive_expected_result.json index 3dbc9e0fbd6..19fe342d867 100644 --- a/assets/queries/k8s/containers_running_as_root/test/positive_expected_result.json +++ b/assets/queries/k8s/containers_running_as_root/test/positive_expected_result.json @@ -2,16 +2,37 @@ { "queryName": "Container Running As Root", "severity": "MEDIUM", - "line": 10 + "line": 10, + "fileName": "positive1.yaml" }, { "queryName": "Container Running As Root", "severity": "MEDIUM", - "line": 28 + "line": 28, + "fileName": "positive1.yaml" }, { "queryName": "Container Running As Root", "severity": "MEDIUM", - "line": 41 + "line": 41, + "fileName": "positive1.yaml" + }, + { + "queryName": "Container Running As Root", + "severity": "MEDIUM", + "line": 10, + "fileName": "positive2.yaml" + }, + { + "queryName": "Container Running As Root", + "severity": "MEDIUM", + "line": 15, + "fileName": "positive2.yaml" + }, + { + "queryName": "Container Running As Root", + "severity": "MEDIUM", + "line": 10, + "fileName": "positive3.yaml" } ]