Distinct from 'Permission denied': EPERM means the operation itself is disallowed for your process — lacking a capability, restricted by seccomp/AppArmor, or namespaced away in containers.
CAP_NET_BIND_SERVICE for low ports, CAP_SYS_ADMIN for mounts, CAP_NET_ADMIN for iptables. Root-in-container ≠ all capabilities: docker drops most by default.
Profiles (especially default container seccomp) block less-common syscalls with EPERM. dmesg/audit logs name the denied syscall for AppArmor.
Rootless containers map your uid; what looks like root isn't — operations the real kernel checks against the host user (mount, network changes) fail with EPERM.
# 'Operation not permitted' = EPERM (capability/policy); 'Permission denied' = EACCES (file perms). Fixes are completely different.
docker run --cap-add=NET_ADMIN ... # compose: cap_add: [NET_ADMIN]
sudo sysctl net.ipv4.ip_unprivileged_port_start=80 # or setcap 'cap_net_bind_service=+ep' /path/to/binary
sudo dmesg | tail ; sudo aa-status 2>/dev/null | head # AppArmor; for seccomp: strace the failing call
--privileged works but removes almost every guard rail: prefer cap-add of exactly what's needed. setcap on binaries is a nice middle path for port 80/443 apps — no root, no container changes.
Modern root is divided into capabilities, and containers/policies drop most of them. CAP_SYS_ADMIN, CAP_NET_ADMIN etc. are checked individually — being uid 0 changes nothing if the capability isn't attached to your process.
The pod's security context (seccomp profile, dropped capabilities, user namespace) restricts syscalls the VM allows. Add the needed capability via securityContext, or redesign the tool to not need it.
Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.
Browse the template store →One-time. Yours to modify. Instant download from the NinjaOps template store.