🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

Kubernetes 1.37 Volume Security: noexec, nosuid, nodev, and emptyDir Modes

Understand the new Kubernetes 1.37 alpha controls for bind mount options and emptyDir permissions, with manifests and a cautious rollout plan.

DevOpsBoys4 min read
Share:Tweet

A read-only container root filesystem does not make every writable path safe. If a Pod mounts an emptyDir or persistent volume without noexec, a compromised process may still download a binary, mark it executable, and run it from that volume.

Kubernetes 1.37 introduces two alpha features that close long-standing gaps: security options on container bind mounts and explicit permission modes for emptyDir directories.

The Two Features Solve Different Problems

VolumeBindMountOptions lets a workload request Linux bind-mount protections on an individual volumeMount:

  • noexec blocks direct execution of binaries from the mount.
  • nosuid prevents set-user-ID and set-group-ID bits from taking effect.
  • nodev prevents files on the mount from being interpreted as device nodes.

EmptyDirVolumeMode controls the Unix mode used when Kubernetes creates an emptyDir. This can replace init containers that run chmod and can add the sticky bit to shared temporary directories.

Both features are alpha in Kubernetes 1.37. They require feature gates on the API server and kubelet and should not be enabled cluster-wide without compatibility testing.

Harden a Writable Temporary Directory

With VolumeBindMountOptions enabled, a Pod can request:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: hardened-app
spec:
  os:
    name: linux
  containers:
    - name: app
      image: alpine:3.22
      command: ["sleep", "3600"]
      securityContext:
        readOnlyRootFilesystem: true
      volumeMounts:
        - name: temp
          mountPath: /tmp
          bindMountOptions:
            - noexec
            - nosuid
            - nodev
  volumes:
    - name: temp
      emptyDir: {}

This creates a read-only root filesystem while retaining writable scratch space with tighter execution and privilege behavior.

noexec is defense in depth, not a sandbox. Interpreters may still read a script from the volume when invoked explicitly, and an attacker with another execution path can remain dangerous. Keep seccomp, AppArmor or SELinux, capabilities, identity, network policy, and least-privilege configuration in place.

Set emptyDir Permissions Directly

A shared /tmp commonly uses mode 01777. The leading 1 sets the sticky bit, allowing users to create files while preventing them from deleting files owned by other users.

With EmptyDirVolumeMode enabled:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: shared-scratch
spec:
  containers:
    - name: builder
      image: alpine:3.22
      command: ["sleep", "3600"]
      volumeMounts:
        - name: scratch
          mountPath: /workspace
    - name: observer
      image: alpine:3.22
      command: ["sleep", "3600"]
      volumeMounts:
        - name: scratch
          mountPath: /workspace
  volumes:
    - name: scratch
      emptyDir:
        mode: 01777

For private application scratch space, a narrower mode such as 0750 may be appropriate when container users and groups are designed accordingly.

Test the Runtime Behavior

After deploying a test Pod, inspect the mount flags and permissions rather than trusting admission alone:

bash
kubectl exec hardened-app -- findmnt -T /tmp -o TARGET,OPTIONS
kubectl exec shared-scratch -c builder -- stat -c '%a %A %n' /workspace

Attempt a controlled execution test from the noexec mount and verify that the kernel rejects direct execution. Also test the application's real package managers, temporary-file libraries, build tools, and sidecars. Some workloads legitimately execute generated files from writable storage and will break under noexec.

Roll Out Without Breaking Workloads

Use a dedicated non-production cluster or node pool because alpha feature gates affect API acceptance and node behavior. Confirm that every relevant control-plane component and kubelet uses compatible configuration.

Then:

  1. Inventory writable mounts and classify why each needs write access.
  2. Start with services that only store caches, uploads, or temporary data.
  3. Add mount options to a small workload cohort.
  4. Observe permission errors, startup failures, and unusual exec attempts.
  5. Create policy templates after real workload validation.
  6. Define how manifests will be reverted if the feature changes before beta.

Avoid automatically adding noexec to every mount through mutation. Build systems, plugin frameworks, language toolchains, and installers may execute files from temporary storage.

Policy and Compliance

Admission policy can require noexec, nosuid, or nodev for selected workload classes after adoption. Keep exceptions explicit and owned. For example, CI builder workloads may need execution from a workspace while API services do not.

The new fields make intent visible in the Pod specification, which is easier to review than an init container running an arbitrary chmod command. They also make compliance evidence more direct, but evidence still needs runtime verification.

Bottom Line

Kubernetes 1.37 finally gives workloads native controls for bind-mount security and emptyDir creation modes. The features solve genuine gaps, especially for read-only-root deployments and shared scratch space.

Because both are alpha, adopt them as an experiment with explicit compatibility and rollback criteria—not as a default silently injected into every Pod.

Sources

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments