diff --git a/docs/index.html b/docs/index.html index 9cb40e33..225da1ec 100644 --- a/docs/index.html +++ b/docs/index.html @@ -26,6 +26,10 @@ .remark-slide-content h1 { font-size: 50px; } .remark-slide-content h2 { font-size: 50px; } .remark-slide-content h3 { font-size: 25px; } + .footnote { + position: absolute; + bottom: 3em; + } .remark-code { font-size: 25px; } .small .remark-code { font-size: 16px; } @@ -4772,6 +4776,245 @@ class: secrets --- +class: namespaces +name: namespaces + +# Improving isolation with User Namespaces + +- *Namespaces* are kernel mechanisms to compartimetalize the system + +- There are different kind of namespaces: `pid`, `net`, `mnt`, `ipc`, `uts`, and `user` + +- For a primer, see "Anatomy of a Container" + ([video](https://www.youtube.com/watch?v=sK5i-N34im8)) + ([slides](https://www.slideshare.net/jpetazzo/cgroups-namespaces-and-beyond-what-are-containers-made-from-dockercon-europe-2015)) + +- The *user namespace* allows to map UIDs between the containers and the host + +- As a result, `root` in a container can map to a non-privileged user on the host + +Note: even without user namespaces, `root` in a container cannot go wild on the host. +
+It is mediated by capabilities, cgroups, namespaces, seccomp, LSMs... + +--- + +class: namespaces + +## User Namespaces in Docker + +- Optional feature added in Docker Engine 1.10 + +- Not enabled by default + +- Has to be enabled at Engine startup, and affects all containers + +- When enabled, `UID:GID` in containers are mapped to a different range on the host + +- Safer than switching to a non-root user (with `-u` or `USER`) in the container +
+ (Since with user namespaces, root escalation maps to a non-privileged user) + +- Can be selectively disabled per container by starting them with `--userns=host` + +--- + +class: namespaces + +## User Namespaces Caveats + +When user namespaces are enabled, containers cannot: + +- Use the host's network namespace (with `docker run --network=host`) + +- Use the host's PID namespace (with `docker run --pid=host`) + +- Run in privileged mode (with `docker run --privileged`) + +... Unless user namespaces are disabled for the container, with flag `--userns=host` + +External volume and graph drivers that don't support user mapping might not work. + +All containers are currently mapped to the same UID:GID range. + +Some of these limitations might be lifted in the future! + +--- + +class: namespaces + +## Filesystem ownership details + +When enabling user namespaces: + +- the UID:GID on disk (in the images and containers) has to match the *mapped* UID:GID + +- existing images and containers cannot work (their UID:GID would have to be changed) + +For practical reasons, when enabling user namespaces, the Docker Engine places containers and images (and everything else) in a different directory. + +As a resut, if you enable user namespaces on an existing installation: + +- all containers and images (and e.g. Swarm data) disappear + +- *if a node is a member of a Swarm, it is then kicked out of the Swarm* + +- everything will re-appear if you disable user namespaces again + +--- + +class: namespaces + +## Picking a node + +- We will select a node where we will enable user namespaces + +- This node will have to be re-added to the Swarm + +- All containers and services running on this node will be rescheduled + +- Let's make sure that we do not pick the node running the registry! + +.exercise[ + +- Check on which node the registry is running: + ```bash + docker service ps registry + ``` + +] + +Pick any other node (noted `nodeX` in the next slides). + +--- + +class: namespaces + +## Logging into the right Engine + +.exercise[ + +- Log into the right node: + ```bash + ssh node`X` + ``` + +] + +--- + +class: namespaces + +## Configuring the Engine + +.exercise[ + +- Create a configuration file for the Engine: + ```bash + echo '{"userns-remap": "default"}' | sudo tee /etc/docker/daemon.json + ``` + +- Restart the Engine: + ```bash + kill $(pidof dockerd) + ``` + +] + +--- + +class: namespaces + +## Checking that User Namespaces are enabled + +.exercise[ + - Notice the new Docker path: + ```bash + docker info | grep var/lib + ``` + + - Notice the new UID:GID permissions: + ```bash + sudo ls -l /var/lib/docker + ``` + +] + +You should see a line like the following: +``` +drwx------ 11 296608 296608 4096 Aug 3 05:11 296608.296608 +``` + +--- + +class: namespaces + +## Add the node back to the Swarm + +.exercise[ + +- Get our manager token from another node: + ```bash + ssh node`Y` docker swarm join-token manager + ``` + +- Copy-paste the join command to the node + +] + +--- + +class: namespaces + +## Check the new UID:GID + +.exercise[ + +- Run a background container on the node: + ```bash + docker run -d --name lockdown alpine sleep 1000000 + ``` + +- Look at the processes in this container: + ```bash + docker top lockdown + ps faux + ``` + +] + +--- + +class: namespaces + +## Comparing on-disk ownership with/without User Namespaces + +.exercise[ + +- Compare the output of the two following commands: + ```bash + docker run alpine ls -l / + docker run --userns=host alpine ls -l / + ``` + +] + +-- + +class: namespaces + +In the first case, it looks like things belong to `root:root`. + +In the second case, we will see the "real" (on-disk) ownership. + +-- + +class: namespaces + +Remember to get back to `node1` when finished! + +--- + ## A reminder about *scope* - Out of the box, Docker API access is "all or nothing"