Running Non-Root User in Docker: Security Best Practice for Java
Fast recall
Quick revision
Core answer
Security awareness in containerized Java deployments — a common finding in security audits
Forgetting to chown application files to the new user — the app fails to start because it can't write to its working directory
Mention read-only root filesystem (--read-only), explain capabilities dropping, discuss distroless images (no shell = reduced attack surface), and show how Kubernetes SecurityContext enforces non-root
Interview-ready guide
Interview answer
By default, Docker containers run as root inside the container. If a vulnerability in your application allows container escape, a root container gives an attacker far more capability than a non-root process would. The fix is two lines in your Dockerfile.
Creating and using a non-root user
- In the runtime stage of your Dockerfile, add
RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuserthenUSER appuser— all subsequent instructions and the CMD run as that user - The application directory must be owned by the non-root user:
COPY --chown=appuser:appgroup target/app.jar /app/app.jar— without the--chown, the binary is owned by root and the non-root process cannot read it - Use a specific numeric UID in Kubernetes environments with PodSecurityContext:
runAsUser: 10001— Kubernetes admission controllers and PSP/PSA configurations often require non-root UIDs, and named users are only meaningful within the container's own/etc/passwd
File permission requirements
- A Spring Boot application with an embedded Tomcat writes temporary files to the system's temp directory by default — ensure the non-root user has write access to
/tmpor configureserver.tomcat.basedirto a path the user owns - JVM crash logs and heap dumps require a writable directory; set
-XX:ErrorFile=/tmp/hs_err_%p.logand-XX:HeapDumpPath=/tmp/heap_dump.hprofto paths the appuser can write - The most common runtime failure after adding a non-root user: the application tries to write to a path owned by root and throws
java.io.IOException: Permission denied— test the container explicitly withdocker run --user appuserbefore pushing to production
Defense in depth
- Non-root is one layer; also combine it with read-only filesystem (
--read-onlyflag), dropped Linux capabilities (--cap-drop=ALL), and no-new-privileges (--security-opt no-new-privileges=true) for a hardened production container - These controls together prevent an attacker from writing executables, escalating privileges, or loading kernel modules even if they achieve code execution inside the container
Running Non-Root User in Docker: Security Best Practice for Java
Direct Answer
Running as root in Docker is a security risk — if the container is compromised, the attacker has root access to the container filesystem and potentially the host if the container escapes. Create a dedicated user in the Dockerfile with RUN adduser, set it with USER instruction before ENTRYPOINT, and ensure the application directory is owned by that user.
Common Mistakes & Pitfalls
Forgetting to chown application files to the new user — the app fails to start because it can't write to its working directory
Check your understanding
Answer these without looking back at the article.
- What are Linux capabilities and why does dropping them improve security?
- What is a distroless container image and what are its security advantages?
- How does readOnlyRootFilesystem in Kubernetes work with Spring Boot's need for temp directories?
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.