Stage 4 · Provision
Registries & Security
Non-Root Containers
Run with USER, drop Linux capabilities, set read-only filesystems, and avoid privileged containers.
Why Non-Root?
Running containers as root gives the process full privileges inside the container. If an attacker exploits a vulnerability, they gain root access. Running as a non-root user limits the damage. Most container security standards require non-root execution.
Setting USER
FROM node:20-alpine
# Create a non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup . .
RUN npm ci --production
# Switch to non-root user
USER appuser
CMD ["node", "server.js"]The USER instruction switches the execution context. All subsequent instructions and the container's CMD run as appuser. The --chown flag on COPY sets correct ownership.
# Run as a specific user
docker run --user 1000:1000 myapp
# Run as root temporarily (for debugging)
docker run --user root myapp
# Verify the running user
docker exec myapp whoami
docker exec myapp idThe --user flag overrides the Dockerfile's USER instruction. Use it to run as different users for testing or debugging.
Linux Capabilities
Linux capabilities break root privileges into distinct units. Docker grants containers a subset of capabilities by default. You can drop all capabilities and add only what is needed, following the principle of least privilege.
# Drop all capabilities, add only what's needed
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp
# Common capabilities
# NET_BIND_SERVICE — bind to ports below 1024
# CHOWN — change file ownership
# SETUID / SETGID — change user/group IDs
# SYS_PTRACE — debug processes (dangerous)
# Run with no new privileges
docker run --security-opt no-new-privileges myappNET_BIND_SERVICE allows binding to ports below 1024 without root. Most applications need only a few capabilities. Drop all and add specific ones.
--privileged gives the container nearly full host access, including all devices and capabilities. It bypasses all security mechanisms. Only use it for Docker-in-Docker or specific system administration tasks.
Read-Only Filesystem
A read-only filesystem prevents containers from writing to the image layers. This stops attackers from modifying binaries or planting malware. Use tmpfs for directories that need write access.
# Read-only filesystem
docker run --read-only myapp
# Allow writes to specific directories
docker run --read-only \
--tmpfs /tmp:rw,noexec \
--tmpfs /var/run:rw \
myapp
# In Dockerfile, handle writable directories
RUN mkdir -p /tmp/app && chown appuser /tmp/appRead-only filesystems prevent modifications to the container. /tmp and /var/run are common exceptions that need write access. --tmpfs mounts memory-backed filesystems for these directories.
Privileged Containers
Privileged containers bypass all security mechanisms. They can access host devices, load kernel modules, and modify system settings. They are equivalent to root on the host. Avoid them in production.
| Flag | Effect | Use Case |
|---|---|---|
| --privileged | Full host access, all capabilities | Docker-in-Docker, system admin |
| --cap-drop ALL | No capabilities | Maximum isolation |
| --cap-add X | Add specific capability | Minimal required privileges |
| --security-opt no-new-privileges | Prevent privilege escalation | Always use this |
Security Checklist
- Run as non-root user with USER instruction
- Drop all capabilities and add only needed ones
- Use read-only filesystem with tmpfs for writable paths
- Never use --privileged in production
- Set no-new-privileges security option
- Scan images with Trivy for vulnerabilities
- Sign images with Cosign
- Use distroless or minimal base images
- Remove setuid/setgid binaries from the image
- Limit container resources with --memory and --cpus
No single security measure is sufficient. Combine non-root execution, dropped capabilities, read-only filesystems, and vulnerability scanning. Each layer reduces the attack surface independently.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.