Back to Blog

Kubernetes Storage Security for the KCSA Exam: hostPath Risks, subPath Escapes, CSI Driver Privileges, Mount Propagation, PV Reclaim Policies, Secret Volumes & the Pod Security Standards Volume Allowlist

A practitioner's KCSA guide to the Storage item in the Cluster Component Security domain — what a hostPath mount really exposes (kubelet credentials, the runtime socket, every Pod's Secrets on the node), why read-only is the only safe hostPath, the subPath symlink CVEs, why CSI node plugins run privileged with Bidirectional mount propagation, the CSIDriver fields that hand drivers Pod identity and service account tokens, inline CSI ephemeral volumes, cluster-scoped PersistentVolumes and cross-namespace data leakage, Retain vs Delete and HonorPVReclaimPolicy, Secret volumes on tmpfs, the Secrets Store CSI Driver, and how every control maps to the Baseline and Restricted Pod Security Standards.

By Sailor Team , October 29, 2026

The KCSA curriculum lists eleven items under Kubernetes Cluster Component Security: API server, controller manager, scheduler, kubelet, container runtime, kube-proxy, Pod, etcd, container networking, client security and storage. Most study material covers the first ten and waves at the eleventh. That is a mistake, because storage is where several of the exam’s other domains collide: a hostPath volume is the single most common container-escape primitive in the Threat Model domain, the Pod Security Standards in Security Fundamentals are largely a list of volume rules, and CSI drivers are the most privileged third-party software most clusters run.

Our KCSA cluster component security guide covers the API server, etcd, kubelet and the rest of the component map. This article is the storage chapter that guide does not have. It explains what each volume type can reach, why some of them are dangerous, how the storage control plane is wired and what privileges it holds, how persistent data can leak across namespaces, and how every one of those risks maps to a control the exam expects you to name. The mechanics of PersistentVolumes, claims and StorageClasses are assumed; if you need them, read the CKA storage guide first.

The Storage Trust Map

Before the risks, the actors. Kubernetes storage is not one component but a small distributed system, and every arrow in it is a trust boundary.

ActorWhere it runsWhat it can doWhy it matters for security
kubeletevery nodemounts volumes into Pod sandboxes, calls CSI node plugins over a UNIX socket under /var/lib/kubelet/plugins/, fetches Secrets and ConfigMaps for Pods bound to its nodeits credentials and its socket are both reachable through a bad hostPath
CSI node pluginDaemonSet on every node, privilegedformats, mounts and unmounts block devices and filesystems on the hosta compromised node plugin is a compromised node
CSI controller pluginDeployment, usually in a system namespacetalks to the storage backend with cloud or array credentials; creates and deletes volumes and snapshotsholds the most valuable storage credentials in the cluster
external-provisioner / attacher / resizer / snapshottersidecars of the controller pluginwatch PVCs, StorageClasses and VolumeAttachments; create PVs; read provisioning Secretscluster-wide RBAC on PersistentVolumes and VolumeAttachments
API objectsetcdPersistentVolume, StorageClass, CSIDriver, CSINode, VolumeAttachment and VolumeSnapshotContent are cluster-scoped; PersistentVolumeClaim and VolumeSnapshot are namespacedwhoever can create cluster-scoped storage objects can reach into every namespace

Two facts from that table drive most of the exam questions:

  1. PersistentVolumes are cluster-scoped. A PV is not “in” a namespace; a claim from any namespace can bind to it. That is convenient for admins and dangerous for tenants, as the section on data lifecycle shows.
  2. CSI node plugins are privileged by design. They have to be, because mounting on the host requires it. The consequence is that your storage vendor’s DaemonSet is inside your trusted computing base whether you like it or not.

hostPath: The Volume Type the Documentation Tells You Not to Use

The Kubernetes volumes documentation opens the hostPath section with an unusually blunt warning: using it “presents many security risks”, and if you can avoid it, you should, by defining a local PersistentVolume instead. The KCSA expects you to know why.

A hostPath volume mounts a path from the node’s filesystem into the container. There is no indirection and no filtering: whatever the kubelet can see at that path, the container sees too. The interesting question is what lives on a node.

Host pathWhat a container that mounts it getsSeverity
/var/lib/kubelet/pods/the projected volumes of every Pod on the node: their Secrets, ConfigMaps and bound service account tokenscritical: lateral movement into every namespace scheduled on the node
/var/lib/kubelet/pki/ and /etc/kubernetes/kubelet.confthe kubelet’s client certificate and kubeconfigcritical: impersonate the node to the API server
/etc/kubernetes/pki/ (control-plane nodes)the cluster CA key, API server and etcd certificatescritical: mint any client certificate, read etcd
/run/containerd/containerd.sock or /var/run/crio/crio.sockthe container runtime APIcritical: start a privileged container on the host, read any container’s filesystem
/etc/, /root/, /home/node configuration, SSH keys, admin kubeconfigshigh
/var/log/system and container logsmedium: credential leakage through logs
/dev/block devices, including the root diskcritical with read-write access

The canonical escape needs none of these specifically. A Pod that mounts / from the host and runs as root can chroot into it and simply be the node. That is the chain the KCSA threat model guide describes under privilege escalation, and it is why the Baseline Pod Security Standard forbids hostPath outright rather than restricting it.

Read-only is not optional

The documentation adds a subtler point that trips up candidates. If you use admission control to restrict hostPath to specific directories, the restriction “is effective only if you also require that every mount of that hostPath volume is read only”. A Pod with a read-write mount of any host path may be able to subvert the host mount and reach beyond the directory it was given. Two consequences:

  • An allowlist of host paths without a read-only requirement is not a security control.
  • The readOnly flag lives on the volumeMount, not the volume. A policy that checks spec.volumes[*].hostPath.path but not spec.containers[*].volumeMounts[*].readOnly is incomplete.

The type field

hostPath.type tells the kubelet what to check before mounting. The default, an empty string, performs no check at all for backward compatibility, which is why real manifests should always set it.

typeBehaviour
"" (default)no checks before mounting
DirectoryOrCreatecreates an empty directory with mode 0755, owned by the kubelet’s user and group, if nothing exists
Directorya directory must already exist
FileOrCreatecreates an empty file with mode 0644 if nothing exists; does not create the parent directory, so the Pod fails to start if the parent is missing
Filea file must already exist
Socketa UNIX socket must exist (this is how you knowingly mount a runtime socket)
CharDevice, BlockDevicea character or block device must exist (Linux nodes only)

From a security standpoint the *OrCreate variants matter because they let a Pod create files and directories on the host as the kubelet’s user, which on almost every node is root.

The legitimate uses

The documentation names two: a log shipper that reads /var/log through a read-only mount, and making a host configuration file available read-only to a static Pod, because static Pods cannot read ConfigMaps. Add CNI and CSI node plugins, node exporters and runtime-security agents, and you have the complete list of workloads that should ever carry a hostPath. Every one of them belongs in a namespace that is explicitly exempted from or set to the privileged Pod Security level, and nowhere else.

hostPath hidden inside a PersistentVolume

Here is the nuance that separates a pass from a strong pass. Pod Security Admission checks the Pod spec. A Pod whose only volume is a persistentVolumeClaim passes the Baseline hostPath check even if the PV behind that claim is a hostPath PV. The admission controller never follows the claim to the volume. Two things follow:

  • A tenant who can create PersistentVolumes can give any namespace host filesystem access regardless of its Pod Security level. PV creation must be restricted to administrators. PVs are cluster-scoped, so the RBAC rule is a ClusterRole, and the verbs to guard are create, update and patch on persistentvolumes.
  • StorageClasses that point at a provisioner capable of creating host-backed volumes deserve the same scrutiny.

A local PersistentVolume is the documentation’s recommended alternative to hostPath not because the data is any less on the host, but because the PV object is created by an administrator, carries nodeAffinity the scheduler honours, and keeps the workload author out of the decision entirely.

