Articles

Hardening Kubernetes v1.37 Container Storage: Bind Mount Options & emptyDir Permissions

Kubernetes v1.37 introduces bind mount options and emptyDir permission modes, letting teams enforce noexec, nosuid, nodev, and sticky‑bit settings directly in pod specs. This outline covers the Linux basics, motivation, activation steps, example manifests, and verification techniques.

Written by:
APin

Senior Technology Analyst • Verified Expert

More from this author
Hardening Kubernetes v1.37 Container Storage: Bind Mount Options & emptyDir Permissions

Kubernetes v1.37 introduces bind mount options and emptyDir permission modes, letting teams enforce noexec, nosuid, nodev, and sticky‑bit settings directly in pod specs. This outline covers the Linux basics, motivation, activation steps, example manifests, and verification techniques.

Linux Foundations: Bind Mount Flags and Sticky Bit

When managing Linux filesystems, Virtual File System (VFS) bind mount flags and directory permission modes serve as foundational controls for securing shared resources. These mechanisms allow administrators to override default behaviors at the kernel level, effectively mitigating risks associated with untrusted binary execution and unauthorized file manipulation within shared storage.

VFS Bind Mount Flags

Bind mount flags restrict operations on a specific filesystem mount point, regardless of the underlying object's permissions. These flags are critical for hardening workloads by enforcing security policies at the boundary of a container or process namespace:

  • noexec: Disallows the direct execution of binaries. Even if a file is marked executable (e.g., via chmod +x), the kernel will deny execution, preventing the runtime of arbitrary malicious payloads.
  • nosuid: Prevents the set-user-identifier (set-uid) and set-group-identifier (set-gid) bits from being honored. This effectively mitigates privilege escalation vectors that rely on executing binaries with elevated permissions.
  • nodev: Prevents the interpretation of character or block special device files. This ensures that a compromised process cannot interact with raw hardware devices via the mounted filesystem.

The Unix Sticky Bit (01777)

While standard permissions (Read, Write, Execute) manage access scope, the sticky bit (mode 01777) provides granular control over file deletion in shared directories. When applied to a directory, the kernel restricts file removal and renaming: only the file owner, the directory owner, or the root user may delete or move a file. This is the standard security configuration for shared scratch spaces like /tmp, as it prevents non-privileged processes from deleting files they do not own, even if the directory itself is globally writable.

By implementing these flags and modes—such as configuring an emptyDir volume with noexec or the 01777 mode—engineers can enforce the principle of least privilege, ensuring that multi-tenant or multi-container pods cannot interfere with one another's data or execute unauthorized binaries within shared writable volumes.

Why Bind Mount Options and emptyDir Modes Matter in Kubernetes

Kubernetes pods have always relied on the container runtime to bind‑mount volumes into the container’s filesystem namespace. Prior to the introduction of the VolumeBindMountOptions and EmptyDirVolumeMode feature gates, those bind mounts were created without the noexec, nosuid, or nodev flags. At the same time, the emptyDir volume type always instantiated its directory with a hard‑coded mode of 0777. Both defaults break the principle of least privilege and conflict with security baselines such as NIST SP 800‑53, ISO 27001 A.12.1, and SOC 2 CC6.1, which require that writable storage be protected against execution of untrusted code and unauthorized file removal.

Audit findings illustrate the practical impact:

  • Issue #48912 documented the “inability to set mount options on emptyDir” as a high‑severity gap.
  • Issue #119627 (Kubernetes 1.24 Security Audit, Finding NCC‑E003660‑7HM) called the missing noexec flag on writable volumes a “security failure”.
  • These reports noted that a compromised container could download a binary to any writable volume, chmod +x it, and execute it even when readOnlyRootFilesystem: true was enforced.

Without the sticky bit (mode 01777) on emptyDir, any process that can discover the shared directory can delete or rename files owned by another container. This enables cross‑container data‑wiping attacks in multi‑container pods such as CI/CD runners or sidecar‑based loggers.

Practical illustration – attempting to run a script on a volume mounted without noexec:

# kubectl exec -it pod -- sh
cd /tmp
echo '#!/bin/sh' > test.sh
chmod +x test.sh
./test.sh   # → sh: ./test.sh: Permission denied (when noexec is set)

