public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [RFC PATCH 1/2] config: allow hypens and dots in config keys
@ 2024-09-24 14:35 Maximiliano Sandoval
  2024-09-24 14:35 ` [pve-devel] [RFC PATCH 2/2] config: add systemd credentials support Maximiliano Sandoval
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Maximiliano Sandoval @ 2024-09-24 14:35 UTC (permalink / raw)
  To: pve-devel

The first character still has to be a letter.

Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
---
 PVE/QemuServer.pm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index b26da505..1566cf91 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -2382,7 +2382,7 @@ sub parse_vm_config {
 	    } else {
 		$handle_error->("vm $vmid - property 'delete' is only allowed in [PENDING]\n");
 	    }
-	} elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
+	} elsif ($line =~ m/^([a-z][a-z_\.-]*\d*):\s*(.+?)\s*$/) {
 	    my $key = $1;
 	    my $value = $2;
 	    if ($section eq 'cloudinit') {
-- 
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] 5+ messages in thread

* [pve-devel] [RFC PATCH 2/2] config: add systemd credentials support
  2024-09-24 14:35 [pve-devel] [RFC PATCH 1/2] config: allow hypens and dots in config keys Maximiliano Sandoval
@ 2024-09-24 14:35 ` Maximiliano Sandoval
  2024-10-22  8:29   ` Fabian Grünbichler
  2024-10-21 12:19 ` [pve-devel] [RFC PATCH 1/2] config: allow hypens and dots in config keys Fiona Ebner
  2024-10-22  6:45 ` Thomas Lamprecht
  2 siblings, 1 reply; 5+ messages in thread
From: Maximiliano Sandoval @ 2024-09-24 14:35 UTC (permalink / raw)
  To: pve-devel; +Cc: Wolfgang Bumiller

Allows to pass systemd credentials to a VM. See [1] for a description of
systemd credentials. This can be potentially used to provision a VM as
per [2]. Values can be passed either as plain text (which might be
base64 encrypted) or by reading the contents of a snippet.

A VM configuration file which, for example, contains:

    systemd.foo: value=bar
    systemd.ssh.authorized_keys.root: snippet=local:snippets/id_ed25519.pub
    systemd.encoded-foo: value=YmFya=,base64=1

will have the following arguments added to its kvm command:

    -smbios 'type=11,value=io.systemd.credential.binary:ssh.authorized_keys.root=c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUZWZkFTYnVHdGdoWXBQQTBUS0w4N3I2dWRYNm5CbEM2L2hLWVZaTTdENzYgZm9vQGJhcgo=' \
    -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

In the example above, the SSH key will be added to
/root/.ssh/authorized_keys provided the file did not exist, see [3].

[1] https://systemd.io/CREDENTIALS/
[2] https://www.freedesktop.org/software/systemd/man/latest/systemd.system-credentials.html
[3] https://www.freedesktop.org/software/systemd/man/latest/systemd.system-credentials.html#ssh.authorized_keys.root

Suggested-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
---
 PVE/QemuServer.pm | 77 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 1566cf91..3ec21064 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -149,6 +149,26 @@ my $watchdog_fmt = {
 };
 PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt);
 
+our $systemd_value_fmt = {
+    value => {
+	description => 'The credential value. base64=1 should be specified if the value is base64 encoded.',
+	type => 'string',
+	optional => 1,
+    },
+    snippet => {
+	type => 'string',
+	description => "Specify a snippet containing the credential's value",
+	format => 'pve-volume-id',
+	optional => 1,
+    },
+    base64 => {
+	description => 'Whether the 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.",
@@ -2039,6 +2059,16 @@ sub parse_guest_agent {
     return $res;
 }
 
+sub parse_systemd_credential {
+    my ($value) = @_;
+
+    return {} if !$value;
+
+    my $res = eval { parse_property_string($systemd_value_fmt, $value) };
+    warn $@ if $@;
+    return $res;
+}
+
 sub get_qga_key {
     my ($conf, $key) = @_;
     return undef if !defined($conf->{agent});
@@ -2390,6 +2420,12 @@ sub parse_vm_config {
 		$conf->{$key} = $value;
 		next;
 	    }
+	    if ($key =~ /^systemd\.([a-z][a-z_\.-]*)$/) {
+		# ignore validation of systemd credentials
+		$conf->{'systemd-credentials'}->{$1} = $value;
+		next;
+	    }
+
 	    eval { $value = check_type($key, $value); };
 	    if ($@) {
 		$handle_error->("vm $vmid - unable to parse value of '$key' - $@");
@@ -3514,6 +3550,27 @@ my sub get_vga_properties {
     return ($vga, $qxlnum);
 }
 
+sub smbios_11_cred_arg {
+    my ($key, $value, $is_encoded) = @_;
+
+    if ($is_encoded) {
+	return ('-smbios', "type=11,value=io.systemd.credential.binary:$key=$value");
+    } else {
+	return ('-smbios', "type=11,value=io.systemd.credential:$key=$value");
+    }
+}
+
+sub read_systemd_custom_file {
+    my ($storage_conf, $path) = @_;
+
+    my ($vtype, undef) = PVE::Storage::parse_volname($storage_conf, $path);
+
+    die "$path is not in the snippets directory\n" if $vtype ne 'snippets';
+
+    my $full_path = PVE::Storage::abs_filesystem_path($storage_conf, $path, 1);
+    return PVE::Tools::file_get_contents($full_path, 1 * 1024 * 1024);
+}
+
 sub config_to_command {
     my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
         $live_restore_backing) = @_;
@@ -4142,6 +4199,26 @@ sub config_to_command {
 	push @$cmd, '-snapshot';
     }
 
+    # set systemd-credentials
+    my $storage_conf;
+    my $systemd_credentials = $conf->{'systemd-credentials'} || {};
+    foreach my $key (keys %$systemd_credentials) {
+	my $opts = parse_systemd_credential($systemd_credentials->{$key});
+	my $is_encoded = $opts->{'base64'} ? 1 : 0;
+	my $value;
+
+	if (my $v = $opts->{'value'}) {
+	    $value = $v;
+	} elsif (my $snippet = $opts->{'snippet'}) {
+	    $storage_conf = PVE::Storage::config() if !defined($storage_conf);
+	    my $contents = read_systemd_custom_file($storage_conf, $snippet);
+	    $value = encode_base64($contents, '');
+	    $is_encoded = 1;
+	}
+
+	push @$cmd, smbios_11_cred_arg($key, $value, $is_encoded) if $value;
+    }
+
     # 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] 5+ messages in thread

* Re: [pve-devel] [RFC PATCH 1/2] config: allow hypens and dots in config keys
  2024-09-24 14:35 [pve-devel] [RFC PATCH 1/2] config: allow hypens and dots in config keys Maximiliano Sandoval
  2024-09-24 14:35 ` [pve-devel] [RFC PATCH 2/2] config: add systemd credentials support Maximiliano Sandoval
