Kubernetes storage can look simple from the application side. A container writes a file to a mounted directory, reads it later, and the application continues working.

The security implications are less obvious.

When Kubernetes uses a host path or bind mount, the container can gain access to a location backed by the node's filesystem. If that location is configured too broadly, a workload may gain access to files or directories that it was never supposed to see.

This becomes particularly important when working with hostPath volumes, local storage, CSI drivers, and other storage mechanisms that ultimately depend on directories on the node.

Kubernetes 1.37 continues the broader effort to make storage behavior more explicit and secure. For developers and cluster administrators, the important lesson is simple: a mounted directory should be treated as a security boundary, not just a storage location.

This article explains bind mounts in Kubernetes, where the security risks come from, how permissions affect access, and what to check before using node-backed storage in production.

What Is a Bind Mount?

A bind mount maps an existing directory from one filesystem location into another location.

In a containerized environment, the general idea looks like this:

Kubernetes Node
|
+-- /var/lib/application-data
|
+------> Container
         |
         +-- /data

The application sees:

/data

but the underlying storage may exist on the Kubernetes node.

This is different from a typical persistent volume abstraction where Kubernetes and a storage plugin manage the lifecycle of the storage independently from the container.

Why Bind Mounts Need Extra Care

A container normally has an isolated filesystem.

When you mount a host directory into that container, you deliberately create a connection between the container and the node.

For example:

Container
   |
   | mounted directory
   v
Node filesystem

If the mounted directory is carefully selected, this can be useful.

If the mount points to a sensitive location, the container may gain access to information or resources outside the application's intended scope.

This is why arbitrary host filesystem access is generally considered a security-sensitive operation.

hostPath and Node Storage

A common Kubernetes mechanism for exposing a node filesystem path is hostPath.

For example:

apiVersion: v1
kind: Pod
metadata:
  name: storage-demo
spec:
  containers:
    - name: app
      image: nginx:latest
      volumeMounts:
        - name: app-data
          mountPath: /data
  volumes:
    - name: app-data
      hostPath:
        path: /var/lib/app-data
        type: DirectoryOrCreate

The container receives /data, while the node provides /var/lib/app-data.

This can be useful for workloads that genuinely need node-local data.

However, it also means that the workload depends on a specific node's filesystem.

Bind Mount vs Persistent Volume

These approaches should not be treated as interchangeable.

Area

Host-backed bind mount / hostPath

Persistent Volume

Storage location

Node filesystem

Storage abstraction

Portability

Usually lower

Usually higher

Node dependency

Often strong

Depends on storage class

Security boundary

Host filesystem is involved

Storage layer provides abstraction

Common use

Node-specific data or system integration

Application persistent storage

Operational complexity

Can be simple initially

Depends on storage backend

For application data, a PersistentVolume-based design is often easier to manage consistently across a cluster.

A host path should have a specific reason to exist.

The Security Boundary

Consider this directory:

/var/lib/app-data

If the application has access only to that directory, the intended boundary is:

Node
|
+-- /var/lib/app-data
|      |
|      +-- Application files
|
+-- /etc
+-- /var/log
+-- /home
+-- other directories

The application should not be able to traverse into unrelated directories.

This is one reason the exact mount path matters.

A dangerous configuration is not necessarily dangerous because hostPath exists. The risk comes from what the workload can access through the mount and what permissions it receives.

Avoid Mounting the Node Root

A configuration such as:

volumes:
  - name: host-root
    hostPath:
      path: /

creates a fundamentally different security situation.

The container now has access to the node's root filesystem.

This can expose:

Mounting / should therefore be treated as an extremely high-risk configuration.

For normal application workloads, there is rarely a good reason to expose the entire node filesystem.

Use the Narrowest Host Path Possible

If a workload requires host-backed storage, prefer a dedicated directory.

For example:

hostPath:
  path: /var/lib/my-application
  type: Directory

rather than:

hostPath:
  path: /var/lib
  type: Directory

The smaller directory creates a narrower security boundary.

The principle is:

Broader mount
     |
     v
More host data exposed

Narrower mount
     |
     v
Less host data exposed

Understand Directory vs DirectoryOrCreate

The hostPath.type field controls how Kubernetes handles the target path.

For example:

type: Directory

expects the directory to already exist.

Whereas:

type: DirectoryOrCreate

allows Kubernetes to create the directory if it does not exist.

That distinction matters operationally.

With Directory, a missing path can prevent the workload from starting.

With DirectoryOrCreate, the path can be created automatically, but administrators still need to understand who owns the directory and what permissions it receives.

Do not use DirectoryOrCreate simply because it makes deployment easier.

File Permissions Still Matter

