Allows to pass system and service credentials to a VM. See [1] for a description of credentials. This can be potentially used to provision a VM as per [2]. Values can be passed either as plain text or as a base64 encoded string when the base64 flag is set.
A VM configuration file which, for example, contains: systemd-cred0: name=foo,value=bar systemd-cred1: name=encoded-foo,value=YmFy,base64=1 will have the following arguments added to its kvm command: -smbios 'type=11,value=io.systemd.credential:foo=bar' \ -smbios 'type=11,value=io.systemd.credential.binary:encoded-foo=YmFy' On the guest these credentials can be read via: dmidecode -t 11 via: systemd-creds --system list systemd-creds --system cat $CREDENTIAL_NAME or at: /run/credentials/@system/$CREDENTIAL_NAME [1] https://systemd.io/CREDENTIALS/ [2] https://www.freedesktop.org/software/systemd/man/latest/systemd.system-credentials.html Suggested-by: Wolfgang Bumiller <w.bumil...@proxmox.com> Signed-off-by: Maximiliano Sandoval <m.sando...@proxmox.com> --- Differences from RFC: - Fixed multiple points from the feedback in the RFC - Uses "systemd-cred$i" instead of "systemd-credential.$name" as a name - The snipped support was dropped - More strict format required on credential names and values PVE/QemuServer.pm | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index ffd5d56b..1f902b8b 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -150,6 +150,31 @@ my $watchdog_fmt = { }; PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt); +my $MAX_CREDENTIALS = 16; + +my $systemd_cred_fmt = { + value => { + description => 'The credential\'s value. This is a Base64 encoded string.' + .' If the value should contain arbitrary binary data,' + .' then the value can be a Base64 encoded string and the base64=1 flag should be set.', + type => 'string', + pattern => '[A-Za-z0-9+\/]+={0,2}', + typetext => '<string>', + }, + name => { + description => 'The credential\'s name. This is a short ASCII string suitable as filename in the filesystem', + type => 'string', + pattern => '[A-Za-z0-9\-\._]+', + typetext => '<string>', + }, + base64 => { + description => 'Whether the credential\'s value is base64 encoded.', + type => 'boolean', + optional => 1, + default => 0, + }, +}; + my $agent_fmt = { enabled => { description => "Enable/disable communication with a QEMU Guest Agent (QGA) running in the VM.", @@ -946,6 +971,13 @@ my $netdesc = { description => "Specify network devices.", }; +my $systemd_cred_desc = { + optional => 1, + type => 'string', + format => $systemd_cred_fmt, + description => 'Specify system and service credentials.', +}; + PVE::JSONSchema::register_standard_option("pve-qm-net", $netdesc); my $ipconfig_fmt = { @@ -1007,6 +1039,10 @@ for (my $i = 0; $i < $MAX_NETS; $i++) { $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc; } +for (my $i = 0; $i < $MAX_CREDENTIALS; $i++) { + $confdesc->{"systemd-cred$i"} = $systemd_cred_desc; +} + foreach my $key (keys %$confdesc_cloudinit) { $confdesc->{$key} = $confdesc_cloudinit->{$key}; } @@ -1955,6 +1991,16 @@ sub parse_guest_agent { return $res; } +sub parse_systemd_credential { + my ($value) = @_; + + return {} if !$value; + + my $res = eval { parse_property_string($systemd_cred_fmt, $value) }; + warn $@ if $@; + return $res; +} + sub get_qga_key { my ($conf, $key) = @_; return undef if !defined($conf->{agent}); @@ -3383,6 +3429,17 @@ my sub get_vga_properties { return ($vga, $qxlnum); } +sub smbios_11_cred_arg { + my ($name, $value, $is_encoded) = @_; + + if ($is_encoded) { + die "value $value is not base64 encoded\n" if $value !~ /^[A-Za-z0-9+\/]+={0,2}$/; + return ('-smbios', "type=11,value=io.systemd.credential.binary:$name=$value"); + } else { + return ('-smbios', "type=11,value=io.systemd.credential:$name=$value"); + } +} + sub config_to_command { my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu, $live_restore_backing) = @_; @@ -4015,6 +4072,21 @@ sub config_to_command { push @$cmd, '-snapshot'; } + for (my $i = 0; $i < $MAX_CREDENTIALS; $i++) { + my $cred_name = "systemd-cred$i"; + + next if !$conf->{$cred_name}; + + my $opts = parse_systemd_credential($conf->{$cred_name}); + my $name = $opts->{'name'}; + my $is_encoded = $opts->{'base64'}; + my $value = $opts->{'value'}; + + if ($value && $name) { + push @$cmd, smbios_11_cred_arg($name, $value, $is_encoded); + } + } + # add custom args if ($conf->{args}) { my $aa = PVE::Tools::split_args($conf->{args}); -- 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel