- Release Signoff Checklist
- Summary
- Motivation
- Proposal
- Workload Context
- Test Plan
- Scoring
- Implementation History
Items marked with (R) are required for the proposed best practice to be included in a release.
- (R) CBPP approvers have approved the CBPP status as
implementable
- (R) CBPP summary, motivation and best practice details are appropriately documented
- (R) Test plan is in place, giving consideration to CNF Test Suite input
- (R) Scoring has been determined
- "Implementation History" section is up-to-date
- Supporting documentation—e.g., additional design documents, links to mailing list discussions/SIG meetings, relevant PRs/issues, release notes
Containers have a list of their own users independent of the host system, one of which is UID 0, the root user. Containers should run processes as a user other than root which makes it easier to run the container images securely.
This best practice benefits the CNF developer, improving the quality of the CNF and reducing the developer's likelihood of having to diagnose problems with the CNF. Validation of the best practice is the responsibility of the CNF developer.
Indirectly, improved CNF quality benefits CNF operators. The proposed tests are runnable by CNF operators as acceptance tests.
SE-Linux based environments will require dropping root privileges. Example: OpenShift
Avoiding root in containers can help to:
- Improve the security and behaviour of applications.
- Add to the defense in depth strategy against external compromises.
- Avoid compromised apps from causing more damage.
This BP recommends that the application not use the UID that can override all protections. This means that file read and write protections can be established.
It does not consider what filesystem write permissions should be in order to benefit from those protections. CNF developers will additionally want to ensure filesystem permissions are tightened up appropriately so that non-root users are prevented from doing damage. This is outside the BP scope.
When building a container, the container should be built to run its processes as a non-root user. setsid processes should not be required to do the work inside a container.
A container's root user has fewer Linux Kernel capabilities and may be distinct from the platform's root (if the container runtime enables user namespaces remap feature).
However, the container's root user does have full read/write access to the container's filesystem. It can read or modify any file. No secrets can be kept from it; it cannot be prevented from changing the content of all executable files on the system.
On a basic level, avoiding the root user means that the container filesystem permissions are enforceable against all processes running in the system. Those processes can be prevented from doing critical things like:
- viewing secrets they should not be viewing
- modifying binaries within the filesystem that will later be executed
Obviously, a well-written CNF would not be attempting to do things it should not do. But all software has bugs. Also, executing processes can be compromised by outside forces, and if this happens filesystem protection is a part of a "Defense in depth" strategy to ensure the compromise does not escalate.
User/group access enforcement will be respected. As an added advantage, fine-grained access enforcement, such as in SELinux, will also hold
All pod types should implement this best practice.
Supply chain attacks are a risk at any point in the supply chain. ‘Defence in depth’ says that we should (a) defend against supply chain attacks but also (b) add mitigations in the case that supply chain attacks happen.
Examples include
- A CNF downloads compromised updates
- A CNF succumbs to code injection
- A CNF succumbs to malicious instructions
- A CNF has a security-compromising bug
In all of these examples, the CNFs using a non-root user for their container processes, have limited the scope of damage a compromised process may cause.
See main defense in depth for supply chain attacks document for more information.
Container images are frequently built from upstream image versions made from OS deployments. These will include things like setsid binaries as a part of their base configuration. If CNF developers follow this best practice they will have to audit and clean up any upstream images to respect this rule (removing files, removing packages or changing permissions as appropriate).
By default, the first process starting in a container runs as root - you have to actively take steps to shed the permissions (Dockerfile USER line, plus installing files with appropriate ownership within the Dockerfile).
We specifically want the process to run as a non-root user so that its access is limited. Of course, if access is limited then the CNF developer must ensure that access is still available to the things the CNF is going to need to access. This will involve changing permissions on data files and on working directories when the container image is constructed (they cannot be changed on startup because the application does not have the right to do that). This may also affect the use of shared volume mounts or host mounts - ownership of and rights on the root directory must permit access to the container users.
- CNF WG discussion
- TAG Security: Cloud Native Security Whitepaper - Least Privilege
- Sysdig: Top 20 Dockerfile best practices - 2021/03/09
- Best practices for pod security in Azure Kubernetes Service (AKS) - 2020/07/28
- RedHat OpenShift Runtime Security Best Practices
- K8s Documentation - Securing a Cluster: Controlling what privileges containers run with
- Security Best Practices for Kubernetes Deployment - 2016/08/31
- Docker and Kubernetes — root vs. privileged - 2020/06/25
- Bitnami on Use Non-Root Containers - 2020/05/13
- Running non-root containers on Openshift
- K8s 11 Ways Not to Get Hacked: 8. Run Containers as a Non-Root User
- Red Hat PDF A PRACTICAL INTRODUCTION TO CONTAINER SECURITY - 2017/05
- CVE-2019-5736: runc container breakout
- CVE-2022-0492: Linux kernel cgroups v1 missing capabilities check when setting release_agent
- Using the rootless containers in RHEL 2019/08
- Understanding root inside and outside a container 2019/12
These are not strictly alternatives as they can be used with non-root, but can be applied to a container running as root.
- Disable all capabilities or limit them
- Do not run the container in privileged mode
Related items include
- Rootless containers as seen with usernetes
- Alternative runtimes like Kata Containers for a different approach to security
An application which follows this best practice will not have any containers with processes running as root
This CBPP will be tested by the CNF Test Suite.
A container image can be tested for compliance:
- The container metadata should indicate that the first process started is started as a non-root user
- The container filesystem will not have setsid-root binaries.
If available, the Dockerfile can be checked to see if a non-root user is used. (Dockerfiles are not the only way to build containers, and the Dockerfile may not be a part of the CNF deliverable.)
- See USER and RUN commands, both of which allow the Dockerfile author to express which user is to be used when launching the container.
The above static analysis definitively confirms that a container cannot elevate privileges to local root as it removes all avenues for doing so.
One can check for processes launched as, or running as container root.
We offer the following applications as examples that operators might wish to evaluate for this purpose:
- Cnitch periodically checks the list of running containers in a Docker environment to see if any are running as container root.
- Falco checks for processes running as container root if the non-root container policy is set.
Scanning systems that periodically check running processes or may not identify all root-owned processes, as it must conduct a scan at the moment a process is running. Similarly, process monitoring will not identify a problem if behaviour requiring a root process is not triggered. This cannot be used as a definitive guarantee of safety but is useful as a secondary check.
This best practice results in a pass/fail on two counts, depending on role.
Static analysis (all items checked for a pass) - CNF developers (testing before delivery) or CNF operators (testing what is delivered):
- Container images indicate their processes should be started as a user other than 0
- Container images should not contain setsid-root binaries (user 0, u+s)
Runtime analysis - CNF operators:
- Operators may use runtime verification, from outside the application, to confirm that containers in processes are not owned by container root
First version: July 2021