# RootlessKit: a Linux native fake root, and what it actually fakes

> RootlessKit gives an unprivileged user a user namespace in which their own ID is 0, which is what lets Docker and Kubernetes run without real root and keeps a container escape from reaching the host's root account. The README is unusually precise about what the fake root can and cannot do, and it also explains why the LD_PRELOAD and ptrace alternatives cannot work for this.

**rootless-containers/rootlesskit** — Linux-native "fake root" for implementing rootless containers

- Repository: https://github.com/rootless-containers/rootlesskit
- Stars: 1,312 · Forks: 127
- Language: Go
- License: Apache-2.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/rootless-containers-rootlesskit

## Why fake root exists at all

RootlessKit is described as a Linux-native implementation of fake root using user namespaces, and the purpose it serves is specific rather than general. The aim is to run Docker and Kubernetes as an unprivileged user, known as rootless mode, so as to protect the real root on the host from potential container breakout attacks. The threat model is worth stating plainly, because it explains the whole design. In a normal container setup the runtime is root, so a container that finds a kernel or runtime escape lands as root on the host, and one compromised container is a compromised machine. With RootlessKit underneath, the daemon runs as an ordinary user with a mapped ID space, and the same escape lands inside that namespace as an unprivileged user with a limited range of subordinate IDs. The real root account is never involved in the container's execution at all, which turns a catastrophic escape into an inconvenience.

## The mechanics, in four kernel facilities

The section titled What RootlessKit actually does is short and precise. RootlessKit creates user namespaces and mount namespaces, and executes `newuidmap(1)` and `newgidmap(1)` together with `subuid(5)` and `subgid(5)`. Those two helper programs are setuid binaries installed on the host, and they are the mechanism by which a user is allowed to map a range of subordinate IDs into a namespace, a capability the kernel grants only to a privileged helper. It also supports isolating network namespaces with userspace NAT using slirp, and kernel-mode NAT using the SUID-enabled `lxc-user-nic(1)` is experimentally supported. The distinction between the two NAT paths is the usual one. Userspace NAT is the portable option that needs no host configuration, while the kernel mode path is faster and requires a setuid helper, which is why it is marked experimental rather than the default.

## What the fake root can and cannot touch

The usage section shows the semantics better than any explanation could. Inside `rootlesskit bash` your UID is mapped to 0, but it is not the real root, and the demonstration is a file listing followed by a failed read.

```console
(host)$ rootlesskit bash
(rootlesskit)# id
uid=0(root) gid=0(root) groups=0(root),65534(nogroup)
(rootlesskit)# ls -l /etc/shadow
-rw-r----- 1 nobody nogroup 1050 Aug 21 19:02 /etc/shadow
(rootlesskit)# cat /etc/shadow
cat: /etc/shadow: Permission denied
```

The file is owned by nobody and nogroup inside the namespace, and reading it fails, which is the point. You are root only with respect to the files whose ownership maps into your subordinate ID range, and the host's real shadow file is owned by an ID you do not hold. The environment is left untouched, so `USER`, `HOME` and `XDG_RUNTIME_DIR` still point at the real account, which is why tools that look up the user's home directory keep working. Two flags complete the picture. The `--copy-up` option isolates a directory from the host by copying its contents up into a temporary overlay, so removing a file inside it does not touch the host, and the network options, with `--net=slirp4netns` and `--disable-host-loopback`, let you create network namespaces as well.

## Why the other fake root tools do not work here

The README has a section on similar projects, and the taxonomy is the most useful thing in the document. Tools based on `LD_PRELOAD`, which is the approach fakeroot takes, are not enough to run rootless containers and lack support for static binaries. Tools based on `ptrace(2)`, which is the approach fakeroot-ng and proot take, are not enough either and are slow. Tools based on user namespaces, the approach `unshare -r`, `podman unshare` and become-root take, are the same family as RootlessKit but come without support for options such as `--copy-up` and `--net`. Each of those claims is a constraint that matters. A preload based fake root cannot help a statically linked binary because there is no dynamic loader to intercept, and it cannot give a container runtime the real namespaces it expects. A ptrace based one pays a syscall interception cost on every call. And a user namespace tool without copy-up has no way to give the container a writable view of `/etc` that leaves the host alone.

## The projects that already depend on it

The list of projects using RootlessKit is the reason to care, because it covers both the container engines and the build and orchestration layers. Docker and Moby use it, and so does Podman, since version 1.8.0, along with nerdctl, the Docker-compatible CLI for containerd, and iSulad, a lightweight container engine. On the build side, BuildKit, the next generation `docker build` backend, uses it. On the Kubernetes side, Usernetes provides Docker and Kubernetes installable under a non-root user's home directory, and k3s, the lightweight Kubernetes distribution, uses it as well. The practical implication is that RootlessKit is not a research project you have to evaluate on its own merits, but a component that a large part of the container ecosystem already assumes, which changes the risk calculation for anyone running rootless containers today.

