The 'cannot open: Permission denied' error occurs when a process inside a Docker container cannot read or write to system files like /etc/passwd. This typically happens due to user namespace remapping, read-only filesystem mounts, SELinux policies, or running commands that require root privileges as a non-root user.
The "cannot open '/etc/passwd': Permission denied" error indicates that a process inside your Docker container is trying to access the /etc/passwd file (or similar system files) but lacks the necessary permissions. This error commonly occurs in these scenarios: - Commands like `useradd`, `usermod`, `groupadd`, or `passwd` need to modify /etc/passwd but the container runs as a non-root user - You've mounted /etc/passwd from the host into the container, and the mount prevents modifications - SELinux or AppArmor security policies are blocking access to the file - Rootless Docker mode uses user namespace remapping that changes effective permissions - The container's filesystem is mounted read-only or with restricted capabilities The error is particularly common in CI/CD pipelines, containers that dynamically create users at runtime, and setups using rootless Docker or Podman.
If you need to run user management commands, ensure you're running as root:
# Check current user
docker exec <container_name> whoami
# Run command as root
docker exec -u root <container_name> useradd newuser
# Or enter an interactive shell as root
docker exec -u 0 -it <container_name> /bin/shIn your Dockerfile, perform user operations before switching to a non-root user:
FROM ubuntu:22.04
# Run user operations as root (default)
RUN useradd -m appuser
# Then switch to non-root user
USER appuser
CMD ["./app"]If you've mounted /etc/passwd or /etc/shadow from the host, user modification commands will fail because mount points cannot be replaced:
# This causes problems:
docker run -v /etc/passwd:/etc/passwd:ro myimage
# The passwd command creates a temp file and tries to rename it,
# which fails on a mount pointSolutions:
1. Don't mount individual files - mount a directory instead if needed:
docker run -v /etc:/etc myimage2. Create users in the Dockerfile instead of at runtime:
RUN useradd -u 1000 -m appuser3. Use NSS (Name Service Switch) for user mapping instead of mounting passwd files:
# Use libnss-extrausers or similar for dynamic user databasesRootless Docker and Podman use user namespaces that remap UIDs/GIDs, which can cause permission issues:
# Check if you're running rootless Docker
docker info | grep -i rootless
# Check user namespace mappings
cat /etc/subuid
cat /etc/subgidSolutions for rootless mode:
1. Use --userns=host to disable user namespace for a container:
docker run --userns=host myimage
# Note: This reduces security isolation2. Ensure proper subuid/subgid configuration:
# Check your user has enough subordinate UIDs
grep $USER /etc/subuid
# Should show: username:100000:65536 (or similar)
# If missing, add them:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER3. For Podman, use the :U volume option:
podman run -v ./data:/app/data:U myimage
# :U tells Podman to chown the volume to match the container userSELinux may block container access to certain files. Check if SELinux is the cause:
# Check SELinux status
getenforce
# Check for SELinux denials
sudo ausearch -m avc -ts recent
# Or check the audit log
sudo grep denied /var/log/audit/audit.log | tailSolutions:
1. Add the :z or :Z flag to volume mounts:
# :z allows the volume to be shared between containers
docker run -v ./data:/app/data:z myimage
# :Z makes the volume private to this container
docker run -v ./data:/app/data:Z myimage2. Use the container_file_t context:
sudo chcon -Rt svirt_sandbox_file_t /path/to/volume3. Create an SELinux policy exception (less recommended):
# Generate a policy module from denials
sudo ausearch -m avc -ts recent | audit2allow -M mycontainer
sudo semodule -i mycontainer.ppIf your container uses a read-only root filesystem, /etc/passwd cannot be modified:
# Check if filesystem is read-only
docker inspect <container> | grep -A5 ReadonlyRootfsSolutions:
1. Mount /etc as a tmpfs for runtime modifications:
docker run --read-only --tmpfs /etc myimage2. Or mount specific files as writable volumes:
docker run --read-only \
-v passwd-data:/etc/passwd \
-v shadow-data:/etc/shadow \
myimage3. Create users in the Dockerfile before setting read-only:
FROM alpine
# Create all users while filesystem is writable
RUN adduser -D appuser
# Application can run read-only since users exist
USER appuser
CMD ["./app"]When using bind mounts, ensure the container user has matching permissions:
# Find your host user's UID/GID
id -u # e.g., 1000
id -g # e.g., 1000Build the container with matching UID:
FROM node:20
# Create user with specific UID matching host user
ARG UID=1000
ARG GID=1000
RUN groupadd -g $GID appgroup \
&& useradd -u $UID -g appgroup -m appuser
USER appuserBuild and run with matching IDs:
# Build with your UID/GID
docker build --build-arg UID=$(id -u) --build-arg GID=$(id -g) -t myapp .
# Or pass at runtime
docker run --user $(id -u):$(id -g) myappAfter applying fixes, verify that file access works:
# Test reading /etc/passwd
docker exec <container> cat /etc/passwd
# Test user lookup
docker exec <container> id
docker exec <container> whoami
# Test user modification (if needed)
docker exec -u root <container> useradd testuser
docker exec <container> grep testuser /etc/passwd
# For volume mounts, test file creation
docker exec <container> touch /app/data/testfileIf using CI/CD, ensure your pipeline logs show successful execution without permission errors.
Understanding /etc/passwd in Containers
The /etc/passwd file maps usernames to numeric UIDs. When you run a container, Linux kernel permission checks use numeric UIDs, not usernames. The container has its own /etc/passwd that's independent from the host's file.
Commands like useradd work by:
1. Creating a temporary file
2. Writing the new passwd data
3. Renaming the temp file to /etc/passwd
This rename fails if /etc/passwd is a mount point (individual file mount) rather than a regular file.
Rootless Docker vs Rootful Docker
In rootful Docker, UID 0 inside the container is UID 0 on the host (real root). In rootless Docker, UID 0 inside the container maps to your unprivileged host UID (e.g., 1000). This is more secure but causes permission mismatches.
Check your mode:
# Rootless shows your user's home path
docker info | grep "Docker Root Dir"
# Rootless: /home/user/.local/share/docker
# Rootful: /var/lib/dockerUser Namespace Mapping
With user namespaces, container UIDs are mapped to different host UIDs:
- Container UID 0 -> Host UID 100000 (example)
- Container UID 1000 -> Host UID 101000
This mapping is defined in /etc/subuid and /etc/subgid.
Security Considerations
Avoid these insecure workarounds:
- Running containers with --privileged just to fix permission issues
- Disabling SELinux (setenforce 0) instead of fixing policies
- Using chmod 777 on host directories
Instead, properly configure user mappings and security contexts.
Container Runtimes Comparison
| Runtime | User Namespace | SELinux Support | Notes |
|---------|---------------|-----------------|-------|
| Docker (rootful) | Optional | Yes | Traditional mode |
| Docker (rootless) | Always | Limited | More secure, more complex |
| Podman | Default | Yes | :U and :Z options |
| Containerd | Configurable | Yes | Lower-level runtime |
CI/CD Specific Issues
CI/CD systems often use restricted container runtimes. If you encounter this error in CI:
1. Check if the CI system uses rootless containers
2. Avoid runtime user creation; create users in Dockerfile
3. Use docker-in-docker (dind) carefully with proper volume mounts
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
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
yaml: line X: found character that cannot start any token
How to fix 'found character that cannot start any token' in Docker Compose