mirror of
https://github.com/systemd/systemd.git
synced 2025-01-06 17:18:12 +03:00
Merge pull request #33042 from poettering/machined-unpriv
machined: unprivileged machine registration
This commit is contained in:
commit
f8f06462e5
15
TODO
15
TODO
@ -242,13 +242,6 @@ Features:
|
||||
assert_ret(). Only export the stuff we are sure about, and keep some symbols
|
||||
internally where things are not clear whether we want other projects to use.
|
||||
|
||||
* machined: allow running in a per-user instance too, to allow unpriv
|
||||
systemd-nspawn and systemd-vmspawn do something useful. (Alternatively: open
|
||||
up system machined to unpriv client's registering their machines, and enforce
|
||||
they come with some prefix or suffix that clarifies they are the
|
||||
user's. i.e. when a user registers a machine it must be called
|
||||
foobar.<username> or so.).
|
||||
|
||||
* importd/…: define per-user dirs for container/VM images too.
|
||||
|
||||
* add a new specifier to unit files that figures out the DDI the unit file is
|
||||
@ -314,12 +307,8 @@ Features:
|
||||
to read them from. This way the data doesn't remain in the SMBIOS blob during
|
||||
runtime, but only in the credentials fs.
|
||||
|
||||
* machined: make machine registration available via varlink to simplify
|
||||
nspawn/vmspawn, and to have an extensible way to register VM/machine metadata
|
||||
|
||||
* ssh-proxy: add support for "ssh machine/foobar" to automatically connect to
|
||||
machined registered machine "foobar". Requires updating machined to track CID
|
||||
and unix-export dir of containers.
|
||||
* machined: optionally track nspawn unix-export/ runtime for each machined, and
|
||||
then update systemd-ssh-proxy so that it can connect to that.
|
||||
|
||||
* add a new ExecStart= flag that inserts the configured user's shell as first
|
||||
word in the command line. (maybe use character '.'). Usecase: tool such as
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "sd-id128.h"
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "bus-polkit.h"
|
||||
#include "hostname-util.h"
|
||||
#include "json-util.h"
|
||||
#include "machine-varlink.h"
|
||||
@ -126,16 +127,18 @@ int vl_method_register(Varlink *link, sd_json_variant *parameters, VarlinkMethod
|
||||
int r;
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "name", SD_JSON_VARIANT_STRING, machine_name, offsetof(Machine, name), SD_JSON_MANDATORY },
|
||||
{ "id", SD_JSON_VARIANT_STRING, sd_json_dispatch_id128, offsetof(Machine, id), 0 },
|
||||
{ "service", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(Machine, service), 0 },
|
||||
{ "class", SD_JSON_VARIANT_STRING, dispatch_machine_class, offsetof(Machine, class), SD_JSON_MANDATORY },
|
||||
{ "leader", SD_JSON_VARIANT_UNSIGNED, machine_leader, offsetof(Machine, leader), 0 },
|
||||
{ "rootDirectory", SD_JSON_VARIANT_STRING, json_dispatch_path, offsetof(Machine, root_directory), 0 },
|
||||
{ "ifIndices", SD_JSON_VARIANT_ARRAY, machine_ifindices, 0, 0 },
|
||||
{ "vSockCid", SD_JSON_VARIANT_UNSIGNED, machine_cid, offsetof(Machine, vsock_cid), 0 },
|
||||
{ "sshAddress", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(Machine, ssh_address), SD_JSON_STRICT },
|
||||
{ "sshPrivateKeyPath", SD_JSON_VARIANT_STRING, json_dispatch_path, offsetof(Machine, ssh_private_key_path), 0 },
|
||||
{ "name", SD_JSON_VARIANT_STRING, machine_name, offsetof(Machine, name), SD_JSON_MANDATORY },
|
||||
{ "id", SD_JSON_VARIANT_STRING, sd_json_dispatch_id128, offsetof(Machine, id), 0 },
|
||||
{ "service", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(Machine, service), 0 },
|
||||
{ "class", SD_JSON_VARIANT_STRING, dispatch_machine_class, offsetof(Machine, class), SD_JSON_MANDATORY },
|
||||
{ "leader", SD_JSON_VARIANT_UNSIGNED, machine_leader, offsetof(Machine, leader), 0 },
|
||||
{ "rootDirectory", SD_JSON_VARIANT_STRING, json_dispatch_path, offsetof(Machine, root_directory), 0 },
|
||||
{ "ifIndices", SD_JSON_VARIANT_ARRAY, machine_ifindices, 0, 0 },
|
||||
{ "vSockCid", SD_JSON_VARIANT_UNSIGNED, machine_cid, offsetof(Machine, vsock_cid), 0 },
|
||||
{ "sshAddress", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(Machine, ssh_address), SD_JSON_STRICT },
|
||||
{ "sshPrivateKeyPath", SD_JSON_VARIANT_STRING, json_dispatch_path, offsetof(Machine, ssh_private_key_path), 0 },
|
||||
{ "allocateUnit", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(Machine, allocate_unit), 0 },
|
||||
VARLINK_DISPATCH_POLKIT_FIELD,
|
||||
{}
|
||||
};
|
||||
|
||||
@ -147,6 +150,16 @@ int vl_method_register(Varlink *link, sd_json_variant *parameters, VarlinkMethod
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = varlink_verify_polkit_async(
|
||||
link,
|
||||
manager->bus,
|
||||
"org.freedesktop.machine1.create-machine",
|
||||
(const char**) STRV_MAKE("name", machine->name,
|
||||
"class", machine_class_to_string(machine->class)),
|
||||
&manager->polkit_registry);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (!pidref_is_set(&machine->leader)) {
|
||||
r = varlink_get_peer_pidref(link, &machine->leader);
|
||||
if (r < 0)
|
||||
@ -159,11 +172,13 @@ int vl_method_register(Varlink *link, sd_json_variant *parameters, VarlinkMethod
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = cg_pidref_get_unit(&machine->leader, &machine->unit);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!machine->allocate_unit) {
|
||||
r = cg_pidref_get_unit(&machine->leader, &machine->unit);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = machine_start(machine, NULL, NULL);
|
||||
r = machine_start(machine, /* properties= */ NULL, /* error= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -57,6 +57,7 @@ struct Machine {
|
||||
bool started:1;
|
||||
bool stopping:1;
|
||||
bool referenced:1;
|
||||
bool allocate_unit;
|
||||
|
||||
sd_bus_message *create_message;
|
||||
|
||||
|
@ -512,7 +512,7 @@ static int manager_varlink_init_machine(Manager *m) {
|
||||
if (m->varlink_machine_server)
|
||||
return 0;
|
||||
|
||||
r = varlink_server_new(&s, VARLINK_SERVER_ROOT_ONLY|VARLINK_SERVER_INHERIT_USERDATA);
|
||||
r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate varlink server object: %m");
|
||||
|
||||
|
@ -91,6 +91,17 @@
|
||||
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.shell org.freedesktop.login1.login</annotate>
|
||||
</action>
|
||||
|
||||
<action id="org.freedesktop.machine1.create-machine">
|
||||
<description gettext-domain="systemd">Create a local virtual machine or container</description>
|
||||
<message gettext-domain="systemd">Authentication is required to create a local virtual machine or container.</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.shell org.freedesktop.login1.login</annotate>
|
||||
</action>
|
||||
|
||||
<action id="org.freedesktop.machine1.manage-images">
|
||||
<description gettext-domain="systemd">Manage local virtual machine and container images</description>
|
||||
<message gettext-domain="systemd">Authentication is required to manage local virtual machine and container images.</message>
|
||||
|
@ -1659,12 +1659,6 @@ static int verify_arguments(void) {
|
||||
SET_FLAG(arg_mount_settings, MOUNT_PRIVILEGED, arg_privileged);
|
||||
|
||||
if (!arg_privileged) {
|
||||
/* machined is not accessible to unpriv clients */
|
||||
if (arg_register) {
|
||||
log_notice("Automatically implying --register=no, since machined is not accessible to unprivileged clients.");
|
||||
arg_register = false;
|
||||
}
|
||||
|
||||
if (!arg_private_network) {
|
||||
log_notice("Automatically implying --private-network, since mounting /sys/ in an unprivileged user namespaces requires network namespacing.");
|
||||
arg_private_network = true;
|
||||
@ -5350,7 +5344,7 @@ static int run_container(
|
||||
}
|
||||
|
||||
if (arg_register || !arg_keep_unit) {
|
||||
if (arg_privileged)
|
||||
if (arg_privileged || arg_register)
|
||||
r = sd_bus_default_system(&bus);
|
||||
else
|
||||
r = sd_bus_default_user(&bus);
|
||||
|
@ -14,7 +14,11 @@ static VARLINK_DEFINE_METHOD(
|
||||
VARLINK_DEFINE_INPUT(ifIndices, VARLINK_INT, VARLINK_ARRAY|VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_INPUT(vSockCid, VARLINK_INT, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_INPUT(sshAddress, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_INPUT(sshPrivateKeyPath, VARLINK_STRING, VARLINK_NULLABLE));
|
||||
VARLINK_DEFINE_INPUT(sshPrivateKeyPath, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_FIELD_COMMENT("Controls whether to allocate a scope unit for the machine to register. If false, the client already took care of that and registered a service/scope specific to the machine."),
|
||||
VARLINK_DEFINE_INPUT(allocateUnit, VARLINK_BOOL, VARLINK_NULLABLE),
|
||||
VARLINK_FIELD_COMMENT("Whether to allow interactive authentication on this operation."),
|
||||
VARLINK_DEFINE_INPUT(allowInteractiveAuthentication, VARLINK_BOOL, VARLINK_NULLABLE));
|
||||
|
||||
static VARLINK_DEFINE_STRUCT_TYPE(
|
||||
Timestamp,
|
||||
|
@ -22,7 +22,8 @@ int register_machine(
|
||||
const char *directory,
|
||||
unsigned cid,
|
||||
const char *address,
|
||||
const char *key_path) {
|
||||
const char *key_path,
|
||||
bool keep_unit) {
|
||||
|
||||
_cleanup_(varlink_unrefp) Varlink *vl = NULL;
|
||||
int r;
|
||||
@ -70,7 +71,9 @@ int register_machine(
|
||||
SD_JSON_BUILD_PAIR_CONDITION(VSOCK_CID_IS_REGULAR(cid), "vSockCid", SD_JSON_BUILD_UNSIGNED(cid)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!!directory, "rootDirectory", SD_JSON_BUILD_STRING(directory)),
|
||||
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(!!key_path, "sshPrivateKeyPath", SD_JSON_BUILD_STRING(key_path)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(isatty(STDIN_FILENO), "allowInteractiveAuthentication", SD_JSON_BUILD_BOOLEAN(true)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!keep_unit, "allocateUnit", SD_JSON_BUILD_BOOLEAN(true)));
|
||||
}
|
||||
|
||||
int unregister_machine(sd_bus *bus, const char *machine_name) {
|
||||
|
@ -11,5 +11,7 @@ int register_machine(
|
||||
const char *directory,
|
||||
unsigned cid,
|
||||
const char *address,
|
||||
const char *key_path);
|
||||
const char *key_path,
|
||||
bool keep_unit);
|
||||
|
||||
int unregister_machine(sd_bus *bus, const char *machine_name);
|
||||
|
@ -107,6 +107,7 @@ static char *arg_forward_journal = NULL;
|
||||
static bool arg_runtime_directory_created = false;
|
||||
static bool arg_privileged = false;
|
||||
static bool arg_register = false;
|
||||
static bool arg_keep_unit = false;
|
||||
static sd_id128_t arg_uuid = {};
|
||||
static char **arg_kernel_cmdline_extra = NULL;
|
||||
static char **arg_extra_drives = NULL;
|
||||
@ -170,6 +171,7 @@ static int help(void) {
|
||||
" --uuid=UUID Set a specific machine UUID for the VM\n"
|
||||
"\n%3$sProperties:%4$s\n"
|
||||
" --register=BOOLEAN Register VM with systemd-machined\n"
|
||||
" --keep-unit Don't let systemd-machined allocate scope unit for us\n"
|
||||
"\n%3$sUser Namespacing:%4$s\n"
|
||||
" --private-users=UIDBASE[:NUIDS]\n"
|
||||
" Configure the UID/GID range to map into the\n"
|
||||
@ -235,6 +237,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_NETWORK_USER_MODE,
|
||||
ARG_UUID,
|
||||
ARG_REGISTER,
|
||||
ARG_KEEP_UNIT,
|
||||
ARG_BIND,
|
||||
ARG_BIND_RO,
|
||||
ARG_EXTRA_DRIVE,
|
||||
@ -277,6 +280,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "network-user-mode", no_argument, NULL, ARG_NETWORK_USER_MODE },
|
||||
{ "uuid", required_argument, NULL, ARG_UUID },
|
||||
{ "register", required_argument, NULL, ARG_REGISTER },
|
||||
{ "keep-unit", no_argument, NULL, ARG_KEEP_UNIT },
|
||||
{ "bind", required_argument, NULL, ARG_BIND },
|
||||
{ "bind-ro", required_argument, NULL, ARG_BIND_RO },
|
||||
{ "extra-drive", required_argument, NULL, ARG_EXTRA_DRIVE },
|
||||
@ -443,6 +447,11 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
r = parse_boolean_argument("--register=", optarg, &arg_register);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case ARG_KEEP_UNIT:
|
||||
arg_keep_unit = true;
|
||||
break;
|
||||
|
||||
case ARG_BIND:
|
||||
@ -2055,7 +2064,8 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
||||
arg_directory,
|
||||
child_cid,
|
||||
child_cid != VMADDR_CID_ANY ? vm_address : NULL,
|
||||
ssh_private_key_path);
|
||||
ssh_private_key_path,
|
||||
arg_keep_unit);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -2229,8 +2239,10 @@ static int verify_arguments(void) {
|
||||
if (!strv_isempty(arg_initrds) && !arg_linux)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --initrd= cannot be used without --linux=.");
|
||||
|
||||
if (arg_register && !arg_privileged)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "--register= requires root privileges, refusing.");
|
||||
if (arg_keep_unit && arg_register && cg_pid_get_owner_uid(0, NULL) >= 0)
|
||||
/* Save the user from accidentally registering either user-$SESSION.scope or user@.service.
|
||||
* The latter is not technically a user session, but we don't need to labour the point. */
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--keep-unit --register=yes may not be used when invoked from a user session.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ if ! systemd-detect-virt -c; then
|
||||
-p DelegateSubgroup=supervisor \
|
||||
-p Environment=SYSTEMD_LOG_LEVEL=debug \
|
||||
--wait -- \
|
||||
systemd-nspawn --keep-unit -i /var/tmp/unpriv.raw --read-only --pipe echo thisisatest >/tmp/unpriv.out2
|
||||
systemd-nspawn --keep-unit --register=no -i /var/tmp/unpriv.raw --read-only --pipe echo thisisatest >/tmp/unpriv.out2
|
||||
echo thisisatest | cmp /tmp/unpriv.out2 -
|
||||
fi
|
||||
|
||||
|
@ -16,7 +16,7 @@ After=network.target modprobe@tun.service
|
||||
RequiresMountsFor=/var/lib/machines/%i
|
||||
|
||||
[Service]
|
||||
ExecStart=systemd-vmspawn --quiet --network-tap --machine=%i
|
||||
ExecStart=systemd-vmspawn --quiet --register=yes --keep-unit --network-tap --machine=%i
|
||||
KillMode=mixed
|
||||
Type=notify
|
||||
Slice=machine.slice
|
||||
|
Loading…
Reference in New Issue
Block a user