Suppose the host directory is:

/var/lib/my-application

The directory might be owned by:

root:root

with restrictive permissions.

The container might run as a non-root user:

securityContext:
  runAsUser: 10001
  runAsGroup: 10001

The application may then receive:

Permission denied

This is not necessarily a Kubernetes storage failure.

It can simply be a Linux filesystem permission issue.

The complete access path is:

Container User
      |
      v
Container Mount
      |
      v
Host Directory
      |
      v
Linux UID/GID + Permissions

All four need to line up.

Use a Non-Root Container

Applications generally should not run as root unless there is a specific operational requirement.

For example:

securityContext:
  runAsNonRoot: true
  runAsUser: 10001
  runAsGroup: 10001
  allowPrivilegeEscalation: false

This reduces the privileges available to the application process.

However, runAsNonRoot does not magically fix host filesystem permissions.

The underlying directory must still be accessible to the configured user.

fsGroup Can Help With Volume Permissions

For volumes that support Kubernetes ownership changes, a pod-level security context can specify an fsGroup.

For example:

securityContext:
  runAsNonRoot: true
  runAsUser: 10001
  runAsGroup: 10001
  fsGroup: 10001

The behavior depends on the volume type and storage implementation.

Do not assume that fsGroup will change permissions for every type of host-backed storage in exactly the same way.

Always test the actual storage mechanism being used.

Read-Only Mounts

If an application only needs to read host data, make the mount read-only.

For example:

volumeMounts:
  - name: host-data
    mountPath: /data
    readOnly: true

This creates an additional protection layer.

The model becomes:

Host Data
   |
   v
Read-only Mount
   |
   v
Container

Even if the application is compromised, the mounted location cannot be modified through that mount.

Read-only access should be the default whenever write access is not required.

Example: Read-Only Node Information

Suppose an application needs to read a specific node-provided directory.

A safer pattern is:

apiVersion: v1
kind: Pod
metadata:
  name: reader
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001

  containers:
    - name: app
      image: example/app:1.0
      securityContext:
        allowPrivilegeEscalation: false
      volumeMounts:
        - name: node-data
          mountPath: /node-data
          readOnly: true

  volumes:
    - name: node-data
      hostPath:
        path: /var/lib/my-application
        type: Directory

This example demonstrates several useful controls:

The actual image and path should be replaced with values appropriate for the workload.

Writable Host Paths Need More Scrutiny

A writable host path creates more risk because the workload can modify node-backed data.

For example:

volumeMounts:
  - name: app-data
    mountPath: /data
    readOnly: false

If write access is required, ask:

  1. Why does the application need host-backed storage?

  2. Can a PersistentVolume be used instead?

  3. Can the directory be isolated?

  4. Can the mount be read-only?

  5. Which user owns the files?

  6. What happens if the pod is compromised?

  7. Can another workload access the same directory?

These questions should be answered before production deployment.

Avoid Sharing Host Directories Between Applications

Suppose two applications use:

/var/lib/shared

If both workloads can write to the same location, one compromised application may be able to alter data consumed by another.

A better design is:

/var/lib/app-a
/var/lib/app-b

with separate permissions.

Storage isolation should follow application trust boundaries.

Use Pod Security Controls

Kubernetes provides mechanisms for controlling workloads that request sensitive capabilities.

Pod Security Standards distinguish between security profiles such as Baseline and Restricted.

Workloads that require host filesystem access should be reviewed carefully against the cluster's Pod Security policy.

A namespace with strong controls can prevent workloads from deploying configurations that violate the organization's security baseline.

For example:

apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted

Whether a particular workload can run under that policy depends on the complete pod specification.

The important point is that storage security should be part of pod security governance rather than handled separately.

Admission Policies Can Add Another Layer

Organizations can also use admission controls to restrict dangerous storage configurations.

A policy can reject workloads that attempt to:

Conceptually:

Pod Request
    |
    v
Admission Policy
    |
    +-- Safe ------> Create Pod
    |
    +-- Unsafe ----> Reject

This is particularly useful in large clusters where manually reviewing every manifest is unrealistic.

Common Mistakes

Mounting /

This exposes far more of the node filesystem than most applications require.

Use a dedicated directory instead.

Running as Root

A root process inside a container increases the consequences of a security failure.

Use a non-root identity whenever possible.

Making Every Mount Writable

If the application only reads data, use:

readOnly: true

Using Broad Host Paths

Avoid:

/var

when the application only needs:

/var/lib/my-application

Assuming fsGroup Always Fixes Permissions

Storage implementations can behave differently.

Test the actual volume type.

Ignoring Node Affinity

Host-backed storage belongs to a specific node.

