Rule Metadata

Last updated: 2024-01-15
🔴
Severity
CRITICAL
🛡️
Category
Workload & Runtime Security
Version
v1.0.0
Downloads
1.2K
Author: Spotter Security Team
Created: 2024-01-10
Compliance:
CIS NIST

Volume Mount With OS Directory Write Permissions

HostPath volumes mounting sensitive OS directories should be read-only.

YAML Configuration

rule.yaml YAML
apiVersion: rules.spotter.dev/v1alpha1
kind: SpotterRule
metadata:
  name: spotter-workload-009
  labels:
    severity: "critical" 
    category: "workload"
  annotations:
    rules.spotter.dev/title: "Volume Mount With OS Directory Write Permissions"
    rules.spotter.dev/version: "1.0.0"
    rules.spotter.dev/cwe: "CWE-732"
    rules.spotter.dev/description: "HostPath volumes mounting sensitive OS directories should be read-only."
spec:
  match:
    resources:
      kubernetes:
        apiGroups:
          - ""
          - "apps"
        versions:
          - "v1"
        kinds:
          - Pod
          - Deployment
          - StatefulSet
          - DaemonSet
        namespaces:
          include: ["*"]
          exclude: ["kube-system", "kube-public"]
        labels:
          exclude:
            rules.spotter.dev/ignore: ["true"]
  cel: |
    (object.kind == 'Pod' && (
      (has(object.spec.containers) && object.spec.containers.exists(c,
        has(c.volumeMounts) && c.volumeMounts.exists(vm,
          (vm.mountPath.startsWith('/etc') || vm.mountPath.startsWith('/var') || vm.mountPath.startsWith('/usr') || vm.mountPath.startsWith('/bin')) &&
          ((!has(vm.readOnly) || vm.readOnly == false) || (has(vm.recursiveReadOnly) && vm.recursiveReadOnly == 'Disabled')) &&
          has(object.spec.volumes) && object.spec.volumes.exists(v, v.name == vm.name &&
            (has(v.hostPath) || has(v.emptyDir) || has(v.scaleIO) || (!has(v.configMap) && !has(v.secret))))
        )
      )) ||
      (has(object.spec.initContainers) && object.spec.initContainers.exists(c,
        has(c.volumeMounts) && c.volumeMounts.exists(vm,
          (vm.mountPath.startsWith('/etc') || vm.mountPath.startsWith('/var') || vm.mountPath.startsWith('/usr') || vm.mountPath.startsWith('/bin')) &&
          ((!has(vm.readOnly) || vm.readOnly == false) || (has(vm.recursiveReadOnly) && vm.recursiveReadOnly == 'Disabled')) &&
          has(object.spec.volumes) && object.spec.volumes.exists(v, v.name == vm.name &&
            (has(v.hostPath) || has(v.emptyDir) || has(v.scaleIO) || (!has(v.configMap) && !has(v.secret))))
        )
      ))
    )) ||
    (object.kind != 'Pod' && (
      (has(object.spec.template.spec.containers) && object.spec.template.spec.containers.exists(c,
        has(c.volumeMounts) && c.volumeMounts.exists(vm,
          (vm.mountPath.startsWith('/etc') || vm.mountPath.startsWith('/var') || vm.mountPath.startsWith('/usr') || vm.mountPath.startsWith('/bin')) &&
          ((!has(vm.readOnly) || vm.readOnly == false) || (has(vm.recursiveReadOnly) && vm.recursiveReadOnly == 'Disabled')) &&
          has(object.spec.template.spec.volumes) && object.spec.template.spec.volumes.exists(v, v.name == vm.name &&
            (has(v.hostPath) || has(v.emptyDir) || has(v.scaleIO) || (!has(v.configMap) && !has(v.secret))))
        )
      )) ||
      (has(object.spec.template.spec.initContainers) && object.spec.template.spec.initContainers.exists(c,
        has(c.volumeMounts) && c.volumeMounts.exists(vm,
          (vm.mountPath.startsWith('/etc') || vm.mountPath.startsWith('/var') || vm.mountPath.startsWith('/usr') || vm.mountPath.startsWith('/bin')) &&
          ((!has(vm.readOnly) || vm.readOnly == false) || (has(vm.recursiveReadOnly) && vm.recursiveReadOnly == 'Disabled')) &&
          has(object.spec.template.spec.volumes) && object.spec.template.spec.volumes.exists(v, v.name == vm.name &&
            (has(v.hostPath) || has(v.emptyDir) || has(v.scaleIO) || (!has(v.configMap) && !has(v.secret))))
        )
      ))
    ))
  remediation:
    manual: "Set `readOnly: true` for hostPath volume mounts that access sensitive OS directories."
  references:
    - title: "Volumes - hostPath"
      url: "https://kubernetes.io/docs/concepts/storage/volumes/#hostpath"