-
Notifications
You must be signed in to change notification settings - Fork 0
/
kubescape.json
1 lines (1 loc) · 65.8 KB
/
kubescape.json
1
{"guid":"","name":"NSA","attributes":{"armoBuiltin":true},"creationTime":"","description":"Implement NSA security advices for K8s ","controls":[{"guid":"","name":"Control plane hardening","attributes":{"armoBuiltin":true},"creationTime":"","description":"Kubernetes control plane API is running with non-secure port enabled which allows attackers to gain unprotected access to the cluster.","remediation":"Set the insecure-port flag of the API server to zero.","rules":[{"guid":"","name":"insecure-port-flag","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\nimport data.cautils as cautils\n\n# Fails if pod has insecure-port flag enabled\ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n container := pod.spec.containers[_]\n\tisInsecurePortFlag(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"The API server container: %v has insecure-port flag enabled\", [ container.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n# Fails if workload has insecure-port flag enabled\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n container := wl.spec.template.spec.containers[_]\n isInsecurePortFlag(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"The API server container: %v has insecure-port flag enabled\", [ container.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\n\t\nisInsecurePortFlag(container){\n cautils.list_contains(container.command, \"--insecure-port=1\")\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"fails if the api server has insecure-port enabled","remediation":"Make sure that the insecure-port flag of the api server is set to 0","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Host PID/IPC privileges","attributes":{"armoBuiltin":true},"creationTime":"","description":"Containers should be as isolated as possible from the host machine. The hostPID and hostIPC fields in Kubernetes may excessively expose the host for potentially malicious actions.","remediation":"Apply least privilege principle and disable the hostPID and hostIPC fields unless strictly needed.","rules":[{"guid":"","name":"host-pid-ipc-privileges","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n\n# Fails if pod has hostPID enabled\ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n\tisHostPID(pod.spec)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"Pod: %v has hostPID enabled\", [pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n# Fails if pod has hostIPC enabled\ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n\tisHostIPC(pod.spec)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"Pod: %v has hostIPC enabled\", [pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n\n# Fails if workload has hostPID enabled\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tisHostPID(wl.spec.template.spec)\n msga := {\n\t\"alertMessage\": sprintf(\"%v: %v has a pod with hostPID enabled\", [wl.kind, wl.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\n# Fails if workload has hostIPC enabled\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tisHostIPC(wl.spec.template.spec)\n msga := {\n\t\"alertMessage\": sprintf(\"%v: %v has a pod with hostIPC enabled\", [wl.kind, wl.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n# Fails if cronjob has hostPID enabled\ndeny[msga] {\n\twl := input[_]\n\twl.kind == \"CronJob\"\n\tisHostPID(wl.spec.jobTemplate.spec.template.spec)\n msga := {\n\t\"alertMessage\": sprintf(\"CronJob: %v has a pod with hostPID enabled\", [wl.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\n# Fails if cronjob has hostIPC enabled\ndeny[msga] {\n\twl := input[_]\n\twl.kind == \"CronJob\"\n\tisHostIPC(wl.spec.jobTemplate.spec.template.spec)\n msga := {\n\t\"alertMessage\": sprintf(\"CronJob: %v has a pod with hostIPC enabled\", [wl.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n# Check that hostPID and hostIPC are set to false. Default is false. Only in pod spec\n\n\nisHostPID(podspec){\n podspec.hostPID == true\n}\n\nisHostIPC(podspec){\n podspec.hostIPC == true\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"fails if pod has hostIPC/hostPID enabled","remediation":"Make sure that the fields hostIPC and hostPID in the pod spec are not set to true (set to false or not present)","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Immutable container filesystem","attributes":{"armoBuiltin":true},"creationTime":"","description":"Mutable container filesystem can be abused to gain malicious code and data injection into containers. Use immutable (read-only) filesystem to limit potential attacks.","remediation":"Set the filesystem of the container to read-only when possible. If the containers application needs to write into the filesystem, it is possible to mount secondary filesystems for specific directories where application require write access. ","rules":[{"guid":"","name":"immutable-container-filesystem","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n\n# Fails if pods has container with mutable filesystem\ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n\tcontainer := pod.spec.containers[_]\n isMutableFilesystem(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container: %v in pod: %v has mutable filesystem\", [container.name, pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n# Fails if workload has container with mutable filesystem \ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n container := wl.spec.template.spec.containers[_]\n isMutableFilesystem(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container :%v in %v: %v has mutable filesystem\", [container.name, wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\n# Fails if cronjob has container with mutable filesystem \ndeny[msga] {\n\twl := input[_]\n\twl.kind == \"CronJob\"\n\tcontainer = wl.spec.jobTemplate.spec.template.spec.containers[_]\n\tisMutableFilesystem(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container :%v in %v: %v has mutable filesystem\", [container.name, wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n# Default of readOnlyRootFilesystem is false. This field is only in container spec and not pod spec\nisMutableFilesystem(container){\n not container.securityContext.readOnlyRootFilesystem\n }","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"fails if container has mutable filesystem","remediation":"Make sure that the securityContext.readOnlyRootFilesystem field in the container/pod spec is set to true","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Non-root containers","attributes":{"armoBuiltin":true},"creationTime":"","description":"Potential attackers may gain access to a container and leverage its privileges to conduct an attack. Hence it is not recommended to deploy containers with root privileges unless it is absolutely necessary.","remediation":"If your application does not need root privileges, make sure to define the runAsUser and runAsGroup under the PodSecurityContext to use user ID 1000 or higher, do not turn on allowPrivlegeEscalation bit and runAsNonRoot is true.","rules":[{"guid":"","name":"non-root-containers","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n\n# Fails if pod has container configured to run as root\ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n\tcontainer := pod.spec.containers[_]\n isRootContainer(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container: %v in pod: %v may run as root\", [container.name, pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n# Fails if pod has container configured to run as root\ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n\tcontainer := pod.spec.containers[_]\n isRootPod(pod, container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container: %v in pod: %v may run as root\", [container.name, pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n\n\n# Fails if workload has container configured to run as root\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n container := wl.spec.template.spec.containers[_]\n isRootContainer(container)\n msga := {\n\t\t\"alertMessage\": sprintf(\"container :%v in %v: %v may run as root\", [container.name, wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n# Fails if workload has container configured to run as root\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n container := wl.spec.template.spec.containers[_]\n isRootPod(wl.spec.template, container)\n msga := {\n\t\t\"alertMessage\": sprintf(\"container :%v in %v: %v may run as root\", [container.name, wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\n# Fails if cronjob has a container configured to run as root\ndeny[msga] {\n\twl := input[_]\n\twl.kind == \"CronJob\"\n\tcontainer = wl.spec.jobTemplate.spec.template.spec.containers[_]\n\t isRootContainer(container)\n msga := {\n\t\t\"alertMessage\": sprintf(\"container :%v in %v: %v may run as root\", [container.name, wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\n\n# Fails if workload has container configured to run as root\ndeny[msga] {\n \twl := input[_]\n\twl.kind == \"CronJob\"\n\tcontainer = wl.spec.jobTemplate.spec.template.spec.containers[_]\n isRootPod(wl.spec.jobTemplate.spec.template, container)\n msga := {\n\t\t\"alertMessage\": sprintf(\"container :%v in %v: %v may run as root\", [container.name, wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\nisRootPod(pod, container) {\n not container.securityContext.runAsUser\n pod.spec.securityContext.runAsUser == 0\n}\n\nisRootPod(pod, container) {\n not container.securityContext.runAsUser\n\tnot container.securityContext.runAsGroup\n\tnot container.securityContext.runAsNonRoot\n not pod.spec.securityContext.runAsUser\n\tnot pod.spec.securityContext.runAsGroup\n pod.spec.securityContext.runAsNonRoot == false\n}\n\nisRootPod(pod, container) {\n not container.securityContext.runAsGroup\n pod.spec.securityContext.runAsGroup == 0\n}\n\nisRootPod(pod, container) {\n\tnot pod.spec.securityContext.runAsGroup\n\tnot pod.spec.securityContext.runAsUser\n \tcontainer.securityContext.runAsNonRoot == false\n}\n\nisRootContainer(container) {\n container.securityContext.runAsUser == 0\n}\n\nisRootContainer(container) {\n container.securityContext.runAsGroup == 0\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"fails if container can run as root","remediation":"Make sure that the user/group in the securityContext of pod/container is set to an id less than 1000, or the runAsNonRoot flag is set to true. Also make sure that the allowPrivilegeEscalation field is set to false","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Privileged container","attributes":{"armoBuiltin":true,"microsoftMitreColumns":["Privilege escalation"]},"creationTime":"","description":"Potential attackers may gain access to privileged containers and inherit access to the host resources. Therefore, it is not recommended to deploy privileged containers unless it is absolutely necessary.","remediation":"Change the deployment and/or pod definition to unprivileged. The securityContext.privileged should be false.","rules":[{"guid":"","name":"rule-privilege-escalation","attributes":{"armoBuiltin":true,"m$K8sThreatMatrix":"Privilege Escalation::privileged container","mitre":"Privilege Escalation","mitreCode":"TA0004"},"creationTime":"","rule":"package armo_builtins\n# Deny mutating action unless user is in group owning the resource\n\n\n#privileged pods\ndeny[msga] {\n\n\tpod := input[_]\n\tpod.kind == \"Pod\"\n\tcontainers := pod.spec.containers[_]\n\tcontainers.securityContext.privileged == true\n msga := {\n\t\t\"alertMessage\": sprintf(\"the following pods are defined as privileged: %v\", [pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 3,\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n }\n}\n\n\n#handles majority of workload resources\ndeny[msga] {\n\twl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n\tcontainers := wl.spec.template.spec.containers[_]\n\tcontainers.securityContext.privileged == true\n\n msga := {\n\t\t\"alertMessage\": sprintf(\"%v: %v is defined as privileged:\", [wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 3,\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n }\n}\n\n#handles cronjob\ndeny[msga] {\n\twl := input[_]\n\twl.kind == \"CronJob\"\n\tcontainers := wl.spec.jobTemplate.spec.template.spec.containers[_]\n\tcontainers.securityContext.privileged == true\n\n msga := {\n\t\t\"alertMessage\": sprintf(\"the following cronjobs are defined as privileged: %v\", [wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 3,\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n }\n}\n\n","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"determines if pods/deployments defined as privileged true","remediation":"avoid defining pods as privilleged","ruleQuery":""}]},{"guid":"","name":"Allowed hostPath","attributes":{"armoBuiltin":true},"creationTime":"","description":"Mounting host directory to the container can be abused to get access to sensitive data and gain persistence on the host machine.","remediation":"Refrain from using host path mount.","rules":[{"guid":"","name":"alert-rw-hostpath","attributes":{"armoBuiltin":true,"m$K8sThreatMatrix":"Persistance::Writable hostPath mount, Lateral Movement::Writable volume mounts on the host"},"creationTime":"","rule":"package armo_builtins\n\n# input: pod\n# apiversion: v1\n# does: returns hostPath volumes\n\ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n volumes := pod.spec.volumes\n volume := volumes[_]\n volume.hostPath\n\tcontainer := pod.spec.containers[_]\n\tvolumeMount := container.volumeMounts[_]\n\tvolumeMount.name == volume.name\n\tisRWMount(volumeMount)\n\n podname := pod.metadata.name\n\n\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"pod: %v has: %v as hostPath volume\", [podname, volume.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n#handles majority of workload resources\ndeny[msga] {\n\twl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n volumes := wl.spec.template.spec.volumes\n volume := volumes[_]\n volume.hostPath\n\tcontainer := wl.spec.template.spec.containers[_]\n\tvolumeMount := container.volumeMounts[_]\n\tvolumeMount.name == volume.name\n\tisRWMount(volumeMount)\n\n\n\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"%v: %v has: %v as hostPath volume\", [wl.kind, wl.metadata.name, volume.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t\n\t}\n}\n\n#handles CronJobs\ndeny[msga] {\n\twl := input[_]\n\twl.kind == \"CronJob\"\n volumes := wl.spec.jobTemplate.spec.template.spec.volumes\n volume := volumes[_]\n volume.hostPath\n\n\tcontainer = wl.spec.jobTemplate.spec.template.spec.containers[_]\n\tvolumeMount := container.volumeMounts[_]\n\tvolumeMount.name == volume.name\n\tisRWMount(volumeMount)\n\n \n\tmsga := {\n\t\"alertMessage\": sprintf(\"%v: %v has: %v as hostPath volume\", [wl.kind, wl.metadata.name, volume.name]),\n\t\"packagename\": \"armo_builtins\",\n\t\"alertScore\": 7,\n\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\nisRWMount(mount) {\n not mount.readOnly\n}\nisRWMount(mount) {\n mount.readOnly == false\n} ","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","CronJob","Pod"]}],"ruleDependencies":[{"packageName":"cautils"},{"packageName":"kubernetes.api.client"}],"description":"determines if any workload contains a hostPath volume with rw permissions","remediation":"Set the readOnly field of the mount to true","ruleQuery":""}]},{"guid":"","name":"Automatic mapping of service account","attributes":{"armoBuiltin":true},"creationTime":"","description":"Potential attacker may gain access to a POD and steal its service account token. Therefore, it is recommended to disable automatic mapping of the service account tokens in service account configuration and enable it only for PODs that need to use them.","remediation":"Only map token to PODs that are really using them. We suggest disabling the automatic mounting of service account tokens to PODs at the service account level, by specifying the securityContext.readOnlyRootFilesystem field to true, and explicitly enabling the map for the PODs which are using it at the POD spec level.","rules":[{"guid":"","name":"automount-service-account","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n# Fails if user account mount tokens in pod by default.\ndeny [msga]{\n serviceaccounts := [serviceaccount | serviceaccount= input[_]; serviceaccount.kind == \"ServiceAccount\"]\n serviceaccount := serviceaccounts[_]\n isAutoMount(serviceaccount)\n\n msga := {\n\t \"alertMessage\": sprintf(\"the following service account: %v in the following namespace: %v mounts service account tokens in pods by default\", [serviceaccount.metadata.name, serviceaccount.metadata.namespace]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [serviceaccount]\n\t\t}\n\t}\n} \n\nisAutoMount(serviceaccount) {\n\tnot serviceaccount.automountServiceAccountToken == false\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Serviceaccount"]}],"ruleDependencies":[],"description":"fails if service account automountServiceAccountToken enabled","remediation":"Make sure that the automountServiceAccountToken field on the service account spec if set to false","ruleQuery":"armo_builtins"}]},{"guid":"","name":"hostNetwork access","attributes":{"armoBuiltin":true},"creationTime":"","description":"Potential attackers may gain access to a POD and inherit access to the entire host network. For example, in AWS case, they will have access to the entire VPC.","remediation":"Only connect PODs to host network when it is necessary. If not, set the hostNetwork field of the pod spec to false, or erase it (false is the default). Whitelist those PODs that need access to host network by design.","rules":[{"guid":"","name":"host-network-access","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n# Fails if pod has hostNetwork enabled\ndeny[msga] {\n pods := [ pod | pod = input[_] ; pod.kind == \"Pod\"]\n pod := pods[_]\n\n isHostNetwork(pod.spec)\n\n \tmsga := {\n\t\"alertMessage\": sprintf(\"Pod: %v is connected to the host network\", [pod.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n# Fails if workload has hostNetwork enabled\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tisHostNetwork(wl.spec.template.spec)\n msga := {\n\t\"alertMessage\": sprintf(\"%v: %v has a pod connected to the host network\", [wl.kind, wl.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n# Fails if cronjob has hostNetwork enabled\ndeny[msga] {\n\twl := input[_]\n\twl.kind == \"CronJob\"\n\tisHostNetwork(wl.spec.jobTemplate.spec.template.spec)\n msga := {\n\t\"alertMessage\": sprintf(\"CronJob: %v has a pod connected to the host network\", [wl.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\nisHostNetwork(podspec) {\n podspec.hostNetwork == true\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"fails if pod has hostNetwork enabled","remediation":"Make sure that the hostNetwork field of the pod spec is not set to true (set to false or not present)","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Resource policies","attributes":{"armoBuiltin":true},"creationTime":"","description":"CPU and memory resources should have a limit set for every container to prevent resource exhaustion.","remediation":"Define LimitRange and ResourceQuota policies to limit resource usage for namespaces or nodes.","rules":[{"guid":"","name":"resource-policies","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n\n# Check if container has limits\ndeny[msga] {\n \tpods := [pod | pod = input[_]; pod.kind == \"Pod\"]\n pod := pods[_]\n\tcontainer := pod.spec.containers[_]\n\tnot container.resources.limits\n\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"there are no resource limits defined for container : %v\", [container.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n\n# Check if container has limits - for workloads\n# If there is no limits specified in the workload, we check the namespace, since if limits are only specified for namespace\n# and not in workload, it won't be on the yaml\ndeny[msga] {\n\twl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n\tcontainer := wl.spec.template.spec.containers[_]\n\tnot container.resources.limits\n\tisNamespaceWithLimits(wl.metadata.namespace)\n\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"there are no resource limits defined for container : %v\", [container.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n\t\n}\n\n# Check if container has limits - for cronjobs\n# If there is no limits specified in the cronjob, we check the namespace, since if limits are only specified for namespace\n# and not in cronjob, it won't be on the yaml\ndeny [msga] {\n wl := input[_]\n\twl.kind == \"CronJob\"\n\tcontainer := wl.spec.jobTemplate.spec.template.spec.containers[_]\n\tnot container.resources.limits\n\tisNamespaceWithLimits(wl.metadata.namespace)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"there are no resource limits defined for container : %v\", [container.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\n# Fails if LimitRange exists but it does not define maximum usage of resources\ndeny[msga] {\n\n limitRanges := [limitRange | limitRange = input[_]; limitRange.kind == \"LimitRange\"]\n limitRange := limitRanges[_]\n\n\tlimits := limitRange.spec.limits[_]\n not limits.max\n\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"the following LimitRange: %v does not define a maximum field for resources\", [limitRange.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [limitRange]\n\t\t}\n\t}\n}\n\n# Fails if ResourQuota exists but it does not define maximum usage of resources\ndeny[msga] {\n resourceQuotas := [resourceQuota | resourceQuota = input[_]; resourceQuota.kind == \"ResourceQuota\"]\n resourceQuota := resourceQuotas[_]\n\n not resourceQuota.spec.hard\n\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"the following ResourQuota: %v does not define a hard field\", [resourceQuota.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [resourceQuota]\n\t\t}\n\t}\n}\n\n\nlist_contains(list, element) {\n some i\n list[i] == element\n}\n\n\n# Check only LimitRange. For ResourceQuota limits need to be specified. \nisNamespaceWithLimits(namespace) {\n limitRanges := [policy.metadata.namespace | policy = input[_]; policy.kind == \"LimitRange\"]\n not list_contains(limitRanges, namespace)\n}\n","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","CronJob","Pod","LimitRange","ResourceQuota"]}],"ruleDependencies":[],"description":"fails if namespace has no resource policies defined","remediation":"Make sure that you definy resource policies (LimitRange or ResourceQuota) which limit the usage of resources for all the namespaces","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Exposed dashboard","attributes":{"armoBuiltin":true,"microsoftMitreColumns":["Initial Access"]},"creationTime":"","description":"If Kubernetes dashboard is exposed externally in Dashboard versions before 2.01, it will allow unauthenticated remote management of the cluster.","remediation":"Update dashboard version to v2.0.1 or above.","rules":[{"guid":"","name":"rule-exposed-dashboard","attributes":{"armoBuiltin":true,"m$K8sThreatMatrix":"Initial Access::Exposed Dashboard"},"creationTime":"","rule":"package armo_builtins\n\n# input: pods\n# apiversion: v1\n# fails if dashboard exists and is exposed\n\ndeny[msga] {\n\tdeployment := input[_]\n startswith(deployment.metadata.name, \"kubernetes-dashboard\")\n container := deployment.spec.template.spec.containers[_]\n version := trim_prefix(container.image, \"kubernetesui/dashboard:v\")\n to_number(replace(version, \".\", \"\")) \u003c 201\n \n\tservice := input[_]\n\tservice.kind == \"Service\"\n\tisNodePortLbService(service)\n count({x | service.spec.selector[x]; deployment.metadata.labels[x]}) == count(service.spec.selector)\n\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"dashboard exists and is exposed %s\", [container.image]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [deployment]\n\t\t}\n }\n}\n\n\n\nisNodePortLbService(service) {\n\tservice.spec.type == \"NodePort\"\n}\n\nisNodePortLbService(service) {\n\tservice.spec.type == \"LoadBalancer\"\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","Service"]}],"ruleDependencies":[],"description":"fails if dashboard exists and is exposed","remediation":"","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Allow privilege escalation","attributes":{"armoBuiltin":true},"creationTime":"","description":"Attackers may gain access to a container and uplift its privilege to enable excessive capabilities.","remediation":"If your application does not need it, make sure the allowPrivilegeEscalation field of the securityContext is set to false.","rules":[{"guid":"","name":"rule-allow-privilege-escalation","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n\n# Fails if pod has container that allow privilege escalation\ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n\tcontainer := pod.spec.containers[_]\n isAllowPrivilegeEscalationContainer(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container: %v in pod: %v allow privilege escalation\", [container.name, pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n\n# Fails if workload has a container that allow privilege escalation\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n container := wl.spec.template.spec.containers[_]\n isAllowPrivilegeEscalationContainer(container)\n msga := {\n\t\t\"alertMessage\": sprintf(\"container :%v in %v: %v allow privilege escalation\", [container.name, wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\n# Fails if cronjob has a container that allow privilege escalation\ndeny[msga] {\n\twl := input[_]\n\twl.kind == \"CronJob\"\n\tcontainer = wl.spec.jobTemplate.spec.template.spec.containers[_]\n\tisAllowPrivilegeEscalationContainer(container)\n msga := {\n\t\t\"alertMessage\": sprintf(\"container :%v in %v: %v allow privilege escalation\", [container.name, wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\nisAllowPrivilegeEscalationContainer(container) {\n container.securityContext.allowPrivilegeEscalation == true\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"fails if container allows privilege escalation","remediation":"Make sure that the allowPrivilegeEscalation field in the securityContext of pod/container is set to false","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Applications credentials in configuration files","attributes":{"armoBuiltin":true,"microsoftMitreColumns":["Credential access","Lateral Movement"]},"creationTime":"","description":"Attackers who have access to configuration files can steal the stored secrets and use them. Checks if ConfigMaps or pods have sensitive information in configuration.","remediation":"Use Kubernetes secrets to store credentials. Use ARMO secret protection solution to improve your security even more.","rules":[{"guid":"","name":"rule-credentials-in-env-var","attributes":{"armoBuiltin":true,"m$K8sThreatMatrix":"Credential access::Applications credentials in configuration files, Lateral Movement::Applications credentials in configuration files"},"creationTime":"","rule":"package armo_builtins\n# import data.cautils as cautils\n# import data.kubernetes.api.client as client\n\ndeny[msga] {\n\tpod := input[_]\n pod.kind == \"Pod\"\n sensitive_key_names := {\"aws_access_key_id\", \"aws_secret_access_key\", \"azure_batchai_storage_account\", \"azure_batchai_storage_key\",\n \"azure_batch_account\", \"azure_batch_key\", \"passwd\",\"password\", \"username\", \"pwd\", \"cred\", \"token\", \"key\", \"cert\"}\n key_name := sensitive_key_names[_]\n container := pod.spec.containers[_]\n env := container.env[_]\n contains(lower(env.name), key_name)\n\tisNotReference(env)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"Pod: %v has sensitive information in environment variables\", [pod.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n }\n}\n\ndeny[msga] {\n\twl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n\n sensitive_key_names := {\"aws_access_key_id\", \"aws_secret_access_key\", \"azure_batchai_storage_account\", \"azure_batchai_storage_key\",\n \"azure_batch_account\", \"azure_batch_key\", \"passwd\",\"password\", \"username\", \"pwd\", \"cred\", \"token\", \"key\", \"cert\"}\n key_name := sensitive_key_names[_]\n container := wl.spec.template.spec.containers[_]\n env := container.env[_]\n contains(lower(env.name), key_name)\n\tisNotReference(env)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"%v: %v has sensitive information in environment variables\", [wl.kind, wl.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n }\n}\n\ndeny[msga] {\n\twl := input[_]\n\twl.kind == \"CronJob\"\n sensitive_key_names := {\"aws_access_key_id\", \"aws_secret_access_key\", \"azure_batchai_storage_account\", \"azure_batchai_storage_key\",\n \"azure_batch_account\", \"azure_batch_key\", \"passwd\",\"password\", \"username\", \"pwd\", \"cred\", \"token\", \"key\", \"cert\"}\n key_name := sensitive_key_names[_]\n\tcontainer := wl.spec.jobTemplate.spec.template.spec.containers[_]\n env := container.env[_]\n contains(lower(env.name), key_name)\n\tisNotReference(env)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"Cronjob: %v has sensitive information in environment variables\", [wl.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n }\n}\n\n\n\nisNotReference(env)\n{\n\tnot env.valueFrom.secretKeyRef\n\tnot env.valueFrom.configMapKeyRef\n}\n\n","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"fails if Pods have sensitive information in configuration","remediation":"","ruleQuery":"armo_builtins"},{"guid":"","name":"rule-credentials-configmap","attributes":{"armoBuiltin":true,"m$K8sThreatMatrix":"Credential access::Applications credentials in configuration files, Lateral Movement::Applications credentials in configuration files"},"creationTime":"","rule":"package armo_builtins\n# import data.cautils as cautils\n# import data.kubernetes.api.client as client\n\n# fails if config map has keys with suspicious name\ndeny[msga] {\n\tconfigmap := input[_]\n configmap.kind == \"ConfigMap\"\n sensitive_key_names := {\"aws_access_key_id\", \"aws_secret_access_key\", \"azure_batchai_storage_account\", \"azure_batchai_storage_key\",\n \"azure_batch_account\", \"azure_batch_key\", \"pass\", \"username\", \"pwd\", \"cred\", \"token\", \"key\", \"cert\"}\n key_name := sensitive_key_names[_]\n map_secret := configmap.data[map_key]\n contains(lower(map_key), key_name)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"this configmap has sensitive information: %v\", [configmap.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [configmap]\n\t\t}\n }\n}\n\n# fails if config map has values with suspicious content - not base 64\ndeny[msga] {\n sensitive_values := {\"BEGIN\", \"PRIVATE KEY\", \"eyJhbGciO\"}\n value := sensitive_values[_]\n\n\tconfigmap := input[_]\n configmap.kind == \"ConfigMap\"\n map_secret := configmap.data[map_key]\n contains(map_secret, value)\n\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"this configmap has sensitive information: %v\", [configmap.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [configmap]\n\t\t}\n }\n}\n\n# fails if config map has values with suspicious content - base 64\ndeny[msga] {\n sensitive_values := {\"BEGIN\", \"PRIVATE KEY\", \"eyJhbGciO\"}\n value := sensitive_values[_]\n\n\tconfigmap := input[_]\n configmap.kind == \"ConfigMap\"\n map_secret := configmap.data[map_key]\n decoded_secret := base64.decode(map_secret)\n contains(decoded_secret, value)\n\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"this configmap has sensitive information: %v\", [configmap.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [configmap]\n\t\t}\n }\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["ConfigMap"]}],"ruleDependencies":[],"description":"fails if ConfigMaps have sensitive information in configuration","remediation":"","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Cluster-admin binding","attributes":{"armoBuiltin":true,"microsoftMitreColumns":["Privilege escalation"]},"creationTime":"","description":"Attackers who have Cluster-admin permissions (can perform any action on any resource), can take advantage of their high privileges for malicious intentions. Determines which subjects have cluster admin permissions.","remediation":"You should apply least privilege principle. Monitor and approve cluster admins and make sure users that do not require cluster-admin are not assigned with this role.","rules":[{"guid":"","name":"rule-list-all-cluster-admins","attributes":{"armoBuiltin":true,"m$K8sThreatMatrix":"Privilege Escalation::Cluster-admin binding"},"creationTime":"","rule":"package armo_builtins\nimport data.cautils as cautils\n\n# input: roles\n# apiversion: v1\n# does: returns roles+ related subjects in rolebinding\n\ndeny[msga] {\n\t roles := [role | role= input[_]; role.kind == \"Role\"]\n rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == \"RoleBinding\"]\n role:= roles[_]\n rolebinding := rolebindings[_]\n\n rule:= role.rules[_]\n\tcanCreate(rule)\n\tcanCreateResources(rule)\n\n\trolebinding.roleRef.kind == \"Role\"\n\trolebinding.roleRef.name == role.metadata.name\n subjects := rolebinding.subjects[_]\n\n \tmsga := {\n\t\"alertMessage\": sprintf(\"the following %v: %v have high privileges, such as cluster-admin\", [subjects.kind, subjects.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [role,rolebinding]\n\t\t}\n }\n}\n\n# input: ClusterRole\n# apiversion: v1\n# does: returns clusterroles+ related subjects in rolebinding\n\ndeny[msga] {\n roles := [role | role= input[_]; role.kind == \"ClusterRole\"]\n rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == \"RoleBinding\"]\n role:= roles[_]\n rolebinding := rolebindings[_]\n\n rule:= role.rules[_]\n\tcanCreate(rule)\n\tcanCreateResources(rule)\n\n\trolebinding.roleRef.kind == \"ClusterRole\"\n\trolebinding.roleRef.name == role.metadata.name\n \n subjects := rolebinding.subjects[_]\n\n \tmsga := {\n\t\"alertMessage\": sprintf(\"the following %v: %v have high privileges, such as cluster-admin\", [subjects.kind, subjects.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [role,rolebinding]\n\t\t}\n }\n}\n\n# input: ClusterRole\n# apiversion: v1\n# does:\treturns clusterroles+ related subjects in clusterrolebinding\n\ndeny[msga] {\n roles := [role | role= input[_]; role.kind == \"ClusterRole\"]\n rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == \"ClusterRoleBinding\"]\n role:= roles[_]\n rolebinding := rolebindings[_]\n\n rule:= role.rules[_]\n\tcanCreate(rule)\n\tcanCreateResources(rule)\n\n\trolebinding.roleRef.kind == \"ClusterRole\"\n\trolebinding.roleRef.name == role.metadata.name\n\t\n subjects := rolebinding.subjects[_]\n\n \tmsga := {\n\t\"alertMessage\": sprintf(\"the following %v: %v have high privileges, such as cluster-admin\", [subjects.kind, subjects.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \"alertObject\": {\n\t\t\t\"k8sApiObjects\": [role,rolebinding]\n\t\t}\n }\n}\n\n\ncanCreate(rule) {\n\tcautils.list_contains(rule.verbs,\"*\")\n}\ncanCreateResources(rule){\n\tcautils.list_contains(rule.resources,\"*\")\n}\n","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Role","ClusterRole","ClusterRoleBinding","RoleBinding"]}],"ruleDependencies":[{"packageName":"cautils"}],"description":"determines which users have cluster admin permissions","remediation":"","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Exec into container","attributes":{"armoBuiltin":true,"microsoftMitreColumns":["Execution"]},"creationTime":"","description":"Attackers who have permissions, can run malicious commands in containers in the cluster using exec command (“kubectl exec”). Determines which subjects have permissions to exec into containers.","remediation":"You should apply least privilege principal (we can point to our audit/least privilege screen). You should monitor and approve users who can exec into containers.","rules":[{"guid":"","name":"exec-into-container","attributes":{"armoBuiltin":true,"m$K8sThreatMatrix":"Privilege Escalation::Exec into container"},"creationTime":"","rule":"\npackage armo_builtins\nimport data.cautils as cautils\n\n\n# input: clusterrolebindings + rolebindings\n# apiversion: rbac.authorization.k8s.io/v1 \n# returns subjects that can exec into container\n\ndeny[msga] {\n\t roles := [role | role= input[_]; role.kind == \"Role\"]\n rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == \"RoleBinding\"]\n role:= roles[_]\n rolebinding := rolebindings[_]\n\n rule:= role.rules[_]\n\tcanExecToPodResource(rule)\n\tcanExecToPodVerb(rule)\n\n\trolebinding.roleRef.kind == \"Role\"\n\trolebinding.roleRef.name == role.metadata.name\n\t\n subjects := rolebinding.subjects[_]\n\n \tmsga := {\n\t\"alertMessage\": sprintf(\"the following %v: %v, can exec into containers\", [subjects.kind, subjects.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [role, rolebinding]\n\t\t}\n\n\t}\n}\n\n\n# input: clusterrolebindings + rolebindings\n# apiversion: rbac.authorization.k8s.io/v1 \n# returns subjects that can exec into container\n\ndeny[msga] {\n roles := [role | role= input[_]; role.kind == \"ClusterRole\"]\n rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == \"RoleBinding\"]\n role:= roles[_]\n rolebinding := rolebindings[_]\n\n rule:= role.rules[_]\n\tcanExecToPodResource(rule)\n\tcanExecToPodVerb(rule)\n\n\trolebinding.roleRef.kind == \"ClusterRole\"\n\trolebinding.roleRef.name == role.metadata.name\n\t\n subjects := rolebinding.subjects[_]\n\n \tmsga := {\n\t\"alertMessage\": sprintf(\"the following %v: %v, can exec into containers\", [subjects.kind, subjects.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [role, rolebinding]\n\t\t}\n\t}\n}\n\n# input: clusterrolebindings + rolebindings\n# apiversion: rbac.authorization.k8s.io/v1 \n# returns subjects that can exec into container\n\ndeny[msga] {\n roles := [role | role= input[_]; role.kind == \"ClusterRole\"]\n rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == \"ClusterRoleBinding\"]\n role:= roles[_]\n rolebinding := rolebindings[_]\n\n rule:= role.rules[_]\n\tcanExecToPodResource(rule)\n\tcanExecToPodVerb(rule)\n\n\trolebinding.roleRef.kind == \"ClusterRole\"\n\trolebinding.roleRef.name == role.metadata.name\n\t\n subjects := rolebinding.subjects[_]\n\n \tmsga := {\n\t\"alertMessage\": sprintf(\"the following %v: %v, can exec into containers\", [subjects.kind, subjects.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n \t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [role, rolebinding]\n\t\t}\n\t}\n}\n\ncanExecToPodVerb(rule) {\n\tcautils.list_contains(rule.verbs, \"create\")\n}\ncanExecToPodVerb(rule) {\n\tcautils.list_contains(rule.verbs, \"*\")\n}\n\ncanExecToPodResource(rule) {\n\tcautils.list_contains(rule.resources,\"pods/exec\")\n}\ncanExecToPodResource(rule) {\n\tcautils.list_contains(rule.resources,\"pods/*\")\n}\ncanExecToPodResource(rule) {\n\tcautils.list_contains(rule.resources,\"*\")\n}\n","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Role","ClusterRole","ClusterRoleBinding","RoleBinding"]}],"ruleDependencies":[{"packageName":"cautils"}],"description":"determines which users have permissions to exec into pods","remediation":"","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Dangerous capabilities","attributes":{"armoBuiltin":true},"creationTime":"","description":"Giving dangerous and unnecessary capabilities for a container can increase the impact of a container compromise.","remediation":"Remove all dangerous capabilities which aren’t necessary for the container.","rules":[{"guid":"","name":"dangerous-capabilities","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n\ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n\tcontainer := pod.spec.containers[_]\n isDangerousCapabilities(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container: %v in pod: %v have dangerous capabilities\", [container.name, pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n\tcontainer := wl.spec.template.spec.containers[_]\n isDangerousCapabilities(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container: %v in workload: %v have dangerous capabilities\", [container.name, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\ndeny[msga] {\n wl := input[_]\n\twl.kind == \"CronJob\"\n\tcontainer := wl.spec.jobTemplate.spec.template.spec.containers[_]\n isDangerousCapabilities(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container: %v in cronjob: %v have dangerous capabilities\", [container.name, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\nisDangerousCapabilities(container){\n dangerousCapabilities := [\"ALL\", \"SYS_ADMIN\", \"NET_ADMIN\"]\n dangerousCapabilitie := dangerousCapabilities[_]\n contains(container.securityContext.capabilities.add[_], dangerousCapabilitie)\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"fails if container has dangrous capabilities","remediation":"Remove all dangerous capabilities which aren’t necessary for the container.","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Insecure capabilities","attributes":{"armoBuiltin":true},"creationTime":"","description":"Giving insecure and unnecessary capabilities for a container can increase the impact of a container compromise.","remediation":"Remove all insecure capabilities which aren’t necessary for the container.","rules":[{"guid":"","name":"insecure-capabilities","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n\ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n\tcontainer := pod.spec.containers[_]\n isDangerousCapabilities(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container: %v in pod: %v have dangerous capabilities\", [container.name, pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n\tcontainer := wl.spec.template.spec.containers[_]\n isDangerousCapabilities(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container: %v in workload: %v have dangerous capabilities\", [container.name, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\ndeny[msga] {\n wl := input[_]\n\twl.kind == \"CronJob\"\n\tcontainer := wl.spec.jobTemplate.spec.template.spec.containers[_]\n isDangerousCapabilities(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"container: %v in cronjob: %v have dangerous capabilities\", [container.name, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\nisDangerousCapabilities(container){\n insecureCapabilities := [\"CHOWN\", \"DAC_OVERRIDE\", \"FSETID\", \"FOWNER\", \"MKNOD\", \"NET_RAW\", \"SETGID\", \"SETUID\", \"SETFCAP\", \"NET_BIND_SERVICE\",\"SYS_CHROOT\",\"KILL\",\"AUDIT_WRITE\"]\n insecureCapabilitie := insecureCapabilities[_]\n contains(container.securityContext.capabilities.add[_], insecureCapabilitie)\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"fails if container has insecure capabilities","remediation":"Remove all insecure capabilities which aren’t necessary for the container.","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Linux hardening","attributes":{"armoBuiltin":true},"creationTime":"","description":"Often, containers are given more privileges than actually needed. This behavior can increase the impact of a container compromise.","remediation":"Make sure you define at least one linux security hardening property out of AppArmor, Seccomp, SELinux or Capabilities.","rules":[{"guid":"","name":"linux-hardening","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n\n# Fails if pod does not define linux security hardening \ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n isUnsafePod(pod)\n container := pod.spec.containers[_]\n isUnsafeContainer(container)\n \n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"Pod: %v does not define any linux security hardening\", [pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n# Fails if workload does not define linux security hardening \ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n isUnsafeWorkload(wl)\n container := wl.spec.template.spec.containers[_]\n isUnsafeContainer(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"Workload: %v does not define any linux security hardening\", [wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\n# Fails if pod does not define linux security hardening \ndeny[msga] {\n\twl := input[_]\n\twl.kind == \"CronJob\"\n isUnsafeCronJob(wl)\n\tcontainer = wl.spec.jobTemplate.spec.template.spec.containers[_]\n isUnsafeContainer(container)\n\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"Cronjob: %v does not define any linux security hardening\", [wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\nisUnsafePod(pod){\n not pod.spec.securityContext.seccompProfile\n not pod.spec.securityContext.seLinuxOptions\n\tannotations := [pod.metadata.annotations[i] | annotaion = i; startswith(i, \"container.apparmor.security.beta.kubernetes.io\")]\n\tnot count(annotations) \u003e 0\n}\n\nisUnsafeContainer(container){\n not container.securityContext.seccompProfile\n not container.securityContext.seLinuxOptions\n not container.securityContext.capabilities.drop\n}\n\nisUnsafeWorkload(wl) {\n not wl.spec.template.spec.securityContext.seccompProfile\n not wl.spec.template.spec.securityContext.seLinuxOptions\n\tannotations := [wl.spec.template.metadata.annotations[i] | annotaion = i; startswith(i, \"container.apparmor.security.beta.kubernetes.io\")]\n\tnot count(annotations) \u003e 0\n}\n\nisUnsafeCronJob(cronjob) {\n not cronjob.spec.jobTemplate.spec.template.spec.securityContext.seccompProfile\n not cronjob.spec.jobTemplate.spec.template.spec.securityContext.seLinuxOptions\n\tannotations := [cronjob.spec.jobTemplate.spec.template.metadata.annotations[i] | annotaion = i; startswith(i, \"container.apparmor.security.beta.kubernetes.io\")]\n\tnot count(annotations) \u003e 0\n}\n\n","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"fails if container does not defien any linux security hardening","remediation":"Make sure you define at least one linux security hardening property out of Seccomp, SELinux or Capabilities.","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Ingress and Egress blocked","attributes":{"armoBuiltin":true},"creationTime":"","description":"By default, you should disable Ingress and Egress traffic on all pods.","remediation":"Define a network policy that restricts ingress and egress connections. ","rules":[{"guid":"","name":"ingress-and-egress-blocked","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n\n# For pods\ndeny[msga] {\n \t\tpods := [pod | pod= input[_]; pod.kind == \"Pod\"]\n\t\tnetworkpolicies := [networkpolicie | networkpolicie= input[_]; networkpolicie.kind == \"NetworkPolicy\"]\n\t\tpod := pods[_]\n\t\tnetworkpoliciesConnectedToPod := [networkpolicie | networkpolicie= networkpolicies[_]; podConnectedToNetworkPolicy(pod, networkpolicie)]\n\t\tcount(networkpoliciesConnectedToPod) \u003e 0\n goodPolicies := [goodpolicie | goodpolicie= networkpoliciesConnectedToPod[_]; isIngerssEgressPolicy(goodpolicie)]\n\t\tcount(goodPolicies) \u003c 1\n\n msga := {\n\t\t\"alertMessage\": sprintf(\"Pod: %v does not have ingress/egress defined\", [pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n\n}\n\n# For pods\ndeny[msga] {\n \t\tpods := [pod | pod= input[_]; pod.kind == \"Pod\"]\n\t\tnetworkpolicies := [networkpolicie | networkpolicie= input[_]; networkpolicie.kind == \"NetworkPolicy\"]\n\t\tpod := pods[_]\n\t\tnetworkpoliciesConnectedToPod := [networkpolicie | networkpolicie= networkpolicies[_]; podConnectedToNetworkPolicy(pod, networkpolicie)]\n\t\tcount(networkpoliciesConnectedToPod) \u003c 1\n\n msga := {\n\t\t\"alertMessage\": sprintf(\"Pod: %v does not have ingress/egress defined\", [pod.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n\n}\n\n# For workloads\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n networkpolicies := [networkpolicie | networkpolicie= input[_]; networkpolicie.kind == \"NetworkPolicy\"]\n\tnetworkpoliciesConnectedToPod := [networkpolicie | networkpolicie= networkpolicies[_]; wlConnectedToNetworkPolicy(wl, networkpolicie)]\n\tcount(networkpoliciesConnectedToPod) \u003e 0\n goodPolicies := [goodpolicie | goodpolicie= networkpoliciesConnectedToPod[_]; isIngerssEgressPolicy(goodpolicie)]\n\tcount(goodPolicies) \u003c 1\n\n msga := {\n\t\t\"alertMessage\": sprintf(\"%v: %v has Pods which don't have ingress/egress defined\", [wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n# For workloads\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n networkpolicies := [networkpolicie | networkpolicie= input[_]; networkpolicie.kind == \"NetworkPolicy\"]\n\tnetworkpoliciesConnectedToPod := [networkpolicie | networkpolicie= networkpolicies[_]; wlConnectedToNetworkPolicy(wl, networkpolicie)]\n\tcount(networkpoliciesConnectedToPod) \u003c 1\n\n msga := {\n\t\t\"alertMessage\": sprintf(\"%v: %v has Pods which don't have ingress/egress defined\", [wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n# For Cronjobs\ndeny[msga] {\n wl := input[_]\n\twl.kind == \"CronJob\"\n networkpolicies := [networkpolicie | networkpolicie= input[_]; networkpolicie.kind == \"NetworkPolicy\"]\n\tnetworkpoliciesConnectedToPod := [networkpolicie | networkpolicie= networkpolicies[_]; cronjobConnectedToNetworkPolicy(wl, networkpolicie)]\n\tcount(networkpoliciesConnectedToPod) \u003e 0\n goodPolicies := [goodpolicie | goodpolicie= networkpoliciesConnectedToPod[_]; isIngerssEgressPolicy(goodpolicie)]\n\tcount(goodPolicies) \u003c 1\n\n msga := {\n\t\t\"alertMessage\": sprintf(\"%v: %v has Pods which don't have ingress/egress defined\", [wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\n# For Cronjobs\ndeny[msga] {\n wl := input[_]\n\twl.kind == \"CronJob\"\n networkpolicies := [networkpolicie | networkpolicie= input[_]; networkpolicie.kind == \"NetworkPolicy\"]\n\tnetworkpoliciesConnectedToPod := [networkpolicie | networkpolicie= networkpolicies[_]; cronjobConnectedToNetworkPolicy(wl, networkpolicie)]\n\tcount(networkpoliciesConnectedToPod) \u003c 1\n\n msga := {\n\t\t\"alertMessage\": sprintf(\"%v: %v has Pods which don't have ingress/egress defined\", [wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\npodConnectedToNetworkPolicy(pod, networkpolicie){\n\tnetworkpolicie.metadata.namespace == pod.metadata.namespace\n count(networkpolicie.spec.podSelector) \u003e 0\n count({x | networkpolicie.spec.podSelector.matchLabels[x] == pod.metadata.labels[x]}) == count(networkpolicie.spec.podSelector.matchLabels)\n}\n\npodConnectedToNetworkPolicy(pod, networkpolicie){\n\tnetworkpolicie.metadata.namespace == pod.metadata.namespace\n count(networkpolicie.spec.podSelector) == 0\n}\n\nwlConnectedToNetworkPolicy(wl, networkpolicie){\n\twl.metadata.namespace == networkpolicie.metadata.namespace\n count(networkpolicie.spec.podSelector) == 0\n}\n\n\nwlConnectedToNetworkPolicy(wl, networkpolicie){\n\twl.metadata.namespace == wl.metadata.namespace\n\tcount(networkpolicie.spec.podSelector) \u003e 0\n count({x | networkpolicie.spec.podSelector.matchLabels[x] == wl.spec.template.metadata.labels[x]}) == count(networkpolicie.spec.podSelector.matchLabels)\n}\n\n\ncronjobConnectedToNetworkPolicy(cj, networkpolicie){\n\tcj.metadata.namespace == networkpolicie.metadata.namespace\n count(networkpolicie.spec.podSelector) == 0\n}\n\ncronjobConnectedToNetworkPolicy(cj, networkpolicie){\n\tcj.metadata.namespace == networkpolicie.metadata.namespace\n\tcount(networkpolicie.spec.podSelector) \u003e 0\n count({x | networkpolicie.spec.podSelector.matchLabels[x] == cj.spec.jobTemplate.spec.template.metadata.labels[x]}) == count(networkpolicie.spec.podSelector.matchLabels)\n}\n\nisIngerssEgressPolicy(networkpolicie) {\n list_contains(networkpolicie.spec.policyTypes, \"Ingress\")\n list_contains(networkpolicie.spec.policyTypes, \"Egress\")\n }\n\nlist_contains(list, element) {\n some i\n list[i] == element\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob","NetworkPolicy"]}],"ruleDependencies":[],"description":"fails if there are no ingress and egress defined for pod","remediation":"Make sure you define ingress and egress policies for all your Pods","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Container hostPort","attributes":{"armoBuiltin":true},"creationTime":"","description":"Configuring hostPort limits you to a particular port, and if any two workloads that specify the same HostPort cannot be deployed to the same node. And if the scale of your workload is larger than the number of nodes in your Kubernetes cluster, the deployment fails.","remediation":"Make sure you do not configure hostPort for the container, if necessary use NodePort / ClusterIP","rules":[{"guid":"","name":"container-hostPort","attributes":{"armoBuiltin":true},"creationTime":"","rule":"package armo_builtins\n\n\n# Fails if pod has container with hostPort\ndeny[msga] {\n pod := input[_]\n pod.kind == \"Pod\"\n container := pod.spec.containers[_]\n\tisHostPort(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"Container: %v has Host-port\", [ container.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [pod]\n\t\t}\n\t}\n}\n\n# Fails if workload has container with hostPort\ndeny[msga] {\n wl := input[_]\n\tspec_template_spec_patterns := {\"Deployment\",\"ReplicaSet\",\"DaemonSet\",\"StatefulSet\",\"Job\"}\n\tspec_template_spec_patterns[wl.kind]\n container := wl.spec.template.spec.containers[_]\n isHostPort(container)\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"Container: %v in %v: %v has Host-port\", [ container.name, wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n# Fails if cronjob has container with hostPort\ndeny[msga] {\n \twl := input[_]\n\twl.kind == \"CronJob\"\n\tcontainer = wl.spec.jobTemplate.spec.template.spec.containers[_]\n isHostPort(container)\n msga := {\n\t\t\"alertMessage\": sprintf(\"Container: %v in %v: %v has Host-port\", [ container.name, wl.kind, wl.metadata.name]),\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertScore\": 7,\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [wl]\n\t\t}\n\t}\n}\n\n\n\nisHostPort(container){\n\tports := container.ports[_]\n ports.hostPort\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["Deployment","ReplicaSet","DaemonSet","StatefulSet","Job","Pod","CronJob"]}],"ruleDependencies":[],"description":"fails if container has hostPort","remediation":"Make sure you do not configure hostPort for the container, if necessary use NodePort / ClusterIP","ruleQuery":"armo_builtins"}]},{"guid":"","name":"Network policies","attributes":{"armoBuiltin":true},"creationTime":"","description":"If no network policy is defined, attackers who gain access to a single container may use it to probe the network. Lists namespaces in which no network policies are defined.","remediation":"Define network policy.","rules":[{"guid":"","name":"internal-networking","attributes":{"armoBuiltin":true,"m$K8sThreatMatrix":"Lateral Movement::Container internal networking, Discovery::Network mapping"},"creationTime":"","rule":"package armo_builtins\n\n# input: network policies\n# apiversion: networking.k8s.io/v1\n# fails if no network policies are defined in a certain namespace\n\ndeny[msga] {\n\tnamespaces := [namespace | namespace = input[_]; namespace.kind == \"Namespace\"]\n\tnamespace := namespaces[_]\n\tpolicy_names := [policy.metadata.namespace | policy = input[_]; policy.kind == \"NetworkPolicy\"]\n\tnot list_contains(policy_names, namespace.metadata.name)\n\n\tmsga := {\n\t\t\"alertMessage\": sprintf(\"no policy is defined for namespace %v\", [namespace.metadata.name]),\n\t\t\"alertScore\": 9,\n\t\t\"packagename\": \"armo_builtins\",\n\t\t\"alertObject\": {\n\t\t\t\"k8sApiObjects\": [namespace]\n\t\t}\n\t}\n}\n\nlist_contains(list, element) {\n some i\n list[i] == element\n}","ruleLanguage":"Rego","match":[{"apiGroups":["*"],"apiVersions":["*"],"resources":["networkpolicies","namespaces"]}],"ruleDependencies":[],"description":"lists namespaces in which no network policies are defined","remediation":"","ruleQuery":"armo_builtins"}]}]}