]> git.ipfire.org Git - thirdparty/systemd.git/blame - docs/BUILDING_IMAGES.md
docs: fix grammar a bit
[thirdparty/systemd.git] / docs / BUILDING_IMAGES.md
CommitLineData
6538c0ef
LP
1---
2title: Safely Building Images
3category: Concepts
4layout: default
5SPDX-License-Identifier: LGPL-2.1-or-later
6---
7
8# Safely Building Images
9
10In many scenarios OS installations are shipped as pre-built images, that
11require no further installation process beyond simple `dd`-ing the image to
12disk and booting it up. When building such "golden" OS images for
13`systemd`-based OSes a few points should be taken into account.
14
15Most of the points described here are implemented by the
16[`mkosi`](https://github.com/systemd/mkosi) OS image builder developed and
17maintained by the systemd project. If you are using or working on another image
18builder it's recommended to keep the following concepts and recommendations in
19mind.
20
21## Resources to Reset
22
23Typically the same OS image shall be deployable in multiple instances, and each
24instance should automatically acquire its own identifying credentials on first
25boot. For that it's essential to:
26
271. Remove the
28 [`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html)
29 file or write the string `uninitialized\n` into it. This file is supposed to
30 carry a 128bit identifier unique to the system. Only when it is reset it
31 will be auto-generated on first boot and thus be truly unique. If this file
32 is not reset, and carries a valid ID every instance of the system will come
33 up with the same ID and that will likely lead to problems sooner or later,
34 as many network-visible identifiers are commonly derived from the machine
e347d53a 35 ID, for example, IPv6 addresses or transient MAC addresses.
6538c0ef
LP
36
372. Remove the `/var/lib/systemd/random-seed` file (see
3976da02 38 [`systemd-random-seed(8)`](https://www.freedesktop.org/software/systemd/man/systemd-random-seed.service.html)),
6538c0ef
LP
39 which is used to seed the kernel's random pool on boot. If this file is
40 shipped pre-initialized, every instance will seed its random pool with the
41 same random data that is included in the image, and thus possibly generate
3976da02
LP
42 random data that is more similar to other instances booted off the same
43 image than advisable.
6538c0ef
LP
44
453. Remove the `/loader/random-seed` file (see
13a5ffa4 46 [`systemd-boot(7)`](https://www.freedesktop.org/software/systemd/man/systemd-boot.html))
6538c0ef
LP
47 from the UEFI System Partition (ESP), in case the `systemd-boot` boot loader
48 is used in the image.
49
3976da02
LP
504. It might also make sense to remove
51 [`/etc/hostname`](https://www.freedesktop.org/software/systemd/man/hostname.html)
52 and
13a5ffa4 53 [`/etc/machine-info`](https://www.freedesktop.org/software/systemd/man/machine-info.html)
6538c0ef
LP
54 which carry additional identifying information about the OS image.
55
005b1267
LP
565. Remove `/var/lib/systemd/credential.secret` which is used for protecting
57 service credentials, see
58 [`systemd.exec(5)`](https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Credentials)
59 and
60 [`systemd-creds(1)`](https://www.freedesktop.org/software/systemd/man/systemd-creds.html)
61 for details. Note that by removing this file access to previously encrypted
62 credentials from this image is lost. The file is automatically generated if
63 a new credential is encrypted and the file does not exist yet.
64
6538c0ef
LP
65## Boot Menu Entry Identifiers
66
3976da02
LP
67The
68[`kernel-install(8)`](https://www.freedesktop.org/software/systemd/man/kernel-install.html)
5c90c67a 69logic used to generate
db811444
ZJS
70[Boot Loader Specification Type #1](https://uapi-group.org/specifications/specs/boot_loader_specification/#type-1-boot-loader-specification-entries)
71entries by default uses the machine ID as stored in `/etc/machine-id` for
72naming boot menu entries and the directories in the ESP to place kernel images
73in. This is done in order to allow multiple installations of the same OS on the
74same system without conflicts. However, this is problematic if the machine ID
75shall be generated automatically on first boot: if the ID is not known before
76the first boot it cannot be used to name the most basic resources required for
77the boot process to complete.
6538c0ef
LP
78
79Thus, for images that shall acquire their identity on first boot only, it is
80required to use a different identifier for naming boot menu entries. To allow
81this the `kernel-install` logic knows the generalized *entry* *token* concept,
82which can be a freely chosen string to use for identifying the boot menu
83resources of the OS. If not configured explicitly it defaults to the machine
84ID. The file `/etc/kernel/entry-token` may be used to configure this string
85explicitly. Thus, golden image builders should write a suitable identifier into
e347d53a 86this file, for example, the `IMAGE_ID=` or `ID=` field from
3976da02
LP
87[`/etc/os-release`](https://www.freedesktop.org/software/systemd/man/os-release.html)
88(also see below). It is recommended to do this before the `kernel-install`
6538c0ef
LP
89functionality is invoked (i.e. before the package manager is used to install
90packages into the OS tree being prepared), so that the selected string is
91automatically used for all entries to be generated.
92
93## Booting with Empty `/var/` and/or Empty Root File System
94
95`systemd` is designed to be able to come up safely and robustly if the `/var/`
96file system or even the entire root file system (with exception of `/usr/`,
97i.e. the vendor OS resources) is empty (i.e. "unpopulated"). With this in mind
98it's relatively easy to build images that only ship a `/usr/` tree, and
99otherwise carry no other data, populating the rest of the directory hierarchy
100on first boot as needed.
101
102Specifically, the following mechanisms are in place:
103
6f396138 1041. The `switch-root` logic in systemd, that is used to switch from the initrd
6538c0ef
LP
105 phase to the host will create the basic OS hierarchy skeleton if missing. It
106 will create a couple of directories strictly necessary to boot up
107 successfully, plus essential symlinks (such as those necessary for the
108 dynamic loader `ld.so` to function).
109
1102. PID 1 will initialize `/etc/machine-id` automatically if not initialized yet
111 (see above).
112
3976da02
LP
1133. The
114 [`nss-systemd(8)`](https://www.freedesktop.org/software/systemd/man/nss-systemd.html)
115 glibc NSS module ensures the `root` and `nobody` users and groups remain
116 resolvable, even without `/etc/passwd` and `/etc/group` around.
6538c0ef
LP
117
1184. The
3976da02 119 [`systemd-sysusers(8)`](https://www.freedesktop.org/software/systemd/man/systemd-sysusers.service.html)
d8b67e05 120 component will automatically populate `/etc/passwd` and `/etc/group` on
6538c0ef
LP
121 first boot with further necessary system users.
122
1235. The
3976da02 124 [`systemd-tmpfiles(8)`](https://www.freedesktop.org/software/systemd/man/systemd-tmpfiles-setup.service.html)
6538c0ef
LP
125 component ensures that various files and directories below `/etc/`, `/var/`
126 and other places are created automatically at boot if missing. Unlike the
127 directories/symlinks created by the `switch-root` logic above this logic is
128 extensible by packages, and can adjust access modes, file ownership and
129 more. Among others this will also link `/etc/os-release` →
130 `/usr/lib/os-release`, ensuring that the OS release information is
131 unconditionally accessible through `/etc/os-release`.
132
3976da02
LP
1336. The
134 [`nss-myhostname(8)`](https://www.freedesktop.org/software/systemd/man/nss-myhostname.html)
135 glibc NSS module will ensure the local host name as well as `localhost`
136 remains resolvable, even without `/etc/hosts` around.
6538c0ef
LP
137
138With these mechanisms the hierarchies below `/var/` and `/etc/` can be safely
139and robustly populated on first boot, so that the OS can safely boot up. Note
140that some auxiliary package are not prepared to operate correctly if their
141configuration data in `/etc/` or their state directories in `/var/` are
142missing. This can typically be addressed via `systemd-tmpfiles` lines that
143ensure the missing files and directories are created if missing. In particular,
144configuration files that are necessary for operation can be automatically
145copied or symlinked from the `/usr/share/factory/etc/` tree via the `C` or `L`
146line types. That said, we recommend that all packages safely fall back to
147internal defaults if their configuration is missing, making such additional
148steps unnecessary.
149
150Note that while `systemd` itself explicitly supports booting up with entirely
151unpopulated images (`/usr/` being the only required directory to be populated)
152distributions might not be there yet: depending on your distribution further,
153manual work might be required to make this scenario work.
154
155## Adapting OS Images to Storage
156
157Typically, if an image is `dd`-ed onto a target disk it will be minimal:
158i.e. only consist of necessary vendor data, and lack "payload" data, that shall
159be individual to the system, and dependent on host parameters. On first boot,
160the OS should take possession of the backing storage as necessary, dynamically
161using available space. Specifically:
162
1631. Additional partitions should be created, that make no sense to ship
164 pre-built in the image. For example `/tmp/` or `/home/` partitions, or even
165 `/var/` or the root file system (see above).
166
1672. Additional partitions should be created that shall function as A/B
168 secondaries for partitions shipped in the original image. In other words: if
169 the `/usr/` file system shall be updated in an A/B fashion it typically
170 makes sense to ship the original A file system in the deployed image, but
171 create the B partition on first boot.
172
1733. Partitions covering only a part of the disk should be grown to the full
174 extent of the disk.
175
1764. File systems in uninitialized partitions should be formatted with a file
177 system of choice.
178
1795. File systems covering only a part of a partition should be grown to the full
180 extent of the partition.
181
1826. Partitions should be encrypted with cryptographic keys generated locally on
183 the machine the system is first booted on, ensuring these keys remain local
184 and are not shared with any other instance of the OS image.
185
186Or any combination of the above: i.e. first create a partition, then encrypt
187it, then format it.
188
189`systemd` provides multiple tools to implement the above logic:
190
1911. The
3976da02 192 [`systemd-repart(8)`](https://www.freedesktop.org/software/systemd/man/systemd-repart.service.html)
6538c0ef
LP
193 component may manipulate GPT partition tables automatically on boot, growing
194 partitions or adding in partitions taking the backing storage size into
195 account. It can also encrypt partitions automatically it creates (even bind
196 to TPM2, automatically) and populate partitions from various sources. It
197 does this all in a robust fashion so that aborted invocations will not leave
198 incompletely set up partitions around.
199
2002. The
3976da02 201 [`systemd-growfs@(8).service`](https://www.freedesktop.org/software/systemd/man/systemd-growfs.html)
6538c0ef 202 tool can automatically grow a file system to the partition it is contained
3976da02
LP
203 in. The `x-systemd.growfs` mount option in `/etc/fstab` is sufficient to
204 enable this logic for specific mounts. Alternatively appropriately set up
205 partitions can set GPT partition flag 59 to request this behaviour, see the
db811444
ZJS
206 [Discoverable Partitions Specification](https://uapi-group.org/specifications/specs/discoverable_partitions_specification)
207 for details. If the file system is already grown it executes no operation.
6538c0ef
LP
208
2093. Similar, the `systemd-makefs@.service` and `systemd-makeswap@.service`
210 services can format file systems and swap spaces before first use, if they
211 carry no file system signature yet. The `x-systemd.makefs` mount option in
212 `/etc/fstab` may be used to request this functionality.
213
214## Provisioning Image Settings
215
216While a lot of work has gone into ensuring `systemd` systems can safely boot
217with unpopulated `/etc/` trees, it sometimes is desirable to set a couple of
218basic settings *after* `dd`-ing the image to disk, but *before* first boot. For
219this the tool
3976da02 220[`systemd-firstboot(1)`](https://www.freedesktop.org/software/systemd/man/systemd-firstboot.html)
6538c0ef
LP
221can be useful, with its `--image=` switch. It may be used to set very basic
222settings, such as the root password or hostname on an OS disk image or
223installed block device.
224
225## Distinguishing First Boot
226
227For various purposes it's useful to be able to distinguish the first boot-up of
228the system from later boot-ups (for example, to set up TPM hardware
229specifically, or register a system somewhere). `systemd` provides mechanisms to
230implement that. Specifically, the `ConditionFirstBoot=` and `AssertFirstBoot=`
231settings may be used to conditionalize units to only run on first boot. See
232[`systemd.unit(5)`](https://www.freedesktop.org/software/systemd/man/systemd.unit.html#ConditionFirstBoot=)
233for details.
234
235A special target unit `first-boot-complete.target` may be used as milestone to
236safely handle first boots where the system is powered off too early: if the
237first boot process is aborted before this target is reached, the following boot
238process will be considered a first boot, too. Once the target is reached,
239subsequent boots will not be considered first boots anymore, even if the boot
240process is aborted immediately after. Thus, services that must complete fully
241before a system shall be considered fully past the first boot should be ordered
242before this target unit.
243
244Whether a system will come up in first boot state or not is derived from the
245initialization status of `/etc/machine-id`: if the file already carries a valid
246ID the system is already past the first boot. If it is not initialized yet it
247is still considered in the first boot state. For details see
248[`machine-id(5)`](https://www.freedesktop.org/software/systemd/man/machine-id.html).
3976da02
LP
249
250## Image Metadata
251
252Typically, when operating with golden disk images it is useful to be able to
253identify them and their version. For this the two fields `IMAGE_ID=` and
254`IMAGE_VERSION=` have been defined in
255[`os-release(5)`](https://www.freedesktop.org/software/systemd/man/os-release.html). These
256fields may be accessed from unit files and similar via the `%M` and `%A`
257specifiers.
258
259Depending on how the images are put together it might make sense to leave the
260OS distribution's `os-release` file as is in `/usr/lib/os-release` but to
261replace the usual `/etc/os-release` symlink with a regular file that extends
262the distribution's file with one augmented with these two additional
263fields.
264
265## Links
266
3f4ead8d
LP
267[`machine-id(5)`](https://www.freedesktop.org/software/systemd/man/machine-id.html)<br>
268[`systemd-random-seed(8)`](https://www.freedesktop.org/software/systemd/man/systemd-random-seed.service.html)<br>
269[`os-release(5)`](https://www.freedesktop.org/software/systemd/man/os-release.html)<br>
db811444
ZJS
270[Boot Loader Specification](https://uapi-group.org/specifications/specs/boot_loader_specification)<br>
271[Discoverable Partitions Specification](https://uapi-group.org/specifications/specs/discoverable_partitions_specification)<br>
3f4ead8d 272[`mkosi`](https://github.com/systemd/mkosi)<br>
3976da02 273[`systemd-boot(7)`](https://www.freedesktop.org/software/systemd/man/systemd-boot.html)<br>
3f4ead8d
LP
274[`systemd-repart(8)`](https://www.freedesktop.org/software/systemd/man/systemd-repart.service.html)<br>
275[`systemd-growfs@(8).service`](https://www.freedesktop.org/software/systemd/man/systemd-growfs.html)<br>