google / google/gvisor

Support pod.spec.hostUsers: false (KEP-127): runsc not advertised as supporting user namespaces in CRI

Open
#13,303 0 comments 2 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
19.3k
Forks
2k
Avg merge
3d 5h
Merged PRs (30d)
264

Description

## Description

Pods with `runtimeClassName: gvisor` and `pod.spec.hostUsers: false` (Kubernetes user namespaces, KEP-127) are rejected by the kubelet before the runsc shim is ever invoked:

```
Failed to create pod sandbox: can't set `spec.hostUsers: false`,
RuntimeClass handler "runsc" does not support user namespaces
```

`runc` works in the same cluster. `crictl info` on the node shows the gap clearly:

```json
{ "name": "runc", "features": { "user_namespaces": true, "recursive_read_only_mounts": true } }
{ "name": "runsc" } // no features object
```

Reproducer:
- Kubernetes 1.35.2 (kubelet honors `RuntimeHandlerFeatures.UserNamespaces` from CRI).
- containerd 2.2.2.
- runsc `release-20260520.0`, shim `containerd-shim-runsc-v1` 2.1.5.
- Linux 6.17 (Ubuntu 24.04).

## Is this feature related to a specific bug?

No standing gVisor bug, but the proximate cause is split between containerd and gVisor:

1. **containerd's `introspectRuntimeFeatures` hardcodes runc as the only runtime it queries for OCI features**:
```go
if r.Type != plugins.RuntimeRuncV2 {
return nil, fmt.Errorf("introspecting OCI runtime features needs the runtime type to be %q, got %q", ...)
}
```
So `io.containerd.runsc.v1` never has its `manager.Info()` Features consulted, even though `pkg/shim/v1/manager.go` already returns them via `specutils.Features()`.

2. **Even if introspection ran, containerd's `supportsCRIUserns` requires both `Linux.Namespaces` to contain `"user"` AND `Linux.MountExtensions.IDMap.Enabled = true`.** runsc satisfies the first (`runsc/specutils/namespace.go:KnownNamespaces` includes `specs.UserNamespace`) but explicitly returns `IDMap.Enabled: false` in `runsc/specutils/specutils.go`.

## Do you have a specific solution in mind?

Two pieces, both probably needed:

- **gVisor side:** Decide whether runsc can advertise idmapped mount support (or an equivalent capability that satisfies kubelet's volume-ownership translation expectations). If idmap mounts aren't on the roadmap, an alternative would be working with containerd to allow runtimes that handle volume ownership another way (gofer-side chown, etc.) to opt in without `IDMap.Enabled`.
- **containerd side (separate issue):** relax `introspectRuntimeFeatures` to call `PluginInfo` for non-runc runtime types as well, so the runsc shim's existing OCI features can actually be surfaced. Happy to file that one separately and link it.

Today the only path I see for `pod.spec.hostUsers: false` to work with `runtimeClassName: gvisor` is patching either side. The corresponding `runc` + `hostUsers: false` configuration works fine on the same node, so this is purely a CRI-advertisement and idmap-feature gap, not a runsc capability gap (runsc itself supports user namespaces via OCI uidMappings, per the [Rootless guide](https://gvisor.dev/docs/user_guide/rootless/) Method 3).

What is the gVisor team's current plan for KEP-127 / `pod.spec.hostUsers: false` interop? Happy to contribute the patch on either side once the direction is clear.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.