Module 7 Lesson 2: Running as Non-Root
·DevOps

Module 7 Lesson 2: Running as Non-Root

Break the 'Root' habit. Learn why running containers as the administrator is the biggest risk in Docker and how to implement a secure USER instruction.

Module 7 Lesson 2: Running as Non-Root

By default, Docker containers run as the root user (ID 0). In Linux, root has the power to do anything. If an attacker finds a vulnerability in your code (e.g., a file upload bug) and they are running as root, they might be able to find a way to escape the container and take over your entire server.

1. The Risk: Escalation and Escape

If a process is root inside a container, it is "kind of" root on the host too.

  • If you mount a sensitive folder (like /etc/shadow) with a bind mount, the root container can add or delete users on your actual laptop/server.
  • Many security "Exploits" rely on having root access to load malicious drivers or change system settings.

2. The Solution: The USER Instruction

You should always create a "Unprivileged" user in your Dockerfile and switch to them before the CMD starts.

FROM python:3.9-slim

# 1. Create a non-root group and user
RUN groupadd -r appgroup && useradd -r -g appgroup appuser

# 2. Setup your app (still as root so you can install things)
WORKDIR /home/appuser
COPY . .
RUN chown -R appuser:appgroup /home/appuser

# 3. SWITCH to the user
USER appuser

# 4. Start the app (now running as appuser)
CMD ["python", "app.py"]

3. The "Permissions" Headache

Once you switch to a non-root user, you will face "Permission Denied" errors.

  • Solution: You must chown (change owner) the files your app needs to work with before you switch to the user.
  • Ports: Non-root users cannot listen on ports below 1024 (like 80 or 443).
    • The Workaround: Have your app listen on port 8080 and use Docker's port mapping (-p 80:8080) to map it to the outside.

4. Overriding at Runtime

You can also force a specific user ID when you start a container using the --user flag.

docker run --user 1000 node:alpine id

(This is often used in CI/CD pipelines to match the UID of the build server).


Exercise: The Permission Test

  1. Run docker run alpine whoami. What is the result?
  2. Now, write a Dockerfile that:
    • Starts from alpine.
    • Adds a user named security_intern.
    • Uses the USER instruction to switch to them.
    • Runs whoami as the final command.
  3. Build and run it. What is the result?
  4. Try to run apk add curl as that user using docker exec. Does it work? Why is this good for security?

Summary

Running as non-root is the #1 defense against "Container Escape" attacks. While it requires a bit more work in your Dockerfile to handle permissions, it is the standard for any professional or financial application.

Next Lesson: Automated defense: Image scanning and vulnerability management.

Subscribe to our newsletter

Get the latest posts delivered right to your inbox.

Subscribe on LinkedIn