]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
doc: document inird credentials + and how to consume credentials in generators
authorLennart Poettering <lennart@poettering.net>
Fri, 30 Jun 2023 09:44:46 +0000 (11:44 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 4 Jul 2023 21:17:17 +0000 (23:17 +0200)
(as well as various other fixes)

docs/CREDENTIALS.md

index 50100cc5b6193b22062bdcf3de392dd7a493974c..da5152c16457b7b099ef9d4400cca1592f78077a 100644 (file)
@@ -51,9 +51,9 @@ purpose. Specifically, the following features are provided:
    allow it, via `ramfs`.)
 
 7. Credentials may be acquired from a hosting VM hypervisor (SMBIOS OEM strings
-   or qemu `fw_cfg`), a hosting container manager, the kernel command line, or
-   from the UEFI environment and the EFI System Partition (via
-   `systemd-stub`). Such system credentials may then be propagated into
+   or qemu `fw_cfg`), a hosting container manager, the kernel command line,
+   from the initrd, or from the UEFI environment via the EFI System Partition
+   (via `systemd-stub`). Such system credentials may then be propagated into
    individual services as needed.
 
 8. Credentials are an effective way to pass parameters into services that run
@@ -72,19 +72,19 @@ Within unit files, there are four settings to configure service credentials.
 1. `LoadCredential=` may be used to load a credential from disk, from an
    `AF_UNIX` socket, or propagate them from a system credential.
 
-2. `ImportCredential=` may be used to load one or more (encrypted) credentials
-   from disk or from the credential stores.
+2. `ImportCredential=` may be used to load one or more (optionally encrypted)
+   credentials from disk or from the credential stores.
 
-2. `SetCredential=` may be used to set a credential to a literal string encoded
+3. `SetCredential=` may be used to set a credential to a literal string encoded
    in the unit file. Because unit files are world-readable (both on disk and
    via D-Bus), this should only be used for credentials that aren't sensitive,
    e.g. public keys or certificates, but not private keys.
 
-3. `LoadCredentialEncrypted=` is similar to `LoadCredential=` but will load an
+4. `LoadCredentialEncrypted=` is similar to `LoadCredential=` but will load an
    encrypted credential, and decrypt it before passing it to the service. For
    details on credential encryption, see below.
 
-4. `SetCredentialEncrypted=` is similar to `SetCredential=` but expects an
+5. `SetCredentialEncrypted=` is similar to `SetCredential=` but expects an
    encrypted credential to be specified literally. Unlike `SetCredential=` it
    is thus safe to be used even for sensitive information, because even though
    unit files are world readable, the ciphertext included in them cannot be
@@ -153,6 +153,33 @@ credentials directory. For daemons that allow passing credentials via a path
 supplied as environment variable, use the `%d` specifier in the `Environment=`
 setting to build valid paths to specific credentials.
 