volumeMounts[*].subPath mounts a subdirectory of a volume instead of its root, so one volume can serve several containers. subPathExpr builds that path from Downward API environment variables, with the documentation’s own example mounting the host directory /var/log/pods/$(POD_NAME) through a hostPath volume. Both features have a security history worth knowing.

  • CVE-2017-1002101 (fixed in 1.7.14, 1.8.9 and 1.9.4): a container could create a symlink inside a volume, and a subPath mount following that symlink gave the container arbitrary access to the host filesystem, even from a volume type as innocuous as emptyDir.
  • CVE-2021-25741 (fixed in 1.19.15, 1.20.11, 1.21.5 and 1.22.2): a symlink-exchange race in the hardened subPath handling reopened the same class of escape.

The kubelet now resolves subPath targets safely, but the lesson is the one the exam likes: the volume plugin runs on the host as root, so bugs in it are host escapes, and patching the kubelet is a storage security control. It is also a reminder that subPath mounts do not receive updates when the underlying Secret or ConfigMap changes, which matters for rotation later in this article.

Mount Propagation and Why CSI Node Plugins Are Privileged

volumeMounts[*].mountPropagation controls whether mounts made after the container starts are shared between host and container.

ModeEquivalentWhat it means
None (default)rprivatethe container sees no later host mounts under the volume, and its own mounts are invisible to the host
HostToContainerrslavethe container sees mounts the host (or a Bidirectional container) makes under the volume
Bidirectionalrsharedmounts the container creates propagate back to the host and to every other container using the volume

The documentation is explicit that Bidirectional “can damage the host operating system” and is therefore allowed only in privileged containers. That single rule explains the shape of every CSI deployment: the node plugin must create mounts under /var/lib/kubelet/pods/... that the kubelet and the Pod’s containers can see, so it mounts /var/lib/kubelet from the host with mountPropagation: Bidirectional, which forces privileged: true. Add the hostPath mounts for the plugin registration directory and the device tree, and the CSI node DaemonSet ends up holding exactly the privileges this article has spent two sections warning about.

The security consequences you should be able to state:

  • Vendor trust is cluster trust. A vulnerability in a CSI node plugin, or a tampered image of one, is node compromise on every node in the cluster. Image signing and verification, which the KCSA platform security guide covers, apply to storage drivers before almost anything else.
  • Namespace isolation. CSI components belong in a dedicated namespace with the privileged Pod Security level, strict RBAC on who can deploy there, and no application workloads alongside them.
  • Mount propagation is a Baseline-safe field only because privileged is not. Bidirectional on an unprivileged container is rejected by the kubelet, not by admission; a policy engine should still reject it early so the failure is visible.

What a CSI Driver Is Allowed to Know: The CSIDriver Object

Each CSI driver registers a cluster-scoped CSIDriver object that tells the kubelet how to treat it. Several of its fields are security decisions.

FieldDefaultWhat it doesSecurity relevance
attachRequiredtruewhether the kubelet waits for a VolumeAttachment before mountingdrivers that skip attach cut the controller out of the loop; fine for local drivers, suspicious for shared storage
podInfoOnMountfalsepasses csi.storage.k8s.io/pod.name, pod.namespace, pod.uid, serviceAccount.name and ephemeral to the driver on every mountlets the driver make per-Pod authorization decisions; also means the driver sees which workloads use it
tokenRequestsunsetthe kubelet requests bound service account tokens for the Pod, with the listed audience and optional expirationSeconds, and hands them to the driverthe driver can authenticate as the Pod to an external system; this is how secret-store drivers obtain cloud credentials for the right identity
requiresRepublishunsetthe kubelet calls NodePublishVolume periodicallyneeded to refresh short-lived credentials; the driver must update files atomically
volumeLifecycleModesPersistentwhether the driver may be used for PVs, for inline ephemeral volumes, or bothonly drivers that list Ephemeral can appear directly in a Pod spec
fsGroupPolicyReadWriteOnceWithFSTypewhether the kubelet applies fsGroup ownership changesNone means a volume keeps whatever permissions the backend gave it
seLinuxMountfalsemount each volume with its own SELinux contextsetting it true on a driver whose volumes share an export breaks isolation rather than improving it

The tokenRequests field deserves a second look because it ties storage to the identity topics in our CKS service account token guide. When a driver lists an audience, every mount hands it a token that proves the Pod’s identity, scoped to that audience and expiring on the schedule the driver asked for. That is a far better design than a driver holding one cluster-wide credential, but it also means the driver is a token-handling component, and its logs, metrics and crash dumps become places where tokens can leak.

Inline CSI ephemeral volumes

A Pod can carry a CSI volume directly, without a PVC:

volumes:
- name: certs
  csi:
    driver: secrets-store.csi.k8s.io
    readOnly: true
    volumeAttributes:
      secretProviderClass: payments-api

Two gates control whether that is allowed. The driver’s CSIDriver must list Ephemeral in volumeLifecycleModes, and the Pod Security Standards treat csi as an allowed volume type at every level, including Restricted. The second point surprises people. The Restricted profile trusts the cluster administrator to have installed only drivers that are safe for workloads to use inline, because the volumeAttributes map is passed to the driver verbatim and could, with a badly designed driver, name arbitrary backend objects. If you run a driver you would not want an untrusted tenant to call, you need an admission policy that allowlists inline drivers; Pod Security Admission will not do it for you. The ValidatingAdmissionPolicy later in this article shows one way.

Secrets referenced by StorageClasses

CSI drivers that need credentials to provision, attach or mount can read them from Secrets named in StorageClass parameters such as csi.storage.k8s.io/provisioner-secret-name and csi.storage.k8s.io/node-publish-secret-name. Those parameters can use templates like ${pvc.namespace} so that per-tenant credentials are read from the tenant’s namespace. The security points: the provisioner needs get on Secrets in whatever namespaces the templates can resolve to, StorageClass creation must be admin-only because a StorageClass can point at any Secret the provisioner can read, and a per-namespace node-publish-secret is how a shared driver avoids one global credential.

Persistent Data Has a Lifecycle, and Each Stage Leaks Differently

Reclaim policies

A PersistentVolume’s persistentVolumeReclaimPolicy decides what happens when its claim is deleted.

PolicyBehaviourSecurity angle
Deletethe PV object and the backing storage are deleted; default for dynamically provisioned volumesleast data left behind, but a deleted claim is unrecoverable, so backups are the compensating control
Retainthe PV moves to Released, keeps its claimRef, and the backing data is untouched until an administrator actsdata survives the workload; it must be wiped or re-bound deliberately
Recycledeprecated: a basic rm -rf on the volume, supported only by the NFS and hostPath pluginsnot a secure erase and not available for CSI volumes; treat it as a wrong answer

A Released PV cannot be bound by a new claim until someone clears its claimRef. The moment an administrator does that without wiping the data, the PV becomes Available to a claim from any namespace, because PVs are cluster-scoped. A tenant who creates a PVC with a matching storageClassName, access mode and size, or who names the PV directly with spec.volumeName, inherits the previous tenant’s data. The exam phrases this as “sensitive data from a deleted application was found in a new namespace”; the answers are a Delete reclaim policy for multi-tenant classes, a wipe-before-reuse procedure for Retain, and RBAC that keeps PV editing with administrators.

Deletion order and the protection finalizers

Kubernetes adds kubernetes.io/pvc-protection to every PVC and kubernetes.io/pv-protection to every PV. A PVC that is still mounted by a Pod stays in Terminating until the Pod goes away; a PV stays until its claim is gone. These finalizers exist to prevent data loss from racing deletions, and they are why a “stuck Terminating PVC” is almost always a Pod still using it, as our finalizers guide explains.

Until recently there was a gap: if the PV was deleted before the PVC, the Delete reclaim policy was not honoured and the backing storage leaked. HonorPVReclaimPolicy, GA in Kubernetes 1.33, closes it with an extra finalizer (external-provisioner.volume.kubernetes.io/finalizer for CSI volumes, kubernetes.io/pv-controller for in-tree ones) so that Delete is applied regardless of deletion order. From a security viewpoint, “leaked” storage is storage nobody is tracking, which is exactly where stale copies of sensitive data accumulate.

