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