And a sticky‑bit enforcement example:

# kubectl exec -it pod -- sh
ls -ld /tmp          # drwxrwxrwt …
su -s /bin/sh -c "touch /tmp/guest_file" guest
su -s /bin/sh -c "rm /tmp/guest_file" nobody   # → Operation not permitted

By applying bindMountOptions: [noexec, nosuid, nodev] and configuring emptyDir: { mode: 01777 }, engineers can align pod storage with established hardening guidelines, prevent arbitrary binary execution, and protect shared scratch space from accidental or malicious deletion—all without resorting to init‑container work‑arounds.

Enabling the Alpha Features in v1.37

Kubernetes v1.37 introduces two Alpha feature gates—VolumeBindMountOptions and EmptyDirVolumeMode—that allow bind‑mount flags (e.g., noexec, nosuid, nodev) and explicit permission bits (including the sticky bit) on emptyDir volumes. Because they are Alpha, the gates must be enabled on both the API server and the kubelet before any pod can reference the new fields.

  • API server: start the server with --feature-gates=VolumeBindMountOptions=true,EmptyDirVolumeMode=true. The flag is evaluated at admission time, so the API server will reject manifests that contain bindMountOptions or mode when the gates are off.
  • Kubelet: use the same --feature-gates flag on each node. The kubelet validates the pod spec after it is scheduled and will refuse to start a pod that requests the Alpha fields on a node where the gates are disabled.

Enabling the gates alone is insufficient; the underlying container runtime must also support the CRI mount_options field. Runtimes advertise this capability via the runtimeFeatures API. If the runtime does not list MountOptions, the kubelet will reject the pod with a clear error, and the scheduler will avoid placing the pod on such nodes because the node’s feature set is reported in the NodeStatus object.

Practical steps for a cluster administrator:

  1. Verify runtime support:
    kubectl get node -o jsonpath='{.status.nodeInfo.runtimeVersion}'
    and consult the runtime’s documentation for CRI mount_options support.
  2. Update the API server manifest (or static pod) to include the feature‑gate flag.
  3. Restart the API server, then update each kubelet configuration with the same flag and restart the kubelet.
  4. Confirm the node reports the feature:
    kubectl get node <node-name> -o yaml | grep -i mount_options

Example pod manifest using both features:

apiVersion: v1
kind: Pod
metadata:
  name: hardened-pod
spec:
  containers:
  - name: app
    image: alpine:latest
    command: ["sleep","3600"]
    securityContext:
      readOnlyRootFilesystem: true
    volumeMounts:
    - name: work
      mountPath: /tmp
      bindMountOptions:
      - noexec
      - nosuid
  volumes:
  - name: work
    emptyDir:
      mode: 01777

When the cluster meets the gate and runtime requirements, the kubelet enforces noexec/nosuid at the bind‑mount level and applies the sticky‑bit mode to the emptyDir, providing native compliance with hardening benchmarks such as CIS Kubernetes and NIST SP 800‑190.

Practical Manifest Examples: Noexec/Nosuid and Sticky Bit

Kubernetes v1.37 introduces bindMountOptions and an emptyDir.mode field that let platform engineers enforce Linux‑level hardening directly in a pod manifest. The options map to VFS mount flags (noexec, nosuid, nodev) while the mode value follows standard Unix permission notation, where 01777 adds the sticky bit (t) to a writable directory. Both features are gated behind VolumeBindMountOptions and EmptyDirVolumeMode and require the container runtime to expose the CRI mount_options capability.

Example 1 – Bind mount options on an emptyDir

apiVersion: v1
kind: Pod
metadata:
  name: hardened-bindmount-pod
  namespace: default
spec:
  os:
    name: linux
  containers:
  - name: hardened-app
    image: alpine:latest
    command: ["sleep","3600"]
    securityContext:
      readOnlyRootFilesystem: true
    volumeMounts:
    - name: temp-storage
      mountPath: /tmp
      bindMountOptions:
      - noexec
      - nosuid
  volumes:
  - name: temp-storage
    emptyDir: {}
  • readOnlyRootFilesystem: keeps the container image immutable; the writable /tmp is the only mutable location.
  • bindMountOptions: applies the MS_NOEXEC and MS_NOSUID flags to the bind mount, preventing execution of binaries and ignoring set‑uid/set‑gid bits.
  • emptyDir: {}: creates a node‑local directory with the default 0777 permissions; the mount flags provide the security hardening.

