A Pod can start successfully with spec.hostUsers: false and still be a bad production candidate. The kernel may support user namespaces while one mounted filesystem does not. A stateless container can prove UID remapping while a persistent volume fails on first write. Admission can accept the Pod while its service account still has excessive Kubernetes API rights. A dashboard can stay green while nobody has captured the host-side mapping that the security review actually asked for.
That is the operating problem this playbook addresses. Kubernetes user namespaces became stable in Kubernetes v1.36, but stable feature state is not the same as workload compatibility. The version-pinned Kubernetes: User Namespaces, v1.36 snapshot (accessed September 15, 2026) marks the feature stable and still makes use an individual Pod decision through spec.hostUsers: false; the Kubernetes: User Namespaces, living concepts page (accessed September 15, 2026) says the same at the research cutoff.
The goal is therefore not “enable user namespaces everywhere.” It is to produce three artifacts per workload: mapping proof, storage compatibility evidence, and a residual-permission assessment. Everything that follows is a proposed operating model unless Kubernetes or Linux behavior is explicitly attributed to a source. The examples are synthetic and were not executed against a real cluster.
Define the isolation claim and freeze the evidence before changing manifests
Start by naming the exact claim. For this rollout, the claim is narrow: when a Linux Pod opts into a user namespace, a process that appears as UID 0 inside that Pod is mapped to an unprivileged host identity, and the workload continues to meet its required storage and application behaviors. Kubernetes documents that root inside the container can map to a different, non-root user on the host and that capabilities granted within the Pod's user namespace are void outside that namespace.
That claim does not say the service account is least-privileged, network traffic is constrained, secrets are safe, or the workload has no dangerous Linux capabilities inside its namespace. Those are separate controls. This article deliberately stays narrower than Refonte Learning's broader Kubernetes production-hardening foundations, which cover cluster, network, identity, supply-chain and operational hardening as a whole.
Control question | What hostUsers: false can change | Evidence required here | Separate owner/review |
Host UID/GID identity | Yes; Pod-visible IDs can be remapped to host IDs | Inside-Pod map plus authorized host observation | Platform / node owner |
Filesystem ownership view | Yes, through idmapped mounts | Read, write, ownership and recreation tests on every mounted filesystem | Storage + workload owner |
Kubernetes API authorization | No | Service-account authorization checks | Security / IAM owner |
Network reachability | No | Existing network-policy evidence remains applicable | Network / security owner |
Secret exposure | No direct reduction | Token/secret mount and RBAC review | Workload + security owner |
Linux capabilities | User-namespace scoping changes their host effect, but does not replace capability minimization | Existing capability set and Pod Security decision | Security reviewer |
Before editing a manifest, freeze the candidate environment. A control-plane version alone is insufficient because user-namespace success depends on the worker kernel, Container Runtime Interface (CRI) implementation, Open Container Initiative (OCI) runtime, kubelet filesystem, volume filesystems and storage path. The official prerequisites explicitly span those layers.
Use a version-controlled evidence record. The following fields are a proposed local inventory, not a Kubernetes API object:
Evidence item | Record | Owner | Acceptance state |
Workload revision | Git commit, image digest, controller kind | Workload owner | Known |
Kubernetes nodes | Minor/patch, node image build | Platform | Known |
Kernel | uname -r plus distribution build reference | Linux/node owner | Known |
CRI runtime | Product and exact version | Platform | Known |
OCI runtime | runc, crun or other supported runtime and version | Platform | Known |
Kubelet Pod filesystem | Mount source, filesystem type for /var/lib/kubelet/pods or custom path | Node owner | Tested |
Each volume | CSI driver or source, filesystem type, access mode, mount purpose | Storage owner | Tested / blocked |
Admission | Pod Security mode/version and other validating controls | Security/platform | Unchanged |
Service account | Name and intended API verbs/resources | Workload/security | Reviewed |
Rollback artifact | Known-good manifest commit/tag | Workload owner | Ready |
Treat “unknown” as a failed gate, not an invitation to infer. Managed Kubernetes products can abstract the node image, runtime configuration or storage implementation. Unless the provider documents the exact combination or you can probe the actual node pool, record support as unverified. Keep the same discipline used for infrastructure ownership and code review: the artifact that changes behavior should have an accountable owner, a diff, an acceptance record and a rollback reference.
The baseline matters as much as the candidate. Capture the unchanged workload's scheduling, startup, health checks, file ownership view, read/write behavior, restart behavior and service indicators before adding hostUsers: false. Without that baseline, a later permission failure becomes an argument about whether the application was already broken.
Local stop rule: do not start rollout if the node/runtime inventory is incomplete, if any required volume path is unclassified, or if the known-good manifest cannot be restored from version control.
Establish kernel, runtime and filesystem eligibility on the candidate node pool
Use an isolated staging node pool first. The version-pinned v1.36 documentation requires Linux support for idmapped mounts on the filesystem containing the kubelet Pod directory and on all filesystems used by Pod volumes. It calls Linux 6.3 the practical minimum because tmpfs gained idmapped-mount support there, which matters because Kubernetes commonly uses tmpfs for items such as mounted service-account tokens and Secrets. The same page lists btrfs, ext4, XFS, FAT, tmpfs and overlayfs among popular filesystems supporting idmapped mounts with Linux 6.3.
For runtimes, that v1.36 snapshot lists runc 1.2+ and crun 1.9+ as OCI runtimes with support, recommending crun 1.13+; for CRI runtimes it lists containerd 2.0+ and CRI-O 1.25+. These are documented baselines, not a certification that any vendor's packaging, kernel backports, snapshotter, CSI stack or node image works together.
The Linux kernel's own Linux kernel: Idmappings documentation (living documentation; accessed September 16, 2026) explains why idmapped mounts matter operationally: they let the same filesystem objects be exposed through a mount with translated ownership, with the translation localized to that mount rather than permanently rewriting on-disk ownership. The kernel documentation specifically contrasts this with recursive chown, whose ownership changes are global and permanent.
Eligibility check | Documented minimum / constraint | Local proof | Gate |
Operating system | Linux-only feature | Node OS inventory | Must pass |
Kernel | Practical minimum Linux 6.3 in Kubernetes docs | Exact candidate-node kernel plus probe Pod | Must pass |
CRI runtime | containerd 2.0+ or CRI-O 1.25+ in v1.36 docs | Runtime version from target node | Must pass |
OCI runtime | runc 1.2+ or crun 1.9+ listed | Runtime version and configured handler | Must pass |
Kubelet Pod path | Filesystem must support idmapped mounts | Filesystem identification plus successful probe | Must pass |
Every mounted volume | Filesystem must support idmapped mounts | Workload-specific mount test | Must pass |
Host namespaces | hostNetwork, hostPID, hostIPC cannot be true with hostUsers: false | Manifest scan | Must be absent/false |
Raw block devices | volumeDevices are disallowed for user-namespace Pods | Manifest scan | Must be absent |
Kubernetes also documents an explicit storage limitation at the cutoff: NFS volumes cannot be mounted in a user-namespace Pod because the Linux NFS client does not support idmapped mounts. The same limitation section disallows raw block volumeDevices, and forbids combining hostUsers: false with hostNetwork: true, hostPID: true or hostIPC: true.
That NFS statement is useful for a failure fixture because it gives you a known-incompatible path without damaging production data. It should not be generalized into “network storage never works.” The decision is about the actual filesystem and mount path presented to the Pod. Likewise, a successful emptyDir or stateless probe is not evidence that a CSI-provisioned persistent volume works.
The living Kubernetes page at the cutoff was last modified September 9, 2026 and still says the feature is stable since v1.36, while the version-pinned v1.36 page is explicitly a static, no-longer-maintained snapshot. Use the pinned page to define the chosen baseline and the living page to detect later documentation changes; do not silently merge behavior from different versions.
A practical eligibility sequence is:
Inventory the node pool. Record kernel, CRI, OCI runtime, kubelet Pod-path filesystem and node image build.
Inventory every mount. Include persistent volumes, emptyDir, Secrets, ConfigMaps, projected volumes and any application-specific mounts. Do not inspect only the PVC that appears “important.”
Reject manifest-level incompatibilities early. Host PID/network/IPC sharing and raw block devices should fail the candidate gate before runtime testing.
Run a probe on the exact node image. A documented minimum is necessary evidence; the probe is what tests the assembled system.
Keep storage qualification per class and per workload. A driver upgrade, filesystem change or new mount should invalidate the relevant compatibility record until retested.
Local stop rule: block the workload when a required filesystem cannot be shown to support the needed idmapped mount, when the Pod requires a prohibited host namespace or raw block device, or when the platform team cannot reproduce the node/runtime combination in a controlled test pool. Do not upgrade production nodes merely to satisfy this article's example baseline; treat a node upgrade as its own infrastructure change with its own rollback plan.
Review hostUsers: false through admission, then prove the mapping on both sides
The manifest change should be intentionally boring. hostUsers: false opts an individual Pod into a user namespace; it is not a cluster-wide declaration that every Pod is isolated this way. The kubelet selects host UID/GID mappings and guarantees that two Pods on the same node do not use the same mapping. Kubernetes also states that fields such as runAsUser, runAsGroup and fsGroup refer to identities inside the container.
For the v1.36 baseline, Kubernetes documents a default in-Pod UID/GID range of 0–65535. By default, kubelet assigns Pod host IDs above that range; a node operator can instead configure a subordinate UID/GID range for the kubelet account. Since Kubernetes v1.33, KubeletConfiguration.userNamespaces.idsPerPod can change the number of IDs assigned per Pod, with 65,536 as the documented default. Capture that node configuration if it is customized. These facts explain allocation mechanics; they still do not justify predicting the numeric host range a recreated workload will receive.
A minimal candidate diff should preserve the workload's existing security context, image digest, service account, volumes and policy labels. This synthetic example is not executed and uses placeholders deliberately:
apiVersion: v1
kind: Pod
metadata:
name: worker-userns-candidate
namespace: <DISPOSABLE_TEST_NAMESPACE>
spec:
hostUsers: false
serviceAccountName: <EXISTING_SERVICE_ACCOUNT>
securityContext:
seccompProfile:
type: RuntimeDefault
containers:
- name: worker
image: <REGISTRY>/<IMAGE>@sha256:<PINNED_DIGEST>
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
command: ["<EXISTING_COMMAND>"]
args: ["<EXISTING_ARGS>"]Do not add privileged mode, host namespaces, a broad capability set, a new service account binding or an unrestricted volume simply to force this candidate to start. If admission rejects the Pod, the rejection is evidence about the policy boundary. Changing policy to make the test green destroys that evidence.
User namespaces interact with Pod Security Standards (PSS) in a version-dependent way. Kubernetes documents that, for Linux Pods using user namespaces, checks on runAsNonRoot and runAsUser are relaxed even under Baseline or Restricted because root in the Pod is not mapped to a privileged host user. Baseline also relaxes certain procMount validation, while Restricted still requires the default or empty ProcMount. Other Restricted controls remain separate, including allowPrivilegeEscalation: false, seccomp requirements and dropping ALL capabilities except the permitted NET_BIND_SERVICE add-back.
Diff item | Expected effect | Approver | Rollback artifact |
spec.hostUsers: false | Create Pod in a user namespace | Platform + security | Baseline Git commit |
Security context | No broadening from baseline | Security | Same baseline commit |
Service account | No change | Workload/security | Existing RBAC manifests |
Volumes | No production path added | Storage/workload | Test fixture manifest |
Node selection | Candidate isolated to staging pool | Platform | Baseline scheduling manifest |
Next, prove the mapping. The official Kubernetes: “Use a User Namespace With a Pod” (accessed September 15, 2026) has the right starting observations: inside the Pod, inspect /proc/self/ns/user and /proc/self/uid_map, then compare namespace information on the host. The task's sample output is illustrative only; your evidence must record your own observed values.
Inside the authorized staging Pod:
set -eu
id
readlink /proc/self/ns/user
cat /proc/self/uid_map
cat /proc/self/gid_mapOn the node, first obtain the container process ID using your approved, runtime-specific inspection procedure. Do not invent a portable PID-discovery command: containerd, CRI-O, managed services and operational access models differ. Once an authorized reviewer has the correct PID, read-only Linux observations can include:
set -eu
PID="<VERIFIED_CONTAINER_PROCESS_PID>"
test -r "/proc/${PID}/uid_map"
ps -o pid,ppid,user,uid,group,gid,comm -p "${PID}"
readlink "/proc/${PID}/ns/user"
cat "/proc/${PID}/uid_map"
cat "/proc/${PID}/gid_map"Record evidence, not an expected magic number:
Observation | Baseline Pod | hostUsers: false candidate | What it proves |
id inside Pod | <record> | <record> | Container-visible process identity |
/proc/self/ns/user | <record> | <record> | User-namespace identity from inside |
/proc/self/uid_map | <record> | <record> | Pod-visible to host UID range mapping |
/proc/self/gid_map | <record> | <record> | Pod-visible to host GID range mapping |
Host ps for verified PID | <record> | <record> | Host-visible process UID/GID |
Host /proc/$PID/ns/user | <record> | <record> | Host-side namespace correlation |
Kubernetes' task says the namespace seen inside the container should differ from the host and uses uid_map comparison as the mapping check. The concepts page adds an important scheduling property: the kubelet chooses non-overlapping mappings for different Pods on the same node. Do not turn that into a promise that a particular numeric host mapping persists after deletion and recreation.
Run a two-Pod test and a recreation test. Schedule two candidates onto the same staging node, capture each mapping, verify the mappings are distinct, then delete and recreate one Pod through its controller and capture the new evidence. Acceptance is about isolation and correct workload behavior, not numeric stability.
Local stop rule: no host-side correlation means no mapping proof. A screenshot of id inside the container alone is insufficient because “root inside” is exactly the condition user namespaces are designed to reinterpret.
Validate storage semantics and keep capabilities, tokens and RBAC as independent gates
Storage validation is where a large fraction of rollout optimism should be spent. Kubernetes v1.36 explains that runAsUser, runAsGroup and fsGroup continue to refer to container identities, and that supported idmapped volume mounts let Pods switch user namespaces without permanently changing volume ownership. The kernel documentation similarly describes idmapped mounts as a temporary, mount-local ownership translation rather than a global ownership rewrite.
Build a disposable dataset that resembles the application's real permission model. For a stateful test, include an existing file owned by the expected application UID/GID, a group-writable directory if the application relies on shared group access, a new-file creation path, a rename/replace path, and a checksum-protected file that must survive Pod recreation.
Storage test | Baseline expected result | Candidate expected result | Acceptance evidence |
Read existing file | Success | Same success | Exit status + checksum |
Create file | Success | Same success | File exists, expected in-Pod owner |
Append/replace | Success | Same success | Content checksum |
Group-shared write | Success where workload requires it | Same success | stat plus application result |
Restart container | Data unchanged | Data unchanged | Before/after checksum |
Recreate Pod | Data unchanged | Data unchanged | Before/after checksum + remount |
Second Pod shares test volume | Baseline-defined behavior | Same application semantics | Cross-Pod read/write test |
Incompatible NFS fixture | Baseline may mount | Userns candidate expected to be blocked/fail | Recorded event/error from real test |
For the incompatible fixture, NFS is a defensible synthetic choice at this cutoff because Kubernetes explicitly says NFS volumes cannot be mounted into a user-namespace Pod due to Linux NFS client limitations. Capture the actual event and runtime error from your environment rather than pasting documentation's example error into an incident record. Kubernetes warns that failure details depend on the container runtime.
Never respond to a candidate's permission failure with chown -R against a production volume. That changes persistent ownership globally, can break the known-good workload, can be extremely expensive on large trees, and defeats the purpose of testing idmapped mount semantics. The Linux kernel documentation explicitly describes recursive ownership changes as global and permanent, whereas idmapped-mount ownership translation is localized to the mount.
Now split the security review into orthogonal questions. A correct UID map is not evidence that the process lacks dangerous capabilities inside its namespace, that its token is unnecessary, or that Role-Based Access Control (RBAC) is least-privileged. The Kubernetes: “Using RBAC Authorization” (accessed September 15, 2026) warns that broad grants can give service accounts unnecessary and potentially escalating API access, and recommends application-specific service accounts with fine-grained bindings.
The KubeCap authors' 2026 study is relevant only as evidence that capability configuration is often neglected in the three open-source datasets they examined: they report 74.67% of projects in those datasets lacked capability configurations. That is not a user-namespace adoption rate, not a production-cluster estimate, and not evidence that your workload needs a particular capability set. The paper's scope supports keeping capability minimization as its own review gate. Yuhao Liu et al.: “KubeCap: A Framework for Capability Minimization in Kubernetes via Static Analysis and LLM-Assisted Rule Inference,” submitted August 27, 2026.
This separation also aligns with layered cloud-security controls: identity, access, runtime and infrastructure controls solve different failure modes and should not be collapsed into one “hardened” label.
Use an authorization check that does not require reading a real Secret. Kubernetes documents kubectl auth can-i with service-account impersonation; the caller performing the check must itself be authorized to impersonate that identity.
set -eu
NS="<DISPOSABLE_TEST_NAMESPACE>"
SA="<WORKLOAD_SERVICE_ACCOUNT>"
SECRET="<SYNTHETIC_SECRET_NAME>"
kubectl auth can-i get "secrets/${SECRET}" \
--as="system:serviceaccount:${NS}:${SA}" \
--namespace="${NS}"For the required overbroad-permission drill, create a disposable namespace fixture in which the workload service account is intentionally granted read access to a synthetic Secret. Do not put real credentials in it. Verify that the authorization check says the action is allowed, then remove the overbroad binding and verify it is denied. Leave hostUsers: false unchanged throughout. The lesson is the separation: UID remapping should continue to pass both before and after the RBAC correction.
Control | Evidence | Pass condition | Residual risk owner |
Host UID mapping | Inside/host namespace and UID/GID maps | Non-host-privileged mapping demonstrated | Platform |
Volume behavior | Test matrix + checksums | Required I/O matches baseline | Storage/workload |
Capabilities | Manifest review against policy | No unexplained broadening | Security |
Service-account authorization | auth can-i and RBAC manifests | Only intended API actions allowed | Security/IAM |
Token mounting | Pod spec and application need | Token absent when unnecessary, otherwise justified | Workload/security |
Admission policy | Admission result and policy version | No weakened policy to force success | Platform/security |
Local stop rule: mapping success cannot override a failed RBAC review, unexplained capability requirement or storage mismatch. Each gate has its own owner and can independently block promotion.
Run the mixed-workload acceptance exercise and classify failures by layer
Use two synthetic workloads on the isolated staging pool. The first is a low-risk stateless worker with no persistent volume. The second is a stateful job that reads and writes a shared test volume. For each, keep an unchanged baseline and a candidate that differs only where required to set hostUsers: false.
The stateless worker goes first because it narrows the kernel/runtime/admission question without hiding behind storage. Run baseline and candidate through scheduling, image pull, init containers, startup probes, readiness, normal processing, termination and recreation. Capture mapping evidence on the candidate. Any arbitrary canary percentage would be a local choice, not a Kubernetes guarantee, so the initial staging scope should be defined by blast radius and owner coverage rather than a copied number.
For the stateful job, use a disposable compatible PVC with representative ownership and sharing semantics. Run baseline and candidate against equivalent datasets, compare checksums and application outcomes, recreate the candidate Pod, then repeat. Add the documented-incompatible NFS fixture as a separate negative test. The NFS result should block that path; it does not justify weakening admission or changing production ownership.
Exercise step | Stateless worker | Stateful job | Proposed acceptance |
Schedule to candidate pool | Required | Required | Correct node image recorded |
Start with baseline | Required | Required | Known-good behavior captured |
Start with userns candidate | Required | Required | No admission/runtime failure |
Capture UID/GID mapping | Required | Required | Inside + host proof complete |
Application transaction | Required | Required | Same functional result |
Volume read/write | N/A | Required | Same semantics as baseline |
Pod recreation | Required | Required | Service/data behavior preserved |
Shared-volume second Pod | N/A | Required if architecture needs it | Baseline-equivalent semantics |
Incompatible storage fixture | Optional | Required for drill | Failure correctly attributed and contained |
RBAC negative check | Required if API-using | Required if API-using | Authorization matches intended role |
The worked decision record should stay explicit about expected versus observed results:
Decision field | Synthetic example |
Workload | stateful-report-job |
Candidate change | spec.hostUsers: false only |
Mapping expectation | Pod-visible IDs map to non-privileged host IDs; actual numbers not preselected |
Compatible storage expectation | Read/write/checksum behavior matches baseline |
Incompatible fixture expectation | NFS candidate is blocked or fails mount/start according to actual environment |
API expectation | Service account cannot read synthetic Secret after overbroad test binding is removed |
Rollout result | <PASS / BLOCK / EXCEPTION PENDING> |
Owners | Platform, workload, storage, security |
Recovery reference | <KNOWN_GOOD_GIT_REF> |
When something fails, classify it before fixing it. Do not call every red Pod “user namespace incompatibility.”
Failure layer | What to capture | Likely owner | First decision |
Manifest / API validation | Server response, rejected fields | Workload/platform | Fix spec or classify unsupported combination |
Admission | Policy name/version and exact denial | Security/platform | Preserve policy; review candidate |
Scheduling | Events, node selectors, taints, pool eligibility | Platform | Correct placement/inventory |
Runtime setup | Kubelet/runtime event and logs | Platform/runtime | Verify CRI/OCI/kernel combination |
Filesystem mount | Mount event, volume type, filesystem, CSI details | Storage/platform | Block path until compatibility proven |
Application permission | App logs, stat, required operation | Workload/storage | Compare baseline/candidate semantics |
Kubernetes API auth | auth can-i, audit/authorization evidence | Security/IAM | Correct RBAC independently |
Kubernetes' user-namespace page includes an example idmapped-mount failure but explicitly notes runtime error details can vary. Therefore, your runbook should require exact observed text from the local event/log record and should never fabricate a vendor error string.
A useful failure drill is intentionally simple. Run the stateful candidate against the incompatible test storage. Confirm the rollout controller or human gate stops there. Confirm nobody edits Pod Security labels, adds privileged mode, injects hostPID, or broadens capabilities to “see if it helps.” Restore the compatible test fixture or the baseline manifest, verify the data checksum, and record the failure as a storage eligibility result.
A second drill uses the intentionally overbroad service-account permission. Mapping and storage can pass while authorization fails the security gate. Remove the binding, re-run kubectl auth can-i, and verify the workload still functions. This demonstrates why “root is remapped” and “the workload cannot read Secrets” are different statements. Kubernetes' RBAC guidance explicitly favors specific resources and verbs over wildcards and warns that broad service-account grants create unnecessary API access.
Local stop rule: uncontrolled rollout stops on any unexplained admission rejection, runtime setup error, required I/O failure, checksum change, lost mapping evidence, policy weakening, or newly required host privilege. The accountable layer owner must either produce evidence for a supported fix or keep the workload on the baseline.
Observe rollout health, rehearse recovery and promote only with an evidence pack
Availability is necessary but not proof of isolation. The v1.36 page documents two kubelet Prometheus metrics for user namespaces: started_user_namespaced_pods_total, counting attempted user-namespaced Pod starts, and started_user_namespaced_pods_errors_total, counting errors creating them. Those metrics can tell you whether candidate creation is happening and failing, but they do not prove which host UID/GID mapping a particular workload received.
Build a bounded-cardinality rollout view around operational questions rather than dumping sensitive process details into labels:
Signal | Purpose | Owner | Response |
User-namespaced Pod start attempts | Candidate activity | Platform | Compare to planned rollout scope |
User-namespaced Pod start errors | Runtime/admission signal | Platform | Stop expansion; classify layer |
Pod startup/restart rate | Workload regression signal | SRE/workload | Compare baseline and candidate |
Application error/latency indicators | Service behavior | SRE/workload | Roll back workload change if threshold breached |
Storage I/O errors | Data-path behavior | Storage/workload | Freeze stateful rollout |
Checksum/integrity test | Data correctness | Workload/storage | Immediate stop on mismatch |
Mapping evidence completeness | Isolation proof | Security/platform | No promotion without record |
The dashboard should follow normal observability principles: connect symptoms to diagnostic evidence, but keep the evidence categories distinct. A green service-level objective does not establish a UID map, and a correct UID map does not establish healthy application behavior.
Recovery starts with the workload manifest, not the node runtime. Keep the known-good baseline in version control and make the user-namespace candidate a reversible workload revision. If a candidate fails a gate, restore that baseline for the approved test scope, recreate the affected Pod through its controller, and verify the same data path the baseline used before the test.
A proposed recovery checklist is:
Freeze further candidate promotion and preserve Pod events, kubelet/runtime logs, mapping evidence and storage test results.
Identify whether data changed. Compare the pre-test and post-test checksums or application-level integrity marker.
Restore <KNOWN_GOOD_GIT_REF> rather than editing the live Pod by hand.
Recreate only the approved test workload; do not drain or rebuild unrelated nodes unless the failure is proven to be node infrastructure.
Verify baseline read/write behavior and application health on the original data path.
Confirm admission and RBAC policy were not relaxed during troubleshooting.
Record the candidate as blocked, with the layer owner and next evidence required.
Treat any node-image, kernel, containerd/CRI-O or OCI-runtime rollback as a separate infrastructure change.
The storage recovery boundary is strict: never recursively chown a production volume as an improvised user-namespace fix. Besides making the test irreversible, that can break the old workload's ownership expectations. The kernel's idmapped-mount design exists precisely to make ownership translation mount-local rather than globally rewriting the filesystem.
Use established monitoring and logging practices to preserve the operational timeline, including events, kubelet/runtime errors and application symptoms, without logging service-account tokens, Secret payloads or unnecessary per-process identity data.
Promotion should be per workload, not per cluster. A proposed evidence-based status model is eligible, validated, adopted, blocked, or exception. “Feature stable” is not a promotion status. An exception should name the reason, owner, compensating control, expiration/review date and evidence needed to retire it.
Promotion artifact | Security sign-off | Storage sign-off | SRE/workload sign-off |
Environment inventory | Review | Review storage fields | Review workload revision |
Manifest diff | Approve no policy weakening | Confirm mounts unchanged/known | Approve rollout artifact |
Mapping proof | Required | Informational | Informational |
Storage matrix | Review residual risk | Required | Required |
RBAC/capability record | Required | N/A | Confirm application need |
Failure drill | Review stop behavior | Review storage recovery | Required |
Known-good rollback | Review unchanged controls | Confirm data path | Required |
A practical sequence is inventory → eligibility → stateless probe → mapping proof → stateful volume test → RBAC/capability review → recovery drill → limited adoption → broader workload-by-workload adoption. Re-open a workload's evidence when the node image, kernel, CRI/OCI runtime, filesystem, CSI driver, security policy, service account or material application permission model changes.
Build a reviewable validation portfolio and answer the remaining user-namespace questions
The useful output of this work is not a slide that says “Kubernetes user namespaces enabled.” It is a small portfolio that another engineer can reproduce: the baseline and candidate manifests, node/runtime inventory, mount inventory, inside/host mapping record, storage matrix, independent RBAC and capability decision, failure drill, rollback reference and owner approvals.
Reviewer question | Evidence to hand over | Reject when |
Is host UID remapping proven? | Inside/host namespace and UID/GID maps | Host correlation missing |
Does required storage work? | Per-volume I/O, ownership and recreation results | Any required path untested or failed |
Were existing controls preserved? | Manifest diff + admission result | Policy weakened to pass |
Is API access independent and least-privileged? | Service-account RBAC manifests + authorized negative checks | Broad unexplained access remains |
Can we recover? | Known-good Git ref + completed rollback drill | Baseline restore/data verification not rehearsed |
Who owns the exception? | Named platform/storage/security/workload owner | Ownership or expiry absent |
For engineers building these habits in a structured learning environment, Refonte Learning's DevOps Engineer Program lists a three-month duration, 12–14 hours per week, and a requirement that participants be engaged in bachelor's or postgraduate studies; its published curriculum includes Linux and scripting, Git/GitHub, CI/CD, Docker and Kubernetes, Terraform, AWS/Azure/GCP, monitoring and logging, and a capstone project. Those foundations map naturally to version-controlled manifests, Linux validation and rollout evidence, but the live page does not verify a specific Kubernetes minor version, a user-namespace lab, idmapped-mount exercises or runtime compatibility testing.
Does every Pod use a user namespace once the feature is stable? No. Kubernetes v1.36 marks the feature stable, but a Pod opts in with spec.hostUsers: false. Feature availability and workload adoption are separate decisions. The living documentation also states that the old feature gate is locked/ignored in current releases; that does not rewrite existing Pod specs into user-namespaced Pods.
Will root still appear as UID 0 inside the container? It can. That is the central point of the model: a process can have root privileges inside its user namespace while mapping to an unprivileged host identity outside it. Your proof is the inside/host namespace and mapping evidence, not the word root from id alone.
Do service-account or RBAC permissions change because hostUsers is false? No documented behavior connects user-namespace UID remapping to Kubernetes API authorization. RBAC is evaluated separately. Use application-specific service accounts and authorized kubectl auth can-i checks to prove intended API access.
Does all storage work with user namespaces? No. Kubernetes requires idmapped-mount support for the kubelet Pod-directory filesystem and all Pod-volume filesystems, disallows raw block volumeDevices, and at the cutoff explicitly states that NFS volumes cannot be mounted in user-namespace Pods because the Linux NFS client lacks idmapped-mount support. Test the real storage stack rather than extrapolating from a stateless Pod.
What should we do when a candidate fails? Stop promotion, preserve the exact failure evidence, classify the failing layer, and restore the known-good workload manifest if service or data-path behavior is at risk. Do not weaken admission to make the test pass, do not add unexplained host privileges, and do not recursively rewrite production ownership. The next action is workload-specific: identify the missing mapping, runtime or storage evidence, assign the accountable owner, and retest only after that evidence changes.
