170 lines
5.6 KiB
Plaintext
170 lines
5.6 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
|
|
Docker volumes), open new network connections, install malicious software, or,
|
|
worse, break out of the container's isolation context by exploiting other
|
|
components.
|
|
|
|
This means giving the possibility to attackers to steal important
|
|
infrastructure files, intellectual property, or personal data.
|
|
|
|
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 services accessible from the Internet.
|
|
* 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 and scratch-based images that untar a Linux
|
|
distribution:
|
|
|
|
[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
|
|
----
|
|
|
|
For multi-stage builds, the non-root user should be on the last stage:
|
|
|
|
[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"]
|
|
----
|
|
|
|
For images that use `scratch` as their base, it is not possible to add non-privileged
|
|
users by default. To do this, add an additional build stage to add the group
|
|
and user, and later copy `/etc/passwd`.
|
|
|
|
Here is an example that uses `adduser` in the first stage to generate a user and add it to the `/etc/passwd` file. In the next stage, this user is added by copying that file over from the previous stage:
|
|
|
|
[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"]
|
|
----
|
|
|
|
== See
|
|
|
|
* CWE - https://cwe.mitre.org/data/definitions/284[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[]
|