1--- 2title: Container Interface 3category: Interfaces 4layout: default 5SPDX-License-Identifier: LGPL-2.1-or-later 6--- 7 8# The Container Interface 9 10Also consult [Writing Virtual Machine or Container 11Managers](https://www.freedesktop.org/wiki/Software/systemd/writing-vm-managers). 12 13systemd has a number of interfaces for interacting with container managers, 14when systemd is used inside of an OS container. If you work on a container 15manager, please consider supporting the following interfaces. 16 17## Execution Environment 18 191. If the container manager wants to control the hostname for a container 20 running systemd it may just set it before invoking systemd, and systemd will 21 leave it unmodified when there is no hostname configured in `/etc/hostname` 22 (that file overrides whatever is pre-initialized by the container manager). 23 242. Make sure to pre-mount `/proc/`, `/sys/`, and `/sys/fs/selinux/` before 25 invoking systemd, and mount `/sys/`, `/sys/fs/selinux/` and `/proc/sys/` 26 read-only (the latter via e.g. a read-only bind mount on itself) in order 27 to prevent the container from altering the host kernel's configuration 28 settings. (As a special exception, if your container has network namespaces 29 enabled, feel free to make `/proc/sys/net/` writable. If it also has user, ipc, 30 uts and pid namespaces enabled, the entire `/proc/sys` can be left writable). 31 systemd and various other subsystems (such as the SELinux userspace) have 32 been modified to behave accordingly when these file systems are read-only. 33 (It's OK to mount `/sys/` as `tmpfs` btw, and only mount a subset of its 34 sub-trees from the real `sysfs` to hide `/sys/firmware/`, `/sys/kernel/` and 35 so on. If you do that, make sure to mark `/sys/` read-only, as that 36 condition is what systemd looks for, and is what is considered to be the API 37 in this context.) 38 393. Pre-mount `/dev/` as (container private) `tmpfs` for the container and bind 40 mount some suitable TTY to `/dev/console`. If this is a pty, make sure to 41 not close the controlling pty during systemd's lifetime. PID 1 will close 42 ttys, to avoid being killed by SAK. It only opens ttys for the time it 43 actually needs to print something. Also, make sure to create device nodes 44 for `/dev/null`, `/dev/zero`, `/dev/full`, `/dev/random`, `/dev/urandom`, 45 `/dev/tty`, `/dev/ptmx` in `/dev/`. It is not necessary to create `/dev/fd` 46 or `/dev/stdout`, as systemd will do that on its own. Make sure to set up a 47 `BPF_PROG_TYPE_CGROUP_DEVICE` BPF program — on cgroupv2 — or the `devices` 48 cgroup controller — on cgroupv1 — so that no other devices but these may be 49 created in the container. Note that many systemd services use 50 `PrivateDevices=`, which means that systemd will set up a private `/dev/` 51 for them for which it needs to be able to create these device nodes. 52 Dropping `CAP_MKNOD` for containers is hence generally not advisable, but 53 see below. 54 554. `systemd-udevd` is not available in containers (and refuses to start), and 56 hence device dependencies are unavailable. The `systemd-udevd` unit files 57 will check for `/sys/` being read-only, as an indication whether device 58 management can work. Therefore make sure to mount `/sys/` read-only in the 59 container (see above). Various clients of `systemd-udevd` also check the 60 read-only state of `/sys/`, including PID 1 itself and `systemd-networkd`. 61 625. If systemd detects it is run in a container it will spawn a single shell on 63 `/dev/console`, and not care about VTs or multiple gettys on VTs. (But see 64 `$container_ttys` below.) 65 666. Either pre-mount all cgroup hierarchies in full into the container, or leave 67 that to systemd which will do so if they are missing. Note that it is 68 explicitly *not* OK to just mount a sub-hierarchy into the container as that 69 is incompatible with `/proc/$PID/cgroup` (which lists full paths). Also the 70 root-level cgroup directories tend to be quite different from inner 71 directories, and that distinction matters. It is OK however, to mount the 72 "upper" parts read-only of the hierarchies, and only allow write-access to 73 the cgroup sub-tree the container runs in. It's also a good idea to mount 74 all controller hierarchies with exception of `name=systemd` fully read-only 75 (this only applies to cgroupv1, of course), to protect the controllers from 76 alteration from inside the containers. Or to turn this around: only the 77 cgroup sub-tree of the container itself (on cgroupv2 in the unified 78 hierarchy, and on cgroupv1 in the `name=systemd` hierarchy) may be writable 79 to the container. 80 817. Create the control group root of your container by either running your 82 container as a service (in case you have one container manager instance per 83 container instance) or creating one scope unit for each container instance 84 via systemd's transient unit API (in case you have one container manager 85 that manages all instances. Either way, make sure to set `Delegate=yes` in 86 it. This ensures that the unit you created will be part of all cgroup 87 controllers (or at least the ones systemd understands). The latter may also 88 be done via `systemd-machined`'s `CreateMachine()` API. Make sure to use the 89 cgroup path systemd put your process in for all operations of the container. 90 Do not add new cgroup directories to the top of the tree. This will not only 91 confuse systemd and the admin, but also prevent your implementation from 92 being "stackable". 93 94## Environment Variables 95 961. To allow systemd (and other programs) to identify that it is executed within 97 a container, please set the `$container` environment variable for PID 1 in 98 the container to a short lowercase string identifying your 99 implementation. With this in place the `ConditionVirtualization=` setting in 100 unit files will work properly. Example: `container=lxc-libvirt` 101 1022. systemd has special support for allowing container managers to initialize 103 the UUID for `/etc/machine-id` to some manager supplied value. This is only 104 enabled if `/etc/machine-id` is empty (i.e. not yet set) at boot time of the 105 container. The container manager should set `$container_uuid` as environment 106 variable for the container's PID 1 to the container UUID. (This is similar 107 to the effect of `qemu`'s `-uuid` switch). Note that you should pass only a 108 UUID here that is actually unique (i.e. only one running container should 109 have a specific UUID), and gets changed when a container gets duplicated. 110 Also note that systemd will try to persistently store the UUID in 111 `/etc/machine-id` (if writable) when this option is used, hence you should 112 always pass the same UUID here. Keeping the externally used UUID for a 113 container and the internal one in sync is hopefully useful to minimize 114 surprise for the administrator. 115 1163. systemd can automatically spawn login gettys on additional ptys. A container 117 manager can set the `$container_ttys` environment variable for the 118 container's PID 1 to tell it on which ptys to spawn gettys. The variable 119 should take a space separated list of pty names, without the leading `/dev/` 120 prefix, but with the `pts/` prefix included. Note that despite the 121 variable's name you may only specify ptys, and not other types of ttys. Also 122 you need to specify the pty itself, a symlink will not suffice. This is 123 implemented in 124 [systemd-getty-generator(8)](https://www.freedesktop.org/software/systemd/man/systemd-getty-generator.html). 125 Note that this variable should not include the pty that `/dev/console` maps 126 to if it maps to one (see below). Example: if the container receives 127 `container_ttys=pts/7 pts/8 pts/14` it will spawn three additional login 128 gettys on ptys 7, 8, and 14. 129 1304. To allow applications to detect the OS version and other metadata of the host 131 running the container manager, if this is considered desirable, please parse 132 the host's `/etc/os-release` and set a `$container_host_<key>=<VALUE>` 133 environment variable for the ID fields described by the [os-release 134 interface](https://www.freedesktop.org/software/systemd/man/os-release.html), eg: 135 `$container_host_id=debian` 136 `$container_host_build_id=2020-06-15` 137 `$container_host_variant_id=server` 138 `$container_host_version_id=10` 139 1405. systemd supports passing immutable binary data blobs with limited size and 141 restricted access to services via the `LoadCredential=` and `SetCredential=` 142 settings. The same protocol may be used to pass credentials from the 143 container manager to systemd itself. The credential data should be placed in 144 some location (ideally a read-only and non-swappable file system, like 145 'ramfs'), and the absolute path to this directory exported in the 146 `$CREDENTIALS_DIRECTORY` environment variable. If the container managers 147 does this, the credentials passed to the service manager can be propagated 148 to services via `LoadCredential=` (see ...). The container manager can 149 choose any path, but `/run/host/credentials` is recommended. 150 151## Advanced Integration 152 1531. Consider syncing `/etc/localtime` from the host file system into the 154 container. Make it a relative symlink to the containers's zoneinfo dir, as 155 usual. Tools rely on being able to determine the timezone setting from the 156 symlink value, and making it relative looks nice even if people list the 157 container's `/etc/` from the host. 158 1592. Make the container journal available in the host, by automatically 160 symlinking the container journal directory into the host journal directory. 161 More precisely, link `/var/log/journal/<container-machine-id>` of the 162 container into the same dir of the host. Administrators can then 163 automatically browse all container journals (correctly interleaved) by 164 issuing `journalctl -m`. The container machine ID can be determined from 165 `/etc/machine-id` in the container. 166 1673. If the container manager wants to cleanly shutdown the container, it might 168 be a good idea to send `SIGRTMIN+3` to its init process. systemd will then 169 do a clean shutdown. Note however, that since only systemd understands 170 `SIGRTMIN+3` like this, this might confuse other init systems. 171 1724. To support [Socket Activated 173 Containers](http://0pointer.de/blog/projects/socket-activated-containers.html) 174 the container manager should be capable of being run as a systemd 175 service. It will then receive the sockets starting with FD 3, the number of 176 passed FDs in `$LISTEN_FDS` and its PID as `$LISTEN_PID`. It should take 177 these and pass them on to the container's init process, also setting 178 $LISTEN_FDS and `$LISTEN_PID` (basically, it can just leave the FDs and 179 `$LISTEN_FDS` untouched, but it needs to adjust `$LISTEN_PID` to the 180 container init process). That's all that's necessary to make socket 181 activation work. The protocol to hand sockets from systemd to services is 182 hence the same as from the container manager to the container systemd. For 183 further details see the explanations of 184 [sd_listen_fds(1)](http://0pointer.de/public/systemd-man/sd_listen_fds.html) 185 and the [blog story for service 186 developers](http://0pointer.de/blog/projects/socket-activation.html). 187 1885. Container managers should stay away from the cgroup hierarchy outside of the 189 unit they created for their container. That's private property of systemd, 190 and no other code should modify it. 191 1926. systemd running inside the container can report when boot-up is complete 193 using the usual `sd_notify()` protocol that is also used when a service 194 wants to tell the service manager about readiness. A container manager can 195 set the `$NOTIFY_SOCKET` environment variable to a suitable socket path to 196 make use of this functionality. (Also see information about 197 `/run/host/notify` below.) 198 199## Networking 200 2011. Inside of a container, if a `veth` link is named `host0`, `systemd-networkd` 202 running inside of the container will by default run DHCPv4, DHCPv6, and 203 IPv4LL clients on it. It is thus recommended that container managers that 204 add a `veth` link to a container name it `host0`, to get an automatically 205 configured network, with no manual setup. 206 2072. Outside of a container, if a `veth` link is prefixed "ve-", `systemd-networkd` 208 will by default run DHCPv4 and DHCPv6 servers on it, as well as IPv4LL. It 209 is thus recommended that container managers that add a `veth` link to a 210 container name the external side `ve-` + the container name. 211 2123. It is recommended to configure stable MAC addresses for container `veth` 213 devices, for example hashed out of the container names. That way it is more 214 likely that DHCP and IPv4LL will acquire stable addresses. 215 216## The `/run/host/` Hierarchy 217 218Container managers may place certain resources the manager wants to provide to 219the container payload below the `/run/host/` hierarchy. This hierarchy should 220be mostly immutable (possibly some subdirs might be writable, but the top-level 221hierarchy — and probably most subdirs should be read-only to the 222container). Note that this hierarchy is used by various container managers, and 223care should be taken to avoid naming conflicts. `systemd` (and in particular 224`systemd-nspawn`) use the hierarchy for the following resources: 225 2261. The `/run/host/incoming/` directory mount point is configured for `MS_SLAVE` 227 mount propagation with the host, and is used as intermediary location for 228 mounts to establish in the container, for the implementation of `machinectl 229 bind`. Container payload should usually not directly interact with this 230 directory: it's used by code outside the container to insert mounts inside 231 it only, and is mostly an internal vehicle to achieve this. Other container 232 managers that want to implement similar functionality might consider using 233 the same directory. 234 2352. The `/run/host/inaccessible/` directory may be set up by the container 236 manager to include six file nodes: `reg`, `dir`, `fifo`, `sock`, `chr`, 237 `blk`. These nodes correspond with the six types of file nodes Linux knows 238 (with the exceptions of symlinks). Each node should be of the specific type 239 and have an all zero access mode, i.e. be inaccessible. The two device node 240 types should have major and minor of zero (which are unallocated devices on 241 Linux). These nodes are used as mount source for implementing the 242 `InaccessiblePath=` setting of unit files, i.e. file nodes to mask this way 243 are overmounted with these "inaccessible" inodes, guaranteeing that the file 244 node type does not change this way but the nodes still become 245 inaccessible. Note that systemd when run as PID 1 in the container payload 246 will create these nodes on its own if not passed in by the container 247 manager. However, in that case it likely lacks the privileges to create the 248 character and block devices nodes (there are fallbacks for this case). 249 2503. The `/run/host/notify` path is a good choice to place the `sd_notify()` 251 socket in, that may be used for the container's PID 1 to report to the 252 container manager when boot-up is complete. The path used for this doesn't 253 matter much as it is communicated via the `$NOTIFY_SOCKET` environment 254 variable, following the usual protocol for this, however it's suitable, and 255 recommended place for this socket in case ready notification is desired. 256 2574. The `/run/host/os-release` file contains the `/etc/os-release` file of the 258 host, i.e. may be used by the container payload to gather limited 259 information about the host environment, on top of what `uname -a` reports. 260 2615. The `/run/host/container-manager` file may be used to pass the same 262 information as the `$container` environment variable (see above), i.e. a 263 short string identifying the container manager implementation. This file 264 should be newline terminated. Passing this information via this file has the 265 benefit that payload code can easily access it, even when running 266 unprivileged without access to the container PID 1's environment block. 267 2686. The `/run/host/container-uuid` file may be used to pass the same information 269 as the `$container_uuid` environment variable (see above). This file should 270 be newline terminated. 271 2727. The `/run/host/credentials/` directory is a good place to pass credentials 273 into the container, using the `$CREDENTIALS_DIRECTORY` protocol, see above. 274 275## What You Shouldn't Do 276 2771. Do not drop `CAP_MKNOD` from the container. `PrivateDevices=` is a commonly 278 used service setting that provides a service with its own, private, minimal 279 version of `/dev/`. To set this up systemd in the container needs this 280 capability. If you take away the capability, then all services that set this 281 flag will cease to work. Use `BPF_PROG_TYPE_CGROUP_DEVICE` BPF programs — on 282 cgroupv2 — or the `devices` controller — on cgroupv1 — to restrict what 283 device nodes the container can create instead of taking away the capability 284 wholesale. (Also see the section about fully unprivileged containers below.) 285 2862. Do not drop `CAP_SYS_ADMIN` from the container. A number of the most 287 commonly used file system namespacing related settings, such as 288 `PrivateDevices=`, `ProtectHome=`, `ProtectSystem=`, `MountFlags=`, 289 `PrivateTmp=`, `ReadWriteDirectories=`, `ReadOnlyDirectories=`, 290 `InaccessibleDirectories=`, and `MountFlags=` need to be able to open new 291 mount namespaces and the mount certain file systems into them. You break all 292 services that make use of these options if you drop the capability. Also 293 note that logind mounts `XDG_RUNTIME_DIR` as `tmpfs` for all logged in users 294 and that won't work either if you take away the capability. (Also see 295 section about fully unprivileged containers below.) 296 2973. Do not cross-link `/dev/kmsg` with `/dev/console`. They are different things, 298 you cannot link them to each other. 299 3004. Do not pretend that the real VTs are available in the container. The VT 301 subsystem consists of all the devices `/dev/tty*`, `/dev/vcs*`, `/dev/vcsa*` 302 plus their `sysfs` counterparts. They speak specific `ioctl()`s and 303 understand specific escape sequences, that other ptys don't understand. 304 Hence, it is explicitly not OK to mount a pty to `/dev/tty1`, `/dev/tty2`, 305 `/dev/tty3`. This is explicitly not supported. 306 3075. Don't pretend that passing arbitrary devices to containers could really work 308 well. For example, do not pass device nodes for block devices to the 309 container. Device access (with the exception of network devices) is not 310 virtualized on Linux. Enumeration and probing of meta information from 311 `/sys/` and elsewhere is not possible to do correctly in a container. Simply 312 adding a specific device node to a container's `/dev/` is *not* *enough* to 313 do the job, as `systemd-udevd` and suchlike are not available at all, and no 314 devices will appear available or enumerable, inside the container. 315 3166. Don't mount only a sub-tree of the `cgroupfs` into the container. This will not 317 work as `/proc/$PID/cgroup` lists full paths and cannot be matched up with 318 the actual `cgroupfs` tree visible, then. (You may "prune" some branches 319 though, see above.) 320 3217. Do not make `/sys/` writable in the container. If you do, 322 `systemd-udevd.service` is started to manage your devices — inside the 323 container, but that will cause conflicts and errors given that the Linux 324 device model is not virtualized for containers on Linux and thus the 325 containers and the host would try to manage the same devices, fighting for 326 ownership. Multiple other subsystems of systemd similarly test for `/sys/` 327 being writable to decide whether to use `systemd-udevd` or assume that 328 device management is properly available on the instance. Among them 329 `systemd-networkd` and `systemd-logind`. The conditionalization on the 330 read-only state of `/sys/` enables a nice automatism: as soon as `/sys/` and 331 the Linux device model are changed to be virtualized properly the container 332 payload can make use of that, simply by marking `/sys/` writable. (Note that 333 as special exception, the devices in `/sys/class/net/` are virtualized 334 already, if network namespacing is used. Thus it is OK to mount the relevant 335 sub-directories of `/sys/` writable, but make sure to leave the root of 336 `/sys/` read-only.) 337 3388. Do not pass the `CAP_AUDIT_CONTROL`, `CAP_AUDIT_READ`, `CAP_AUDIT_WRITE` 339 capabilities to the container, in particular not to those making use of user 340 namespaces. The kernel's audit subsystem is still not virtualized for 341 containers, and passing these credentials is pointless hence, given the 342 actual attempt to make use of the audit subsystem will fail. Note that 343 systemd's audit support is partially conditioned on these capabilities, thus 344 by dropping them you ensure that you get an entirely clean boot, as systemd 345 will make no attempt to use it. If you pass the capabilities to the payload 346 systemd will assume that audit is available and works, and some components 347 will subsequently fail in various ways. Note that once the kernel learnt 348 native support for container-virtualized audit, adding the capability to the 349 container description will automatically make the container payload use it. 350 351## Fully Unprivileged Container Payload 352 353First things first, to make this clear: Linux containers are not a security 354technology right now. There are more holes in the model than in swiss cheese. 355 356For example: if you do not use user namespacing, and share root and other users 357between container and host, the `struct user` structures will be shared between 358host and container, and hence `RLIMIT_NPROC` and so of the container users 359affect the host and other containers, and vice versa. This is a major security 360hole, and actually is a real-life problem: since Avahi sets `RLIMIT_NPROC` of 361its user to 2 (to effectively disallow `fork()`ing) you cannot run more than 362one Avahi instance on the entire system... 363 364People have been asking to be able to run systemd without `CAP_SYS_ADMIN` and 365`CAP_SYS_MKNOD` in the container. This is now supported to some level in 366systemd, but we recommend against it (see above). If `CAP_SYS_ADMIN` and 367`CAP_SYS_MKNOD` are missing from the container systemd will now gracefully turn 368off `PrivateTmp=`, `PrivateNetwork=`, `ProtectHome=`, `ProtectSystem=` and 369others, because those capabilities are required to implement these options. The 370services using these settings (which include many of systemd's own) will hence 371run in a different, less secure environment when the capabilities are missing 372than with them around. 373 374With user namespacing in place things get much better. With user namespaces the 375`struct user` issue described above goes away, and containers can keep 376`CAP_SYS_ADMIN` safely for the user namespace, as capabilities are virtualized 377and having capabilities inside a container doesn't mean one also has them 378outside. 379 380## Final Words 381 382If you write software that wants to detect whether it is run in a container, 383please check `/proc/1/environ` and look for the `container=` environment 384variable. Do not assume the environment variable is inherited down the process 385tree. It generally is not. Hence check the environment block of PID 1, not your 386own. Note though that this file is only accessible to root. systemd hence early 387on also copies the value into `/run/systemd/container`, which is readable for 388everybody. However, that's a systemd-specific interface and other init systems 389are unlikely to do the same. 390 391Note that it is our intention to make systemd systems work flawlessly and 392out-of-the-box in containers. In fact we are interested to ensure that the same 393OS image can be booted on a bare system, in a VM and in a container, and behave 394correctly each time. If you notice that some component in systemd does not work 395in a container as it should, even though the container manager implements 396everything documented above, please contact us. 397