# systemd-keyring-setup.service

systemd

systemd-keyring-setup.service

8

systemd-keyring-setup.service

systemd-keyring-setup

Enroll certificates into kernel keyrings

`systemd-keyring-setup.service`

/usr/lib/systemd/systemd-keyring-setup

OPTIONS

KEYRING

# Description

`systemd-keyring-setup.service` is an early boot service that enrolls X.509 certificates into the kernel keyrings used to verify signatures on dm-verity volumes, fs-verity files and BPF programs, and then seals these keyrings. The certificates are read from the [File Hierarchy for the Verification of OS Artifacts](https://uapi-group.org/specifications/specs/file_hierarchy_for_the_verification_of_os_artifacts/) (VOA). This allows the kernel to verify signatures with keys provided by the OS vendor or the local administrator, without rebuilding the kernel and without enrolling the keys into the firmware.

The following keyrings are provisioned, each from a VOA *context* of the `kernel-keyring` purpose:

| Keyring | VOA context | Used to verify |
|----|----|----|
| `.dm-verity` | `dm-verity` | Signatures of the root hashes of dm-verity volumes, such as those of Discoverable Disk Images set up by `systemd-veritysetup@.service(8)`, `systemd-dissect(1)` or the `RootImage=` setting of services |
| `.fs-verity` | `fs-verity` | Built-in signatures of fs-verity protected files |
| `.bpf` | `bpf` | Signatures of BPF programs |

Keyrings and VOA contexts

The kernel only uses the `.dm-verity` and `.bpf` keyrings once they have been sealed, and seals them itself while they are still empty, unless `dm_verity.keyring_unsealed=1` or `bpf.keyring_unsealed=1` is specified on the kernel command line, respectively. Hence, these options are required to provision the two keyrings, see below. The `.fs-verity` keyring is not sealed by the kernel, and is used as soon as it contains a key.

For each keyring that is not sealed yet, the service enrolls the certificates it finds and then seals the keyring: it installs a restriction so that only certificates signed by a key in the keyring can be added afterwards, and removes the permission to change this restriction or the permissions of the keyring. The keyring is sealed even if no certificates were found, or if some of them could not be enrolled. Keys that were already in the keyring before the service ran are sealed in as well, and a warning is logged about them.

The service runs both in the initrd and on the host. Usually, the keyrings are provisioned in the initrd, since the root file system might itself be a dm-verity volume that is verified with one of the enrolled keys. When the service runs again on the host, the keyrings have been sealed already. In this case, only certificates signed by a key that was enrolled earlier can be added, and all other certificates are rejected. Certificates that have been enrolled already are skipped.

# Certificate Directories and Precedence

Certificates are read from the VOA load paths `/etc/voa/`, `/run/voa/`, `/usr/local/share/voa/` and `/usr/share/voa/`, in order of decreasing priority. For each keyring, artifact verifiers are read from `OS/kernel-keyring/CONTEXT/x509/NAME-certificate.pem`, and trust anchors from `OS/trust-anchor-kernel-keyring/CONTEXT/x509/NAME-certificate.pem` below each load path. Both are enrolled into the same keyring, and only differ in how their usage is checked, see below. \<NAME\> may consist of lowercase letters, digits, `.`, `_` and `-`, other files are ignored. Each file must contain a single PEM-encoded certificate. A file that contains more than one certificate is ignored as a whole. CA certificates should be placed in separate files among the trust anchors instead.

Certificates are looked up for two OS identifiers derived from `os-release(5)`: the exact identifier, and the value of `ID=` alone. The exact identifier consists of the values of `ID=`, `VERSION_ID=`, `VARIANT_ID=`, `IMAGE_ID=` and `IMAGE_VERSION=`, separated by `:`. A field that is not set is left empty, and unset fields at the end are omitted. For example, `ID=debian` and `VERSION_ID=13` result in the identifiers `debian:13` and `debian`. If `ID=` is not set, `linux` is used. If one of the other fields contains characters that are not permitted by the VOA specification, only the value of `ID=` is used. If `ID=` itself contains such characters, no certificates are looked up. The `keyring-setup.os` credential may be used to specify the identifiers explicitly, see below.

Note that the VOA specification requires different semantics than the usual logic for configuration files, where a file in a directory with higher priority replaces a file with the same name in a directory with lower priority. Instead, X.509 certificates are merged: all files in all load paths are used. A certificate that is found in more than one place is only enrolled once. If two different certificates have the same subject and key identifier, only one of them can be added to a keyring. In this case, certificates found for the exact OS identifier take precedence over the ones found for the value of `ID=` alone, and among those, the certificate from the load path with the highest priority is enrolled.

A certificate may be masked by placing a symlink to `/dev/null` with the same file name in any of the load paths, usually in `/etc/voa/` or `/run/voa/`. As required by the VOA specification, a masked certificate is ignored in all load paths, including the ones with a higher priority than the one containing the symlink. Masking is meant as a substitute for revocation: if a certificate is considered compromised, a single symlink ensures that none of its copies is enrolled. Other symlinks are followed as long as they point to a location within the VOA hierarchy, and symlinks to certificate files only if the target has the same file name.

To make sure that certificates cannot be placed by unprivileged users, files that are executable or world-writable, and directories that are world-writable, are ignored. Once a directory owned by an unprivileged user has been entered, the lookup does not continue into files or directories owned by anyone else.

As required by the VOA specification, the usage of each certificate is checked against its purpose. An artifact verifier is ignored if it has an extended key usage extension that permits neither code signing nor any extended key usage, or a key usage extension that does not permit digital signatures. A trust anchor that is not a CA certificate is enrolled nonetheless, since self-signed certificates that act as their own trust anchor are common, but a message is logged about it. Certificates with invalid extensions are ignored.

# Credentials

`systemd-keyring-setup` supports the service credentials logic as implemented by `ImportCredential=`/`LoadCredential=`/`SetCredential=` (see `systemd.exec(5)` for details). The following credentials are used when passed in:

`keyring-setup.dm-verity.NAME`; `keyring-setup.fs-verity.NAME`; `keyring-setup.bpf.NAME`  
A PEM-encoded X.509 certificate to enroll into the `.dm-verity`, `.fs-verity` or `.bpf` keyring, respectively. \<NAME\> may consist of lowercase letters, digits, `.`, `_` and `-`. As suggested by the VOA specification for certificates obtained from elsewhere, the certificate is not enrolled directly, but is first written to `/run/voa/OS/kernel-keyring/CONTEXT/x509/NAME-certificate.pem`, using the first OS identifier. Hence, masking and merging apply to it like to any other file in the hierarchy. Only the certificate itself is written there, so that a private key included in the credential is not made readable to other users. A credential that does not contain exactly one certificate is ignored.

`keyring-setup.os`  
A whitespace-separated list of up to 64 OS identifiers to use instead of the ones derived from `os-release(5)`. This is useful for generic initrds, whose `os-release` does not match the one of the host. If the list is empty, too long or contains an invalid identifier, the credential is ignored and the identifiers derived from `os-release` are used.

See `systemd.system-credentials(7)` for details about system credentials.

# Options

If one or more \<KEYRING\> names, such as `.dm-verity`, are specified, only those keyrings are processed. Otherwise, all keyrings listed above are processed.

The following options are understood:

`--dry-run`  
Show which certificates would be enrolled into which keyring, and the current state of the keyrings, without changing anything.

`--json=` is only supported together with `--dry-run`.

# Exit status

On success, 0 is returned. This includes the cases where a keyring does not exist, or has been provisioned by an earlier run already. If a certificate or a credential could not be used, for example because it is malformed, or because it is not signed by a key in a keyring that has been sealed already, 65 (`EX_DATAERR`) is returned. `systemd-keyring-setup.service` treats this exit status as success. On other failures, a different non-zero exit status is returned.

# Kernel Command Line

`dm_verity.keyring_unsealed=`; `bpf.keyring_unsealed=`  
These options are interpreted by the kernel. If set to `1`, the kernel leaves the `.dm-verity` or `.bpf` keyring unsealed during boot, so that it can be provisioned by `systemd-keyring-setup.service`. Otherwise, the kernel seals the keyring while it is still empty, and no certificates can be enrolled into it.

# Security Considerations

The enrolled certificates can only be trusted as much as the files they were read from. The intended deployment is to provision the keyrings from the initrd of a signed Unified Kernel Image, see `systemd-stub(7)`.

Until a keyring is sealed, any sufficiently privileged process may add arbitrary keys to it. After it has been sealed, privileged processes may still remove keys from it, and add certificates that are signed by a key in the keyring, but they cannot add other keys, or change the restriction or the permissions of the keyring. The keyrings stay sealed until the next reboot. A soft reboot, see `systemd-soft-reboot.service(8)`, does not reset them.

If dm-verity is built as a kernel module, unloading and reloading the module discards the `.dm-verity` keyring, including its seal, and creates a new, empty one. If `dm_verity.keyring_unsealed=1` is set, the new keyring may then be provisioned with arbitrary keys again. `systemd-keyring-setup` logs a warning if a keyring belongs to a loadable kernel module. For high-security setups, dm-verity should be built into the kernel.

Note that kexec will unseal and empty the keyrings. If enabled and allowed, the caller may use it to load their own certificates into the chain of trust, so this is out of scope for this component and needs to be handled by the system integrators with an appropriate security policy.

# See Also

`systemd(1)`, `systemd-veritysetup@.service(8)`, `systemd-dissect(1)`, `systemd-stub(7)`, `systemd.system-credentials(7)`, `os-release(5)`, `keyctl(1)`