]> git.ipfire.org Git - thirdparty/systemd.git/blob - docs/CREDENTIALS.md
Merge pull request #23653 from aafeijoo-suse/ask-for-recovery-key
[thirdparty/systemd.git] / docs / CREDENTIALS.md
1 ---
2 title: Credentials
3 category: Concepts
4 layout: default
5 SPDX-License-Identifier: LGPL-2.1-or-later
6 ---
7
8 # System and Service Credentials
9
10 The `systemd` service manager supports a "credential" concept for securely
11 acquiring and passing credential data to systems and services. The precise
12 nature of the credential data is up to applications, but the concept is
13 intended to provide systems and services with potentially security sensitive
14 cryptographic keys, certificates, passwords, identity information and similar
15 types of information. It may also be used as generic infrastructure for
16 parameterizing systems and services.
17
18 Traditionally, data of this nature has often been provided to services via
19 environment variables (which is problematic because by default they are
20 inherited down the process tree, have size limitations, and issues with binary
21 data) or simple, unencrypted files on disk. `systemd`'s system and service
22 credentials are supposed to provide a better alternative for this
23 purpose. Specifically, the following features are provided:
24
25 1. Service credentials are acquired at the moment of service activation, and
26 released on service deactivation. They are immutable during the service
27 runtime.
28
29 2. Service credentials are accessible to service code as regular files, the
30 path to access them is derived from the environment variable
31 `$CREDENTIALS_DIRECTORY`.
32
33 3. Access to credentials is restricted to the service's user. Unlike
34 environment variables the credential data is not propagated down the process
35 tree. Instead each time a credential is accessed an access check is enforced
36 by the kernel. If the service is using file system namespacing the loaded
37 credential data is invisible to any other services.
38
39 4. Service credentials may be acquired from files on disk, specified as literal
40 strings in unit files, acquired from another service dynamically via an
41 `AF_UNIX` socket, or inherited from the system credentials the system itself
42 received.
43
44 5. Credentials may optionally be encrypted and authenticated, either with a key
45 derived from a local TPM2 chip, or one stored in `/var/`, or both. This
46 encryption is supposed to *just* *work*, and requires no manual setup. (That
47 is besides first encrypting relevant credentials with one simple command,
48 see below.)
49
50 6. Service credentials are placed in non-swappable memory. (If permissions
51 allow it, via `ramfs`.)
52
53 7. Credentials may be acquired from a hosting VM hypervisor (SMBIOS OEM strings
54 or qemu `fw_cfg`), a hosting container manager, the kernel command line, or
55 from the UEFI environment and the EFI System Partition (via
56 `systemd-stub`). Such system credentials may then be propagated into
57 individual services as needed.
58
59 8. Credentials are an effective way to pass parameters into services that run
60 with `RootImage=` or `RootDirectory=` and thus cannot read these resources
61 directly from the host directory tree.
62 Specifically, [Portable Services](PORTABLE_SERVICES.md) may be
63 parameterized this way securely and robustly.
64
65 9. Credentials can be binary and relatively large (though currently an overall
66 size limit of 1M per service is enforced).
67
68 ## Configuring per-Service Credentials
69
70 Within unit files, there are four settings to configure service credentials.
71
72 1. `LoadCredential=` may be used to load a credential from disk, from an
73 `AF_UNIX` socket, or propagate them from a system credential.
74
75 2. `SetCredential=` may be used to set a credential to a literal string encoded
76 in the unit file. Because unit files are world-readable (both on disk and
77 via D-Bus), this should only be used for credentials that aren't sensitive,
78 i.e. public keys/certificates – but not private keys.
79
80 3. `LoadCredentialEncrypted=` is similar to `LoadCredential=` but will load an
81 encrypted credential, and decrypt it before passing it to the service. For
82 details on credential encryption, see below.
83
84 4. `SetCredentialEncrypted=` is similar to `SetCredential=` but expects an
85 encrypted credential to be specified literally. Unlike `SetCredential=` it
86 is thus safe to be used even for sensitive information, because even though
87 unit files are world readable, the ciphertext included in them cannot be
88 decoded unless access to TPM2/encryption key is available.
89
90 Each credential configured with these options carries a short name (suitable
91 for inclusion in a filename) in the unit file, under which the invoked service
92 code can then retrieve it. Each name should only be specified once.
93
94 For details about these four settings [see the man
95 page](https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Credentials).
96
97 It is a good idea to also enable mount namespacing for services that process
98 credentials configured this way. If so, the runtime credential directory of the
99 specific service is not visible to any other service. Use `PrivateMounts=` as
100 minimal option to enable such namespacing. Note that many other sandboxing
101 settings (e.g. `ProtectSystem=`, `ReadOnlyPaths=` and similar) imply
102 `PrivateMounts=`, hence oftentimes it's not necessary to set this option
103 explicitly.
104
105 ## Programming Interface from Service Code
106
107 When a service is invoked with one or more credentials set it will have an
108 environment variable `$CREDENTIALS_DIRECTORY` set. It contains an absolute path
109 to a directory the credentials are placed in. In this directory for each
110 configured credential one file is placed. In addition to the
111 `$CREDENTIALS_DIRECTORY` environment variable passed to the service processes
112 the `%d` specifier in unit files resolves to the service's credential
113 directory.
114
115 Example unit file:
116
117 ```
118
119 [Service]
120 ExecStart=/usr/bin/myservice.sh
121 LoadCredential=foobar:/etc/myfoobarcredential.txt
122 Environment=FOOBARPATH=%d/foobar
123
124 ```
125
126 Associated service shell script `/usr/bin/myservice.sh`:
127
128 ```sh
129 #!/bin/sh
130
131 sha256sum $CREDENTIAL_PATH/foobar
132 sha256sum $FOOBARPATH
133
134 ```
135
136 A service defined like this will get the contents of the file
137 `/etc/myfoobarcredential.txt` passed as credential `foobar`, which is hence
138 accessible under `$CREDENTIALS_DIRECTORY/foobar`. Since we additionally pass
139 the path to it as environment variable `$FOOBARPATH` the credential is also
140 accessible as the path in that environment variable. When invoked, the service
141 will hence show the same SHA256 hash value of `/etc/myfoobarcredential.txt`
142 twice.
143
144 In an ideal world, well-behaved service code would directly support credentials
145 passed this way, i.e. look for `$CREDENTIALS_DIRECTORY` and load the credential
146 data it needs from there. For daemons that do not support this but allow
147 passing credentials via a path supplied over the command line use
148 `${CREDENTIAL_PATH}` in the `ExecStart=` command line to reference the
149 credentials directory. For daemons that allow passing credentials via a path
150 supplied as environment variable, use the `%d` specifier in the `Environment=`
151 setting to build valid paths to specific credentials.
152
153 ## Tools
154
155 The
156 [`systemd-creds`](https://www.freedesktop.org/software/systemd/man/systemd-creds.html)
157 tool is provided to work with system and service credentials. It may be used to
158 access and enumerate system and service credentials, or to encrypt/decrypt credentials
159 (for details about the latter, see below).
160
161 When invoked from service context, `systemd-creds` passed without further
162 parameters will list passed credentials. The `systemd-creds cat xyz` command
163 may be used to write the contents of credential `xyz` to standard output. If
164 these calls are combined with the `--system` switch credentials passed to the
165 system as a whole are shown, instead of the those passed to the service the
166 command is invoked from.
167
168 Example use:
169
170 ```sh
171 systemd-run -P --wait -p LoadCredential=abc:/etc/hosts systemd-creds cat abc
172 ```
173
174 This will invoke a transient service with a credential `abc` sourced from the
175 system's `/etc/hosts` file. This credential is then written to standard output
176 via `systemd-creds cat`.
177
178 ## Encryption
179
180 Credentials are supposed to be useful for carrying sensitive information, such
181 as cryptographic key material. For this kind of data (symmetric) encryption and
182 authentication is provided to make storage of the data at rest safer. The data
183 may be encrypted and authenticated with AES256-GCM. The encryption key can
184 either be one derived from the local TPM2 device, or one stored in
185 `/var/lib/systemd/credential.secret`, or a combination of both. If a TPM2
186 device is available and `/var/` resides on persistent storage the default
187 behaviour is to use the combination of both for encryption, thus ensuring that
188 credentials protected this way can only be decrypted and validated on the
189 local hardware and OS installation. Encrypted credentials stored on disk thus
190 cannot be decrypted without access to the TPM2 chip and the aforementioned key
191 file `/var/lib/systemd/credential.secret`. Moreover, credentials cannot be
192 prepared on another machine than the local one.
193
194 The `systemd-creds` tool provides the commands `encrypt` and `decrypt` to
195 encrypt and decrypt/authenticate credentials. Example:
196
197 ```sh
198 systemd-creds encrypt plaintext.txt ciphertext.cred
199 shred -u plaintext.txt
200 systemd-run -P --wait -p LoadCredentialEncrypted=foobar:$(pwd)/ciphertext.cred systemd-creds cat foobar
201 ```
202
203 This will first create an encrypted copy of the file `plaintext.txt` in the
204 encrypted credential file `ciphertext.cred`. It then securely removes the
205 source file. It then runs a transient service, that reads the encrypted file
206 and passes it as decrypted credential `foobar` to the invoked service binary
207 (which here is the `systemd-creds` tool, which just writes the data
208 it received to standard output).
209
210 Instead of storing the encrypted credential as a separate file on disk, it can
211 also be embedded in the unit file. Example:
212
213 ```
214 systemd-creds encrypt -p --name=foobar plaintext.txt -
215 ```
216
217 This will output a `SetCredentialEncrypted=` line that can directly be used in
218 a unit file. e.g.:
219
220 ```
221
222 [Service]
223 ExecStart=/usr/bin/systemd-creds cat foobar
224 SetCredentialEncrypted=foobar: \
225 k6iUCUh0RJCQyvL8k8q1UyAAAAABAAAADAAAABAAAAC1lFmbWAqWZ8dCCQkAAAAAgAAAA \
226 AAAAAALACMA0AAAACAAAAAAfgAg9uNpGmj8LL2nHE0ixcycvM3XkpOCaf+9rwGscwmqRJ \
227 cAEO24kB08FMtd/hfkZBX8PqoHd/yPTzRxJQBoBsvo9VqolKdy9Wkvih0HQnQ6NkTKEdP \
228 HQ08+x8sv5sr+Mkv4ubp3YT1Jvv7CIPCbNhFtag1n5y9J7bTOKt2SQwBOAAgACwAAABIA \
229 ID8H3RbsT7rIBH02CIgm/Gv1ukSXO3DMHmVQkDG0wEciABAAII6LvrmL60uEZcp5qnEkx \
230 SuhUjsDoXrJs0rfSWX4QAx5PwfdFuxPusgEfTYIiCb8a/W6RJc7cMweZVCQMbTARyIAAA \
231 AAJt7Q9F/Gz0pBv1Lc4Dpn1WpebyBBm+vQ5N/lSKW2XSm8cONwCopxpDc7wJjXg7OTR6r \
232 xGCpIvGXLt3ibwJl81woLya2RRjIvc/R2zNm/yWzZAjiOLPih4SuHthqiX98ey8PUmZJB \
233 VGXglCZFjBx+d7eCqTIdghtp5pkDGwMJT6pjw4FfyFK2nJPawFKPAqzw9DK2iYttFeXi5 \
234 19xCfLBH9NKS/idlYXrhp+XIEtsr26s4lx5y10Goyc3qDOR3RD2cuZj0gHwV35hhhhcCz \
235 JaYytef1X/YL+7fYH5kuE4rxSksoUuA/LhtjszBeGbcbIT+O8SuvBJHLKTSHxPL8FTyk3 \
236 L4FSkEHs0rYwUIkKmnGohDdsYrMJ2fjH3yDNBP16aD1+f/Nuh75cjhUnGsDLt9K4hGg== \
237
238 ```
239
240 ## Inheritance from Container Managers, Hypervisors, Kernel Command Line, or the UEFI Boot Environment
241
242 Sometimes it is useful to parameterize whole systems the same way as services,
243 via `systemd` credentials. In particular, it might make sense to boot a
244 system with a set of credentials that are then propagated to individual
245 services where they are ultimately consumed.
246
247 `systemd` supports four ways to pass credentials to systems:
248
249 1. A container manager may set the `$CREDENTIALS_DIRECTORY` environment
250 variable for systemd running as PID 1 in the container, the same way as
251 systemd would set it for a service it
252 invokes. [`systemd-nspawn(1)`](https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html#Credentials)'s
253 `--set-credential=` and `--load-credential=` switches implement this, in
254 order to pass arbitrary credentials from host to container payload. Also see
255 the [Container Interface](CONTAINER_INTERFACE.md)
256 documentation.
257
258 2. Quite similar, VMs can be passed credentials via SMBIOS OEM strings (example
259 qemu command line switch `-smbios
260 type=11,value=io.systemd.credential:foo=bar` or `-smbios
261 type=11,value=io.systemd.credential.binary:foo=YmFyCg==`, the latter taking
262 a Base64 encoded argument to permit binary credentials being passed
263 in). Alternatively, qemu VMs can be invoked with `-fw_cfg
264 name=opt/io.systemd.credentials/foo,string=bar` to pass credentials from
265 host through the hypervisor into the VM via qemu's `fw_cfg` mechanism. (All
266 three of these specific switches would set credential `foo` to `bar`.)
267 Passing credentials via the SMBIOS mechanism is typically preferable over
268 `fw_cfg` since it is faster and less specific to the chosen VMM
269 implementation. Moreover, `fw_cfg` has a 55 character limitation
270 on names passed that way. So some settings may not fit.
271
272 3. Credentials can also be passed into a system via the kernel command line,
273 via the `systemd.set-credential=` kernel command line option. Note though
274 that any data specified here is visible to any userspace application via
275 `/proc/cmdline`. This is hence typically not useful to pass sensitive
276 information.
277
278 4. Credentials may also be passed from the UEFI environment to userspace, if
279 the
280 [`systemd-stub`](https://www.freedesktop.org/software/systemd/man/systemd-stub.html)
281 UEFI kernel stub is used. This allows placing encrypted credentials in the
282 EFI System Partition, which are then picked up by `systemd-stub` and passed
283 to the kernel and ultimately userspace where systemd receives them. This is
284 useful to implement secure parameterization of vendor-built and signed
285 initial RAM disks, as userspace can place credentials next to these EFI
286 kernels, and be sure they can be accessed securely from initrd context.
287
288 Credentials passed to the system may be enumerated/displayed via `systemd-creds
289 --system`. They may also be propagated down to services, via the
290 `LoadCredential=` setting. Example:
291
292 ```
293 systemd-nspawn --set-credential=mycred:supersecret -i test.raw -b
294 ```
295
296 or
297
298 ```
299 qemu-system-x86_64 \
300 -machine type=q35,accel=kvm,smm=on \
301 -smp 2 \
302 -m 1G \
303 -cpu host \
304 -nographic \
305 -nodefaults \
306 -serial mon:stdio \
307 -drive if=none,id=hd,file=test.raw,format=raw \
308 -device virtio-scsi-pci,id=scsi \
309 -device scsi-hd,drive=hd,bootindex=1 \
310 -smbios type=11,value=io.systemd.credential:mycred=supersecret
311 ```
312
313 Either of these lines will boot a disk image `test.raw`, once as container via
314 `systemd-nspawn`, and once as VM via `qemu`. In each case the credential
315 `mycred` is set to `supersecret`.
316
317 Inside of the system invoked that way the credential may then be viewed:
318
319 ```sh
320 systemd-creds --system cat mycred
321 ```
322
323 Or propagated to services further down:
324
325 ```
326 systemd-run -p LoadCredential=mycred -P --wait systemd-creds cat mycred
327 ```
328
329 ## Well-Known Credentials
330
331 Various services shipped with `systemd` consume credentials for tweaking behaviour:
332
333 * [`systemd-sysusers(8)`](https://www.freedesktop.org/software/systemd/man/systemd-sysusers.html)
334 will look for the credentials `passwd.hashed-password.<username>`,
335 `passwd.plaintext-password.<username>` and `passwd.shell.<username>` to
336 configure the password (either in UNIX hashed form, or plaintext) or shell of
337 system users created. Replace `<username>` with the system user of your
338 choice, for example `root`.
339
340 * [`systemd-firstboot(1)`](https://www.freedesktop.org/software/systemd/man/systemd-firstboot.html)
341 will look for the credentials `firstboot.locale`, `firstboot.locale-messages`,
342 `firstboot.keymap`, `firstboot.timezone`, that configure locale, keymap or
343 timezone settings in case the data is not yet set in `/etc/`.
344
345 In future more services are likely to gain support for consuming credentials.
346
347 Example:
348
349 ```
350 systemd-nspawn -i test.raw \
351 --set-credential=passwd.hashed-password.root:$(mkpasswd mysecret) \
352 --set-credential=firstboot.locale:C.UTF-8 \
353 -b
354 ```
355
356 This boots the specified disk image as `systemd-nspawn` container, and passes
357 the root password `mysecret`and default locale `C.UTF-8` to use to it. This
358 data is then propagated by default to `systemd-sysusers.service` and
359 `systemd-firstboot.service`, where it is applied. (Note that these services
360 will only do so if these settings in `/etc/` are so far unset, i.e. they only
361 have an effect on *unprovisioned* systems, and will never override data already
362 established in `/etc/`.) A similar line for qemu is:
363
364 ```
365 qemu-system-x86_64 \
366 -machine type=q35,accel=kvm,smm=on \
367 -smp 2 \
368 -m 1G \
369 -cpu host \
370 -nographic \
371 -nodefaults \
372 -serial mon:stdio \
373 -drive if=none,id=hd,file=test.raw,format=raw \
374 -device virtio-scsi-pci,id=scsi \
375 -device scsi-hd,drive=hd,bootindex=1 \
376 -smbios type=11,value=io.systemd.credential:passwd.hashed-password.root=$(mkpasswd mysecret) \
377 -smbios type=11,value=io.systemd.credential:firstboot.locale=C.UTF-8
378 ```
379
380 ## Relevant Paths
381
382 From *service* perspective the runtime path to find loaded credentials in is
383 provided in the `$CREDENTIALS_DIRECTORY` environment variable.
384
385 At runtime, credentials passed to the *system* are placed in
386 `/run/credentials/@system/` (for regular credentials, such as those passed from
387 a container manager or via qemu) and `/run/credentials/@encrypted/` (for
388 credentials that must be decrypted/validated before use, such as those from
389 `systemd-stub`).
390
391 The `LoadCredential=` and `LoadCredentialEncrypted=` settings when configured
392 with a relative source path will search for the source file to read the
393 credential from automatically. Primarily, these credentials are searched among
394 the credentials passed into the system. If not found there, they are searched
395 in `/etc/credstore/`, `/run/credstore/`,
396 `/usr/lib/credstore/`. `LoadCredentialEncrypted=` will also search
397 `/etc/credstore.encrypted/` and similar directories. These directories are
398 hence a great place to store credentials to load on the system.
399
400 ## Conditionalizing Services
401
402 Sometimes it makes sense to conditionalize system services and invoke them only
403 if the right system credential is passed to the system. use the
404 `ConditionCredential=` and `AssertCredential=` unit file settings for that.