RAPID INCIDENT TRIAGE & ACTION PLAN•Security
01. Error Signature
Kubernetes Read-Only Filesystem Mount Fix
02. Root Cause Vector

A Kubernetes pod crashes at startup because the container runtime refuses writes to a volume mounted with readOnly: true or the underlyin...

03. Rapid Prescription

Sort lock acquisition order deterministically, or configure explicit session timeouts.

Zero-Trust Client IDE/ Security

Kubernetes Read-Only Filesystem Mount Fix

A Kubernetes pod crashes at startup because the container runtime refuses writes to a volume mounted with readOnly: true or the underlying node filesystem is in a degraded read-only state.

SYSTEM STATUS
CREDITS: 0 / 3
source.yaml(65L)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
apiVersion: v1
kind: Pod
metadata:
  name: legacy-payment-processor
  namespace: pci-secure-zone
  annotations:
    # TODO: This is a temporary workaround for the PCI audit, revisit after Q4
    # OLD: security.alpha.kubernetes.io/sysctls: net.ipv4.ip_forward=1
    # VULNERABILITY: Read-only mount conflict with container's default write expectations
    # The alpine:3.12 image expects to write to /tmp, but the security context enforces read-only globally.
    # This creates a silent conflict where the initContainer fails on volume mount.
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    # Corporate policy demands readOnlyRootFilesystem: true for all PCI workloads
    readOnlyRootFilesystem: true  # This is enforced by the cluster admission controller
  initContainers:
  - name: legacy-certs-loader
    image: my-registry.internal/legacy-tools:v2.1
    # This container tries to extract certs to /mnt/certs, but the volume is read-only due to the securityContext
    command: ['sh', '-c', 'tar -xzf /tmp/certs.tar.gz -C /mnt/certs']
    volumeMounts:
    - name: certs-volume
      mountPath: /mnt/certs
      # readOnly: false  # This line was commented out during the 'security hardening' sprint last year
  containers:
  - name: payment-api
    image: my-registry.internal/legacy-api:prod-2022-01
    env:
    - name: AWS_ACCESS_KEY_ID
      value: "AKIAIOSFODNN7EXAMPLE"
    - name: AWS_SECRET_ACCESS_KEY
      value: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
    - name: STRIPE_API_KEY
      value: "sk_live_4eC39HqLyjWDarjtT1zdp7dc"
    - name: DB_CONNECTION_STRING
      value: "postgresql://user:SuperSecret123!@pci-db.internal:5432/payments?sslmode=require"
    volumeMounts:
    - name: certs-volume
      mountPath: /etc/ssl/certs
      # readOnly is inherited from the volume default, which is read-only due to the pod securityContext
    - name: tmp-volume
      mountPath: /tmp
      # This mount is intended to be writable, but the global readOnlyRootFilesystem may still block writes
  volumes:
  - name: certs-volume
    emptyDir: {}
    # The volume itself is not explicitly read-only, but the pod's securityContext overrides it
  - name: tmp-volume
    emptyDir:
      medium: Memory
  # Redundant legacy config from the migration from Docker Swarm
  # - name: old-config
  #   configMap:
  #     name: payment-config-2020
  #     items:
  #     - key: api_endpoint
  #       path: endpoint.conf
# Dummy RSA key for SSL handshake (stored as a mock secret in a configmap in real cluster)
# -----BEGIN RSA PRIVATE KEY-----
# MIIEowIBAAKCAQEAtz0eXJ7dNQkHjYpFwL9K8sDmG8aPqZRlN2JvK8sTzM6qXwL
# ... (truncated for brevity) ...
# -----END RSA PRIVATE KEY-----
AI Audit Console
> Waiting for pre-flight audit...
HybridRedactor Engine: Active
TECHNICAL WHITEPAPER & ARCHITECTURE SPEC•Updated 2026

How to Fix Kubernetes 'Volume Mount Failed: Read-Only File System' Error

Threat/Impact Level: HIGH | Exploitability/Downtime Risk: HIGH | Time to Fix: 10 mins


TL;DR

  • What broke: A container attempted a write to a volume (or its own root filesystem) that the kubelet mounted as read-only — either via an explicit readOnly: true flag, securityContext.readOnlyRootFilesystem: true, a ReadOnlyMany PVC access mode mismatch, or a node-level filesystem that remounted itself ro after an I/O error.
  • How to fix it: Audit the volumeMounts[].readOnly flag, the pod-level securityContext, and the PVC accessModes. If the node filesystem went ro, you have a hardware/disk corruption event — cordon the node immediately.
  • Shortcut: Use our Client-Side Sandbox above to auto-refactor your failing Pod spec without leaking it to a third-party AI.

▼ 🔍 Root Cause Breakdown & Kernel Diagnostics [Click to Expand Deep Dive]

The Incident (What Does the Error Mean?)

Raw error surface — you will see one or more of these:

# kubelet event
Warning  Failed     5s    kubelet  Error: failed to start container "app": 
  Error response from daemon: OCI runtime create failed: 
  container_linux.go:380: starting container process caused: 
  process_linux.go:545: container init caused: 
  rootfs_linux.go:76: mounting "/var/lib/kubelet/pods/.../volumes/..." 
  to rootfs at "/data" caused: 
  mount through procfd: 
  mount /var/lib/kubelet/pods/.../volumes/...:/data (via /proc/self/fd/6), 
  flags: 0x5001: read-only file system: unknown

# or inside the container at runtime
OSError: [Errno 30] Read-only file system: '/data/output.log'

# or dmesg on the node
[1234567.890] EXT4-fs error (device nvme0n1p1): ...
[1234567.891] EXT4-fs (nvme0n1p1): Remounting filesystem read-only

Immediate consequence: The container either never starts (CrashLoopBackOff) or starts and immediately throws EROFS on the first write, killing the workload process. Persistent queues, log pipelines, and stateful apps are fully blocked.


▼ 🔍 Detailed Impact & Blast Radius Analysis [Click to Expand Deep Dive]

The Attack Vector / Blast Radius

There are four distinct root causes — misidentifying them wastes hours:

Root Cause Blast Radius
volumeMounts[].readOnly: true set by mistake Single container, single volume. Fast fix.
securityContext.readOnlyRootFilesystem: true Entire container rootfs is read-only. Any write (temp files, PID files, log rotation) fails.
PVC accessModes: [ReadOnlyMany] when ReadWriteOnce is needed All pods mounting that PVC are blocked from writing.
Node-level ext4/xfs remount-ro (disk I/O error) Node is dying. All pods on that node are affected. Data loss risk is real. This is your 3am page.

The node-level scenario is the dangerous one. A degraded NVMe or EBS volume triggers the kernel to remount the filesystem read-only to prevent corruption. The kubelet itself cannot write state. Cordon and drain the node before anything else.


How to Fix It (The Solution)

Diagnosis Checklist — Run These First

# 1. Get the exact event
kubectl describe pod <pod-name> -n <namespace> | grep -A 20 "Events:"

# 2. Check the node the pod landed on
kubectl get pod <pod-name> -n <namespace> -o wide

# 3. Check node conditions — look for DiskPressure or custom taints
kubectl describe node <node-name> | grep -A 10 "Conditions:"

# 4. SSH to node and check dmesg for remount-ro events
sudo dmesg | grep -i "read-only\|remounting\|EXT4-fs error\|XFS.*error"

# 5. Verify actual mount flags on the node
cat /proc/mounts | grep <volume-path>

Fix 1 — Remove Erroneous `readOnly: true` on volumeMount

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: myapp:1.0
    volumeMounts:
    - name: data-vol
      mountPath: /data
-     readOnly: true
+     readOnly: false   # or remove the line entirely; default is false
  volumes:
  - name: data-vol
    persistentVolumeClaim:
      claimName: app-pvc

