Q: Why should containers run as a non-root user?
Answer:
By default, the process inside a Docker container runs as root (UID 0). This is a significant security risk because if an attacker breaks out of the container (a container escape), they gain root access to the host machine.
The Risk
# ❌ Default: runs as root
FROM node:20-alpine
WORKDIR /app
COPY . .
CMD ["node", "index.js"]
# Inside the container: whoami → root
If someone exploits a vulnerability in your Node.js app, they have root-level access inside the container. Combined with a kernel exploit, this could mean root on the host.
The Fix: Create and Use a Non-Root User
FROM node:20-alpine
WORKDIR /app
# Create a non-root user and group
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Install deps as root (needs permissions)
COPY package*.json ./
RUN npm ci --only=production
# Copy app code
COPY . .
# Change ownership of app files to the non-root user
RUN chown -R appuser:appgroup /app
# Switch to non-root user for all subsequent commands
USER appuser
EXPOSE 3000
CMD ["node", "index.js"]
# Inside the container: whoami → appuser
Other Approaches
1. Use --user at runtime:
docker run --user 1000:1000 myapp
2. Use official base images that already set a non-root user:
Many official images (like node) include a pre-created user:
FROM node:20-alpine
USER node # Built-in non-root user
3. Read-only filesystem:
docker run --read-only --tmpfs /tmp myapp
This prevents any writes to the container filesystem, further limiting attack surface.
Additional Hardening
# Drop all Linux capabilities, add back only what's needed
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp
# Prevent privilege escalation
docker run --security-opt no-new-privileges myapp
[!TIP] In Kubernetes, you enforce this via
securityContextin the Pod spec:securityContext: runAsNonRoot: true runAsUser: 1000 readOnlyRootFilesystem: true