Access modes and single-writer guarantees

ReadWriteOnce is a node-level guarantee: two Pods on the same node can both write. ReadWriteOncePod, GA since Kubernetes 1.29, is the Pod-level guarantee, enforced by the scheduler and the kubelet. When a scenario needs one workload to have exclusive access to a volume, for integrity rather than performance, ReadWriteOncePod is the field being tested.

Snapshots and clones carry the data with them

VolumeSnapshot is namespaced but its VolumeSnapshotContent is cluster-scoped and references real backend data. RBAC on volumesnapshotcontents and on who can restore a snapshot into a new PVC is part of data protection, and an exported snapshot is a copy of everything that was on the volume, including whatever the application wrote in plaintext.

Encryption at rest belongs to the backend

Kubernetes does not encrypt volume contents. Encryption at rest for PVs is a property of the storage backend, usually requested through StorageClass parameters (a cloud disk class with encrypted: "true" and a key reference, for example). Do not confuse it with the EncryptionConfiguration that protects Secrets inside etcd, which our CKS secrets encryption guide covers; the exam offers both as answer options and expects you to pick the one that matches the data in question.

Secrets as Volumes: tmpfs, Modes and the Secrets Store CSI Driver

Native Secret volumes

When a Pod mounts a Secret as a volume, the kubelet writes it to a tmpfs (RAM-backed) filesystem, so it never touches the node’s disk, and mounts it read-only. Three details carry exam weight:

  • File modes. The default defaultMode is 0644. Anyone who can read the Pod’s filesystem as another user can read the Secret; set 0400 or a per-item mode for credentials.
  • Updates. The kubelet refreshes mounted Secrets on its sync period, but a container that mounts a Secret through subPath never receives updates. Rotation plans that rely on file watching break silently on subPath.
  • Environment variables are worse. They are visible in /proc/<pid>/environ, inherited by child processes, and routinely dumped into crash reports. Mount, do not inject, and note that the data path from /var/lib/kubelet/pods/ back to these files is the reason hostPath was the first topic in this article.

The kubelet can only fetch Secrets for Pods bound to its node, thanks to the Node authorizer described in our authorization chain guide. That scoping is what makes a node compromise a node-sized breach rather than a cluster-sized one, and it is exactly the boundary a hostPath to the kubelet’s credentials erases.

emptyDir with medium: Memory is also tmpfs, counts against the container’s memory limit, and is the right place for scratch files you do not want on disk; set sizeLimit so it cannot be used to exhaust node memory, a theme the KCSA denial-of-service guide develops.

Projected volumes and bound tokens

A projected volume combines Secrets, ConfigMaps, Downward API fields and a serviceAccountToken source into one directory. The token source is what makes the modern service account token short-lived and audience-bound (expirationSeconds, audience), and it is the pattern the kubelet uses for the default token mount. The CKS guide linked above owns the details; for the KCSA, know that a projected token is the secure replacement for the legacy long-lived token Secret.

The Secrets Store CSI Driver

The Secrets Store CSI Driver is a Kubernetes SIG project that mounts secrets from an external store (AWS, Azure, GCP, Vault, Akeyless, Conjur, OpenBao providers) into a Pod as a CSI inline ephemeral volume. A SecretProviderClass CRD describes which objects to fetch; the Pod references it through volumeAttributes as shown earlier. Why it belongs in a storage-security article:

  • The secret material never has to exist as a Kubernetes Secret in etcd at all. Mounted content lives in the Pod’s volume on the node and disappears with the Pod.
  • The driver authenticates the Pod to the external store using the CSIDriver tokenRequests and podInfoOnMount mechanisms above: pod identity in, scoped credential out.
  • The optional sync as Kubernetes Secret feature (secretObjects in the SecretProviderClass) creates a real Secret from the mounted content so it can be consumed as an environment variable or by an Ingress. The documentation notes that the Secret is only created once a Pod mounts the volume and is deleted when the last consuming Pod goes away. The trade-off is that you are back to storing the value in etcd, so etcd encryption at rest becomes relevant again.
  • Rotation is an alpha feature, off by default, enabled with --enable-secret-rotation=true. Since v1.6.0 it uses the CSI RequiresRepublish mechanism: the kubelet periodically calls NodePublishVolume and the driver re-fetches from the provider once the --rotation-poll-interval (default 2m) has elapsed. Applications must watch the files; environment variables derived from a synced Secret do not update without a Pod restart.
  • The driver itself runs as a privileged DaemonSet, like every CSI node plugin, which is one more reason to keep it in a dedicated system namespace.

