Linux Rootless Containers with Buildah Explained
This article explores how the Linux operating system facilitates the execution and creation of rootless containers using the Buildah image-building tool. By leveraging core Linux kernel security primitives—primarily user namespaces, subordinate UID/GID mappings, and user-space storage and networking subsystems—Linux allows Buildah to build Open Container Initiative (OCI) images entirely within unprivileged user space without requiring root privileges or a background daemon.
The Foundation: Linux User Namespaces
The primary Linux kernel feature powering rootless containers is the
user namespace (user_namespaces(7)). Namespaces isolate
system resources so that a group of processes perceives a dedicated
instance of those resources.
A user namespace specifically isolates security-related attributes: user IDs (UIDs), group IDs (GIDs), keys, and capabilities. When Buildah initiates a build process as an unprivileged user:
- It requests the creation of a new user namespace using the
clone()orunshare()system calls with theCLONE_NEWUSERflag. - Inside this namespace, the invoking unprivileged host user is mapped to UID 0 (root).
- The process is granted full Linux capabilities (such as
CAP_CHOWN,CAP_MKNOD, andCAP_SETUID) strictly within the scope of that user namespace. - Outside the namespace, the process retains only the permissions and constraints of the standard unprivileged user on the host system.
Subordinate UID and GID Mapping
Standard container images typically involve files owned by multiple
different UIDs and GIDs (e.g., bin, daemon,
nobody). Because a regular Linux user only controls one UID
and GID by default, Linux provides subordinate UID and GID mechanisms to
allocate ranges of IDs to non-root users.
- Configuration Files: The mappings are defined in
/etc/subuidand/etc/subgid. An entry likeuser:100000:65536grants the user a block of 65,536 subordinate IDs starting at 100000. - Helper Utilities: The kernel delegates the mapping
setup to setuid-root helper binaries:
newuidmapandnewgidmap. Buildah invokes these utilities to configure the/proc/[pid]/uid_mapand/proc/[pid]/gid_mapinterfaces, mapping the host's subordinate IDs to internal container IDs (e.g., UIDs 1–65535 inside the container).
This architecture allows Buildah to run chown or package
manager commands that assign arbitrary file ownership inside the build
environment without colliding with host system accounts.
Storage and the Filesystem Layer
Building an image requires modifying file layers, creating temporary mounts, and tracking changes. Linux handles rootless storage through specialized paths and drivers:
- Storage Location: Rather than writing to the
system-wide
/var/lib/containers/storage, rootless Buildah operates out of the user's home directory, typically$HOME/.local/share/containers/storage. - OverlayFS in User Namespaces: Modern Linux kernels (version 5.11 and later) allow mounting OverlayFS directly within an unprivileged user namespace. When supported, the kernel directly manages layer copy-up operations.
- FUSE OverlayFS Fallback: On older kernels or
distributions where unprivileged native OverlayFS is restricted, Buildah
uses
fuse-overlayfs. This FUSE (Filesystem in Userspace) driver intercepts filesystem calls and performs copy-on-write layering entirely in user space, bypassing kernel-level mount restrictions.
Networking in Rootless Builds
When Buildah executes commands that require network access (such as
RUN apt update or RUN curl), the Linux kernel
blocks standard network namespace creation by unprivileged users if
external interface routing is required.
To resolve this, Linux environments run user-space networking tools:
- slirp4netns / pasta: These tools create a TAP device inside the container's network namespace and translate network calls into standard, unprivileged socket operations on the host. The host kernel processes the packets as ordinary outbound traffic originating from the non-root user.
Daemonless Architecture
Unlike traditional container platforms that rely on a privileged
background daemon running as root (such as the Docker daemon), Buildah
does not use a client-server model. When a user runs
buildah bud or buildah from:
- Buildah executes directly as a child process of the user's current shell.
- It interacts directly with the Linux kernel APIs.
- Once the build process finishes, the temporary namespaces and helper processes terminate, leaving behind the generated OCI-compliant image artifacts in user-owned local storage.
By combining user namespaces, UID/GID allocation, user-space storage drivers, and user-mode networking, Linux provides an isolated, unprivileged sandbox that Buildah utilizes to build production-ready container images securely.