vmspawn: Add --user/--system and support user session machined registration
The UX of registering with the user session machined instance is much better as there won't be an authorization prompt. To make that available for users, let's add --user and --system switches for vmspawn. For backwards compat, we'll still try to register with the system machined instance if the user machined instance is not available.
This commit is contained in:
committed by
Yu Watanabe
parent
2ff1a84b19
commit
4e805ec152
@@ -69,6 +69,18 @@
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--system</option></term>
|
||||
<term><option>--user</option></term>
|
||||
|
||||
<listitem><para>Specify whether to interact with the user manager or the system manager and whether
|
||||
to register with the user machined instance or the system machined instance. If
|
||||
unspecified, the system manager and machined instance will be used when running as root, otherwise
|
||||
the user manager and machined instance will be used.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<refsect2>
|
||||
|
||||
@@ -29,7 +29,7 @@ _systemd_vmspawn() {
|
||||
local i verb comps
|
||||
|
||||
local -A OPTS=(
|
||||
[STANDALONE]='-h --help --version -q --quiet --no-pager -n --network-tap --network-user-mode'
|
||||
[STANDALONE]='-h --help --version -q --quiet --no-pager -n --network-tap --network-user-mode --user --system'
|
||||
[PATH]='-D --directory -i --image --linux --initrd --extra-drive --forward-journal'
|
||||
[BOOL]='--kvm --vsock --tpm --secure-boot --discard-disk --register --pass-ssh-key'
|
||||
[FIRMWARE]='--firmware'
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "errno-util.h"
|
||||
#include "json-util.h"
|
||||
#include "log.h"
|
||||
#include "path-lookup.h"
|
||||
#include "pidref.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-util.h"
|
||||
@@ -29,7 +30,8 @@ int register_machine(
|
||||
unsigned cid,
|
||||
const char *address,
|
||||
const char *key_path,
|
||||
bool keep_unit) {
|
||||
bool allocate_unit,
|
||||
RuntimeScope scope) {
|
||||
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
|
||||
int r;
|
||||
@@ -38,7 +40,12 @@ int register_machine(
|
||||
assert(service);
|
||||
|
||||
/* First try to use varlink, as it provides more features (such as SSH support). */
|
||||
r = sd_varlink_connect_address(&vl, "/run/systemd/machine/io.systemd.Machine");
|
||||
_cleanup_free_ char *p = NULL;
|
||||
r = runtime_directory_generic(scope, "systemd/machine/io.systemd.Machine", &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_varlink_connect_address(&vl, p);
|
||||
if (r == -ENOENT || ERRNO_IS_DISCONNECT(r)) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
@@ -59,12 +66,12 @@ int register_machine(
|
||||
(uint32_t) (pidref_is_set(pidref) ? pidref->pid : 0),
|
||||
strempty(directory));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r));
|
||||
return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r));
|
||||
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to machined on /run/systemd/machine/io.systemd.Machine: %m");
|
||||
return log_error_errno(r, "Failed to connect to machined on %p: %m", p);
|
||||
|
||||
return varlink_callbo_and_log(
|
||||
vl,
|
||||
@@ -79,7 +86,7 @@ int register_machine(
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!!address, "sshAddress", SD_JSON_BUILD_STRING(address)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!!key_path, "sshPrivateKeyPath", SD_JSON_BUILD_STRING(key_path)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(isatty_safe(STDIN_FILENO), "allowInteractiveAuthentication", SD_JSON_BUILD_BOOLEAN(true)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!keep_unit, "allocateUnit", SD_JSON_BUILD_BOOLEAN(true)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(allocate_unit, "allocateUnit", SD_JSON_BUILD_BOOLEAN(true)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(pidref_is_set(pidref), "leaderProcessId", JSON_BUILD_PIDREF(pidref)));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ int register_machine(
|
||||
unsigned cid,
|
||||
const char *address,
|
||||
const char *key_path,
|
||||
bool keep_unit);
|
||||
bool allocate_unit,
|
||||
RuntimeScope scope);
|
||||
|
||||
int unregister_machine(sd_bus *bus, const char *machine_name);
|
||||
|
||||
+62
-18
@@ -123,7 +123,6 @@ static uid_t arg_uid_shift = UID_INVALID, arg_uid_range = 0x10000U;
|
||||
static RuntimeMountContext arg_runtime_mounts = {};
|
||||
static char *arg_firmware = NULL;
|
||||
static char *arg_forward_journal = NULL;
|
||||
static bool arg_privileged = false;
|
||||
static bool arg_register = true;
|
||||
static bool arg_keep_unit = false;
|
||||
static sd_id128_t arg_uuid = {};
|
||||
@@ -144,6 +143,7 @@ static char **arg_bind_user = NULL;
|
||||
static char *arg_bind_user_shell = NULL;
|
||||
static bool arg_bind_user_shell_copy = false;
|
||||
static char **arg_bind_user_groups = NULL;
|
||||
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_directory, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
@@ -184,6 +184,8 @@ static int help(void) {
|
||||
" -q --quiet Do not show status information\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
" --no-ask-password Do not prompt for password\n"
|
||||
" --user Interact with user manager\n"
|
||||
" --system Interact with system manager\n"
|
||||
"\n%3$sImage:%4$s\n"
|
||||
" -D --directory=PATH Root directory for the VM\n"
|
||||
" -i --image=FILE|DEVICE Root file system disk image or device for the VM\n"
|
||||
@@ -308,6 +310,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_BIND_USER,
|
||||
ARG_BIND_USER_SHELL,
|
||||
ARG_BIND_USER_GROUP,
|
||||
ARG_SYSTEM,
|
||||
ARG_USER,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@@ -360,6 +364,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "bind-user", required_argument, NULL, ARG_BIND_USER },
|
||||
{ "bind-user-shell", required_argument, NULL, ARG_BIND_USER_SHELL },
|
||||
{ "bind-user-group", required_argument, NULL, ARG_BIND_USER_GROUP },
|
||||
{ "system", no_argument, NULL, ARG_SYSTEM },
|
||||
{ "user", no_argument, NULL, ARG_USER },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -730,6 +736,14 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
break;
|
||||
|
||||
case ARG_SYSTEM:
|
||||
arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
|
||||
break;
|
||||
|
||||
case ARG_USER:
|
||||
arg_runtime_scope = RUNTIME_SCOPE_USER;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1808,7 +1822,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
||||
|
||||
/* Registration always happens on the system bus */
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *system_bus = NULL;
|
||||
if (arg_register || arg_privileged) {
|
||||
if (arg_register || arg_runtime_scope == RUNTIME_SCOPE_SYSTEM) {
|
||||
r = sd_bus_default_system(&system_bus);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open system bus: %m");
|
||||
@@ -1823,7 +1837,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
||||
/* Scope allocation happens on the user bus if we are unpriv, otherwise system bus. */
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *user_bus = NULL;
|
||||
_cleanup_(sd_bus_unrefp) sd_bus *runtime_bus = NULL;
|
||||
if (arg_privileged)
|
||||
if (arg_runtime_scope == RUNTIME_SCOPE_SYSTEM)
|
||||
runtime_bus = sd_bus_ref(system_bus);
|
||||
else {
|
||||
r = sd_bus_default_user(&user_bus);
|
||||
@@ -1949,10 +1963,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
||||
if (asprintf(&subdir, "systemd/vmspawn.%" PRIx64, random_u64()) < 0)
|
||||
return log_oom();
|
||||
|
||||
r = runtime_directory(
|
||||
arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
|
||||
subdir,
|
||||
&runtime_dir);
|
||||
r = runtime_directory(arg_runtime_scope, subdir, &runtime_dir);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to lookup runtime directory: %m");
|
||||
if (r > 0) { /* We need to create our own runtime dir */
|
||||
@@ -2762,7 +2773,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
||||
}
|
||||
|
||||
bool scope_allocated = false;
|
||||
if (!arg_keep_unit && (!arg_register || !arg_privileged)) {
|
||||
if (!arg_keep_unit && (!arg_register || arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)) {
|
||||
r = allocate_scope(
|
||||
runtime_bus,
|
||||
arg_machine,
|
||||
@@ -2778,7 +2789,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
||||
|
||||
scope_allocated = true;
|
||||
} else {
|
||||
if (arg_privileged)
|
||||
if (arg_runtime_scope == RUNTIME_SCOPE_SYSTEM)
|
||||
r = cg_pid_get_unit(0, &unit);
|
||||
else
|
||||
r = cg_pid_get_user_unit(0, &unit);
|
||||
@@ -2786,7 +2797,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
||||
return log_error_errno(r, "Failed to get our own unit: %m");
|
||||
}
|
||||
|
||||
bool registered = false;
|
||||
bool registered_system = false, registered_runtime = false;
|
||||
if (arg_register) {
|
||||
char vm_address[STRLEN("vsock/") + DECIMAL_STR_MAX(unsigned)];
|
||||
xsprintf(vm_address, "vsock/%u", child_cid);
|
||||
@@ -2800,11 +2811,38 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
||||
child_cid,
|
||||
child_cid != VMADDR_CID_ANY ? vm_address : NULL,
|
||||
ssh_private_key_path,
|
||||
arg_keep_unit || !arg_privileged);
|
||||
if (r < 0)
|
||||
return r;
|
||||
!arg_keep_unit && arg_runtime_scope == RUNTIME_SCOPE_SYSTEM,
|
||||
RUNTIME_SCOPE_SYSTEM);
|
||||
if (r < 0) {
|
||||
/* if privileged the request to register definitely failed */
|
||||
if (arg_runtime_scope == RUNTIME_SCOPE_SYSTEM)
|
||||
return r;
|
||||
|
||||
registered = true;
|
||||
log_notice_errno(r, "Failed to register machine in system context, will try in user context.");
|
||||
} else
|
||||
registered_system = true;
|
||||
|
||||
if (arg_runtime_scope == RUNTIME_SCOPE_USER) {
|
||||
r = register_machine(
|
||||
runtime_bus,
|
||||
arg_machine,
|
||||
arg_uuid,
|
||||
"systemd-vmspawn",
|
||||
&child_pidref,
|
||||
arg_directory,
|
||||
child_cid,
|
||||
child_cid != VMADDR_CID_ANY ? vm_address : NULL,
|
||||
ssh_private_key_path,
|
||||
!arg_keep_unit,
|
||||
RUNTIME_SCOPE_USER);
|
||||
if (r < 0) {
|
||||
if (!registered_system) /* neither registration worked: fail */
|
||||
return r;
|
||||
|
||||
log_notice_errno(r, "Failed to register machine in user context, but succeeded in system context, will proceed.");
|
||||
} else
|
||||
registered_runtime = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Report that the VM is now set up */
|
||||
@@ -2905,8 +2943,10 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
||||
if (scope_allocated)
|
||||
terminate_scope(runtime_bus, arg_machine);
|
||||
|
||||
if (registered)
|
||||
if (registered_system)
|
||||
(void) unregister_machine(system_bus, arg_machine);
|
||||
if (registered_runtime)
|
||||
(void) unregister_machine(runtime_bus, arg_machine);
|
||||
|
||||
if (use_vsock) {
|
||||
if (exit_status == INT_MAX) {
|
||||
@@ -2928,8 +2968,12 @@ static int determine_names(void) {
|
||||
if (arg_machine) {
|
||||
_cleanup_(image_unrefp) Image *i = NULL;
|
||||
|
||||
r = image_find(arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
|
||||
IMAGE_MACHINE, arg_machine, NULL, &i);
|
||||
/* Use both user and system images in user mode, use only system images in system mode. */
|
||||
r = image_find(arg_runtime_scope == RUNTIME_SCOPE_USER ? _RUNTIME_SCOPE_INVALID : arg_runtime_scope,
|
||||
IMAGE_MACHINE,
|
||||
arg_machine,
|
||||
/* root= */ NULL,
|
||||
&i);
|
||||
if (r == -ENOENT)
|
||||
return log_error_errno(r, "No image for machine '%s'.", arg_machine);
|
||||
if (r < 0)
|
||||
@@ -2993,7 +3037,7 @@ static int run(int argc, char *argv[]) {
|
||||
|
||||
log_setup();
|
||||
|
||||
arg_privileged = getuid() == 0;
|
||||
arg_runtime_scope = getuid() == 0 ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER;
|
||||
|
||||
r = parse_environment();
|
||||
if (r < 0)
|
||||
|
||||
Reference in New Issue
Block a user