From 1a30285590c2f40f256d0628950ef9243b2c1938 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 8 Jan 2024 11:25:56 +0100 Subject: [PATCH] network-generator: pick up .netdev/.link/.network configuration via credentials To me this is the last major basic functionality that couldn't be configured via credentials: the network. We do not invent any new format for this, but simply copy relevant creds 1:1 into /run/systemd/network/ to open up the full functionality of networkd to VM hosts. --- man/systemd-network-generator.service.xml | 35 +++++++++ man/systemd.system-credentials.xml | 24 ++++++ src/network/generator/main.c | 80 +++++++++++++++++++- test/units/testsuite-74.network-generator.sh | 27 +++++++ units/systemd-network-generator.service.in | 3 + 5 files changed, 167 insertions(+), 2 deletions(-) create mode 100755 test/units/testsuite-74.network-generator.sh diff --git a/man/systemd-network-generator.service.xml b/man/systemd-network-generator.service.xml index 5682339560a..1d498cbf1dd 100644 --- a/man/systemd-network-generator.service.xml +++ b/man/systemd-network-generator.service.xml @@ -117,6 +117,41 @@ for option syntax and details. + + Credentials + + systemd-network-generator supports the service credentials logic as implemented + by + ImportCredential=/LoadCredential=/SetCredential= + (see systemd.exec5 for + details). The following credentials are used when passed in: + + + + network.netdev.* + network.link.* + network.network.* + + These credentials should contain valid + systemd.netdev5, + systemd.link5, + systemd.network5 + configuration data. From each matching credential a separate file is created. Example: a passed + credential network.link.50-foobar will be copied into a configuration file + 50-foobar.link. + + Note that the resulting files are created world-readable, it's hence recommended to not include + secrets in these credentials, but supply them via separate credentials directly to + systemd-networkd.service. + + + + + + Note that by default the systemd-network-generator.service unit file is set up + to inherit the these credentials from the service manager. + + See Also diff --git a/man/systemd.system-credentials.xml b/man/systemd.system-credentials.xml index ab6cab2e06a..b2d491fe581 100644 --- a/man/systemd.system-credentials.xml +++ b/man/systemd.system-credentials.xml @@ -137,6 +137,30 @@ + + network.netdev.* + network.link.* + network.network.* + + Configures network devices. Read by + systemd-network-generator.service8. These + credentials directly translate to a matching *.netdev, + *.link or *.network file. Example: the contents of a + credential network.link.50-foobar will be copied into a file + 50-foobar.link. See + systemd.netdev5, + systemd.link5, + systemd.network5 + for details. + + Note that the resulting files are created world-readable, it's hence recommended to not include + secrets in these credentials, but supply them via separate credentials directly to + systemd-networkd.service. + + + + + passwd.hashed-password.root passwd.plaintext-password.root diff --git a/src/network/generator/main.c b/src/network/generator/main.c index 0439a9d7697..540b6df4fc5 100644 --- a/src/network/generator/main.c +++ b/src/network/generator/main.c @@ -3,6 +3,8 @@ #include #include "build.h" +#include "copy.h" +#include "creds-util.h" #include "fd-util.h" #include "fs-util.h" #include "generator.h" @@ -12,6 +14,7 @@ #include "network-generator.h" #include "path-util.h" #include "proc-cmdline.h" +#include "recurse-dir.h" #define NETWORKD_UNIT_DIRECTORY "/run/systemd/network" @@ -122,6 +125,76 @@ static int context_save(Context *context) { return r; } +static int pick_up_credentials(void) { + _cleanup_close_ int credential_dir_fd = -EBADF; + int r, ret = 0; + + credential_dir_fd = open_credentials_dir(); + if (IN_SET(credential_dir_fd, -ENXIO, -ENOENT)) /* Credential env var not set, or dir doesn't exist. */ + return 0; + if (credential_dir_fd < 0) + return log_error_errno(credential_dir_fd, "Failed to open credentials directory: %m"); + + _cleanup_free_ DirectoryEntries *des = NULL; + r = readdir_all(credential_dir_fd, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, &des); + if (r < 0) + return log_error_errno(r, "Failed to enumerate credentials: %m"); + + FOREACH_ARRAY(i, des->entries, des->n_entries) { + static const struct { + const char *credential_prefix; + const char *filename_suffix; + } table[] = { + { "network.link.", ".link" }, + { "network.netdev.", ".netdev" }, + { "network.network.", ".network" }, + }; + + _cleanup_free_ char *fn = NULL; + struct dirent *de = *i; + + if (de->d_type != DT_REG) + continue; + + FOREACH_ARRAY(t, table, ELEMENTSOF(table)) { + const char *e = startswith(de->d_name, t->credential_prefix); + + if (e) { + fn = strjoin(e, t->filename_suffix); + if (!fn) + return log_oom(); + + break; + } + } + + if (!fn) + continue; + + if (!filename_is_valid(fn)) { + log_warning("Passed credential '%s' would result in invalid filename '%s', ignoring.", de->d_name, fn); + continue; + } + + _cleanup_free_ char *output = path_join(NETWORKD_UNIT_DIRECTORY, fn); + if (!output) + return log_oom(); + + r = copy_file_at( + credential_dir_fd, de->d_name, + AT_FDCWD, output, + /* open_flags= */ 0, + 0644, + /* flags= */ 0); + if (r < 0) + RET_GATHER(ret, log_warning_errno(r, "Failed to copy credential %s → file %s: %m", de->d_name, output)); + else + log_info("Installed %s from credential.", output); + } + + return ret; +} + static int help(void) { printf("%s [OPTIONS...] [-- KERNEL_CMDLINE]\n" " -h --help Show this help\n" @@ -174,7 +247,7 @@ static int parse_argv(int argc, char *argv[]) { static int run(int argc, char *argv[]) { _cleanup_(context_clear) Context context = {}; - int r; + int r, ret = 0; log_setup(); @@ -212,7 +285,10 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_warning_errno(r, "Failed to merge multiple command line options: %m"); - return context_save(&context); + RET_GATHER(ret, context_save(&context)); + RET_GATHER(ret, pick_up_credentials()); + + return ret; } DEFINE_MAIN_FUNCTION(run); diff --git a/test/units/testsuite-74.network-generator.sh b/test/units/testsuite-74.network-generator.sh new file mode 100755 index 00000000000..e7ccea1ede6 --- /dev/null +++ b/test/units/testsuite-74.network-generator.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +at_exit() { + rm -f /run/credstore/network.network.50-testme + rm -f /run/systemd/system/systemd-network-generator.service.d/50-testme.conf +} + +trap at_exit EXIT + +mkdir -p /run/credstore +cat > /run/credstore/network.network.50-testme <