Skip to content

Commit 99e9f89

Browse files
committed
sysusers: read passwords from the credentials logic
Let's make use of our own credentials infrastructure in our tools: let's hook up systemd-sysusers with the credentials logic, so that the root password can be provisioned this way. This is really useful when working with stateless systems, in particular nspawn's "--volatile=yes" switch, as this works now: # systemd-nspawn -i foo.raw --volatile=yes --set-credential=passwd.plaintext-password:foo For the first time we have a nice, non-interactive way to provision the root password for a fully stateless system from the container manager. Yay!
1 parent fc682be commit 99e9f89

File tree

3 files changed

+110
-1
lines changed

3 files changed

+110
-1
lines changed

man/systemd-sysusers.xml

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,60 @@
126126
<xi:include href="standard-options.xml" xpointer="help" />
127127
<xi:include href="standard-options.xml" xpointer="version" />
128128
</variablelist>
129+
</refsect1>
130+
131+
<refsect1>
132+
<title>Credentials</title>
133+
134+
<para><command>systemd-sysusers</command> supports the service credentials logic as implemented by
135+
<varname>LoadCredential=</varname>/<varname>SetCredential=</varname> (see
136+
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
137+
details). The following credentials are used when passed in:</para>
138+
139+
<variablelist>
140+
<varlistentry>
141+
<term><literal>passwd.hashed-password.<replaceable>user</replaceable></literal></term>
142+
<listitem><para>A UNIX hashed password string to use for the specified user, when creating an entry
143+
for it. This is particularly useful for the <literal>root</literal> user as it allows provisioning
144+
the default root password to use via a unit file drop-in or from a container manager passing in this
145+
credential. Note that setting this credential has no effect if the specified user account already
146+
exists. This credential is hence primarily useful in first boot scenarios or systems that are fully
147+
stateless and come up with an empty <filename>/etc/</filename> on every boot.</para></listitem>
148+
</varlistentry>
149+
150+
<varlistentry>
151+
<term><literal>passwd.plaintext-password.<replaceable>user</replaceable></literal></term>
152+
153+
<listitem><para>Similar to <literal>passwd.hashed-password.<replaceable>user</replaceable></literal>
154+
but expect a literal, plaintext password, which is then automatically hashed before used for the user
155+
account. If both the hashed and the plaintext credential are specified for the same user the
156+
former takes precedence. It's generally recommended to specify the hashed version; however in test
157+
environments with weaker requirements on security it might be easier to pass passwords in plaintext
158+
instead.</para></listitem>
159+
</varlistentry>
160+
161+
<varlistentry>
162+
<term><literal>passwd.shell.<replaceable>user</replaceable></literal></term>
163+
164+
<listitem><para>Specifies the shell binary to use for the the specified account when creating it.</para></listitem>
165+
</varlistentry>
166+
</variablelist>
167+
168+
<para>Note that by default the <filename>systemd-sysusers.service</filename> unit file is set up to
169+
inherit the <literal>passwd.hashed-password.root</literal>,
170+
<literal>passwd.plaintext-password.root</literal> and <literal>passwd.shell.root</literal> credentials
171+
from the service manager. Thus, when invoking a container with an unpopulated <filename>/etc/</filename>
172+
for the first time it is possible to configure the root user's password to be <literal>systemd</literal>
173+
like this:</para>
174+
175+
<para><programlisting># systemd-nspawn --image=… --set-credential=password.hashed-password.root:'$y$j9T$yAuRJu1o5HioZAGDYPU5d.$F64ni6J2y2nNQve90M/p0ZP0ECP/qqzipNyaY9fjGpC' …</programlisting></para>
176+
177+
<para>Note again that the data specified in these credentials is consulted only when creating an account
178+
for the first time, it may not be used for changing the password or shell of an account that already
179+
exists.</para>
129180

181+
<para>Use <citerefentry><refentrytitle>mkpasswd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
182+
for generating UNIX password hashes from the command line.</para>
130183
</refsect1>
131184