+Encrypted credentials are automatically decrypted/authenticated during service
+activation, so that service code only receives plaintext credentials.
+
+## Programming Interface from Generator Code
+
+[Generators](https://www.freedesktop.org/software/systemd/man/systemd.generator.html)
+may generate native unit files from external configuration or system
+parameters, such as system credentials. Note that they run outside of service
+context, and hence will not receive encrypted credentials in plaintext
+form. Specifically, credentials passed into the system in encrypted form will
+be placed as they are in a directory referenced by the
+`$ENCRYPTED_CREDENTIALS_DIRECTORY` environment variable, and those passed in
+plaintext form will be placed in `$CREDENTIALS_DIRECTORY`. Use a command such
+as `systemd-creds --system cat …` to access both forms of credentials, and
+decrypt them if needed (see
+[systemd-creds(1)](https://www.freedesktop.org/software/systemd/man/systemd-creds.html)
+for details.
+
+Note that generators typically run very early during boot (similar to initrd
+code), earlier than the `/var/` file system is necessarily mounted (which is
+where the system's credential encryption secret is located). Thus it's a good
+idea to encrypt credentials with `systemd-creds encrypt --with-key=auto-initrd`
+if they shall be consumed by a generator, to ensure they are locked to the TPM2
+only, not the credentials secret stored below `/var/`.
+
+For further details about encrypted credentials, see below.
+
 ## Tools
 
 The
@@ -194,6 +221,12 @@ cannot be decrypted without access to the TPM2 chip and the aforementioned key
 file `/var/lib/systemd/credential.secret`. Moreover, credentials cannot be
 prepared on a machine other than the local one.
 
+Decryption generally takes place at the moment of service activation. This
+means credentials passed to the system can be either encrypted or plaintext and
+remain that way all the way while they are propagated to their consumers, until
+the moment of service activation when they are decrypted and authenticated, so
+that the service only sees plaintext credentials.
+
 The `systemd-creds` tool provides the commands `encrypt` and `decrypt` to
 encrypt and decrypt/authenticate credentials. Example:
 
@@ -247,7 +280,7 @@ via `systemd` credentials. In particular, it might make sense to boot a
 system with a set of credentials that are then propagated to individual
 services where they are ultimately consumed.
 
-`systemd` supports four ways to pass credentials to systems:
+`systemd` supports five ways to pass credentials to systems:
 
 1. A container manager may set the `$CREDENTIALS_DIRECTORY` environment
    variable for systemd running as PID 1 in the container, the same way as
@@ -255,8 +288,7 @@ services where they are ultimately consumed.
    invokes. [`systemd-nspawn(1)`](https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html#Credentials)'s
    `--set-credential=` and `--load-credential=` switches implement this, in
    order to pass arbitrary credentials from host to container payload. Also see
-   the [Container Interface](CONTAINER_INTERFACE.md)
-   documentation.
+   the [Container Interface](CONTAINER_INTERFACE.md) documentation.
 
 2. Quite similar, VMs can be passed credentials via SMBIOS OEM strings (example
    qemu command line switch `-smbios
@@ -269,16 +301,17 @@ services where they are ultimately consumed.
    three of these specific switches would set credential `foo` to `bar`.)
    Passing credentials via the SMBIOS mechanism is typically preferable over
    `fw_cfg` since it is faster and less specific to the chosen VMM
-   implementation. Moreover, `fw_cfg` has a 55 character limitation
-   on names passed that way. So some settings may not fit.
+   implementation. Moreover, `fw_cfg` has a 55 character limitation on names
+   passed that way. So some settings may not fit.
 
-3. Credentials can also be passed into a system via the kernel command line,
-   via the `systemd.set-credential=` kernel command line option. Note though
-   that any data specified here is visible to any userspace application via
-   `/proc/cmdline`. This is hence typically not useful to pass sensitive
-   information.
+3. Credentials may be passed from the initrd to the host during the initrd →
+   host transition. Provisioning systems that run in the initrd may use this to
+   install credentials on the system. All files placed in
+   `/run/credentials/@initrd/` are imported into the set of file system
+   credentials during the transition. The files (and their directory) are
+   removed once this is completed.
 
-4. Credentials may also be passed from the UEFI environment to userspace, if
+5. Credentials may also be passed from the UEFI environment to userspace, if
    the
    [`systemd-stub`](https://www.freedesktop.org/software/systemd/man/systemd-stub.html)
    UEFI kernel stub is used. This allows placing encrypted credentials in the
@@ -288,6 +321,12 @@ services where they are ultimately consumed.
    initrds, as userspace can place credentials next to these EFI kernels, and
    be sure they can be accessed securely from initrd context.
 
+4. Credentials can also be passed into a system via the kernel command line,
+   via the `systemd.set-credential=` kernel command line option. Note though
+   that any data specified here is visible to all userspace applications (even
+   unprivileged ones) via `/proc/cmdline`. Typically, this is hence not useful
+   to pass sensitive information, and should be avoided.
+
 Credentials passed to the system may be enumerated/displayed via `systemd-creds
 --system`. They may also be propagated down to services, via the
 `LoadCredential=` setting. Example:
@@ -359,6 +398,9 @@ Various services shipped with `systemd` consume credentials for tweaking behavio
   will look for the credentials `tmpfiles.extra` with arbitrary tmpfiles.d lines.
   Can be encoded in base64 to allow easily passing it on the command line.
 
+* Further well-known credentials are documented in
+  [`systemd.system-credentials(7)`](https://www.freedesktop.org/software/systemd/man/systemd.system-credentials.html).
+
 In future more services are likely to gain support for consuming credentials.
 
 Example:
@@ -427,6 +469,11 @@ READY=1
 From *service* perspective the runtime path to find loaded credentials in is
 provided in the `$CREDENTIALS_DIRECTORY` environment variable.
 
+From *generator* perspective the runtime path to find credentials passed into
+the system in plaintext form in is provided in `$CREDENTIALS_DIRECTORY`, and
+those passed into the system in encrypted form is provided in
+`$ENCRYPTED_CREDENTIALS_DIRECTORY`.
+
 At runtime, credentials passed to the *system* are placed in
 `/run/credentials/@system/` (for regular credentials, such as those passed from
 a container manager or via qemu) and `/run/credentials/@encrypted/` (for
@@ -434,13 +481,14 @@ credentials that must be decrypted/validated before use, such as those from
 `systemd-stub`).
 
 The `ImportCredential=` setting (and the `LoadCredential=` and
-`LoadCredentialEncrypted=` settings when configured with a relative source path)
-will search for the source file to read the credential from automatically. Primarily,
-these credentials are searched among the credentials passed into the system. If
-not found there, they are searched in `/etc/credstore/`, `/run/credstore/`,
+`LoadCredentialEncrypted=` settings when configured with a relative source
+path) will search for the source file to read the credential from
+automatically. Primarily, these credentials are searched among the credentials
+passed into the system. If not found there, they are searched in
+`/etc/credstore/`, `/run/credstore/`,
 `/usr/lib/credstore/`. `LoadCredentialEncrypted=` will also search
-`/etc/credstore.encrypted/` and similar directories. `ImportCredential` will search
-both the non-encrypted and encrypted directories. These directories are
+`/etc/credstore.encrypted/` and similar directories. `ImportCredential=` will
+search both the non-encrypted and encrypted directories. These directories are
 hence a great place to store credentials to load on the system.
 
 ## Conditionalizing Services