## Installing it, and the host requirements that bite

The build is `make && sudo make install`, and three binaries land in `/usr/local/bin`: `rootlesskit`, `rootlessctl`, and `rootlesskit-docker-proxy`, which the README marks as deprecated and required only for Docker before version 28. The host requirements are where installations actually fail. `newuidmap` and `newgidmap` must be installed, and they come from the uidmap package on most distributions. The `/etc/subuid` and `/etc/subgid` files should contain more than 65536 sub-IDs for your user, with the example given being a single line naming the user, a start ID and a count, and the README notes these files are configured automatically on most distributions and links to a guide for the ones where they are not. Old distributions may also need the `kernel.unprivileged_userns_clone=1` sysctl set. The AppArmor requirement is the one that surprises people, because on Ubuntu 24.04 or later the `rootlesskit` binary is expected to be exactly under `/usr/bin`, and to install it anywhere else, such as the default `/usr/local/bin`, you need to write a custom AppArmor profile.

## The build pipeline and the module layout

The Dockerfile is a multi-stage build with several targets, and the comments explain what each one is for. The build stage is a Go image on Alpine with the toolchain installed, and the rootlesskit stage compiles with `CGO_ENABLED=0` and checks that the produced binaries are not dynamic, with an artifact stage that copies them into a scratch image, so the released binary has no libc dependency at all. A cross stage uses a script under `hack/` to build for other platforms. The test stage deliberately uses a non-Alpine Go image, with the comment that `go test -race` requires it, and it installs iptables and nftables so that the source-IP transparent path can be tested, preferring nft and falling back to iptables. The last stage is the most interesting, since it builds the shadow utilities from the upstream source in order to produce a `newuidmap` that can be run without privileged mode. The Go module is `github.com/rootless-containers/rootlesskit/v3` and targets Go 1.26, with dependencies that map onto the feature set, the containernetworking plugins, gvisor-tap-vsock, the vpnkit library, a TCP proxy library, a DHCP library, urfave/cli, logrus, semver and gotest.tools. The Makefile builds the three binaries and has a `cross` target that calls the script in `hack/`.

## Conclusion

Adopt RootlessKit if you run containers on a shared or multi-tenant machine and you need Docker or Kubernetes to work for a user who has no root account, because the namespace approach is the only one of the fake root techniques that actually holds up for container workloads. Do not adopt it as a general privilege escalation mechanism, since the mapping is bounded by the subuid and subgid ranges the real root has configured. Before you install, check the host requirements, since `newuidmap` and `newgidmap` must be installed, your account needs more than 65536 subordinate IDs in `/etc/subuid` and `/etc/subgid`, and on Ubuntu 24.04 or later the binary has to sit exactly at `/usr/bin` unless you write an AppArmor profile. The licence is Apache-2.0, the current release is v3.3.0 from 2026-10-14, and the last push was the same day.

## FAQ

### What does RootlessKit do?

It creates user namespaces and mount namespaces, executes `newuidmap(1)` and `newgidmap(1)` with the `subuid(5)` and `subgid(5)` ranges, and can isolate network namespaces with userspace NAT using slirp. Its purpose is to let Docker and Kubernetes run as an unprivileged user so that the real root on the host is protected from container breakout attacks.

### Is the root inside rootlesskit real root?

No. Inside `rootlesskit bash` your UID is mapped to 0, but it is not the real root, and the README demonstrates it by listing `/etc/shadow` as owned by nobody and nogroup and then failing to read it. The environment variables are left untouched, so `USER`, `HOME` and `XDG_RUNTIME_DIR` still refer to your real account.

### What host requirements does RootlessKit need?

`newuidmap` and `newgidmap` must be installed, `/etc/subuid` and `/etc/subgid` should contain more than 65536 sub-IDs for your user, old distributions may need the `kernel.unprivileged_userns_clone=1` sysctl, and on Ubuntu 24.04 or later the binary is expected to be exactly under `/usr/bin` unless you install a custom AppArmor profile.

### How do I install RootlessKit?

Run `make && sudo make install`, which installs `rootlesskit`, `rootlessctl` and the deprecated `rootlesskit-docker-proxy` into `/usr/local/bin`. The proxy is only required for Docker before version 28 and the Makefile notes it will be removed in RootlessKit v4.

## Sources

- [Issues](https://github.com/rootless-containers/rootlesskit/issues)
- [License: Apache-2.0](https://github.com/rootless-containers/rootlesskit/blob/master/LICENSE)
- [README](https://github.com/rootless-containers/rootlesskit/blob/master/README.md)
- [Releases](https://github.com/rootless-containers/rootlesskit/releases)
- [rootless-containers/rootlesskit on GitHub](https://github.com/rootless-containers/rootlesskit)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rootless-containers-rootlesskit