@ 2024-10-21 12:19 ` Fiona Ebner
  2024-10-22  6:45 ` Thomas Lamprecht
  2 siblings, 0 replies; 5+ messages in thread
From: Fiona Ebner @ 2024-10-21 12:19 UTC (permalink / raw)
  To: Proxmox VE development discussion, Maximiliano Sandoval; +Cc: Thomas Lamprecht

Am 24.09.24 um 16:35 schrieb Maximiliano Sandoval:
> The first character still has to be a letter.
> 
> Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
> ---
>  PVE/QemuServer.pm | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index b26da505..1566cf91 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -2382,7 +2382,7 @@ sub parse_vm_config {
>  	    } else {
>  		$handle_error->("vm $vmid - property 'delete' is only allowed in [PENDING]\n");
>  	    }
> -	} elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
> +	} elsif ($line =~ m/^([a-z][a-z_\.-]*\d*):\s*(.+?)\s*$/) {
>  	    my $key = $1;
>  	    my $value = $2;
>  	    if ($section eq 'cloudinit') {

Regarding the hyphen, see also:
https://lore.proxmox.com/pve-devel/7c911e11-d1cb-415b-9282-b40faa34dc9b@proxmox.com/#t

Also friendly ping for @Thomas for that mail, in particular, for where
this should be documented.


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


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

* Re: [pve-devel] [RFC PATCH 1/2] config: allow hypens and dots in config keys
  2024-09-24 14:35 [pve-devel] [RFC PATCH 1/2] config: allow hypens and dots in config keys Maximiliano Sandoval
  2024-09-24 14:35 ` [pve-devel] [RFC PATCH 2/2] config: add systemd credentials support Maximiliano Sandoval
  2024-10-21 12:19 ` [pve-devel] [RFC PATCH 1/2] config: allow hypens and dots in config keys Fiona Ebner
@ 2024-10-22  6:45 ` Thomas Lamprecht
  2 siblings, 0 replies; 5+ messages in thread
From: Thomas Lamprecht @ 2024-10-22  6:45 UTC (permalink / raw)
  To: Proxmox VE development discussion, Maximiliano Sandoval

s/hypens/hyphens/

Am 24/09/2024 um 16:35 schrieb Maximiliano Sandoval:
> The first character still has to be a letter.

Such a patch really must have more rationale for why each character
is required, e.g. for hyphens it would be allowing using kebab-case
like we use for (most) new schema properties, might be obvious to
you, but it hasn't to be obvious for every dev or (potential)
contributor. Dot on the other hand isnt' obvious to me, do we use
that anywhere, why should it be allowed for properties if we want
to switch everything to kebab-case in the  long term? As this would
only allow adding further inconsistency?


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


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

* Re: [pve-devel] [RFC PATCH 2/2] config: add systemd credentials support
  2024-09-24 14:35 ` [pve-devel] [RFC PATCH 2/2] config: add systemd credentials support Maximiliano Sandoval
@ 2024-10-22  8:29   ` Fabian Grünbichler
  0 siblings, 0 replies; 5+ messages in thread
From: Fabian Grünbichler @ 2024-10-22  8:29 UTC (permalink / raw)
  To: Proxmox VE development discussion; +Cc: Wolfgang Bumiller

On September 24, 2024 4:35 pm, Maximiliano Sandoval wrote:
> Allows to pass systemd credentials to a VM. See [1] for a description of
> systemd credentials. This can be potentially used to provision a VM as
> per [2]. Values can be passed either as plain text (which might be
> base64 encrypted) or by reading the contents of a snippet.
> 
> A VM configuration file which, for example, contains:
> 
>     systemd.foo: value=bar
>     systemd.ssh.authorized_keys.root: snippet=local:snippets/id_ed25519.pub
>     systemd.encoded-foo: value=YmFya=,base64=1

why not our usual scheme?

systemd0: key=foo,value=bar
systemd1: key=ssh.authorized_keys.root,snippet=local:snippets/id_ed25519.pub
systemd2: key=encoded-foo,value=YmFya=,base64=1

if need be, the key could be persisted base64-encoded (e.g., if it can
contain characters used as delimiters or otherwise special)

> will have the following arguments added to its kvm command:
> 
>     -smbios 'type=11,value=io.systemd.credential.binary:ssh.authorized_keys.root=c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUZWZkFTYnVHdGdoWXBQQTBUS0w4N3I2dWRYNm5CbEM2L2hLWVZaTTdENzYgZm9vQGJhcgo=' \
>     -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
> 
> In the example above, the SSH key will be added to
> /root/.ssh/authorized_keys provided the file did not exist, see [3].
> 
> [1] https://systemd.io/CREDENTIALS/
> [2] https://www.freedesktop.org/software/systemd/man/latest/systemd.system-credentials.html
> [3] https://www.freedesktop.org/software/systemd/man/latest/systemd.system-credentials.html#ssh.authorized_keys.root
> 
> Suggested-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
> Signed-off-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
> ---
>  PVE/QemuServer.pm | 77 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 77 insertions(+)
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 1566cf91..3ec21064 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -149,6 +149,26 @@ my $watchdog_fmt = {
>  };
>  PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt);
>  
> +our $systemd_value_fmt = {
> +    value => {
> +	description => 'The credential value. base64=1 should be specified if the value is base64 encoded.',
> +	type => 'string',

nack - this needs some sort of restriction (e.g. a sane character set
for non-base64 encoded values, or base64)

> +	optional => 1,
> +    },
> +    snippet => {
> +	type => 'string',
> +	description => "Specify a snippet containing the credential's value",
> +	format => 'pve-volume-id',

not too sure about adding yet more usage to the already overloaded and
problematic snippet feature that we want to get rid of/overhaul..

> +	optional => 1,
> +    },
> +    base64 => {
> +	description => 'Whether the 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.",
> @@ -2039,6 +2059,16 @@ sub parse_guest_agent {
>      return $res;
>  }
>  
> +sub parse_systemd_credential {
> +    my ($value) = @_;
> +
> +    return {} if !$value;
> +
> +    my $res = eval { parse_property_string($systemd_value_fmt, $value) };
> +    warn $@ if $@;

why? if you do this, it needs to be optin via a $noerr parameter..

> +    return $res;
> +}
> +
>  sub get_qga_key {
>      my ($conf, $key) = @_;
>      return undef if !defined($conf->{agent});
> @@ -2390,6 +2420,12 @@ sub parse_vm_config {

you only touch parse_vm_config.. how does this work on read-modify-write
cycles??

>  		$conf->{$key} = $value;
>  		next;
>  	    }
> +	    if ($key =~ /^systemd\.([a-z][a-z_\.-]*)$/) {
> +		# ignore validation of systemd credentials
> +		$conf->{'systemd-credentials'}->{$1} = $value;
> +		next;
> +	    }
> +

this part here would not be needed if it were a regular config option
instead of getting special treatment..

>  	    eval { $value = check_type($key, $value); };

but this part here would still trigger schema validation then, which
would be a plus!

>  	    if ($@) {
>  		$handle_error->("vm $vmid - unable to parse value of '$key' - $@");
> @@ -3514,6 +3550,27 @@ my sub get_vga_properties {
>      return ($vga, $qxlnum);
>  }
>  
> +sub smbios_11_cred_arg {
> +    my ($key, $value, $is_encoded) = @_;
> +
> +    if ($is_encoded) {
> +	return ('-smbios', "type=11,value=io.systemd.credential.binary:$key=$value");
> +    } else {
> +	return ('-smbios', "type=11,value=io.systemd.credential:$key=$value");
> +    }
> +}
> +
> +sub read_systemd_custom_file {
> +    my ($storage_conf, $path) = @_;
> +
> +    my ($vtype, undef) = PVE::Storage::parse_volname($storage_conf, $path);
> +
> +    die "$path is not in the snippets directory\n" if $vtype ne 'snippets';
> +
> +    my $full_path = PVE::Storage::abs_filesystem_path($storage_conf, $path, 1);
> +    return PVE::Tools::file_get_contents($full_path, 1 * 1024 * 1024);
> +}

this is a 1:1 copy of
PVE::QemuServer::Cloudinit::read_cloudinit_snippets_file ..

> +
>  sub config_to_command {
>      my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
>          $live_restore_backing) = @_;
> @@ -4142,6 +4199,26 @@ sub config_to_command {
>  	push @$cmd, '-snapshot';
>      }
>  
> +    # set systemd-credentials
> +    my $storage_conf;
> +    my $systemd_credentials = $conf->{'systemd-credentials'} || {};
> +    foreach my $key (keys %$systemd_credentials) {
> +	my $opts = parse_systemd_credential($systemd_credentials->{$key});
> +	my $is_encoded = $opts->{'base64'} ? 1 : 0;
> +	my $value;
> +
> +	if (my $v = $opts->{'value'}) {
> +	    $value = $v;
> +	} elsif (my $snippet = $opts->{'snippet'}) {
> +	    $storage_conf = PVE::Storage::config() if !defined($storage_conf);

why? config_to_command already has a copy of the storage config..

> +	    my $contents = read_systemd_custom_file($storage_conf, $snippet);
> +	    $value = encode_base64($contents, '');
> +	    $is_encoded = 1;
> +	}
> +
> +	push @$cmd, smbios_11_cred_arg($key, $value, $is_encoded) if $value;
> +    }
> +
>      # 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
> 
> 
> 


_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


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

end of thread, other threads:[~2024-10-22  8:29 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-09-24 14:35 [pve-devel] [RFC PATCH 1/2] config: allow hypens and dots in config keys Maximiliano Sandoval
2024-09-24 14:35 ` [pve-devel] [RFC PATCH 2/2] config: add systemd credentials support Maximiliano Sandoval
2024-10-22  8:29   ` Fabian Grünbichler
2024-10-21 12:19 ` [pve-devel] [RFC PATCH 1/2] config: allow hypens and dots in config keys Fiona Ebner
2024-10-22  6:45 ` Thomas Lamprecht

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal