all lists on lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH qemu-server] config: add system and service credentials support
@ 2025-04-02 14:36 Maximiliano Sandoval
  2025-04-03  7:49 ` Thomas Lamprecht
  0 siblings, 1 reply; 7+ messages in thread
From: Maximiliano Sandoval @ 2025-04-02 14:36 UTC (permalink / raw)
  To: pve-devel; +Cc: Wolfgang Bumiller

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.bumiller@proxmox.com>
Signed-off-by: Maximiliano Sandoval <m.sandoval@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


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-04-03  9:42 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-04-02 14:36 [pve-devel] [PATCH qemu-server] config: add system and service credentials support Maximiliano Sandoval
2025-04-03  7:49 ` Thomas Lamprecht
2025-04-03  7:56   ` Thomas Lamprecht
2025-04-03  8:48     ` Maximiliano Sandoval
2025-04-03  8:34   ` Maximiliano Sandoval
2025-04-03  9:04     ` Thomas Lamprecht
2025-04-03  9:42       ` Lukas Wagner

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal