From af5edf3a28daeb31d4c80771a0dfafa9febb01f4 Mon Sep 17 00:00:00 2001 From: thespad Date: Thu, 5 Dec 2024 20:19:13 +0000 Subject: [PATCH 1/7] Initial non-root docs --- docs/misc/non-root.md | 60 +++++++++++++++++++++++++++++++++++++ docs/misc/support-policy.md | 3 +- 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 docs/misc/non-root.md diff --git a/docs/misc/non-root.md b/docs/misc/non-root.md new file mode 100644 index 000000000..e8a630102 --- /dev/null +++ b/docs/misc/non-root.md @@ -0,0 +1,60 @@ +# Running Containers As A Non-Root User + +!!! warning + Running containers as a non-root user is an advanced topic and should not be undertaken without a full understanding of everything documented below. + +## What? + +If you run one of our typical images in a standard Docker setup, the container itself will run as `root`. After init we then drop to an unprivileged user, `abc` to run the actual application service(s). We do this because at the time we designed our architecture the alternative - setting a fixed unprivileged user at build time - would have prevented us from offering the range of options that wanted to. While it is now possible to use the `--user` parameter to run any container as an arbitrary user, it hasn't been something we've been able to support before now. + +## Why? + +Some people take the position that a container running as root *at any point* is an unacceptable security risk. Those people typically misunderstand the attack surface of containers and where the risks actually lie. Having said that, there *are* some risks with having containers running as root; generally, a better solution to running every container as an unprivileged user is to run Docker itself rootless, but that's not always desirable. In these situations, being able to run a single container as a unprivileged user has its benefits. + +To give you some sense of a potential risk, let's take our SabNZBd image and let's imagine you've exposed it to the internet and for some reason allowed unauthenticated access. Now let's assume a user were to discover a Remote Code Execution vulnerability in SabNZBd, and were able to exploit it to get a shell in the container (not a simple task, but let's be generous). At this point you have a shell running as the unprivileged `abc` account, which heavily limits what you can do. There's no sudo/doas in the container so you'd likely need to chain a Privilege Escalation vulnerability (within the limited set of packages installed) to get root. Even at that point, with root access inside the container, you would then need a further Container Escape vulnerability in order to do anything meaningful to the host beyond simply deleting or modifying data in a mounted path (which you could do as a non-root user anyway). That said, some of our containers do require additional Capabilities to run, and these *could* be exploited by a user with root to affect the host in various ways. + +## How? + +Creating a container with `--user :` or: + +```yaml +services: + somecontainer: + image: someimage + user: : +``` + +Will run the container as that user, and that cannot then be changed without recreating it. It's never quite that simple, however. + +Our images use s6 as a supervisor and that needs to be able to write its service files to `/run`; many applications expect to be able to write to their working directory, changing UIDs and GIDs requires writing to `/etc/passwd` & `/etc/group`, installing new packages requires writing to numerous locations, and mods need to be extracted to the container filesystem. In short, there are some heavy limitations around operation of our images with a non-root user: + +* The PUID & PGID variables will not have any effect, the container will instead run applications with the UID & GID of the user you have specified +* You will need to manually manage the permissions of any mounted volumes or paths +* Docker Mods will not be run +* Custom Services will not be run +* Custom Scripts will be limited in their functionality + +For all of these reasons, we recommend you *do not* switch existing container instances to run with a non-root user without careful testing. + +For example: + +```yaml +services: + sonarr: + image: lscr.io/linuxserver/sonarr:latest + container_name: sonarr + environment: + - TZ=Europe/London + volumes: + - /path/to/sonarr/data:/config + - /path/to/tvseries:/tv + - /path/to/downloadclient-downloads:/downloads + ports: + - 8989:8989 + restart: unless-stopped + user: 1000:1000 +``` + +## Support Policy + +Operation of our images with a non-root user is supported on a Reasonable Endeavours basis and *only* for images which we have specifically tested. These images will have their ability to be run with a non-root user noted in the readme, along with any additional caveats. Please see our [Support Policy](https://linuxserver.io/supportpolicy) for more details. diff --git a/docs/misc/support-policy.md b/docs/misc/support-policy.md index b4bf2ea3c..a07d13e71 100644 --- a/docs/misc/support-policy.md +++ b/docs/misc/support-policy.md @@ -57,7 +57,6 @@ The following configurations are entirely unsupported and we will not provide he The following configurations are entirely unsupported and you are unlikely to be able to get them to work at all, or experience serious issues if you do: -* Use of the `user` directive to run containers as a custom UID/GID * Use of a custom `init` for Docker * Overriding container entrypoints @@ -67,9 +66,11 @@ The following configurations don't fit nicely into any single category because " * Running our containers with a root (`0`) PUID or PGID * Running our containers with a read-only container filesystem. Please [read the docs](https://docs.linuxserver.io/misc/read-only/). +* Use of the `user` directive to run containers as a custom UID/GID. Please [read the docs](https://docs.linuxserver.io/misc/non-root/). ## Change History +* 2024-12-05 - Move non-root users to Weird Exceptions * 2024-06-13 - Add read-only running * 2024-02-13 - Add Weird Exceptions section * 2024-02-05 - Add ipvlan/macvlan networks From 93c5d0a7ef5e381a01a99f0399f80e4cfd60eaef Mon Sep 17 00:00:00 2001 From: thespad Date: Thu, 5 Dec 2024 20:30:24 +0000 Subject: [PATCH 2/7] Fix casing --- docs/misc/non-root.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/misc/non-root.md b/docs/misc/non-root.md index e8a630102..6784a7431 100644 --- a/docs/misc/non-root.md +++ b/docs/misc/non-root.md @@ -11,7 +11,7 @@ If you run one of our typical images in a standard Docker setup, the container i Some people take the position that a container running as root *at any point* is an unacceptable security risk. Those people typically misunderstand the attack surface of containers and where the risks actually lie. Having said that, there *are* some risks with having containers running as root; generally, a better solution to running every container as an unprivileged user is to run Docker itself rootless, but that's not always desirable. In these situations, being able to run a single container as a unprivileged user has its benefits. -To give you some sense of a potential risk, let's take our SabNZBd image and let's imagine you've exposed it to the internet and for some reason allowed unauthenticated access. Now let's assume a user were to discover a Remote Code Execution vulnerability in SabNZBd, and were able to exploit it to get a shell in the container (not a simple task, but let's be generous). At this point you have a shell running as the unprivileged `abc` account, which heavily limits what you can do. There's no sudo/doas in the container so you'd likely need to chain a Privilege Escalation vulnerability (within the limited set of packages installed) to get root. Even at that point, with root access inside the container, you would then need a further Container Escape vulnerability in order to do anything meaningful to the host beyond simply deleting or modifying data in a mounted path (which you could do as a non-root user anyway). That said, some of our containers do require additional Capabilities to run, and these *could* be exploited by a user with root to affect the host in various ways. +To give you some sense of a potential risk, let's take our SABnzbd image and let's imagine you've exposed it to the internet and for some reason allowed unauthenticated access. Now let's assume a user were to discover a Remote Code Execution vulnerability in SABnzbd, and were able to exploit it to get a shell in the container (not a simple task, but let's be generous). At this point you have a shell running as the unprivileged `abc` account, which heavily limits what you can do. There's no sudo/doas in the container so you'd likely need to chain a Privilege Escalation vulnerability (within the limited set of packages installed) to get root. Even at that point, with root access inside the container, you would then need a further Container Escape vulnerability in order to do anything meaningful to the host beyond simply deleting or modifying data in a mounted path (which you could do as a non-root user anyway). That said, some of our containers do require additional Capabilities to run, and these *could* be exploited by a user with root to affect the host in various ways. ## How? From 6952508f8fefab9023402031acc27fcc095072c6 Mon Sep 17 00:00:00 2001 From: thespad Date: Thu, 5 Dec 2024 20:30:32 +0000 Subject: [PATCH 3/7] Remove PUID/PGID from example --- docs/misc/read-only.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/misc/read-only.md b/docs/misc/read-only.md index 538597cbb..3fb1568e9 100644 --- a/docs/misc/read-only.md +++ b/docs/misc/read-only.md @@ -57,8 +57,6 @@ services: image: lscr.io/linuxserver/sonarr:latest container_name: sonarr environment: - - PUID=1000 - - PGID=1000 - TZ=Europe/London volumes: - /path/to/sonarr/data:/config From 082ddefa773e9005a2e56a479a8f3895a13f5266 Mon Sep 17 00:00:00 2001 From: thespad Date: Fri, 6 Dec 2024 13:37:10 +0000 Subject: [PATCH 4/7] Remove `version` key from examples --- docs/general/docker-compose.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/general/docker-compose.md b/docs/general/docker-compose.md index bab31103a..a5958b591 100644 --- a/docs/general/docker-compose.md +++ b/docs/general/docker-compose.md @@ -37,7 +37,6 @@ As v2 runs as a plugin instead of a standalone binary, it is invoked by `docker Here's a basic example for deploying a Linuxserver container with docker compose: ```yaml -version: "2.1" services: heimdall: image: linuxserver/heimdall @@ -67,7 +66,6 @@ You can have multiple services managed by a single compose yaml. Copy the conten Let's say you have the following in a yaml file named `compose.yml`: ```yaml -version: "2.1" services: heimdall: image: linuxserver/heimdall From 13fe09ce3587162b85a677a6a042971cf6f28d9a Mon Sep 17 00:00:00 2001 From: thespad Date: Fri, 6 Dec 2024 13:37:19 +0000 Subject: [PATCH 5/7] Add note about rootless --- docs/misc/non-root.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/misc/non-root.md b/docs/misc/non-root.md index 6784a7431..ebf5e38dc 100644 --- a/docs/misc/non-root.md +++ b/docs/misc/non-root.md @@ -7,6 +7,8 @@ If you run one of our typical images in a standard Docker setup, the container itself will run as `root`. After init we then drop to an unprivileged user, `abc` to run the actual application service(s). We do this because at the time we designed our architecture the alternative - setting a fixed unprivileged user at build time - would have prevented us from offering the range of options that wanted to. While it is now possible to use the `--user` parameter to run any container as an arbitrary user, it hasn't been something we've been able to support before now. +The other approach is to run [Docker itself rootless](https://docs.docker.com/engine/security/rootless/). This creates a separate user and network namespace for your containers that separates them from the host and means that even containers nominally running as `root` don't have root permissions on your host. + ## Why? Some people take the position that a container running as root *at any point* is an unacceptable security risk. Those people typically misunderstand the attack surface of containers and where the risks actually lie. Having said that, there *are* some risks with having containers running as root; generally, a better solution to running every container as an unprivileged user is to run Docker itself rootless, but that's not always desirable. In these situations, being able to run a single container as a unprivileged user has its benefits. From 046d8465aa87f9a06afbf5a140e8e351e0c51cb9 Mon Sep 17 00:00:00 2001 From: thespad Date: Fri, 6 Dec 2024 13:46:19 +0000 Subject: [PATCH 6/7] Add disambiguation, tweak wording --- docs/misc/non-root.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/misc/non-root.md b/docs/misc/non-root.md index ebf5e38dc..d7f27e376 100644 --- a/docs/misc/non-root.md +++ b/docs/misc/non-root.md @@ -7,13 +7,13 @@ If you run one of our typical images in a standard Docker setup, the container itself will run as `root`. After init we then drop to an unprivileged user, `abc` to run the actual application service(s). We do this because at the time we designed our architecture the alternative - setting a fixed unprivileged user at build time - would have prevented us from offering the range of options that wanted to. While it is now possible to use the `--user` parameter to run any container as an arbitrary user, it hasn't been something we've been able to support before now. -The other approach is to run [Docker itself rootless](https://docs.docker.com/engine/security/rootless/). This creates a separate user and network namespace for your containers that separates them from the host and means that even containers nominally running as `root` don't have root permissions on your host. +The other approach is to run [Docker itself rootless](https://docs.docker.com/engine/security/rootless/). This creates a separate user and network namespace for your containers that separates them from the host and means that even containers nominally running as `root` don't have root permissions on your host. Running a container as a non-root user and running it rootless are **not** the same, but are commonly conflated. ## Why? -Some people take the position that a container running as root *at any point* is an unacceptable security risk. Those people typically misunderstand the attack surface of containers and where the risks actually lie. Having said that, there *are* some risks with having containers running as root; generally, a better solution to running every container as an unprivileged user is to run Docker itself rootless, but that's not always desirable. In these situations, being able to run a single container as a unprivileged user has its benefits. +Some people take the position that a container running as root *at any point in any configuration* is an unacceptable security risk. Those people typically misunderstand the attack surface of containers and where the risks actually lie. Having said that, there *are* some risks with having containers running as root, depending on the environment; generally, a better solution to running every container as an unprivileged user is to run Docker itself rootless, but that's not always desirable. In these situations, being able to run a single container as a unprivileged user has its benefits. -To give you some sense of a potential risk, let's take our SABnzbd image and let's imagine you've exposed it to the internet and for some reason allowed unauthenticated access. Now let's assume a user were to discover a Remote Code Execution vulnerability in SABnzbd, and were able to exploit it to get a shell in the container (not a simple task, but let's be generous). At this point you have a shell running as the unprivileged `abc` account, which heavily limits what you can do. There's no sudo/doas in the container so you'd likely need to chain a Privilege Escalation vulnerability (within the limited set of packages installed) to get root. Even at that point, with root access inside the container, you would then need a further Container Escape vulnerability in order to do anything meaningful to the host beyond simply deleting or modifying data in a mounted path (which you could do as a non-root user anyway). That said, some of our containers do require additional Capabilities to run, and these *could* be exploited by a user with root to affect the host in various ways. +To give you some sense of the scope of potential risk, let's take our SABnzbd image, imagine you've exposed it to the internet, and for some reason allowed unauthenticated access. Now let's assume a user were to discover a Remote Code Execution vulnerability in SABnzbd, and were able to exploit it to get a shell in the container (not a simple task, but let's be generous). At this point they have a shell running as the unprivileged `abc` account, which heavily limits what they can do. There's no sudo/doas in the container so they'd likely need to chain a Privilege Escalation vulnerability (within the limited set of packages installed) to get root. Even at that point, with root access inside the container, they would then need a further Container Escape vulnerability in order to do anything meaningful to the host beyond simply deleting or modifying data in a mounted path (which they could do as a non-root user anyway). That said, some of our containers do require additional Capabilities to run, and these *could* be exploited by a user with root to affect the host in various ways. ## How? From d52930c020d2db640e707703bfbd8bcd3b00bc38 Mon Sep 17 00:00:00 2001 From: thespad Date: Thu, 12 Dec 2024 18:43:16 +0000 Subject: [PATCH 7/7] Tweak wording and example --- docs/misc/non-root.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/misc/non-root.md b/docs/misc/non-root.md index d7f27e376..0611d0c88 100644 --- a/docs/misc/non-root.md +++ b/docs/misc/non-root.md @@ -7,7 +7,7 @@ If you run one of our typical images in a standard Docker setup, the container itself will run as `root`. After init we then drop to an unprivileged user, `abc` to run the actual application service(s). We do this because at the time we designed our architecture the alternative - setting a fixed unprivileged user at build time - would have prevented us from offering the range of options that wanted to. While it is now possible to use the `--user` parameter to run any container as an arbitrary user, it hasn't been something we've been able to support before now. -The other approach is to run [Docker itself rootless](https://docs.docker.com/engine/security/rootless/). This creates a separate user and network namespace for your containers that separates them from the host and means that even containers nominally running as `root` don't have root permissions on your host. Running a container as a non-root user and running it rootless are **not** the same, but are commonly conflated. +The other approach is to run [Docker itself rootless](https://docs.docker.com/engine/security/rootless/). This creates a separate user and network namespace for your containers and means that even containers nominally running as `root` don't have root permissions on your host. Running a container as a non-root user and running it rootless are **not** the same, but are commonly conflated. ## Why? @@ -30,7 +30,7 @@ Will run the container as that user, and that cannot then be changed without rec Our images use s6 as a supervisor and that needs to be able to write its service files to `/run`; many applications expect to be able to write to their working directory, changing UIDs and GIDs requires writing to `/etc/passwd` & `/etc/group`, installing new packages requires writing to numerous locations, and mods need to be extracted to the container filesystem. In short, there are some heavy limitations around operation of our images with a non-root user: -* The PUID & PGID variables will not have any effect, the container will instead run applications with the UID & GID of the user you have specified +* The PUID & PGID variables will not have any effect, the container will instead run applications with the UID & GID of the user you have specified via the `--user` parameter * You will need to manually manage the permissions of any mounted volumes or paths * Docker Mods will not be run * Custom Services will not be run @@ -43,16 +43,16 @@ For example: ```yaml services: sonarr: - image: lscr.io/linuxserver/sonarr:latest - container_name: sonarr + image: lscr.io/linuxserver/radarr:latest + container_name: radarr environment: - TZ=Europe/London volumes: - - /path/to/sonarr/data:/config - - /path/to/tvseries:/tv + - /path/to/radarr/data:/config + - /path/to/movies:/movies - /path/to/downloadclient-downloads:/downloads ports: - - 8989:8989 + - 7878:7878 restart: unless-stopped user: 1000:1000 ```