This error occurs when a Docker container attempts to use a Linux capability that has not been granted. The container is trying to perform a privileged operation (like modifying network interfaces or mounting filesystems) but lacks the required capability. Fix by adding specific capabilities with --cap-add or reviewing your security constraints.
When Docker runs a container, it operates with a restricted set of Linux capabilities by default. Linux capabilities are a way to break down the monolithic root privileges into smaller, more granular permissions. Instead of giving a process full root access, the kernel can grant specific capabilities like CAP_NET_ADMIN (network administration) or CAP_SYS_ADMIN (system administration). Docker drops most capabilities by default for security reasons. The default set includes only basic capabilities like CHOWN, DAC_OVERRIDE, FSETID, FOWNER, MKNOD, NET_RAW, SETGID, SETUID, SETFCAP, SETPCAP, NET_BIND_SERVICE, SYS_CHROOT, KILL, and AUDIT_WRITE. When your application tries to perform an operation requiring a capability outside this default set, the kernel denies the operation with "capability not permitted." This error commonly appears when: - Running network tools that need to modify interfaces (requires CAP_NET_ADMIN) - Mounting filesystems inside containers (requires CAP_SYS_ADMIN) - Running Docker inside Docker or LXC (nested containerization) - Using applications that require low-level system access - Running security tools or network analyzers
First, determine which capability your application needs. Common capabilities and their use cases:
| Capability | Purpose |
|------------|---------|
| CAP_NET_ADMIN | Network interface configuration, iptables, routing |
| CAP_SYS_ADMIN | Mount operations, namespace management, many admin tasks |
| CAP_NET_RAW | Raw socket access, ping, packet capture |
| CAP_SYS_PTRACE | Debugging, strace, process inspection |
| CAP_IPC_LOCK | Memory locking (mlock, mlockall) |
| CAP_SYS_TIME | System clock modification |
Check what your application is trying to do:
# Run with strace to see failing syscalls
docker run --rm -it --cap-add SYS_PTRACE your-image strace -f your-command 2>&1 | grep -i "permission denied\|operation not permitted"Common operations and their required capabilities:
- ip link, ip addr, iptables -> CAP_NET_ADMIN
- mount, umount -> CAP_SYS_ADMIN
- ping (ICMP) -> CAP_NET_RAW
- strace, gdb -> CAP_SYS_PTRACE
Once you know which capability is needed, add it using the --cap-add flag. Always prefer adding specific capabilities over using --privileged.
Add a single capability:
# For network administration (iptables, ip commands)
docker run --cap-add NET_ADMIN your-image
# For system administration tasks
docker run --cap-add SYS_ADMIN your-image
# For raw network access
docker run --cap-add NET_RAW your-imageAdd multiple capabilities:
docker run --cap-add NET_ADMIN --cap-add SYS_ADMIN your-imageNote: Docker uses capability names without the CAP_ prefix. Use NET_ADMIN not CAP_NET_ADMIN.
In Docker Compose:
version: "3"
services:
myapp:
image: your-image
cap_add:
- NET_ADMIN
- SYS_ADMINConfirm which capabilities your container actually has:
Check current capabilities inside the container:
# Run an interactive shell with your capabilities
docker run --rm -it --cap-add NET_ADMIN ubuntu:22.04 bash
# Inside the container, check capabilities
apt-get update && apt-get install -y libcap2-bin
capsh --printExpected output will show capabilities like:
Current: cap_chown,cap_dac_override,...,cap_net_admin,...
Bounding set: cap_chown,cap_dac_override,...,cap_net_admin,...Check capabilities of running containers:
# List capabilities for all containers
docker ps -q | xargs docker inspect --format '{{.Name}}: CapAdd={{.HostConfig.CapAdd}} CapDrop={{.HostConfig.CapDrop}}'Test if the capability works:
# Test NET_ADMIN capability
docker run --rm --cap-add NET_ADMIN ubuntu:22.04 ip link set lo down && echo "Success" || echo "Failed"Even with the right capability, seccomp (secure computing mode) may block the required system calls.
Test with seccomp disabled (for debugging only):
docker run --security-opt seccomp=unconfined --cap-add NET_ADMIN your-imageIf this works, create a custom seccomp profile:
1. Get Docker's default seccomp profile:
curl -o default-seccomp.json https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json2. Modify it to allow required syscalls
3. Use your custom profile:
docker run --security-opt seccomp=custom-seccomp.json --cap-add NET_ADMIN your-imageWarning: Disabling seccomp reduces container security. Only disable for debugging or use a minimal custom profile that allows only required syscalls.
Security modules like AppArmor (Ubuntu/Debian) or SELinux (RHEL/CentOS) may also block operations.
For AppArmor (Ubuntu/Debian):
# Test with AppArmor disabled (debugging only)
docker run --security-opt apparmor=unconfined --cap-add NET_ADMIN your-imageIf you see unknown AppArmor profiles causing issues:
# Remove unknown AppArmor profiles
sudo aa-remove-unknownFor SELinux (RHEL/CentOS/Fedora):
# Check SELinux denials
sudo ausearch -m avc -ts recent
# Test with SELinux in permissive mode (debugging only)
docker run --security-opt label=disable --cap-add NET_ADMIN your-imageCreate custom policies for production rather than disabling security modules.
Running Docker inside LXC or Docker-in-Docker has additional restrictions.
For Docker-in-Docker:
# Run with privileged mode (use with caution)
docker run --privileged -v /var/run/docker.sock:/var/run/docker.sock docker:latest
# Or with specific capabilities for DinD
docker run --cap-add SYS_ADMIN --cap-add NET_ADMIN \
--security-opt seccomp=unconfined \
--security-opt apparmor=unconfined \
docker:dindFor Docker inside LXC:
1. Enable nesting in LXC:
# In LXC config
lxc.include = /usr/share/lxc/config/nesting.conf2. Grant required capabilities to the LXC container:
# In Proxmox, enable nesting and FUSE in container options
# Or manually add to config:
lxc.cap.drop =
features: nesting=1For Proxmox: Ensure virtualization is enabled in BIOS and the container has nesting enabled.
The --privileged flag grants all capabilities and disables security restrictions. Use only when absolutely necessary.
Run a privileged container:
docker run --privileged your-imageWhat --privileged does:
- Grants ALL Linux capabilities
- Disables seccomp filtering
- Gives access to all host devices
- Mounts /dev and /sys as read-write
- Essentially gives container root-level access to the host
Security implications:
- Container can escape to the host
- Container can access host devices
- Container can modify host kernel parameters
- Breaks container isolation model
Better alternative - identify minimum required capabilities:
# Instead of --privileged, use only what you need
docker run \
--cap-add NET_ADMIN \
--cap-add SYS_ADMIN \
--cap-add MKNOD \
your-imageIn production, always prefer specific capabilities over --privileged.
For containers running in Kubernetes, configure capabilities in the pod security context.
Add capabilities in Kubernetes:
apiVersion: v1
kind: Pod
metadata:
name: capability-pod
spec:
containers:
- name: app
image: your-image
securityContext:
capabilities:
add:
- NET_ADMIN
- SYS_ADMINDrop all and add specific (recommended):
securityContext:
capabilities:
drop:
- ALL
add:
- NET_ADMINFor privileged pods (use sparingly):
securityContext:
privileged: trueNote: Pod Security Policies (PSP) or Pod Security Standards may restrict capabilities. Check with your cluster admin if capabilities are being dropped at the policy level.
### Understanding Linux Capabilities in Docker
Docker's default capability set is designed to balance functionality with security. The following capabilities are granted by default:
- AUDIT_WRITE: Write to kernel auditing log
- CHOWN: Change file ownership
- DAC_OVERRIDE: Bypass file permission checks
- FOWNER: Bypass permission checks for file owner operations
- FSETID: Set file capabilities
- KILL: Send signals to processes
- MKNOD: Create special files
- NET_BIND_SERVICE: Bind to ports below 1024
- NET_RAW: Use raw sockets
- SETFCAP: Set file capabilities
- SETGID/SETUID: Change process GID/UID
- SETPCAP: Modify process capabilities
- SYS_CHROOT: Use chroot
### Rootless Docker Considerations
Rootless Docker has additional capability limitations because it runs without root privileges on the host:
# Check if running rootless
docker info | grep -i rootlessIn rootless mode, some capabilities like CAP_NET_ADMIN may not work even when added because the user namespace doesn't have the required host-level permissions.
Workarounds for rootless mode:
- Run specific operations on the host instead of in the container
- Use slirp4netns for network operations
- Configure /etc/sysctl.conf for required kernel parameters
### Security Best Practices
1. Principle of least privilege: Only add capabilities actually needed
2. Drop all, add specific: Use --cap-drop ALL then add only what's required
3. Test in development: Identify minimum capabilities before production
4. Document requirements: Note why each capability is needed
5. Audit regularly: Review containers for unnecessary privileges
# Recommended secure pattern
docker run \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--read-only \
--security-opt no-new-privileges:true \
your-image### Debugging Capability Issues
Trace system calls to identify what's blocked:
# Requires SYS_PTRACE capability
docker run --cap-add SYS_PTRACE --security-opt seccomp=unconfined \
your-image strace -f your-commandCheck kernel capability masks:
# Inside container
cat /proc/self/status | grep -i capCommon capability combinations:
| Use Case | Capabilities Needed |
|----------|-------------------|
| Network tools | NET_ADMIN, NET_RAW |
| Docker-in-Docker | SYS_ADMIN, NET_ADMIN, MKNOD |
| Debugging/profiling | SYS_PTRACE |
| NFS/FUSE mounts | SYS_ADMIN |
| Time synchronization | SYS_TIME |
image operating system "linux" cannot be used on this platform
How to fix 'image operating system linux cannot be used on this platform' in Docker
manifest unknown: manifest unknown
How to fix 'manifest unknown' in Docker
cannot open '/etc/passwd': Permission denied
How to fix 'cannot open: Permission denied' in Docker
Error response from daemon: failed to create the ipvlan port
How to fix 'failed to create the ipvlan port' in Docker
toomanyrequests: Rate exceeded for anonymous users
How to fix 'Rate exceeded for anonymous users' in Docker Hub