Merge pull request #28207 from poettering/initrd-creds

various credential improvements (including initrd creds, creds in generators, fstab + getty creds)
This commit is contained in:
Luca Boccassi
2023-07-05 10:29:33 +01:00
committed by GitHub
38 changed files with 1143 additions and 213 deletions

36
TODO
View File

@@ -131,12 +131,6 @@ Deprecations and removals:
Features:
* use kernel 6.3's "noswap" parameter in tmpfs in place of ramfs for storing
credentials.
* import-creds: allocate a non-swap-backed fs for /run/credentials/@system,
like we do for services.
* new "systemd-pcrlock" component for dealing with PCR4. Design idea:
1. define /{etc,usr,var/lib}/pcrlock.d/<component>/<version>.pcrlock
2. these files contain list of hashes that will be measured when component is
@@ -225,12 +219,10 @@ Features:
support .microcode in PE add-ons, so that a microcode update can be shipped
independently of any kernel.
* add clean mechanism concept for passing env/creds from initrd to host on
switch root, so that cloud-init and similar have a clean, sane method to pass
along the stuff they picked up, without patching any dirs. Maybe add
SwitchRootEx() as new bus call that takes these as argument. When adding
SwitchRootEx() we should maybe also add a flags param that allows disabling
and enabling whether serialization is requested during switch root.
* Maybe add SwitchRootEx() as new bus call that takes env vars to set for new
PID 1 as argument. When adding SwitchRootEx() we should maybe also add a
flags param that allows disabling and enabling whether serialization is
requested during switch root.
* introduce a .acpitable section for early ACPI table override
@@ -249,10 +241,6 @@ Features:
scenarios. Maybe insist sealing is done additionally against some keypair in
the TPM to which access is updated on each boot, for the next, or so?
* open up creds for uses in generators, and document clearly that encrypted
creds are only supported if strictly tpm bound, but not when using the host
secret (as that is only available if /var/ is around.
* logind: when logging in, always take an fd to the home dir, to keep the dir
busy, so that autofs release can never happen. (this is generally a good
idea, and specifically works around the fact the autofs ignores busy by mount
@@ -819,10 +807,9 @@ Features:
* Process credentials in:
• networkd/udevd: add a way to define additional .link, .network, .netdev files
via the credentials logic.
fstab-generator: allow defining additional fstab-like mounts via
credentials (similar: crypttab-generator, verity-generator,
integrity-generator)
• getty-generator: allow defining additional getty instances via a credential
crypttab-generator: allow defining additional crypttab-like volumes via
credentials (similar: verity-generator, integrity-generator). Use
fstab-generator logic as inspiration.
• run-generator: allow defining additional commands to run via a credential
• resolved: allow defining additional /etc/hosts entries via a credential (it
might make sense to then synthesize a new combined /etc/hosts file in /run
@@ -837,9 +824,6 @@ Features:
systemd.homed.register or so with JSON user records to automatically
register if not registered yet. Usecase: deploy a system, and add an
account one can directly log into.
• initialize machine ID from systemd credential picked up from the ESP via
sd-stub, so that machine ID is stable even on systems where unified kernels
are used, and hence kernel cmdline cannot be modified locally
• in gpt-auto-generator: check partition uuids against such uuids supplied via
sd-stub credentials. That way, we can support parallel OS installations with
pre-built kernels.
@@ -948,11 +932,6 @@ Features:
https://0pointer.net/blog/testing-my-system-code-in-usr-without-modifying-usr.html
https://0pointer.net/blog/running-an-container-off-the-host-usr.html
* add a clear concept how the initrd can make up credentials on their own to
pass to the system when transitioning into the host OS. usecase: things like
cloud-init/ignitation and similar can parameterize the host with data they
acquire.
* sd-event: compat wd reuse in inotify code: keep a set of removed watch
descriptors, and clear this set piecemeal when we see the IN_IGNORED event
for it, or when read() returns EAGAIN or on IN_Q_OVERFLOW. Then, whenever we
@@ -969,7 +948,6 @@ Features:
- kernel-install should be able to pick up initrd sysexts automatically and
place them next to EFI kernel, for sd-stub to pick them up.
- systemd-fstab-generator should look for rootfs device to mount in creds
- pid 1 should look for machine ID in creds
- systemd-resume-generator should look for resume partition uuid in creds
- sd-stub: automatically pick up microcode from ESP (/loader/microcode/*)
and synthesize initrd from it, and measure it. Signing is not necessary, as

View 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,13 @@ 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=` and `systemd.set_credential_binary=`
kernel command line options (the latter takes Base64 encoded binary
data). 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 +399,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 +470,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 +482,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

View File

@@ -49,6 +49,15 @@
<variablelist id='environment-variables' />
</refsect1>
<refsect1>
<title>System Credentials</title>
<para>System credentials understood by the system and service manager and various other
components:</para>
<variablelist id='system-credentials' />
</refsect1>
<refsect1>
<title>EFI variables</title>

View File

@@ -72,6 +72,7 @@
<term><varname>systemd.setenv=</varname></term>
<term><varname>systemd.machine_id=</varname></term>
<term><varname>systemd.set_credential=</varname></term>
<term><varname>systemd.set_credential_binary=</varname></term>
<term><varname>systemd.import_credentials=</varname></term>
<term><varname>systemd.reload_limit_interval_sec=</varname></term>
<term><varname>systemd.reload_limit_burst=</varname></term>

View File

@@ -308,10 +308,10 @@
(see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details). The following credentials are used when passed in:</para>
<variablelist>
<variablelist class='system-credentials'>
<varlistentry>
<term><literal>passwd.hashed-password.root</literal></term>
<term><literal>passwd.plaintext-password.root</literal></term>
<term><varname>passwd.hashed-password.root</varname></term>
<term><varname>passwd.plaintext-password.root</varname></term>
<listitem><para>A hashed or plaintext version of the root password to use, in place of prompting the
user. These credentials are equivalent to the same ones defined for the
@@ -320,7 +320,7 @@
</varlistentry>
<varlistentry>
<term><literal>passwd.shell.root</literal></term>
<term><varname>passwd.shell.root</varname></term>
<listitem><para>Specifies the shell binary to use for the specified account.
Equivalent to the credential of the same name defined for the
@@ -329,20 +329,20 @@
</varlistentry>
<varlistentry>
<term><literal>firstboot.locale</literal></term>
<term><literal>firstboot.locale-messages</literal></term>
<term><varname>firstboot.locale</varname></term>
<term><varname>firstboot.locale-messages</varname></term>
<listitem><para>These credentials specify the locale settings to set during first boot, in place of
prompting the user.</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>firstboot.keymap</literal></term>
<term><varname>firstboot.keymap</varname></term>
<listitem><para>This credential specifies the keyboard setting to set during first boot, in place of
prompting the user.</para>
<para>Note the relationship to the <literal>vconsole.keymap</literal> credential understood by
<para>Note the relationship to the <varname>vconsole.keymap</varname> credential understood by
<citerefentry><refentrytitle>systemd-vconsole-setup.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>:
both ultimately affect the same setting, but <varname>firstboot.keymap</varname> is written into
<filename>/etc/vconsole.conf</filename> on first boot (if not already configured), and then read from
@@ -352,7 +352,7 @@
</varlistentry>
<varlistentry>
<term><literal>firstboot.timezone</literal></term>
<term><varname>firstboot.timezone</varname></term>
<listitem><para>This credential specifies the system timezone setting to set during first boot, in
place of prompting the user.</para></listitem>

View File

@@ -269,6 +269,21 @@ systemd.swap=/dev/sda2:x-systemd.makefs</programlisting>
</variablelist>
</refsect1>
<refsect1>
<title>System Credentials</title>
<variablelist class='system-credentials'>
<varlistentry>
<term><varname>fstab.extra</varname></term>
<listitem><para>This credential may contain addition mounts to establish, in the same format as
<citerefentry
project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>, with
one mount per line. It is read in addition to <filename>/etc/fstab</filename>.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<para>

View File

@@ -85,11 +85,29 @@
</variablelist>
</refsect1>
<refsect1>
<title>System Credentials</title>
<variablelist class='system-credentials'>
<varlistentry>
<term><varname>getty.ttys.serial</varname></term>
<term><varname>getty.ttys.container</varname></term>
<listitem><para>These system credentials may be used to spawn additional login prompts on selected
TTYs. The two credentials should contain a newline-separated list of TTY names to spawn instances of
<filename>serial-getty@.service</filename> (in case of <varname>getty.ttys.serial</varname>) and
<filename>container-getty@.service</filename> (in case of <varname>getty.ttys.container</varname>)
on.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.system-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>agetty</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>

View File

@@ -407,7 +407,7 @@ search foobar.com barbar.com
(see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details). The following credentials are used when passed in:</para>
<variablelist>
<variablelist class='system-credentials'>
<varlistentry>
<term><varname>network.dns</varname></term>
<term><varname>network.search_domains</varname></term>

View File

@@ -89,9 +89,9 @@
(see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details). The following credentials are used when passed in:</para>
<variablelist>
<variablelist class='system-credentials'>
<varlistentry>
<term><literal>sysctl.extra</literal></term>
<term><varname>sysctl.extra</varname></term>
<listitem><para>The contents of this credential may contain additional lines to operate on. The
credential contents should follow the same format as any other <filename>sysctl.d/</filename> drop-in

View File

@@ -143,9 +143,9 @@
(see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details). The following credentials are used when passed in:</para>
<variablelist>
<variablelist class='system-credentials'>
<varlistentry>
<term><literal>passwd.hashed-password.<replaceable>user</replaceable></literal></term>
<term><varname>passwd.hashed-password.<replaceable>user</replaceable></varname></term>
<listitem><para>A UNIX hashed password string to use for the specified user, when creating an entry
for it. This is particularly useful for the <literal>root</literal> user as it allows provisioning
the default root password to use via a unit file drop-in or from a container manager passing in this
@@ -155,7 +155,7 @@
</varlistentry>
<varlistentry>
<term><literal>passwd.plaintext-password.<replaceable>user</replaceable></literal></term>
<term><varname>passwd.plaintext-password.<replaceable>user</replaceable></varname></term>
<listitem><para>Similar to <literal>passwd.hashed-password.<replaceable>user</replaceable></literal>
but expect a literal, plaintext password, which is then automatically hashed before used for the user
@@ -166,13 +166,13 @@
</varlistentry>
<varlistentry>
<term><literal>passwd.shell.<replaceable>user</replaceable></literal></term>
<term><varname>passwd.shell.<replaceable>user</replaceable></varname></term>
<listitem><para>Specifies the shell binary to use for the specified account when creating it.</para></listitem>
</varlistentry>
<varlistentry>
<term><literal>sysusers.extra</literal></term>
<term><varname>sysusers.extra</varname></term>
<listitem><para>The contents of this credential may contain additional lines to operate on. The
credential contents should follow the same format as any other <filename>sysusers.d/</filename>

View File

@@ -250,9 +250,9 @@
(see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details). The following credentials are used when passed in:</para>
<variablelist>
<variablelist class='system-credentials'>
<varlistentry>
<term><literal>tmpfiles.extra</literal></term>
<term><varname>tmpfiles.extra</varname></term>
<listitem><para> The contents of this credential may contain additional lines to operate on. The
credential contents should follow the same format as any other <filename>tmpfiles.d/</filename>

View File

@@ -57,7 +57,7 @@
(see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details). The following credentials are used when passed in:</para>
<variablelist>
<variablelist class='system-credentials'>
<varlistentry>
<term><varname>vconsole.keymap</varname></term>
<term><varname>vconsole.keymap_toggle</varname></term>

View File

@@ -3274,18 +3274,21 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
11) with a prefix of <literal>io.systemd.credential:</literal> or
<literal>io.systemd.credential.binary:</literal>. In both cases a key/value pair separated by
<literal>=</literal> is expected, in the latter case the right-hand side is Base64 decoded when
parsed (thus permitting binary data to be passed in). Example
<ulink url="https://www.qemu.org/docs/master/system/index.html">qemu</ulink>
switch: <literal>-smbios
parsed (thus permitting binary data to be passed in). Example <ulink
url="https://www.qemu.org/docs/master/system/index.html">qemu</ulink> switch: <literal>-smbios
type=11,value=io.systemd.credential:xx=yy</literal>, or <literal>-smbios
type=11,value=io.systemd.credential.binary:rick=TmV2ZXIgR29ubmEgR2l2ZSBZb3UgVXA=</literal>. Alternatively,
use the <command>qemu</command> <literal>fw_cfg</literal> node
<literal>opt/io.systemd.credentials/</literal>. Example <command>qemu</command> switch: <literal>-fw_cfg
name=opt/io.systemd.credentials/mycred,string=supersecret</literal>. They may also be specified on
the kernel command line using the <literal>systemd.set_credential=</literal> switch (see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>) and from
the UEFI firmware environment via
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
<literal>opt/io.systemd.credentials/</literal>. Example <command>qemu</command> switch:
<literal>-fw_cfg name=opt/io.systemd.credentials/mycred,string=supersecret</literal>. They may also
be passed from the UEFI firmware environment via
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
from the initrd (see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>), or be
specified on the kernel command line using the <literal>systemd.set_credential=</literal> and
<literal>systemd.set_credential_binary=</literal> switches (see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> this is
not recommended since unprivileged userspace can read the kernel command line). </para>
<para>If referencing an <constant>AF_UNIX</constant> stream socket to connect to, the connection will
originate from an abstract namespace socket, that includes information about the unit and the

View File

@@ -190,6 +190,20 @@
<varname>ConditionArchitecture=</varname> in
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>$CREDENTIALS_DIRECTORY</varname></term>
<term><varname>$ENCRYPTED_CREDENTIALS_DIRECTORY</varname></term>
<listitem><para>If set, refers to the directory system credentials have been placed in. Credentials
passed into the system in plaintext form will be placed in <varname>$CREDENTIALS_DIRECTORY</varname>,
and those passed in in encrypted form will be placed in
<varname>$ENCRYPTED_CREDENTIALS_DIRECTORY</varname>. Use the
<citerefentry><refentrytitle>systemd-creds</refentrytitle><manvolnum>1</manvolnum></citerefentry>
command to automatically decrypt/authenticate credentials passed in, if needed. Specifically, use the
<command>systemd-creds --system cat</command> command.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@@ -40,7 +40,7 @@
<refsect1>
<title>Well known system credentials</title>
<variablelist>
<variablelist class='system-credentials'>
<varlistentry>
<term><varname>firstboot.keymap</varname></term>
<listitem>
@@ -52,7 +52,7 @@
<varlistentry>
<term><varname>firstboot.locale</varname></term>
<term><varname>firstboot.locale-message</varname></term>
<term><varname>firstboot.locale-messages</varname></term>
<listitem>
<para>The system locale to set (e.g. <literal>de_DE.UTF-8</literal>). Read by
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
@@ -186,6 +186,15 @@
</listitem>
</varlistentry>
<varlistentry>
<term><varname>fstab.extra</varname></term>
<listitem>
<para>Additional mounts to establish at boot. For details, see
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>vconsole.keymap</varname></term>
<term><varname>vconsole.keymap_toggle</varname></term>
@@ -198,6 +207,14 @@
</listitem>
</varlistentry>
<varlistentry>
<term><varname>getty.ttys.serial</varname></term>
<term><varname>getty.ttys.container</varname></term>
<listitem><para>Used for spawning additional login prompts, see
<citerefentry><refentrytitle>systemd-getty-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry> for details.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>vmm.notify_socket</varname></term>
<listitem>
@@ -208,6 +225,15 @@
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>system.machine_id</varname></term>
<listitem>
<para>Takes a 128bit ID to initialize the machine ID from (if it is not set yet). Interpreted by
the service manager (PID 1). For details see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@@ -932,12 +932,15 @@
<varlistentry>
<term><varname>systemd.set_credential=</varname></term>
<term><varname>systemd.set_credential_binary=</varname></term>
<listitem><para>Sets a system credential, which can then be propagated to system services using the
<varname>ImportCredential=</varname> or <varname>LoadCredential=</varname> setting, see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details. Takes a pair of credential name and value, separated by a colon. Note that the kernel
command line is typically accessible by unprivileged programs in
details. Takes a pair of credential name and value, separated by a colon. The
<varname>systemd.set_credential=</varname> parameter expects the credential value in literal text
form, the <varname>systemd.set_credential_binary=</varname> parameter takes binary data encoded in
Base64. Note that the kernel command line is typically accessible by unprivileged programs in
<filename>/proc/cmdline</filename>. Thus, this mechanism is not suitable for transferring sensitive
data. Use it only for data that is not sensitive (e.g. public keys/certificates, rather than private
keys), or in testing/debugging environments.</para>
@@ -1051,9 +1054,42 @@
<refsect1>
<title>System credentials</title>
<para>The service manager when run as PID 1 reads the following system credentials:</para>
<para>During initialization the service manager will import credentials from various sources into the
system's set of credentials, which can then be propagated into services and consumed by
generators:</para>
<variablelist>
<itemizedlist>
<listitem><para>When the service manager first initializes it will read system credentials from SMBIOS
Type 11 vendor strings
<varname>io.systemd.credential:<replaceable>name</replaceable>=<replaceable>value</replaceable></varname>,
and
<varname>io.systemd.credential.binary:<replaceable>name</replaceable>=<replaceable>value</replaceable></varname>.</para></listitem>
<listitem><para>At the same time it will import credentials from QEMU <literal>fw_cfg</literal>. (Note
that the SMBIOS mechanism is generally preferred, because it is faster and generic.)</para></listitem>
<listitem><para>Credentials may be passed via the kernel command line, using the
<varname>systemd.set-credential=</varname> parameter, see above.</para></listitem>
<listitem><para>Credentials may be passed from the UEFI environment via
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para></listitem>
<listitem><para>When the service manager is invoked during the initrd → host transition it will import
all files in <filename>/run/credentials/@initrd/</filename> as system credentials.</para></listitem>
</itemizedlist>
<para>Invoke
<citerefentry><refentrytitle>systemd-creds</refentrytitle><manvolnum>1</manvolnum></citerefentry> as
follows to see the list of credentials passed into the system:</para>
<programlisting># systemd-creds --system list</programlisting>
<para>For further information see <ulink url="https://systemd.io/CREDENTIALS">System and Service
Credentials</ulink> documentation.</para>
<para>The service manager when run as PID 1 consumes the following system credentials:</para>
<variablelist class='system-credentials'>
<varlistentry>
<term><varname>vmm.notify_socket</varname></term>
<listitem>
@@ -1069,6 +1105,16 @@
notification via VSOCK when a virtual machine has finished booting.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>system.machine_id</varname></term>
<listitem>
<para>Takes a 128bit hexadecimal ID to initialize <filename>/etc/machine-id</filename> from, if the
file is not set up yet. See
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@@ -18,9 +18,9 @@
static int run(const char *dest, const char *dest_early, const char *dest_late) {
if (in_initrd() > 0) {
if (in_initrd()) {
log_debug("Skipping generator, running in the initrd.");
return 0;
return EXIT_SUCCESS;
}
if (detect_container() > 0) {

View File

@@ -3182,6 +3182,10 @@ static int acquire_credentials(
if (dfd < 0)
return -errno;
r = fd_acl_make_writable(dfd); /* Add the "w" bit, if we are reusing an already set up credentials dir where it was unset */
if (r < 0)
return r;
/* First, load credentials off disk (or acquire via AF_UNIX socket) */
HASHMAP_FOREACH(lc, context->load_credentials) {
_cleanup_close_ int sub_fd = -EBADF;
@@ -3313,8 +3317,9 @@ static int acquire_credentials(
left -= add;
}
if (fchmod(dfd, 0500) < 0) /* Now take away the "w" bit */
return -errno;
r = fd_acl_make_read_only(dfd); /* Now take away the "w" bit */
if (r < 0)
return r;
/* After we created all keys with the right perms, also make sure the credential store as a whole is
* accessible */
@@ -3384,7 +3389,7 @@ static int setup_credentials_internal(
if (r < 0)
return r;
r = mount_nofollow_verbose(LOG_DEBUG, NULL, workspace, NULL, MS_BIND|MS_REMOUNT|MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL);
r = mount_nofollow_verbose(LOG_DEBUG, NULL, workspace, NULL, MS_BIND|MS_REMOUNT|credentials_fs_mount_flags(/* ro= */ false), NULL);
if (r < 0)
return r;
@@ -3395,57 +3400,34 @@ static int setup_credentials_internal(
if (workspace_mounted < 0) {
/* Nothing is mounted on the workspace yet, let's try to mount something now */
for (int try = 0;; try++) {
if (try == 0) {
/* Try "ramfs" first, since it's not swap backed */
r = mount_nofollow_verbose(LOG_DEBUG, "ramfs", workspace, "ramfs", MS_NODEV|MS_NOEXEC|MS_NOSUID, "mode=0700");
if (r >= 0) {
workspace_mounted = true;
break;
}
r = mount_credentials_fs(workspace, CREDENTIALS_TOTAL_SIZE_MAX, /* ro= */ false);
if (r < 0) {
/* If that didn't work, try to make a bind mount from the final to the workspace, so that we can make it writable there. */
r = mount_nofollow_verbose(LOG_DEBUG, final, workspace, NULL, MS_BIND|MS_REC, NULL);
if (r < 0) {
if (!ERRNO_IS_PRIVILEGE(r)) /* Propagate anything that isn't a permission problem */
return r;
} else if (try == 1) {
_cleanup_free_ char *opts = NULL;
if (must_mount) /* If we it's not OK to use the plain directory
* fallback, propagate all errors too */
return r;
if (asprintf(&opts, "mode=0700,nr_inodes=1024,size=%zu", (size_t) CREDENTIALS_TOTAL_SIZE_MAX) < 0)
return -ENOMEM;
/* Fall back to "tmpfs" otherwise */
r = mount_nofollow_verbose(LOG_DEBUG, "tmpfs", workspace, "tmpfs", MS_NODEV|MS_NOEXEC|MS_NOSUID, opts);
if (r >= 0) {
workspace_mounted = true;
break;
}
/* If we lack privileges to bind mount stuff, then let's gracefully
* proceed for compat with container envs, and just use the final dir
* as is. */
workspace_mounted = false;
} else {
/* If that didn't work, try to make a bind mount from the final to the workspace, so that we can make it writable there. */
r = mount_nofollow_verbose(LOG_DEBUG, final, workspace, NULL, MS_BIND|MS_REC, NULL);
if (r < 0) {
if (!ERRNO_IS_PRIVILEGE(r)) /* Propagate anything that isn't a permission problem */
return r;
if (must_mount) /* If we it's not OK to use the plain directory
* fallback, propagate all errors too */
return r;
/* If we lack privileges to bind mount stuff, then let's gracefully
* proceed for compat with container envs, and just use the final dir
* as is. */
workspace_mounted = false;
break;
}
/* Make the new bind mount writable (i.e. drop MS_RDONLY) */
r = mount_nofollow_verbose(LOG_DEBUG, NULL, workspace, NULL, MS_BIND|MS_REMOUNT|MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL);
r = mount_nofollow_verbose(LOG_DEBUG, NULL, workspace, NULL, MS_BIND|MS_REMOUNT|credentials_fs_mount_flags(/* ro= */ false), NULL);
if (r < 0)
return r;
workspace_mounted = true;
break;
}
}
} else
workspace_mounted = true;
}
assert(!must_mount || workspace_mounted > 0);
@@ -3477,7 +3459,7 @@ static int setup_credentials_internal(
if (install) {
/* Make workspace read-only now, so that any bind mount we make from it defaults to read-only too */
r = mount_nofollow_verbose(LOG_DEBUG, NULL, workspace, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL);
r = mount_nofollow_verbose(LOG_DEBUG, NULL, workspace, NULL, MS_BIND|MS_REMOUNT|credentials_fs_mount_flags(/* ro= */ true), NULL);
if (r < 0)
return r;

View File

@@ -70,21 +70,36 @@ static void import_credentials_context_free(ImportCredentialContext *c) {
c->target_dir_fd = safe_close(c->target_dir_fd);
}
static int acquire_encrypted_credential_directory(ImportCredentialContext *c) {
static int acquire_credential_directory(ImportCredentialContext *c, const char *path, bool with_mount) {
int r;
assert(c);
assert(path);
if (c->target_dir_fd >= 0)
return c->target_dir_fd;
r = mkdir_safe_label(ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, 0700, 0, 0, MKDIR_WARN_MODE);
if (r < 0)
return log_error_errno(r, "Failed to create " ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY ": %m");
r = path_is_mount_point(path, NULL, 0);
if (r < 0) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to determine if %s is a mount point: %m", path);
c->target_dir_fd = open(ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
r = mkdir_safe_label(path, 0700, 0, 0, MKDIR_WARN_MODE);
if (r < 0)
return log_error_errno(r, "Failed to create %s mount point: %m", path);
r = 0; /* Now it exists and is not a mount point */
}
if (r > 0)
/* If already a mount point, then remount writable */
(void) mount_nofollow_verbose(LOG_WARNING, NULL, path, NULL, MS_BIND|MS_REMOUNT|credentials_fs_mount_flags(/* ro= */ false), NULL);
else if (with_mount)
/* If not a mount point yet, and the credentials are not encrypted, then let's try to mount a no-swap fs there */
(void) mount_credentials_fs(path, CREDENTIALS_TOTAL_SIZE_MAX, /* ro= */ false);
c->target_dir_fd = open(path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
if (c->target_dir_fd < 0)
return log_error_errno(errno, "Failed to open " ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY ": %m");
return log_error_errno(errno, "Failed to open %s: %m", path);
return c->target_dir_fd;
}
@@ -137,7 +152,7 @@ static int finalize_credentials_dir(const char *dir, const char *envvar) {
if (r < 0)
log_warning_errno(r, "Failed to make '%s' a mount point, ignoring: %m", dir);
else
(void) mount_nofollow_verbose(LOG_WARNING, NULL, dir, NULL, MS_BIND|MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_RDONLY|MS_REMOUNT, NULL);
(void) mount_nofollow_verbose(LOG_WARNING, NULL, dir, NULL, MS_BIND|MS_REMOUNT|credentials_fs_mount_flags(/* ro= */ true), NULL);
if (setenv(envvar, dir, /* overwrite= */ true) < 0)
return log_error_errno(errno, "Failed to set $%s environment variable: %m", envvar);
@@ -227,7 +242,7 @@ static int import_credentials_boot(void) {
if (!credential_size_ok(&context, n, st.st_size))
continue;
r = acquire_encrypted_credential_directory(&context);
r = acquire_credential_directory(&context, ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, /* with_mount= */ false);
if (r < 0)
return r;
@@ -261,48 +276,23 @@ static int import_credentials_boot(void) {
return 0;
}
static int acquire_credential_directory(ImportCredentialContext *c) {
int r;
assert(c);
if (c->target_dir_fd >= 0)
return c->target_dir_fd;
r = path_is_mount_point(SYSTEM_CREDENTIALS_DIRECTORY, NULL, 0);
if (r < 0) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to determine if " SYSTEM_CREDENTIALS_DIRECTORY " is a mount point: %m");
r = mkdir_safe_label(SYSTEM_CREDENTIALS_DIRECTORY, 0700, 0, 0, MKDIR_WARN_MODE);
if (r < 0)
return log_error_errno(r, "Failed to create " SYSTEM_CREDENTIALS_DIRECTORY " mount point: %m");
r = 0; /* Now it exists and is not a mount point */
}
if (r == 0)
/* If not a mountpoint yet, try to mount a ramfs there (so that this stuff isn't swapped
* out), but if that doesn't work, let's just use the regular tmpfs it already is. */
(void) mount_nofollow_verbose(LOG_WARNING, "ramfs", SYSTEM_CREDENTIALS_DIRECTORY, "ramfs", MS_NODEV|MS_NOEXEC|MS_NOSUID, "mode=0700");
c->target_dir_fd = open(SYSTEM_CREDENTIALS_DIRECTORY, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
if (c->target_dir_fd < 0)
return log_error_errno(errno, "Failed to open " SYSTEM_CREDENTIALS_DIRECTORY ": %m");
return c->target_dir_fd;
}
static int proc_cmdline_callback(const char *key, const char *value, void *data) {
ImportCredentialContext *c = ASSERT_PTR(data);
_cleanup_free_ void *binary = NULL;
_cleanup_free_ char *n = NULL;
_cleanup_close_ int nfd = -EBADF;
const char *colon;
const char *colon, *d;
bool base64;
size_t l;
int r;
assert(key);
if (!proc_cmdline_key_streq(key, "systemd.set_credential"))
if (proc_cmdline_key_streq(key, "systemd.set_credential"))
base64 = false;
else if (proc_cmdline_key_streq(key, "systemd.set_credential_binary"))
base64 = true;
else
return 0;
colon = value ? strchr(value, ':') : NULL;
@@ -321,12 +311,24 @@ static int proc_cmdline_callback(const char *key, const char *value, void *data)
}
colon++;
l = strlen(colon);
if (base64) {
r = unbase64mem(colon, SIZE_MAX, &binary, &l);
if (r < 0) {
log_warning_errno(r, "Failed to decode binary credential '%s' data, ignoring: %m", n);
return 0;
}
d = binary;
} else {
d = colon;
l = strlen(colon);
}
if (!credential_size_ok(c, n, l))
return 0;
r = acquire_credential_directory(c);
r = acquire_credential_directory(c, SYSTEM_CREDENTIALS_DIRECTORY, /* with_mount= */ true);
if (r < 0)
return r;
@@ -336,7 +338,7 @@ static int proc_cmdline_callback(const char *key, const char *value, void *data)
if (nfd < 0)
return nfd;
r = loop_write(nfd, colon, l, /* do_poll= */ false);
r = loop_write(nfd, d, l, /* do_poll= */ false);
if (r < 0) {
(void) unlinkat(c->target_dir_fd, n, 0);
return log_error_errno(r, "Failed to write credential: %m");
@@ -433,7 +435,7 @@ static int import_credentials_qemu(ImportCredentialContext *c) {
continue;
}
r = acquire_credential_directory(c);
r = acquire_credential_directory(c, SYSTEM_CREDENTIALS_DIRECTORY, /* with_mount= */ true);
if (r < 0)
return r;
@@ -535,7 +537,7 @@ static int parse_smbios_strings(ImportCredentialContext *c, const char *data, si
if (!credential_size_ok(c, cn, cdata_len))
continue;
r = acquire_credential_directory(c);
r = acquire_credential_directory(c, SYSTEM_CREDENTIALS_DIRECTORY, /* with_mount= */ true);
if (r < 0)
return r;
@@ -611,27 +613,157 @@ static int import_credentials_smbios(ImportCredentialContext *c) {
return 0;
}
static int import_credentials_initrd(ImportCredentialContext *c) {
_cleanup_free_ DirectoryEntries *de = NULL;
_cleanup_close_ int source_dir_fd = -EBADF;
int r;
assert(c);
/* This imports credentials from /run/credentials/@initrd/ into our credentials directory and deletes
* the source directory afterwards. This is run once after the initrd → host transition. This is
* supposed to establish a well-defined avenue for initrd-based host configurators to pass
* credentials into the main system. */
if (in_initrd())
return 0;
source_dir_fd = open("/run/credentials/@initrd", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
if (source_dir_fd < 0) {
if (errno == ENOENT)
log_debug_errno(errno, "No credentials passed from initrd.");
else
log_warning_errno(errno, "Failed to open '/run/credentials/@initrd', ignoring: %m");
return 0;
}
r = readdir_all(source_dir_fd, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT, &de);
if (r < 0) {
log_warning_errno(r, "Failed to read '/run/credentials/@initrd' contents, ignoring: %m");
return 0;
}
FOREACH_ARRAY(entry, de->entries, de->n_entries) {
_cleanup_close_ int cfd = -EBADF, nfd = -EBADF;
const struct dirent *d = *entry;
struct stat st;
if (!credential_name_valid(d->d_name)) {
log_warning("Credential '%s' has invalid name, ignoring.", d->d_name);
continue;
}
cfd = openat(source_dir_fd, d->d_name, O_RDONLY|O_CLOEXEC);
if (cfd < 0) {
log_warning_errno(errno, "Failed to open %s, ignoring: %m", d->d_name);
continue;
}
if (fstat(cfd, &st) < 0) {
log_warning_errno(errno, "Failed to stat %s, ignoring: %m", d->d_name);
continue;
}
r = stat_verify_regular(&st);
if (r < 0) {
log_warning_errno(r, "Credential file %s is not a regular file, ignoring: %m", d->d_name);
continue;
}
if (!credential_size_ok(c, d->d_name, st.st_size))
continue;
r = acquire_credential_directory(c, SYSTEM_CREDENTIALS_DIRECTORY, /* with_mount= */ true);
if (r < 0)
return r;
nfd = open_credential_file_for_write(c->target_dir_fd, SYSTEM_CREDENTIALS_DIRECTORY, d->d_name);
if (nfd == -EEXIST)
continue;
if (nfd < 0)
return nfd;
r = copy_bytes(cfd, nfd, st.st_size, 0);
if (r < 0) {
(void) unlinkat(c->target_dir_fd, d->d_name, 0);
return log_error_errno(r, "Failed to create credential '%s': %m", d->d_name);
}
c->size_sum += st.st_size;
c->n_credentials++;
log_debug("Successfully copied initrd credential '%s'.", d->d_name);
(void) unlinkat(source_dir_fd, d->d_name, 0);
}
source_dir_fd = safe_close(source_dir_fd);
if (rmdir("/run/credentials/@initrd") < 0)
log_warning_errno(errno, "Failed to remove /run/credentials/@initrd after import, ignoring: %m");
return 0;
}
static int import_credentials_trusted(void) {
_cleanup_(import_credentials_context_free) ImportCredentialContext c = {
.target_dir_fd = -EBADF,
};
int q, w, r;
int q, w, r, y;
/* This is invoked during early boot when no credentials have been imported so far. (Specifically, if
* the $CREDENTIALS_DIRECTORY or $ENCRYPTED_CREDENTIALS_DIRECTORY environment variables are not set
* yet.) */
r = import_credentials_qemu(&c);
w = import_credentials_smbios(&c);
q = import_credentials_proc_cmdline(&c);
y = import_credentials_initrd(&c);
if (c.n_credentials > 0) {
int z;
log_debug("Imported %u credentials from kernel command line/smbios/fw_cfg.", c.n_credentials);
log_debug("Imported %u credentials from kernel command line/smbios/fw_cfg/initrd.", c.n_credentials);
z = finalize_credentials_dir(SYSTEM_CREDENTIALS_DIRECTORY, "CREDENTIALS_DIRECTORY");
if (z < 0)
return z;
}
return r < 0 ? r : w < 0 ? w : q;
return r < 0 ? r : w < 0 ? w : q < 0 ? q : y;
}
static int merge_credentials_trusted(const char *creds_dir) {
_cleanup_(import_credentials_context_free) ImportCredentialContext c = {
.target_dir_fd = -EBADF,
};
int r;
/* This is invoked after the initrd → host transitions, when credentials already have been imported,
* but we might want to import some more from the initrd. */
if (in_initrd())
return 0;
/* Do not try to merge initrd credentials into foreign credentials directories */
if (!path_equal_ptr(creds_dir, SYSTEM_CREDENTIALS_DIRECTORY)) {
log_debug("Not importing initrd credentials, as foreign $CREDENTIALS_DIRECTORY has been set.");
return 0;
}
r = import_credentials_initrd(&c);
if (c.n_credentials > 0) {
int z;
log_debug("Merged %u credentials from initrd.", c.n_credentials);
z = finalize_credentials_dir(SYSTEM_CREDENTIALS_DIRECTORY, "CREDENTIALS_DIRECTORY");
if (z < 0)
return z;
}
return r;
}
static int symlink_credential_dir(const char *envvar, const char *path, const char *where) {
@@ -657,6 +789,79 @@ static int symlink_credential_dir(const char *envvar, const char *path, const ch
return 0;
}
static int setenv_notify_socket(void) {
_cleanup_free_ char *address = NULL;
int r;
r = read_credential_with_decryption("vmm.notify_socket", (void **)&address, /* ret_size= */ NULL);
if (r < 0)
return log_warning_errno(r, "Failed to read 'vmm.notify_socket' credential, ignoring: %m");
if (isempty(address))
return 0;
if (setenv("NOTIFY_SOCKET", address, /* replace= */ 1) < 0)
return log_warning_errno(errno, "Failed to set $NOTIFY_SOCKET environment variable, ignoring: %m");
return 1;
}
static int report_credentials_per_func(const char *title, int (*get_directory_func)(const char **ret)) {
_cleanup_free_ DirectoryEntries *de = NULL;
_cleanup_close_ int dir_fd = -EBADF;
_cleanup_free_ char *ll = NULL;
const char *d = NULL;
int r, c = 0;
assert(title);
assert(get_directory_func);
r = get_directory_func(&d);
if (r < 0) {
if (r == -ENXIO) /* Env var not set */
return 0;
return log_warning_errno(r, "Failed to determine %s directory: %m", title);
}
dir_fd = open(d, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
if (dir_fd < 0)
return log_warning_errno(errno, "Failed to open credentials directory %s: %m", d);
r = readdir_all(dir_fd, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT, &de);
if (r < 0)
return log_warning_errno(r, "Failed to enumerate credentials directory %s: %m", d);
FOREACH_ARRAY(entry, de->entries, de->n_entries) {
const struct dirent *e = *entry;
if (!credential_name_valid(e->d_name))
continue;
if (!strextend_with_separator(&ll, ", ", e->d_name))
return log_oom();
c++;
}
if (ll)
log_info("Received %s: %s", title, ll);
return c;
}
static void report_credentials(void) {
int p, q;
p = report_credentials_per_func("regular credentials", get_credentials_dir);
q = report_credentials_per_func("untrusted credentials", get_encrypted_credentials_dir);
log_full(p > 0 || q > 0 ? LOG_INFO : LOG_DEBUG,
"Acquired %i regular credentials, %i untrusted credentials.",
p > 0 ? p : 0,
q > 0 ? q : 0);
}
int import_credentials(void) {
const char *received_creds_dir = NULL, *received_encrypted_creds_dir = NULL;
bool envvar_set = false;
@@ -690,6 +895,10 @@ int import_credentials(void) {
r = q;
}
q = merge_credentials_trusted(received_creds_dir);
if (r >= 0)
r = q;
} else {
_cleanup_free_ char *v = NULL;
@@ -713,18 +922,10 @@ int import_credentials(void) {
r = q;
}
if (r >= 0) {
_cleanup_free_ char *address = NULL;
report_credentials();
r = read_credential("vmm.notify_socket", (void **)&address, /* ret_size= */ NULL);
if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO))
log_warning_errno(r, "Failed to read 'vmm.notify_socket' credential, ignoring: %m");
else if (r >= 0 && !isempty(address)) {
r = setenv("NOTIFY_SOCKET", address, /* replace= */ 1);
if (r < 0)
log_warning_errno(errno, "Failed to set $NOTIFY_SOCKET environment variable, ignoring: %m");
}
}
/* Propagate vmm_notify_socket credential → $NOTIFY_SOCKET env var */
(void) setenv_notify_socket();
return r;
}

View File

@@ -2224,10 +2224,15 @@ static int initialize_runtime(
return r;
}
/* Pull credentials from various sources into a common credential directory (we do
* this here, before setting up the machine ID, so that we can use credential info
* for setting up the machine ID) */
(void) import_credentials();
(void) os_release_status();
(void) hostname_setup(true);
/* Force transient machine-id on first boot. */
machine_id_setup(NULL, /* force_transient= */ first_boot, arg_machine_id, NULL);
machine_id_setup(/* root= */ NULL, /* force_transient= */ first_boot, arg_machine_id, /* ret_machine_id */ NULL);
(void) loopback_setup();
bump_unix_max_dgram_qlen();
bump_file_max_and_nr_open();
@@ -2306,10 +2311,6 @@ static int initialize_runtime(
(void) bump_rlimit_nofile(saved_rlimit_nofile);
(void) bump_rlimit_memlock(saved_rlimit_memlock);
/* Pull credentials from various sources into a common credential directory */
if (arg_runtime_scope == RUNTIME_SCOPE_SYSTEM && !skip_setup)
(void) import_credentials();
return 0;
}

Some files were not shown because too many files have changed in this diff Show More