All Policies

Ensure Read Only hostPath

Pods which are allowed to mount hostPath volumes in read/write mode pose a security risk even if confined to a "safe" file system on the host and may escape those confines (see https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts). The only true way to ensure safety is to enforce that all Pods mounting hostPath volumes do so in read only mode. This policy checks all containers for any hostPath volumes and ensures they are explicitly mounted in readOnly mode.

Policy Definition

/other/ensure-readonly-hostpath/ensure-readonly-hostpath.yaml

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: ensure-readonly-hostpath
 5  annotations:
 6    policies.kyverno.io/title: Ensure Read Only hostPath
 7    policies.kyverno.io/category: Other
 8    policies.kyverno.io/severity: medium
 9    policies.kyverno.io/minversion: 1.6.0
10    kyverno.io/kyverno-version: 1.6.2
11    kyverno.io/kubernetes-version: "1.23"
12    policies.kyverno.io/subject: Pod
13    policies.kyverno.io/description: >-
14      Pods which are allowed to mount hostPath volumes in read/write mode pose a security risk
15      even if confined to a "safe" file system on the host and may escape those confines (see
16      https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts). The only true way
17      to ensure safety is to enforce that all Pods mounting hostPath volumes do so in read only
18      mode. This policy checks all containers for any hostPath volumes and ensures they are
19      explicitly mounted in readOnly mode.      
20spec:
21  background: false
22  validationFailureAction: audit
23  rules:
24  - name: ensure-hostpaths-readonly
25    match:
26      any:
27      - resources:
28          kinds:
29            - Pod
30    preconditions:
31      all:
32      - key: "{{ request.operation || 'BACKGROUND' }}"
33        operator: AnyIn
34        value:
35        - CREATE
36        - UPDATE
37    validate:
38      message: All hostPath volumes must be mounted as readOnly.
39      foreach:
40      # Fetch all volumes in the Pod which are a hostPath. Store the names in an array. There could be multiple in a Pod so can't assume just one.
41      - list: "request.object.spec.volumes[?hostPath][]"
42        deny:
43          conditions:
44          # For every name found for a hostPath volume (stored as `{{element}}`), check all containers, initContainers, and ephemeralContainers which mount this volume and
45          # total up the number of them. Compare that to the ones with that same name which explicitly specify that `readOnly: true`. If these two
46          # counts aren't equal, deny the Pod because at least one is attempting to mount that hostPath in read/write mode. Note that the absence of
47          # the `readOnly: true` field implies read/write access. Therefore, every hostPath volume must explicitly specify that it should be mounted
48          # in readOnly mode, regardless of where that occurs in a Pod.
49            any:
50            - key: "{{ request.object.spec.[containers, initContainers, ephemeralContainers][].volumeMounts[?name == '{{element.name}}'][] | length(@) }}"
51              operator: NotEquals
52              value: "{{ request.object.spec.[containers, initContainers, ephemeralContainers][].volumeMounts[?name == '{{element.name}}' && readOnly] [] | length(@) }}"