Example 2 – Sticky‑bit emptyDir mode

apiVersion: v1
kind: Pod
metadata:
  name: hardened-emptydir-pod
  namespace: default
spec:
  os:
    name: linux
  containers:
  - name: app-container
    image: alpine:latest
    command: ["sleep","3600"]
    volumeMounts:
    - name: shared-tmp
      mountPath: /tmp
  volumes:
  - name: shared-tmp
    emptyDir:
      mode: 01777
  • mode: 01777: sets the directory permissions to rwxrwxrwt, enabling the sticky bit so only a file’s owner (or root) may delete or rename it.
  • volumeMounts.mountPath: exposes the hardened directory at /tmp for all containers in the pod.
  • emptyDir: works with any medium (disk, memory, HugePages) and now respects the explicit mode without requiring an init container.

After deployment, kubectl exec into each pod to verify the enforcement: attempts to run a script in the first pod are blocked with “Permission denied”, and ls -ld /tmp in the second pod shows the trailing t indicating the sticky bit is active.

Verification and Real‑World Use Cases

Before testing enforcement, understand the underlying Linux mechanisms. A bind mount can be created with the noexec flag, which sets the MS_NOEXEC attribute on the mount point, preventing the kernel from executing any file located on that filesystem. The sticky bit (mode 01777) on a directory restricts deletion or renaming of files to the file’s owner or to root, a behavior commonly relied upon for shared /tmp spaces.

To verify that a pod respects noexec, use kubectl exec to create an executable script on a volume that was declared with bindMountOptions: [noexec, nosuid]. The expected outcome is a “Permission denied” error from the shell, confirming that the kernel rejected execution at the mount level.

# Exec into the pod
kubectl exec -it hardened-bindmount-pod -- sh

# Create a script on /tmp
cd /tmp
printf '#!/bin/sh\n echo "Running untrusted code"\n' > test.sh
chmod +x test.sh

# Attempt execution
./test.sh
# → sh: ./test.sh: Permission denied

To confirm sticky‑bit enforcement, inspect the directory mode and attempt cross‑user deletion. The directory should display the trailing t (e.g., drwxrwxrwt), and a user other than the file’s owner must receive an “Operation not permitted” error when trying to remove the file.

# Exec into the pod
kubectl exec -it hardened-emptydir-pod -- sh

# Verify mode
ls -ld /tmp
# → drwxrwxrwt 2 root root ...

# Create a file as user "guest"
su -s /bin/sh -c "touch /tmp/guest_file" guest

# Attempt removal as user "nobody"
su -s /bin/sh -c "rm /tmp/guest_file" nobody
# → rm: can't remove '/tmp/guest_file': Operation not permitted

Common enterprise scenarios that benefit from these controls include:

  • Securing temporary workspaces: Mount emptyDir with noexec and nosuid to prevent a compromised process from executing payloads downloaded to a writable directory.
  • Multi‑container CI/CD pods: Apply mode: 01777 to an emptyDir shared between a builder and a logger. Each container can write its artifacts, but the sticky bit stops one container from deleting another’s files, preserving build integrity.
  • Database temporary storage: Use mode: 0750 on an emptyDir that holds a database’s temp files. Only the database user and its group can read/write, enforcing the principle of least privilege for side‑car containers such as monitoring agents.

When deploying these features, remember they are gated behind the VolumeBindMountOptions and EmptyDirVolumeMode alpha flags. Enable the flags on the API server and kubelet, verify runtime support for the CRI mount_options field, and test with kubectl exec as shown to ensure compliance with standards such as SOC 2, ISO 27001, or NIST 800‑53, which require demonstrable control over executable media and file‑system permissions.

Editorial Policy & Research Methodology

Our findings are based on rigorous internal research, verified industry benchmarks, and direct technical implementation experience from our enterprise client projects. All statistics and technical claims are reviewed by senior engineers before publication to ensure accuracy, transparency, and helpfulness for our readers.

Have an Idea?

Let's Build Something Amazing Together.