Skip to content

Commit

Permalink
Fix M-112 and use CEL optional values and variables in built-in checks (
Browse files Browse the repository at this point in the history
#39)

* feat: use optional values and variables in built-in checks

* feat: update M-113 to fail for any explicitly bad setter (including pod-level)

* feat: skip checks for pods in windows nodes

* fix M-112
  • Loading branch information
matheusfm authored Mar 14, 2024
1 parent c46c1b4 commit 87ffbce
Show file tree
Hide file tree
Showing 34 changed files with 158 additions and 199 deletions.
5 changes: 1 addition & 4 deletions internal/builtins/cis/M-500_default_namespace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,4 @@ match:
version: v1
resource: jobs
validations:
- expression: >
has(object.metadata.namespace)
&& (type(object.metadata.namespace) == string)
&& !(object.metadata.namespace == 'default')
- expression: object.metadata.?namespace.orValue("default") != "default"
8 changes: 4 additions & 4 deletions internal/builtins/general/M-401_unmanaged_pod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ match:
- group: ""
version: v1
resource: pods
variables:
- name: owners
expression: object.metadata.?ownerReferences.orValue([])
validations:
- expression: >
has(object.metadata.ownerReferences) &&
object.metadata.ownerReferences != null &&
object.metadata.ownerReferences.size() > 0 &&
object.metadata.ownerReferences.exists(o, has(o.controller) && o.controller == true)
variables.owners != null && variables.owners.exists(o, o.?controller.orValue(false) == true)
11 changes: 6 additions & 5 deletions internal/builtins/general/M-402_readiness_probe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ match:
- group: apps
version: v1
resource: replicasets
variables:
- name: owners
expression: object.metadata.?ownerReferences.orValue([])
validations:
- expression: >
(
object.kind == "Pod" &&
has(object.metadata.ownerReferences) &&
object.metadata.ownerReferences != null &&
object.metadata.ownerReferences.size() > 0 &&
object.metadata.ownerReferences.exists(o, has(o.kind) && has(o.apiVersion) && o.kind == "Job" && o.apiVersion == "batch/v1")
variables.owners != null &&
variables.owners.exists(o, o.?kind.orValue("") == "Job" && o.?apiVersion.orValue("") == "batch/v1")
)
||
podSpec.containers.all(container, has(container.readinessProbe) || has(container.startupProbe))
podSpec.containers.all(c, has(c.readinessProbe) || has(c.startupProbe))
9 changes: 6 additions & 3 deletions internal/builtins/general/M-403_liveness_probe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ match:
- group: apps
version: v1
resource: replicasets
variables:
- name: owners
expression: object.metadata.?ownerReferences.orValue([])
validations:
- expression: >
(
object.kind == "Pod" &&
has(object.metadata.ownerReferences) &&
object.metadata.ownerReferences.exists(o, has(o.kind) && has(o.apiVersion) && o.kind == "Job" && o.apiVersion == "batch/v1")
variables.owners != null &&
variables.owners.exists(o, o.?kind.orValue("") == "Job" && o.?apiVersion.orValue("") == "batch/v1")
)
||
podSpec.containers.all(container, has(container.livenessProbe))
podSpec.containers.all(c, has(c.livenessProbe))
6 changes: 1 addition & 5 deletions internal/builtins/general/M-404_memory_requests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,4 @@ match:
resource: jobs
validations:
- expression: >
allContainers.all(container,
has(container.resources) &&
has(container.resources.requests) &&
has(container.resources.requests.memory)
)
allContainers.all(c, c.?resources.?requests.?memory.orValue("") != "")
6 changes: 1 addition & 5 deletions internal/builtins/general/M-405_cpu_requests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,4 @@ match:
resource: jobs
validations:
- expression: >
allContainers.all(container,
has(container.resources) &&
has(container.resources.requests) &&
has(container.resources.requests.cpu)
)
allContainers.all(c, c.?resources.?requests.?cpu.orValue("") != "")
6 changes: 1 addition & 5 deletions internal/builtins/general/M-406_memory_limit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,4 @@ match:
resource: jobs
validations:
- expression: >
allContainers.all(container,
has(container.resources) &&
has(container.resources.limits) &&
has(container.resources.limits.memory)
)
allContainers.all(c, c.?resources.?limits.?memory.orValue("") != "")
6 changes: 1 addition & 5 deletions internal/builtins/general/M-407_cpu_limit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,4 @@ match:
resource: jobs
validations:
- expression: >
allContainers.all(container,
has(container.resources) &&
has(container.resources.limits) &&
has(container.resources.limits.cpu)
)
allContainers.all(c, c.?resources.?limits.?cpu.orValue("") != "")
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ match:
resource: jobs
validations:
- expression: >
allContainers.all(container,
!has(container.command) ||
size(container.command) == 0 ||
container.command.all(cmd,
!cmd.contains("sudo"))
)
allContainers.all(c,
c.?command.orValue([]).all(cmd, !cmd.contains("sudo"))
)
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,4 @@ match:
resource: jobs
validations:
- expression: >
allContainers.all(container,
!container.image.contains("k8s.grc.io"))
allContainers.all(c, !c.image.contains("k8s.grc.io"))
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,4 @@ match:
resource: replicasets
validations:
- expression: >
!has(podSpec.restartPolicy) ||
has(podSpec.restartPolicy) &&
(podSpec.restartPolicy =='Always')
podSpec.?restartPolicy.orValue("Always") == 'Always'
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ match:
resource: jobs
validations:
- expression: >
has(podSpec.automountServiceAccountToken) && podSpec.automountServiceAccountToken == false
podSpec.?automountServiceAccountToken.orValue(true) == false
message: "Pod with Service Account token mounted automatically"
2 changes: 1 addition & 1 deletion internal/builtins/mitre/M-203_ssh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ validations:
!has(object.spec.ports) ||
object.spec.ports.all(p,
!(p.port in params.sshPorts) &&
(!has(p.targetPort) || !(p.targetPort in params.sshPorts))
!(p.?targetPort.orValue(0) in params.sshPorts)
)
message: "Service could be routing to SSH server"
Expand Down
6 changes: 1 addition & 5 deletions internal/builtins/nsa/M-300_read_only_root_filesystem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,5 @@ match:
resource: jobs
validations:
- expression: >
allContainers.all(container,
has(container.securityContext) &&
has(container.securityContext.readOnlyRootFilesystem) &&
container.securityContext.readOnlyRootFilesystem == true
)
allContainers.all(c, c.?securityContext.?readOnlyRootFilesystem.orValue(false) == true)
message: "Container is able to write to the root filesystem"
11 changes: 2 additions & 9 deletions internal/builtins/pss/baseline/M-100_host_process.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,8 @@ match:
resource: jobs
validations:
- expression: >
!has(podSpec.securityContext) ||
!has(podSpec.securityContext.windowsOptions) ||
!has(podSpec.securityContext.windowsOptions.hostProcess) ||
podSpec.securityContext.windowsOptions.hostProcess == false
podSpec.?securityContext.?windowsOptions.?hostProcess.orValue(false) == false
message: "Pod with privileged access to the Windows node"
- expression: >
allContainers.all(container,
!has(container.securityContext) ||
!has(container.securityContext.windowsOptions) ||
!has(container.securityContext.windowsOptions.hostProcess) ||
container.securityContext.windowsOptions.hostProcess == false)
allContainers.all(c, c.?securityContext.?windowsOptions.?hostProcess.orValue(false) == false)
message: "Container with privileged access to the Windows node"
6 changes: 3 additions & 3 deletions internal/builtins/pss/baseline/M-101_host_namespaces.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ match:
resource: jobs
validations:
- expression: >
(!has(podSpec.hostNetwork) || podSpec.hostNetwork == false) &&
(!has(podSpec.hostPID) || podSpec.hostPID == false) &&
(!has(podSpec.hostIPC) || podSpec.hostIPC == false)
podSpec.?hostNetwork.orValue(false) == false &&
podSpec.?hostPID.orValue(false) == false &&
podSpec.?hostIPC.orValue(false) == false
message: "Pod sharing host namespace"
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,5 @@ match:
resource: jobs
validations:
- expression: >
allContainers.all(container,
!has(container.securityContext) ||
!has(container.securityContext.privileged) ||
container.securityContext.privileged == false)
allContainers.all(c, c.?securityContext.?privileged.orValue(false) == false)
message: "Container running in privileged mode"
7 changes: 1 addition & 6 deletions internal/builtins/pss/baseline/M-103_capabilities.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,5 @@ params:
- SYS_CHROOT
validations:
- expression: >
allContainers.all(container,
!has(container.securityContext) ||
!has(container.securityContext.capabilities) ||
!has(container.securityContext.capabilities.add) ||
container.securityContext.capabilities.add.all(cap, cap in params.allowedCapabilities)
)
allContainers.all(c, c.?securityContext.?capabilities.?add.orValue([]).all(cap, cap in params.allowedCapabilities))
message: "Container running with not allowed capabilities"
2 changes: 1 addition & 1 deletion internal/builtins/pss/baseline/M-104_host_path_volumes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ match:
resource: jobs
validations:
- expression: >
!has(podSpec.volumes) || podSpec.volumes.all(vol, !has(vol.hostPath))
podSpec.?volumes.orValue([]).all(v, !has(v.hostPath))
message: "Pod with mounted host volume"
11 changes: 2 additions & 9 deletions internal/builtins/pss/baseline/M-105_host_ports.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,8 @@ match:
version: v1
resource: jobs
params:
allowedHostPorts: []
allowedHostPorts: [0]
validations:
- expression: >
allContainers.all(container,
!has(container.ports) ||
container.ports.all(port,
!has(port.hostPort) ||
port.hostPort == 0 ||
port.hostPort in params.allowedHostPorts
)
)
allContainers.all(c, c.?ports.orValue([]).all(p, p.?hostPort.orValue(0) in params.allowedHostPorts))
message: "Container exposing not allowed port on the host"
39 changes: 7 additions & 32 deletions internal/builtins/pss/baseline/M-107_selinux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,48 +47,23 @@ params:
- container_t
- container_init_t
- container_kvm_t
- ""
validations:
- expression: >
!has(podSpec.securityContext) ||
!has(podSpec.securityContext.seLinuxOptions) ||
!has(podSpec.securityContext.seLinuxOptions.type) ||
podSpec.securityContext.seLinuxOptions.type == '' ||
podSpec.securityContext.seLinuxOptions.type in params.allowedSELinuxTypes
podSpec.?securityContext.?seLinuxOptions.?type.orValue("") in params.allowedSELinuxTypes
message: "Pod with not allowed SELinux type"
- expression: >
allContainers.all(container,
!has(container.securityContext) ||
!has(container.securityContext.seLinuxOptions) ||
!has(container.securityContext.seLinuxOptions.type) ||
container.securityContext.seLinuxOptions.type == '' ||
container.securityContext.seLinuxOptions.type in params.allowedSELinuxTypes
)
allContainers.all(c, c.?securityContext.?seLinuxOptions.?type.orValue("") in params.allowedSELinuxTypes)
message: "Container with not allowed SELinux type"
- expression: >
!has(podSpec.securityContext) ||
!has(podSpec.securityContext.seLinuxOptions) ||
!has(podSpec.securityContext.seLinuxOptions.user) ||
podSpec.securityContext.seLinuxOptions.user == ''
podSpec.?securityContext.?seLinuxOptions.?user.orValue("") == ""
message: "Pod with forbidden SELinux user"
- expression: >
allContainers.all(container,
!has(container.securityContext) ||
!has(container.securityContext.seLinuxOptions) ||
!has(container.securityContext.seLinuxOptions.user) ||
container.securityContext.seLinuxOptions.user == ''
)
allContainers.all(c, c.?securityContext.?seLinuxOptions.?user.orValue("") == "")
message: "Container with forbidden SELinux user"
- expression: >
!has(podSpec.securityContext) ||
!has(podSpec.securityContext.seLinuxOptions) ||
!has(podSpec.securityContext.seLinuxOptions.role) ||
podSpec.securityContext.seLinuxOptions.role == ''
podSpec.?securityContext.?seLinuxOptions.?role.orValue("") == ""
message: "Pod with forbidden SELinux role"
- expression: >
allContainers.all(container,
!has(container.securityContext) ||
!has(container.securityContext.seLinuxOptions) ||
!has(container.securityContext.seLinuxOptions.role) ||
container.securityContext.seLinuxOptions.role == ''
)
allContainers.all(c, c.?securityContext.?seLinuxOptions.?role.orValue("") == "")
message: "Container with forbidden SELinux role"
6 changes: 1 addition & 5 deletions internal/builtins/pss/baseline/M-108_proc_mount.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,5 @@ match:
resource: jobs
validations:
- expression: >
allContainers.all(container,
!has(container.securityContext) ||
!has(container.securityContext.procMount) ||
container.securityContext.procMount == 'Default'
)
allContainers.all(c, c.?securityContext.?procMount.orValue("Default") == "Default")
message: "Container using forbidden proc mount type"
12 changes: 2 additions & 10 deletions internal/builtins/pss/baseline/M-109_seccomp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,8 @@ match:
resource: jobs
validations:
- expression: >
!has(podSpec.securityContext) ||
!has(podSpec.securityContext.seccompProfile) ||
!has(podSpec.securityContext.seccompProfile.type) ||
podSpec.securityContext.seccompProfile.type != 'Unconfined'
podSpec.?securityContext.?seccompProfile.?type.orValue("") != "Unconfined"
message: "Pod using forbidden seccomp profile"
- expression: >
allContainers.all(container,
!has(container.securityContext) ||
!has(container.securityContext.seccompProfile) ||
!has(container.securityContext.seccompProfile.type) ||
container.securityContext.seccompProfile.type != 'Unconfined'
)
allContainers.all(c, c.?securityContext.?seccompProfile.?type.orValue("") != "Unconfined")
message: "Container using forbidden seccomp profile"
7 changes: 4 additions & 3 deletions internal/builtins/pss/baseline/M-110_sysctls.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ params:
- net.ipv4.ip_unprivileged_port_start
- net.ipv4.tcp_syncookies
- net.ipv4.ping_group_range
variables:
- name: sysctls
expression: podSpec.?securityContext.?sysctls.orValue([])
validations:
- expression: >
!has(podSpec.securityContext) ||
!has(podSpec.securityContext.sysctls) ||
podSpec.securityContext.sysctls.all(s,
variables.sysctls.size() == 0 || variables.sysctls.all(s,
s.name == null ||
s.name in params.allowedSysctls
)
Expand Down
8 changes: 5 additions & 3 deletions internal/builtins/pss/restricted/M-111_volume_types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,12 @@ params:
- persistentVolumeClaim
- projected
- secret
variables:
- name: volumes
expression: podSpec.?volumes.orValue([])
validations:
- expression: >
!has(podSpec.volumes) ||
podSpec.volumes.all(volume,
volume.exists(key, key in params.allowedVolumeTypes)
variables.volumes.size() == 0 || variables.volumes.all(v,
v.exists(key, key in params.allowedVolumeTypes)
)
message: "Not allowed volume type used"
10 changes: 4 additions & 6 deletions internal/builtins/pss/restricted/M-112_privilege_escalation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,9 @@ match:
- group: batch
version: v1
resource: jobs
variables:
- name: isWindows
expression: podSpec.?os.?name.orValue("") == "windows"
validations:
- expression: >
allContainers.all(container,
!has(container.securityContext) ||
!has(container.securityContext.allowPrivilegeEscalation) ||
container.securityContext.allowPrivilegeEscalation == false
)
message: "Container with allowed privilege escalation"
variables.isWindows || allContainers.all(c, c.?securityContext.?allowPrivilegeEscalation.orValue(true) == false)
Loading

0 comments on commit 87ffbce

Please sign in to comment.