Mapping Storage Controls to the Pod Security Standards

The Pod Security Standards are where the exam expects you to land most storage questions. The storage-relevant controls are few and precise.

ControlBaselineRestrictedWhere it is checked
hostPath volumesforbidden (spec.volumes[*].hostPath must be nil)forbiddenPod spec only; a hostPath PV behind a PVC is not detected
Volume typesany type other than hostPathonly configMap, csi, downwardAPI, emptyDir, ephemeral, persistentVolumeClaim, projected, secretevery item in spec.volumes[*] must set exactly one of the allowed fields
privileged (and therefore Bidirectional propagation)forbiddenforbiddencontainer securityContext
fsGroup, supplementalGroupsunrestrictedunrestrictedcovered in our securityContext internals guide

Three observations make good exam answers:

  • The Restricted list contains eight types. As of the v1.37 documentation it does not include image volumes, so an OCI artifact mounted as an image volume (stable since Kubernetes 1.36, always read-only) is rejected in a Restricted namespace. Watch the release notes for that to change.
  • Restricted allows csi and ephemeral (generic ephemeral volumes, which are PVC-backed), which is why the inline-driver allowlist discussed earlier has to come from a separate admission policy.
  • Restricted still allows persistentVolumeClaim, so the PV-level hostPath bypass applies at every level. Pod Security Standards constrain Pods; RBAC on PersistentVolumes and StorageClasses constrains the storage behind them. You need both.

Closing the gaps with a ValidatingAdmissionPolicy

Pod Security Admission is deliberately simple. For the two gaps above, a ValidatingAdmissionPolicy written in CEL is the built-in option (the platform security guide covers where it sits among the admission controllers). This example allows hostPath only under /var/log and only when every mount of it is read-only, and allowlists the inline CSI drivers a namespace may use:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: storage-guardrails
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups: [""]
      apiVersions: ["v1"]
      operations: ["CREATE", "UPDATE"]
      resources: ["pods"]
  variables:
  - name: containers
    expression: >-
      object.spec.containers
      + (has(object.spec.initContainers) ? object.spec.initContainers : [])
  validations:
  - expression: >-
      !has(object.spec.volumes) || object.spec.volumes.all(v,
        !has(v.hostPath) || (
          v.hostPath.path.startsWith("/var/log") &&
          variables.containers.all(c, !has(c.volumeMounts) ||
            c.volumeMounts.all(m, m.name != v.name || (has(m.readOnly) && m.readOnly)))))
    message: "hostPath volumes must be under /var/log and every mount must be readOnly"
  - expression: >-
      !has(object.spec.volumes) || object.spec.volumes.all(v,
        !has(v.csi) || v.csi.driver in ["secrets-store.csi.k8s.io"])
    message: "only approved inline CSI drivers may be used"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: storage-guardrails
spec:
  policyName: storage-guardrails
  validationActions: ["Deny"]
  matchResources:
    namespaceSelector:
      matchExpressions:
      - key: kubernetes.io/metadata.name
        operator: NotIn
        values: ["kube-system", "storage-system"]

The binding excludes the system namespaces where CSI drivers and log shippers legitimately need what the policy forbids. That exclusion list is your trusted computing base; keep it short and review who can deploy into those namespaces.

A Storage Security Checklist You Can Defend

