180 lines
5.4 KiB
Plaintext
180 lines
5.4 KiB
Plaintext
![]() |
Running containers as a privileged user weakens their runtime security,
|
||
|
allowing any user whose code runs on the container to perform administrative
|
||
|
actions. +
|
||
|
In Linux containers, the privileged user is usually named `root`. In Windows containers, the equivalent is `ContainerAdministrator`.
|
||
|
|
||
|
A malicious user can run code on a system either thanks to actions that could
|
||
|
be deemed legitimate - depending on internal business logic or operational
|
||
|
management shells - or thanks to malicious actions. For example, with arbitrary
|
||
|
code execution after exploiting a service that the container hosts.
|
||
|
|
||
|
Suppose the container is not hardened to prevent using a shell, interpreter, or
|
||
|
https://man7.org/linux/man-pages/man7/capabilities.7.html[Linux capabilities].
|
||
|
In this case, the malicious user can read and exfiltrate any file (including
|
||
|
from Docker volumes), open new network connections, install malicious software,
|
||
|
or, worse, break out of the container's isolation context by exploiting other
|
||
|
components.
|
||
|
|
||
|
Depending on the infrastructure's resilience, attackers may then extend their
|
||
|
attack to other services, such as Kubernetes clusters or cloud providers, in
|
||
|
order to maximize their reach.
|
||
|
|
||
|
== Ask Yourself Whether
|
||
|
|
||
|
This container:
|
||
|
|
||
|
* Serves internet-facing services.
|
||
|
* Does not require a privileged user to run.
|
||
|
|
||
|
There is a risk if you answered yes to any of those questions.
|
||
|
|
||
|
== Recommended Secure Coding Practices
|
||
|
|
||
|
In the Dockerfile:
|
||
|
|
||
|
* Create a new default user and use it with the `USER` statement.
|
||
|
** Some container maintainers create a specific user to be used without explicitly setting it as default, such as `postgresql` or `zookeeper`. It is recommended to use these users instead of root.
|
||
|
** On Windows containers, the `ContainerUser` is available for this purpose.
|
||
|
|
||
|
Or, at launch time:
|
||
|
|
||
|
* Use the `user` argument when calling Docker or in the docker-compose file.
|
||
|
* Add fine-grained Linux capabilities to perform specific actions that require root privileges.
|
||
|
|
||
|
If this image is already explicitly set to launch with a non-privileged user, you can
|
||
|
add it to the safe images list rule property of your SonarQube instance, without the tag.
|
||
|
|
||
|
== Sensitive Code Example
|
||
|
|
||
|
For any image that does not provide a user by default, regardless of their
|
||
|
underlying operating system:
|
||
|
|
||
|
[source,docker]
|
||
|
----
|
||
|
# Sensitive
|
||
|
FROM alpine
|
||
|
|
||
|
ENTRYPOINT ["id"]
|
||
|
----
|
||
|
|
||
|
For multi-stage builds, the last stage is non-compliant if it does not contain
|
||
|
the `USER` instruction with a non-root user:
|
||
|
|
||
|
[source,docker]
|
||
|
----
|
||
|
FROM alpine as builder
|
||
|
COPY Makefile ./src /
|
||
|
RUN make build
|
||
|
USER nonroot
|
||
|
|
||
|
# Sensitive, previous user settings are dropped
|
||
|
FROM alpine as runtime
|
||
|
COPY --from=builder bin/production /app
|
||
|
ENTRYPOINT ["/app/production"]
|
||
|
----
|
||
|
|
||
|
|
||
|
== Compliant Solution
|
||
|
|
||
|
For Linux-based images:
|
||
|
|
||
|
[source,docker]
|
||
|
----
|
||
|
FROM alpine
|
||
|
|
||
|
RUN addgroup -S nonroot \
|
||
|
&& adduser -S nonroot -G nonroot
|
||
|
|
||
|
USER nonroot
|
||
|
|
||
|
ENTRYPOINT ["id"]
|
||
|
----
|
||
|
|
||
|
For Windows-based images, you can use `ContainerUser` or create a new user:
|
||
|
|
||
|
[source,docker]
|
||
|
----
|
||
|
FROM mcr.microsoft.com/windows/servercore:ltsc2019
|
||
|
|
||
|
RUN net user /add nonroot
|
||
|
|
||
|
USER nonroot
|
||
|
----
|
||
|
|
||
|
If the `scratch` Dockerfile untars a Linux distribution, the "Linux image"
|
||
|
solution should be applied. Else, you have a choice between using a pre-written
|
||
|
`/etc/passwd` file (regardless of the host operating system) or using a
|
||
|
multi-stage build.
|
||
|
|
||
|
[source,docker]
|
||
|
----
|
||
|
FROM scratch
|
||
|
|
||
|
COPY etc_passwd /etc/passwd
|
||
|
# contains "nonroot:x:1337:1337:nonroot:/nonroot:/usr/sbin/nologin"
|
||
|
|
||
|
USER nonroot
|
||
|
|
||
|
COPY production_binary /app
|
||
|
|
||
|
ENTRYPOINT ["/app/production_binary"]
|
||
|
----
|
||
|
|
||
|
or you can use a multi-stage build:
|
||
|
|
||
|
[source,docker]
|
||
|
----
|
||
|
FROM alpine:latest as security_provider
|
||
|
RUN addgroup -S nonroot \
|
||
|
&& adduser -S nonroot -G nonroot
|
||
|
|
||
|
FROM scratch as production
|
||
|
COPY --from=security_provider /etc/passwd /etc/passwd
|
||
|
USER nonroot
|
||
|
COPY production_binary /app
|
||
|
ENTRYPOINT ["/app/production_binary"]
|
||
|
----
|
||
|
|
||
|
|
||
|
For multi-stage builds:
|
||
|
[source,docker]
|
||
|
----
|
||
|
FROM alpine as builder
|
||
|
COPY Makefile ./src /
|
||
|
RUN make build
|
||
|
|
||
|
FROM alpine as runtime
|
||
|
RUN addgroup -S nonroot \
|
||
|
&& adduser -S nonroot -G nonroot
|
||
|
COPY --from=builder bin/production /app
|
||
|
USER nonroot
|
||
|
ENTRYPOINT ["/app/production"]
|
||
|
----
|
||
|
|
||
|
== See
|
||
|
|
||
|
* https://cwe.mitre.org/data/definitions/284.html[MITRE, CWE-284] - Improper Access Control
|
||
|
* https://hub.docker.com/r/nginxinc/nginx-unprivileged[nginxinc/nginx-unprivileged: Example of a non-root container by default]
|
||
|
* https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/container-security#when-to-use-containeradmin-and-containeruser-user-accounts[Microsoft docs, When to use ContainerAdmin and ContainerUser user accounts]
|
||
|
|
||
|
ifdef::env-github,rspecator-view[]
|
||
|
|
||
|
'''
|
||
|
== Implementation Specification
|
||
|
(visible only on this page)
|
||
|
|
||
|
=== Message
|
||
|
|
||
|
* Noncompliant scratch images: "Scratch images run as root by default. Make sure it is safe here."
|
||
|
* Official noncompliant image: "The `image` image runs with root as the default user. Make sure it is safe here."
|
||
|
* Microsoft non-compliant images: "This image runs with root or containerAdministrator as the default user. Make sure it is safe here."
|
||
|
* Unofficial noncompliant image: "This image might run with root as the default user. Make sure it is safe here."
|
||
|
* The last USER is root or containerAdministrator: "Setting the default user as root might unnecessarily make the application unsafe. Make sure it is safe here."
|
||
|
|
||
|
=== Highlighting
|
||
|
|
||
|
* Unsafe FROM: "FROM name" instruction
|
||
|
* Last USER is root or containerAdministrator: "USER name" instruction
|
||
|
|
||
|
endif::env-github,rspecator-view[]
|