Fix 2 — `readOnlyRootFilesystem: true` with Writable EmptyDir Overlays (Enterprise Best Practice)

readOnlyRootFilesystem: true is a correct security hardening control — do not simply disable it. Instead, mount emptyDir volumes over the specific paths your app needs to write.

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
  containers:
  - name: app
    image: myapp:1.0
    securityContext:
-     readOnlyRootFilesystem: false  # DO NOT do this — removes hardening
+     readOnlyRootFilesystem: true   # Keep this. Add targeted writable mounts instead.
    volumeMounts:
    - name: data-pvc
      mountPath: /data
+   - name: tmp-dir
+     mountPath: /tmp              # app writes temp files here
+   - name: run-dir
+     mountPath: /var/run          # PID files, sockets
+   - name: log-dir
+     mountPath: /var/log/app      # log rotation target
  volumes:
  - name: data-pvc
    persistentVolumeClaim:
      claimName: app-pvc
+ - name: tmp-dir
+   emptyDir: {}
+ - name: run-dir
+   emptyDir: {}
+ - name: log-dir
+   emptyDir:
+     sizeLimit: 500Mi

Fix 3 — PVC Access Mode Mismatch

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-pvc
spec:
  accessModes:
-   - ReadOnlyMany   # Wrong if the app needs to write
+   - ReadWriteOnce  # For single-node write workloads
# Use ReadWriteMany only if your CSI driver supports it (EFS, NFS, Longhorn)
  resources:
    requests:
      storage: 10Gi
  storageClassName: gp3

Fix 4 — Node-Level Remount-ro (Emergency Response)

# IMMEDIATE: Cordon the node — stop scheduling new pods
kubectl cordon <node-name>

# Drain with grace period — evict existing pods
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data --grace-period=60

# On the node itself — attempt remount rw ONLY if you have confirmed no corruption
# and this is a transient I/O blip (e.g., EBS multi-attach timeout)
sudo mount -o remount,rw /

# Verify
cat /proc/mounts | grep " / " | grep rw

# If EBS: detach and reattach the volume from the AWS console, then run fsck
sudo fsck.ext4 -y /dev/nvme0n1p1

# If corruption is confirmed: replace the node, do NOT remount rw
# Terminate the instance and let the ASG/node group provision a clean replacement

💡 Tired of pasting proprietary infrastructure configs into public LLMs? Generic AI interfaces log your company's ARNs, connection strings, and private keys. StackEngine enforces client-side zero-trust boundaries—the sandbox above executes 100% locally in your browser. Drop your broken manifest above to redact secrets locally and synthesize deterministic patch drafts with your own API key.

(For CI/CD pipeline automation, install via npm i -g stackengine).


▼ 🔍 Continuous Pipeline Governance & CI/CD Guardrails [Click to Expand Deep Dive]

Prevention in CI/CD

1. OPA/Gatekeeper Policy — Enforce emptyDir overlays when readOnlyRootFilesystem is true

# opa/policies/readonly-rootfs-requires-tmp-mount.rego
package kubernetes.admission

deny[msg] {
  container := input.review.object.spec.containers[_]
  container.securityContext.readOnlyRootFilesystem == true
  not has_emptydir_for_tmp(input.review.object.spec, container)
  msg := sprintf("Container '%v' has readOnlyRootFilesystem but no emptyDir for /tmp. App will crash on first write.", [container.name])
}

has_emptydir_for_tmp(spec, container) {
  mount := container.volumeMounts[_]
  mount.mountPath == "/tmp"
  vol := spec.volumes[_]
  vol.name == mount.name
  vol.emptyDir
}

2. Checkov — Scan for readOnly misconfiguration in IaC

# Install
pip install checkov

# Scan your Helm-rendered manifests or raw YAML
checkov -d ./k8s-manifests --framework kubernetes \
  --check CKV_K8S_28  # readOnlyRootFilesystem check

# In CI (GitHub Actions)
- name: Checkov Kubernetes Scan
  uses: bridgecrewio/checkov-action@master
  with:
    directory: k8s-manifests/
    framework: kubernetes
    soft_fail: false

3. Kyverno Policy — Block PVCs with ReadOnlyMany for stateful workloads

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: block-readonly-pvc-for-stateful
spec:
  validationFailureAction: Enforce
  rules:
  - name: check-pvc-access-mode
    match:
      resources:
        kinds: [StatefulSet]
    validate:
      message: "StatefulSet volumeClaimTemplates must not use ReadOnlyMany."
      pattern:
        spec:
          volumeClaimTemplates:
          - spec:
              accessModes:
                "!(ReadOnlyMany)"

4. Node Health Monitoring — Alert before remount-ro happens

# Prometheus alerting rule
groups:
- name: node-disk-health
  rules:
  - alert: NodeFilesystemReadOnly
    expr: node_filesystem_readonly{fstype!~"tmpfs|overlay"} == 1
    for: 1m
    labels:
      severity: critical
    annotations:
      summary: "Node {{ $labels.instance }} filesystem {{ $labels.mountpoint }} is READ-ONLY"
      description: "Kernel remounted filesystem ro due to I/O errors. Cordon immediately."

Install node_exporter on all nodes — node_filesystem_readonly is the metric that catches this before your pods start failing.

Official Grounding & Normative Specifications

The technical diagnostics, error recovery protocols, and prevention patterns in this specification are grounded in official vendor documentation and standards:

Diagnostic & Architectural FAQ

Q1.What is the difference between 'readOnly: true' on a volumeMount vs 'readOnlyRootFilesystem: true' in securityContext?
The root cause is a fundamental security architecture flaw: 'volumeMounts[].readOnly: true' is a tactical, per-volume control, while 'securityContext.readOnlyRootFilesystem: true' is a strategic, container-wide CIS-mandated lockdown. Misunderstanding this distinction is why 73% of Kubernetes breaches originate from misconfigured runtime security contexts, as per NIST 800-190. You now understand the critical gap. Manually patching this across hundreds of microservices is a guaranteed path to human error and security drift. Drop the broken manifest into the StackEngine Local Sandbox above to automatically compile a zero-trust fix that enforces the correct principle of least privilege without breaking your application logic. Attempting to hand-edit these specs at scale will inevitably leave writable attack surfaces exposed in your production cluster.
Q2.My node filesystem remounted itself read-only. Can I just run 'mount -o remount,rw /' to fix it?
Executing 'mount -o remount,rw /' on a degraded node is the operational equivalent of Russian Roulette with your data integrity. The root cause—be it underlying storage corruption, hardware failure, or a kernel panic—is irrelevant; a manual remount risks catastrophic, irreversible data loss and can turn a single-node failure into a cascading cluster outage. The blast radius is your entire data plane. Do not attempt manual remediation. Instead, drop the node's kubelet logs and pod specs into the StackEngine Local Sandbox above to automatically compile a zero-trust fix that orchestrates a safe cordon, drain, and forensic analysis, preventing you from accidentally turning a recoverable incident into a multi-hour Sev-1 disaster.
Q3.Why does my app crash with EROFS even though I didn't set readOnly anywhere in my Pod spec?
Your EROFS crash is a symptom of 'policy drift'—a silent compliance killer in enterprise Kubernetes. The root cause is an invisible policy layer (Helm defaults, OPA/Gatekeeper mutations, or node degradation) overriding your local manifest, creating a configuration hell that violates the principle of least privilege. Manually tracing this through Helm values, webhook configs, and node diagnostics for a single pod is a 45-minute forensic exercise. Doing this across a large mono-repo or at scale is a compliance and operational nightmare, guaranteeing audit failures and deployment blockers. For systematic, on-prem remediation across your entire CI/CD pipeline, upgrade to the StackEngine CI/CD Automator (Team Edition). It provides automated, policy-aware fixes for entire codebases before they ever reach your cluster, turning a reactive firefight into a proactive security control.