From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <pve-devel-bounces@lists.proxmox.com> Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id E67D31FF17C for <inbox@lore.proxmox.com>; Wed, 2 Apr 2025 16:36:35 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 23A5B1D3F9; Wed, 2 Apr 2025 16:36:24 +0200 (CEST) From: Maximiliano Sandoval <m.sandoval@proxmox.com> To: pve-devel@lists.proxmox.com Date: Wed, 2 Apr 2025 16:36:20 +0200 Message-Id: <20250402143620.440158-1-m.sandoval@proxmox.com> X-Mailer: git-send-email 2.39.5 MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.096 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH qemu-server] config: add system and service credentials support X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com> List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe> List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/> List-Post: <mailto:pve-devel@lists.proxmox.com> List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help> List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe> Reply-To: Proxmox VE development discussion <pve-devel@lists.proxmox.com> Cc: Wolfgang Bumiller <w.bumiller@proxmox.com> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" <pve-devel-bounces@lists.proxmox.com> 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