RiskControlExam keyword
container escape through host filesystemBaseline or Restricted PSS; no hostPath outside exempted system namespaceshostPath, Baseline
allowed hostPath becomes an escape anywayrequire readOnly: true on every mount; prefer local PVsread-only
hostPath smuggled through a PVadmin-only RBAC on persistentvolumes and storageclassescluster-scoped
storage driver compromiseimage signing, dedicated privileged namespace, patchingCSI node plugin, Bidirectional
untrusted tenants calling arbitrary inline driversadmission allowlist of csi.driver valuesCSI ephemeral volume
data left behind after deletionDelete reclaim for multi-tenant classes, wipe before reusing Retain PVs, HonorPVReclaimPolicyReleased, claimRef
two writers corrupting a volumeReadWriteOncePodaccess mode
credentials on diskSecret volumes (tmpfs), defaultMode: 0400, no env varstmpfs
credentials in etcd at allSecrets Store CSI Driver without syncSecretProviderClass
secrets in etcdEncryptionConfiguration with a KMS providerencryption at rest
memory or disk exhaustion through volumessizeLimit on emptyDir, ephemeral-storage limitsnode-pressure eviction

How the KCSA Tests Storage

The exam is multiple choice and does not ask you to write a PV. It asks you to recognise which control answers a scenario. Patterns to expect:

Scenario wordingWhat is being testedBest answer
”A developer’s Pod mounts / from the node and the node was compromised”hostPath as an escape primitiveenforce Baseline PSS; the volume type should never have been admitted
”A log agent needs /var/log but the security team objects”legitimate hostPathread-only mount, dedicated namespace at the privileged level
”Pod Security Admission is set to Restricted but a Pod still reached the host filesystem”PV-level bypassthe PV was a hostPath PV; restrict PV creation
”Why does the storage vendor’s DaemonSet require privileged: true?“mount propagationBidirectional propagation is allowed only in privileged containers
”A new team found another team’s files on a freshly bound volume”reclaim policy and cluster-scoped PVsRetain PV reused without wiping; use Delete or a wipe procedure
”Storage was still billed after the application was removed”deletion-order leakHonorPVReclaimPolicy (GA 1.33)
“Secrets must never be written to the node’s disk”Secret volume mediumtmpfs-backed Secret volume, not env vars
”Rotated certificate not picked up by the container”subPath update behaviourmount the whole Secret without subPath
”Secrets should not be stored in etcd”external secret storesSecrets Store CSI Driver without the sync feature
”Which Restricted volume type allows an OCI artifact?“the allowlistnone; image is not in the Restricted list

Common Mistakes

  • Treating local PVs as inherently safe. They remove the workload author from the decision; the data is still on the node and the PV still needs admin-only RBAC.
  • Allowlisting host paths without requiring read-only mounts. The documentation says this is not an effective restriction. Policies must check volumeMounts[*].readOnly.
  • Assuming Pod Security Admission inspects PersistentVolumes. It inspects Pods. persistentVolumeClaim is allowed everywhere, including Restricted.
  • Believing Restricted forbids CSI. It allows csi; inline driver allowlists are your job.
  • Choosing Recycle as a secure-wipe answer. It is deprecated, limited to NFS and hostPath, and performs a plain delete.
  • Confusing volume encryption with etcd encryption. EncryptionConfiguration protects Secrets in etcd; PV encryption is a backend property requested through a StorageClass.
  • Rotating Secrets that are mounted via subPath. They never update.
  • Forgetting that a CSI driver is a token handler. tokenRequests hands it bound service account tokens; its logs and debug endpoints are in scope for secret hygiene.

Frequently Asked Questions

Why is hostPath considered a security risk in Kubernetes?

A hostPath volume gives a container direct access to the node’s filesystem. From there it can read the kubelet’s credentials, the container runtime socket and every other Pod’s Secrets under /var/lib/kubelet/pods/, which turns a compromised container into a compromised node. The Baseline Pod Security Standard forbids hostPath entirely, and the Kubernetes documentation recommends a local PersistentVolume instead.

Is a read-only hostPath mount safe?

