Docker: Using the non-root approach to enforce container security

Docker: Using the non-root approach to enforce container security

·

2 min read

Running containers such as non-root is one of the most popular best practices for security.

This approach prevents malicious code from gaining permissions in the container host. It also allows running containers on Kubernetes distributions that don’t allow running containers as root, such as OpenShift. For more information about the reasons to use a non-root container, check these blog posts:

To convert the Docker image into a non-root container, change the default user from root to nonroot:

...
EXPOSE 80
+ useradd -r -u 1001 -g nonroot root
+ USER nonroot
CMD ["node", "/app/server.js"]
...

Tip

Add the nonroot user to the root group.

Take these details into consideration when moving a container to non-root:

  • File permissions: What directories should be writable by the application? Adapt them by giving writing permissions to the non-root users. Check Linux Wiki for more information about changing permissions.

  • Port access: You cannot use privileged (1-1023) ports anymore.

  • Debugging: You cannot perform any action that requires privileged permissions for debugging purposes.

Tip

It is important to understand that you should not move a container to a non-root approach and then use sudo to gain higher-lever privileges, as this defeats the purpose of using a non-root approach. Similarly, you should also ensure that the non-root user account is not part of the sudoers group, to maximize security and avoid any risk of it obtaining root privileges.

Our sample application uses port 80 to listen for connections. Adapt it to use an alternative port such as 8080:

  • Dockerfile:

      ...
      COPY --from=builder /tiller-proxy /proxy
      - EXPOSE 80
      + EXPOSE 8080
      RUN useradd -r -u 1001 -g root nonroot
      ...
    
  • server.js:

      ...
      const serverHost = '127.0.0.1';
      - const serverPort = 80;
      + const serverPort = 8080;
      ...
    

On the other hand, the application writes its log in the /var/log/app.log file. Give permissions to the nonroot user on that directory:

...
RUN useradd -r -u 1001 -g root nonroot
EXPOSE 80
+ RUN chmod -R g+rwX /var/log
USER nonroot
...

Test it:

$ docker build . -t express-image:0.0.7
$ docker run --rm -p 8080:8080 -d express-image:0.0.7
$ curl http://127.0.0.1:8080
Hello world
$ docker exec express-app whoami
nonroot
$ docker stop express-app

As you can see, everything is working as expected and now your container is not running as root anymore.