BuildKit entitlements are how you grant your build process specific permissions to access resources on your host machine or network, going beyond just the build context itself.
Let’s watch a build try to do something it’s not supposed to, and then fix it.
Imagine you have a Dockerfile that tries to access a local network service during the build:
# Dockerfile
FROM alpine:latest
RUN apk add --no-cache curl
RUN curl http://my-internal-api.local:8080/health
If you try to build this with a recent version of BuildKit (which is the default for Docker and other tools now), you’ll likely hit an error like this:
#11 0.123 curl: (6) Could not resolve host: my-internal-api.local
#11 0.123
#11 0.123 ERROR: process "/bin/sh -c apk add --no-cache curl && curl http://my-internal-api.local:8080/health" did not complete successfully: exit code 6
This looks like a DNS issue, or maybe your my-internal-api.local isn’t actually running. But what if it is running, and you can curl it just fine from your host machine? The problem isn’t with curl or your network; it’s with BuildKit’s security model.
BuildKit, by default, sandboxes build operations. It doesn’t automatically trust that a RUN command should be able to reach out to arbitrary network addresses or access host files. This is a good thing! It prevents malicious Dockerfiles from exfiltrating data or attacking your internal infrastructure.
To allow this specific RUN command to access http://my-internal-api.local:8080, you need to grant it an entitlement. You do this by passing the --allow flag to buildctl build or when configuring BuildKit in your Docker daemon.
Here’s how you’d build it using buildctl:
buildctl build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--allow network.host \
--allow network.dns \
--output type=image,name=my-app:latest
The key flags here are --allow network.host and --allow network.dns.
--allow network.host: This grants the build process the ability to make outbound network connections to any host.--allow network.dns: This allows the build process to perform DNS lookups, which is necessary to resolvemy-internal-api.local.
Without these, BuildKit blocks the network request at a fundamental level, preventing the curl command from even attempting to resolve the hostname. By specifying these entitlements, you’re explicitly telling BuildKit: "It’s okay for this build to use host networking and DNS."
Common Causes and Fixes:
-
Attempting to access network resources (HTTP, databases, internal APIs):
- Diagnosis: Your
RUNcommand fails with errors likeCould not resolve host,Connection refused, orNetwork is unreachablewhen trying to access an address that is accessible from your host. - Fix: Add
--allow network.hostand potentially--allow network.dnsto yourbuildctl buildcommand or configure them in your BuildKit daemon settings. - Why it works: This explicitly permits the build container to initiate outbound network connections.
- Diagnosis: Your
-
Accessing host files/directories not in the build context:
- Diagnosis: Your
RUNcommand tries to read from or write to a path on your host that isn’t part of thecontextyou provided to BuildKit (e.g.,/etc/my-secret-config). - Fix: Use
--mount type=bind,source=/path/on/host,target=/path/in/buildwithin yourDockerfile’sRUNinstruction and ensure the corresponding entitlement is granted if it’s a sensitive operation. Forbuildctl, you’d use--local <name>=/path/on/hostand reference<name>in theRUNcommand as a mount, or use--allow mount.bindif you intend to let the build dynamically bind mounts. More granularly, you might grant--allow mount.host-srcor--allow mount.host-destdepending on the exact operation. - Why it works: This allows BuildKit to map host directories into the build container, making them accessible to
RUNcommands.
- Diagnosis: Your
-
Using Docker socket (
/var/run/docker.sock) inside a build:- Diagnosis: Your build needs to interact with the Docker daemon (e.g., to pull images, build nested Docker images). Errors might involve permission denied when accessing the socket.
- Fix: Add
--allow docker.socketto yourbuildctl buildcommand. ForDockerfiles, this is often handled by mounting the socket using--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock. - Why it works: This grants permission to access the Docker daemon’s control interface.
-
Running privileged commands (
setuid,setgid, etc.):- Diagnosis: Your build process requires elevated privileges that are normally restricted within a container, often related to system-level operations.
- Fix: Add
--allow capabilities.setuidor--allow capabilities.setgidas needed. For more general privileged operations,--allow privilegedmight be used, but this is a broad and potentially insecure grant. - Why it works: These entitlements bypass specific Linux capability restrictions for the build process.
-
Using specific Linux capabilities not covered by defaults:
- Diagnosis: Your build needs fine-grained control over system resources, such as network packet manipulation (
CAP_NET_RAW) or system time changes (CAP_SYS_TIME). - Fix: Add entitlements like
--allow capabilities.net_rawor--allow capabilities.sys_time. - Why it works: This grants specific, fine-grained Linux capabilities to the build process, allowing it to perform operations that would otherwise be denied.
- Diagnosis: Your build needs fine-grained control over system resources, such as network packet manipulation (
-
Accessing host’s
/procor/sysfilesystem:- Diagnosis: Your build needs to inspect or modify kernel parameters or hardware information directly from the host’s virtual filesystems.
- Fix: Use
--allow procfsor--allow sysfs. - Why it works: These entitlements allow BuildKit to map the host’s
/procand/sysdirectories into the build environment.
-
Running builds with root privileges on the host (less common for BuildKit itself, more for how it’s invoked):
- Diagnosis: While BuildKit aims to reduce the need for host root, some older configurations or specific tools might indirectly require it for certain operations.
- Fix: Ensure the user invoking
buildctlor running the Docker daemon has appropriate permissions, and configure BuildKit entitlements carefully rather than relying on host root. - Why it works: BuildKit entitlements are designed to avoid needing host root for most build tasks by granting specific, limited permissions to the build process itself.
After granting the necessary entitlements, your curl command will now resolve my-internal-api.local and attempt to connect. If the API is running and accessible, the build will succeed.
The next error you’ll likely encounter, if you’re not careful with entitlements, is a permission denied when trying to write the final image layer to disk, especially if BuildKit is running as a non-root user and doesn’t have write access to the configured build output directory.