diff --git a/man/systemd-firstboot.xml b/man/systemd-firstboot.xml
index 1001924902..46fe0a0682 100644
--- a/man/systemd-firstboot.xml
+++ b/man/systemd-firstboot.xml
@@ -283,7 +283,69 @@
+
+
+ Credentials
+
+ systemd-firstboot supports the service credentials logic as implemented by
+ LoadCredential=/SetCredential= (see
+ systemd.exec1 for
+ details). The following credentials are used when passed in:
+
+
+
+ passwd.hashed-password.root
+ passwd.plaintext-password.root
+
+ 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
+ systemd-sysusers.service8
+ service.
+
+
+
+ passwd.shell.root
+
+ Specifies the shell binary to use for the the specified account when creating
+ it. Equivalent to the credential of the same name defined for the
+ systemd-sysusers.service8
+ service.
+
+
+
+ firstboot.locale
+ firstboot.locale-messages
+
+ These credentials specify the locale settings to set during first boot, in place of
+ prompting the user.
+
+
+
+ firstboot.keymap
+
+ This credential specifies the keyboard setting to set during first boot, in place of
+ prompting the user.
+
+
+
+ firstboot.timezone
+
+ This credential specifies the system timezone setting to set during first boot, in
+ place of prompting the user.
+
+
+
+ Note that by default the systemd-firstboot.service unit file is set up to
+ inherit the listed credentials
+ from the service manager. Thus, when invoking a container with an unpopulated /etc/
+ for the first time it is possible to configure the root user's password to be systemd
+ like this:
+
+ # systemd-nspawn --image=… --set-credential=firstboot.locale:de_DE.UTF-8 …
+
+ Note that these credentials are only read and applied during the first boot process. Once they are
+ applied they remain applied for subsequent boots, and the credentials are not considered anymore.
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index 42b9ca776f..01af1033e5 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "ask-password-api.h"
#include "copy.h"
+#include "creds-util.h"
#include "dissect-image.h"
#include "env-file.h"
#include "fd-util.h"
@@ -232,11 +233,29 @@ static bool locale_is_ok(const char *name) {
static int prompt_locale(void) {
_cleanup_strv_free_ char **locales = NULL;
+ bool acquired_from_creds = false;
int r;
if (arg_locale || arg_locale_messages)
return 0;
+ r = read_credential("firstboot.locale", (void**) &arg_locale, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential firstboot.locale, ignoring: %m");
+ else
+ acquired_from_creds = true;
+
+ r = read_credential("firstboot.locale-messages", (void**) &arg_locale_messages, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential firstboot.locale-message, ignoring: %m");
+ else
+ acquired_from_creds = true;
+
+ if (acquired_from_creds) {
+ log_debug("Acquired locale from credentials.");
+ return 0;
+ }
+
if (!arg_prompt_locale)
return 0;
@@ -336,6 +355,14 @@ static int prompt_keymap(void) {
if (arg_keymap)
return 0;
+ r = read_credential("firstboot.keymap", (void**) &arg_keymap, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential firstboot.keymap, ignoring: %m");
+ else {
+ log_debug("Acquired keymap from credential.");
+ return 0;
+ }
+
if (!arg_prompt_keymap)
return 0;
@@ -407,6 +434,14 @@ static int prompt_timezone(void) {
if (arg_timezone)
return 0;
+ r = read_credential("firstboot.timezone", (void**) &arg_timezone, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential firstboot.timezone, ignoring: %m");
+ else {
+ log_debug("Acquired timezone from credential.");
+ return 0;
+ }
+
if (!arg_prompt_timezone)
return 0;
@@ -558,6 +593,22 @@ static int prompt_root_password(void) {
if (arg_root_password)
return 0;
+ r = read_credential("passwd.hashed-password.root", (void**) &arg_root_password, NULL);
+ if (r == -ENOENT) {
+ r = read_credential("passwd.plaintext-password.root", (void**) &arg_root_password, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Couldn't read credential 'passwd.{hashed|plaintext}-password.root', ignoring: %m");
+ else {
+ arg_root_password_is_hashed = false;
+ return 0;
+ }
+ } else if (r < 0)
+ log_debug_errno(r, "Couldn't read credential 'passwd.hashed-password.root', ignoring: %m");
+ else {
+ arg_root_password_is_hashed = true;
+ return 0;
+ }
+
if (!arg_prompt_root_password)
return 0;
@@ -631,7 +682,18 @@ static int find_shell(const char *path, const char *root) {
static int prompt_root_shell(void) {
int r;
- if (arg_root_shell || !arg_prompt_root_shell)
+ if (arg_root_shell)
+ return 0;
+
+ r = read_credential("passwd.shell.root", (void**) &arg_root_shell, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read credential passwd.shell.root, ignoring: %m");
+ else {
+ log_debug("Acquired root shell from credential.");
+ return 0;
+ }
+
+ if (!arg_prompt_root_shell)
return 0;
print_welcome();
diff --git a/units/systemd-firstboot.service b/units/systemd-firstboot.service
index d7f445ef35..2e57b064c1 100644
--- a/units/systemd-firstboot.service
+++ b/units/systemd-firstboot.service
@@ -25,3 +25,14 @@ ExecStart=systemd-firstboot --prompt-locale --prompt-timezone --prompt-root-pass
StandardOutput=tty
StandardInput=tty
StandardError=tty
+
+# Optionally, pick up basic fields from credentials passed to the service
+# manager. This is useful for importing this data from nspawn's
+# --set-credential= switch.
+LoadCredential=passwd.hashed-password.root
+LoadCredential=passwd.plaintext-password.root
+LoadCredential=passwd.shell.root
+LoadCredential=firstboot.locale
+LoadCredential=firstboot.locale-messages
+LoadCredential=firstboot.keymap
+LoadCredential=firstboot.timezone