132185
<refsect1>
@@ -141,7 +194,9 @@
141194
<para>
142195
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
143196
<citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
144-
<ulink url="https://systemd.io/UIDS-GIDS">Users, Groups, UIDs and GIDs on systemd systems</ulink>
197+
<ulink url="https://systemd.io/UIDS-GIDS">Users, Groups, UIDs and GIDs on systemd systems</ulink>,
198+
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
199+
<citerefentry><refentrytitle>mkpasswd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
145200
</para>
146201
</refsect1>
147202

src/sysusers/sysusers.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@
66
#include "alloc-util.h"
77
#include "conf-files.h"
88
#include "copy.h"
9+
#include "creds-util.h"
910
#include "def.h"
1011
#include "dissect-image.h"
1112
#include "fd-util.h"
1213
#include "fileio.h"
1314
#include "format-util.h"
1415
#include "fs-util.h"
1516
#include "hashmap.h"
17+
#include "libcrypt-util.h"
1618
#include "main-func.h"
19+
#include "memory-util.h"
1720
#include "mount-util.h"
1821
#include "nscd-flush.h"
1922
#include "pager.h"
@@ -429,6 +432,8 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
429432
}
430433

431434
ORDERED_HASHMAP_FOREACH(i, todo_uids) {
435+
_cleanup_free_ char *creds_shell = NULL, *cn = NULL;
436+
432437
struct passwd n = {
433438
.pw_name = i->name,
434439
.pw_uid = i->uid,
@@ -446,6 +451,17 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
446451
.pw_shell = i->shell ?: (char*) default_shell(i->uid),
447452
};
448453

454+
/* Try to pick up the shell for this account via the credentials logic */
455+
cn = strjoin("passwd.shell.", i->name);
456+
if (!cn)
457+
return -ENOMEM;
458+
459+
r = read_credential(cn, (void**) &creds_shell, NULL);
460+
if (r < 0)
461+
log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
462+
else
463+
n.pw_shell = creds_shell;
464+
449465
r = putpwent_sane(&n, passwd);
450466
if (r < 0)
451467
return r;
@@ -530,6 +546,9 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
530546
}
531547

532548
ORDERED_HASHMAP_FOREACH(i, todo_uids) {
549+
_cleanup_(erase_and_freep) char *creds_password = NULL;
550+
_cleanup_free_ char *cn = NULL;
551+
533552
struct spwd n = {
534553
.sp_namp = i->name,
535554
.sp_pwdp = (char*) "!*", /* lock this password, and make it invalid */
@@ -542,6 +561,34 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
542561
.sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */
543562
};
544563

564+
/* Try to pick up the password for this account via the credentials logic */
565+
cn = strjoin("passwd.hashed-password.", i->name);
566+
if (!cn)
567+
return -ENOMEM;
568+
569+
r = read_credential(cn, (void**) &creds_password, NULL);
570+
if (r == -ENOENT) {
571+
_cleanup_(erase_and_freep) char *plaintext_password = NULL;
572+
573+
free(cn);
574+
cn = strjoin("passwd.plaintext-password.", i->name);
575+
if (!cn)
576+
return -ENOMEM;
577+
578+
r = read_credential(cn, (void**) &plaintext_password, NULL);
579+
if (r < 0)
580+
log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
581+
else {
582+
r = hash_password(plaintext_password, &creds_password);
583+
if (r < 0)
584+
return log_debug_errno(r, "Failed to hash password: %m");
585+
}
586+
} else if (r < 0)
587+
log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
588+
589+
if (creds_password)
590+
n.sp_pwdp = creds_password;
591+
545592
r = putspent_sane(&n, shadow);
546593
if (r < 0)
547594
return r;

units/systemd-sysusers.service

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,10 @@ Type=oneshot
2121
RemainAfterExit=yes
2222
ExecStart=systemd-sysusers
2323
TimeoutSec=90s
24+
25+
# Optionally, pick up a root password and shell for the root user from a
26+
# credential passed to the service manager. This is useful for importing this
27+
# data from nspawn's --set-credential= switch.
28+
LoadCredential=passwd.hashed-password.root
29+
LoadCredential=passwd.plaintext-password.root
30+
LoadCredential=passwd.shell.root

0 commit comments

Comments
 (0)