It is far safer, and it is the only configuration under which an admission-time allowlist of host paths is meaningful. The documentation states that restricting hostPath to specific directories works only if every mount of that volume is read-only; a read-write mount of any host path may allow the container to subvert the mount. Even read-only, the path should be narrow and the workload should live in a dedicated system namespace.

Why do CSI node plugins run as privileged containers?

They must create mounts on the host that the kubelet and other containers can see, which requires mountPropagation: Bidirectional, and Kubernetes allows Bidirectional only in privileged containers because it can damage the host operating system. The consequence is that every CSI node DaemonSet is part of the cluster’s trusted computing base.

Can a PersistentVolume leak data between namespaces?

Yes. PersistentVolumes are cluster-scoped. A Retain PV whose claimRef is cleared without wiping the data becomes Available to a claim from any namespace, and a PVC can even target it by name with spec.volumeName. Use the Delete reclaim policy for multi-tenant StorageClasses, wipe Retain volumes before reuse, and keep PV editing with administrators.

What does HonorPVReclaimPolicy change?

Before it, deleting a PV before its PVC could skip the Delete reclaim policy and leak the backing storage. HonorPVReclaimPolicy, GA in Kubernetes 1.33, adds a finalizer so the reclaim policy is honoured regardless of deletion order, which stops untracked copies of data from accumulating in the storage backend.

Which volume types does the Restricted Pod Security Standard allow?

Exactly eight: configMap, csi, downwardAPI, emptyDir, ephemeral, persistentVolumeClaim, projected and secret. hostPath is forbidden from Baseline upward, and as of the v1.37 documentation image volumes are not on the Restricted list. Because csi is allowed, restricting which drivers may be used inline requires a separate admission policy.

Are Kubernetes Secrets written to the node’s disk when mounted?

No. Secret volumes are backed by tmpfs, a RAM-backed filesystem, and are mounted read-only. Set a restrictive defaultMode such as 0400, avoid subPath mounts if you rely on rotation, and prefer volumes over environment variables, which leak through /proc and crash dumps.

What is the Secrets Store CSI Driver and how is it different from a Kubernetes Secret?

It mounts secrets from an external store such as a cloud secret manager or Vault directly into a Pod as a CSI inline volume, so the value never has to exist in etcd. A SecretProviderClass describes what to fetch, and the driver uses bound service account tokens to authenticate the Pod to the store. The optional sync feature creates a Kubernetes Secret from the mounted content, which reintroduces etcd storage and its encryption requirements.

Conclusion

Storage is listed as one component in the KCSA’s Cluster Component Security domain, but it behaves like a cross-section of the whole exam. hostPath is the threat model’s favourite escape; read-only mounts, the local PV alternative and the Baseline standard are its controls. CSI node plugins need Bidirectional mount propagation and therefore privilege, so storage drivers are trusted computing base and must be treated as such. PersistentVolumes are cluster-scoped, so reclaim policies and admin-only PV RBAC are tenant-isolation controls, and HonorPVReclaimPolicy stops data from leaking through deletion-order bugs. Secret volumes live on tmpfs, subPath breaks rotation, and the Secrets Store CSI Driver lets you keep secrets out of etcd entirely. Finally, the Pod Security Standards constrain only what is in the Pod spec, which is why PV and StorageClass RBAC, and a small ValidatingAdmissionPolicy, finish the job they start.

If you want to check that these distinctions are automatic under exam conditions, Sailor.sh’s KCSA Certification-Ready Mock Exam Bundle puts storage scenarios alongside the rest of the component security domain across five timed mock exams with explanations, so a wrong answer on reclaim policies or hostPath becomes a fixed mental model rather than a surprise on test day. Pair it with the KCSA exam guide, the KCSA study plan and the free KCSA practice questions to round out your preparation.

Continue with the KCSA cluster component security guide for the other ten components, the Pod Security Standards guide for the admission side of every rule above, and the isolation and multi-tenancy guide for where storage boundaries fit among the others.

Limited Time Offer: Get 80% off all Mock Exam Bundles | Sale ends in 7 days. Start learning today.

Claim Now