A workload depending on node-local data may not behave correctly if Kubernetes schedules it elsewhere.

Scheduling and Node Locality

Host-backed storage creates a relationship between a workload and the node containing the data.

For example:

Node A
|
+-- /var/lib/app-data
       |
       +-- Application data

Pod
|
+-- Must access Node A

If the pod moves to Node B:

Node B
|
+-- /var/lib/app-data
       |
       +-- Different or missing data

This can cause application failures.

For node-local storage, scheduling rules and storage configuration need to be designed together.

A PersistentVolume with appropriate node affinity may be more suitable than manually assuming a particular node.

Troubleshooting Permission Denied

If the application reports:

Permission denied

check the identity inside the container:

id

Then inspect the mounted directory:

ls -ld /data
ls -la /data

If you have appropriate access on the node, inspect the host directory:

ls -ld /var/lib/my-application

Compare:

Container UID
Container GID
Host directory UID
Host directory GID
Filesystem permissions

Do not immediately solve the problem by running the container as root.

That can hide the actual permission configuration problem.

Troubleshooting Mount Failures

Check the pod events:

kubectl describe pod <pod-name>

Look at the Events section for errors related to:

You can also inspect the volume definition:

kubectl get pod <pod-name> -o yaml

This is useful when the deployed configuration differs from the manifest you expected.

Troubleshooting Data Disappearing

If data exists when a pod runs on one node but disappears after rescheduling, investigate whether the application is using node-local storage.

Check:

kubectl get pod <pod-name> -o wide

Then identify the node where the pod is running.

If the storage comes from:

Node A -> /var/lib/app-data

moving the workload to Node B can expose a different directory.

This is a storage design issue rather than simply a Kubernetes deployment problem.

When Should You Use hostPath?

A host path can be appropriate when the workload genuinely needs access to node-local resources.

Examples can include:

It is generally less appropriate for ordinary application persistence when a PersistentVolume can provide the required storage abstraction.

When Should You Use a PersistentVolume?

Use a PersistentVolume-based design when the application needs persistent data without directly depending on arbitrary node filesystem paths.

A typical architecture is:

Application
    |
    v
PersistentVolumeClaim
    |
    v
StorageClass
    |
    v
Storage Backend

This provides a cleaner separation between the application and the physical storage implementation.

Production Checklist

Before deploying a host-backed mount, check the following:

[ ] Is hostPath actually required?
[ ] Is the mounted directory as narrow as possible?
[ ] Can the mount be read-only?
[ ] Does the container run as non-root?
[ ] Is privilege escalation disabled?
[ ] Are UID/GID permissions correct?
[ ] Is the host directory dedicated to the workload?
[ ] Can another workload access the same directory?
[ ] Does the workload depend on a particular node?
[ ] Are scheduling constraints configured?
[ ] Are Pod Security controls enabled?
[ ] Are admission policies available?
[ ] Have failure and rescheduling scenarios been tested?

Advantages and Disadvantages

Advantages

Disadvantages

Direct access to node-local data

Creates a strong node dependency

Simple for certain infrastructure workloads

Can expose host filesystem data

Useful for specialized workloads

Harder to migrate between nodes

Can be efficient for local storage

Requires careful permission management

Easy to understand initially

Broad mounts can create serious security risks

Best Practices

Prefer the Smallest Possible Mount

Only expose the directory the application actually needs.

Use Read-Only Access When Possible

Read-only mounts reduce the ability of a compromised application to modify node data.

Run as Non-Root

Use a dedicated application UID and GID.

Keep Host Directories Isolated

Do not share sensitive host directories across unrelated workloads.

Use Admission Controls

Prevent dangerous storage configurations before they reach the cluster.

Treat Node Locality as a Design Requirement

If the storage exists on a particular node, make sure scheduling and failure handling account for that dependency.

Prefer Kubernetes Storage Abstractions for Application Data

If the application simply needs persistent storage, evaluate a PersistentVolume rather than exposing the node filesystem directly.

Summary

Bind mounts and hostPath volumes can be useful in Kubernetes, but they create a direct relationship between a workload and the node's filesystem. That relationship makes storage configuration a security concern as well as an operational concern.

The safest approach is to expose the smallest possible directory, use read-only mounts whenever write access is unnecessary, run containers as non-root users, and avoid mounting sensitive node paths.

For ordinary application persistence, PersistentVolumes generally provide a cleaner abstraction than directly exposing host filesystem directories. When node-local storage is required, scheduling, permissions, failure handling, and security policies need to be designed together.

The key rule is simple: if a container does not need access to a host directory, do not mount it. If it does need access, give it the smallest and most restricted mount that satisfies the requirement.