[PATCH 2/5] secret: Set up default encryption secret key for the virtsecretd service

Arun Menon via Devel posted 5 patches 3 days, 17 hours ago
There is a newer version of this series
[PATCH 2/5] secret: Set up default encryption secret key for the virtsecretd service
Posted by Arun Menon via Devel 3 days, 17 hours ago
This commit sets the foundation for encrypting the libvirt secrets by providing a
secure way to pass a secret encryption key to the virtsecretd service.

A random secret key is generated using the new virt-secret-init-encryption
service. This key can be consumed by the virtsecretd service.

By using the "Before=" directive in the new virt-secret-init-encryption
service and using "Requires=" directive in the virtsecretd service,
we make sure that the daemon is run only after we have an encrypted
secret key file generated and placed in /var/lib/libvirt/secrets.
The virtsecretd service can then read the key from CREDENTIALS_DIRECTORY. [1]

This setup therefore provides a default key out-of-the-box for initial use.
A subsequent commit will introduce the logic for virtsecretd
to access and use this key via the $CREDENTIALS_DIRECTORY environment variable. [2]

[1] https://www.freedesktop.org/software/systemd/man/latest/systemd-creds.html
[2] https://systemd.io/CREDENTIALS/

Signed-off-by: Arun Menon <armenon@redhat.com>
---
 libvirt.spec.in                                   |  4 ++++
 src/meson.build                                   |  1 +
 src/remote/libvirtd.service.in                    |  2 ++
 src/secret/meson.build                            | 15 +++++++++++++++
 src/secret/virt-secret-init-encryption.service.in |  7 +++++++
 src/secret/virtsecretd.service.extra.in           |  8 ++++++++
 6 files changed, 37 insertions(+)
 create mode 100644 src/secret/virt-secret-init-encryption.service.in

diff --git a/libvirt.spec.in b/libvirt.spec.in
index ccfe75135b..8505a220c7 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -1890,13 +1890,16 @@ exit 0
 %pre daemon-driver-secret
 %libvirt_sysconfig_pre virtsecretd
 %libvirt_systemd_unix_pre virtsecretd
+%libvirt_systemd_oneshot_pre virt-secret-init-encryption
 
 %posttrans daemon-driver-secret
 %libvirt_sysconfig_posttrans virtsecretd
 %libvirt_systemd_unix_posttrans virtsecretd
+%libvirt_systemd_unix_posttrans virt-secret-init-encryption
 
 %preun daemon-driver-secret
 %libvirt_systemd_unix_preun virtsecretd
+%libvirt_systemd_unix_preun virt-secret-init-encryption
 
 %pre daemon-driver-storage-core
 %libvirt_sysconfig_pre virtstoraged
@@ -2248,6 +2251,7 @@ exit 0
 %{_datadir}/augeas/lenses/virtsecretd.aug
 %{_datadir}/augeas/lenses/tests/test_virtsecretd.aug
 %{_unitdir}/virtsecretd.service
+%{_unitdir}/virt-secret-init-encryption.service
 %{_unitdir}/virtsecretd.socket
 %{_unitdir}/virtsecretd-ro.socket
 %{_unitdir}/virtsecretd-admin.socket
diff --git a/src/meson.build b/src/meson.build
index 47c978cc1f..f18f562fd9 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -837,6 +837,7 @@ if conf.has('WITH_LIBVIRTD')
         'sbindir': sbindir,
         'sysconfdir': sysconfdir,
         'initconfdir': initconfdir,
+        'localstatedir': localstatedir,
         'name': unit['name'],
         'service': unit['service'],
         'SERVICE': unit['service'].to_upper(),
diff --git a/src/remote/libvirtd.service.in b/src/remote/libvirtd.service.in
index b0a062e885..84447e0bcf 100644
--- a/src/remote/libvirtd.service.in
+++ b/src/remote/libvirtd.service.in
@@ -29,6 +29,8 @@ Conflicts=xendomains.service
 Type=notify-reload
 Environment=LIBVIRTD_ARGS="--timeout 120"
 EnvironmentFile=-@initconfdir@/libvirtd
+Environment=SECRETS_ENCRYPTION_KEY=%d/secrets-encryption-key
+LoadCredentialEncrypted=secrets-encryption-key:@localstatedir@/lib/libvirt/secrets/secrets-encryption-key
 ExecStart=@sbindir@/libvirtd $LIBVIRTD_ARGS
 ExecReload=/bin/kill -HUP $MAINPID
 KillMode=process
diff --git a/src/secret/meson.build b/src/secret/meson.build
index 3b859ea7b4..b0977eadc8 100644
--- a/src/secret/meson.build
+++ b/src/secret/meson.build
@@ -31,6 +31,21 @@ if conf.has('WITH_SECRETS')
     'name': 'virtsecretd',
   }
 
+  virt_secret_init_encryption_conf = configuration_data()
+
+  virt_secret_init_encryption_conf.set('localstatedir', localstatedir)
+  virt_secret_init_encryption_conf.set('name', 'Libvirt Secret Encryption Init')
+  virt_secret_init_encryption_conf.set('service', 'virt-secret-init-encryption')
+  virt_secret_init_encryption_conf.set('SERVICE', 'virt-secret-init-encryption'.to_upper())
+
+  configure_file(
+    input: 'virt-secret-init-encryption.service.in',
+    output: '@0@.service'.format('virt-secret-init-encryption'),
+    configuration: virt_secret_init_encryption_conf,
+    install: true,
+    install_dir: unitdir,
+  )
+
   virt_daemon_units += {
     'service': 'virtsecretd',
     'name': 'secret',
diff --git a/src/secret/virt-secret-init-encryption.service.in b/src/secret/virt-secret-init-encryption.service.in
new file mode 100644
index 0000000000..0a23d452e8
--- /dev/null
+++ b/src/secret/virt-secret-init-encryption.service.in
@@ -0,0 +1,7 @@
+[Unit]
+Before=virtsecretd.service
+ConditionPathExists=!@localstatedir@/lib/libvirt/secrets/secrets-encryption-key
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/sh -c 'umask 0066 && (dd if=/dev/urandom status=none bs=32 count=1 | systemd-creds encrypt --name=secrets-encryption-key - @localstatedir@/lib/libvirt/secrets/secrets-encryption-key)'
diff --git a/src/secret/virtsecretd.service.extra.in b/src/secret/virtsecretd.service.extra.in
index 1fc8c672f7..116458b22a 100644
--- a/src/secret/virtsecretd.service.extra.in
+++ b/src/secret/virtsecretd.service.extra.in
@@ -1,2 +1,10 @@
 # The contents of this unit will be merged into a base template.
 # Additional units might be merged as well. See meson.build for details.
+#
+[Unit]
+Requires=virt-secret-init-encryption.service
+After=virt-secret-init-encryption.service
+
+[Service]
+LoadCredentialEncrypted=secrets-encryption-key:@localstatedir@/lib/libvirt/secrets/secrets-encryption-key
+Environment=SECRETS_ENCRYPTION_KEY=%d/secrets-encryption-key
-- 
2.51.1
Re: [PATCH 2/5] secret: Set up default encryption secret key for the virtsecretd service
Posted by Peter Krempa via Devel 3 hours ago
On Tue, Dec 09, 2025 at 01:22:28 +0530, Arun Menon via Devel wrote:
> This commit sets the foundation for encrypting the libvirt secrets by providing a
> secure way to pass a secret encryption key to the virtsecretd service.
> 
> A random secret key is generated using the new virt-secret-init-encryption
> service. This key can be consumed by the virtsecretd service.
> 
> By using the "Before=" directive in the new virt-secret-init-encryption
> service and using "Requires=" directive in the virtsecretd service,
> we make sure that the daemon is run only after we have an encrypted
> secret key file generated and placed in /var/lib/libvirt/secrets.
> The virtsecretd service can then read the key from CREDENTIALS_DIRECTORY. [1]
> 
> This setup therefore provides a default key out-of-the-box for initial use.
> A subsequent commit will introduce the logic for virtsecretd
> to access and use this key via the $CREDENTIALS_DIRECTORY environment variable. [2]
> 
> [1] https://www.freedesktop.org/software/systemd/man/latest/systemd-creds.html
> [2] https://systemd.io/CREDENTIALS/
> 
> Signed-off-by: Arun Menon <armenon@redhat.com>
> ---
>  libvirt.spec.in                                   |  4 ++++
>  src/meson.build                                   |  1 +
>  src/remote/libvirtd.service.in                    |  2 ++
>  src/secret/meson.build                            | 15 +++++++++++++++
>  src/secret/virt-secret-init-encryption.service.in |  7 +++++++
>  src/secret/virtsecretd.service.extra.in           |  8 ++++++++
>  6 files changed, 37 insertions(+)
>  create mode 100644 src/secret/virt-secret-init-encryption.service.in

[...]

> diff --git a/src/remote/libvirtd.service.in b/src/remote/libvirtd.service.in
> index b0a062e885..84447e0bcf 100644
> --- a/src/remote/libvirtd.service.in
> +++ b/src/remote/libvirtd.service.in
> @@ -29,6 +29,8 @@ Conflicts=xendomains.service
>  Type=notify-reload
>  Environment=LIBVIRTD_ARGS="--timeout 120"
>  EnvironmentFile=-@initconfdir@/libvirtd
> +Environment=SECRETS_ENCRYPTION_KEY=%d/secrets-encryption-key
> +LoadCredentialEncrypted=secrets-encryption-key:@localstatedir@/lib/libvirt/secrets/secrets-encryption-key
>  ExecStart=@sbindir@/libvirtd $LIBVIRTD_ARGS
>  ExecReload=/bin/kill -HUP $MAINPID
>  KillMode=process

IIUC the libvird.service.in unit needs to depend the same way on
'virt-secret-init-encryption.service' as virtsecredtd.service does.

> diff --git a/src/secret/meson.build b/src/secret/meson.build
> index 3b859ea7b4..b0977eadc8 100644
> --- a/src/secret/meson.build
> +++ b/src/secret/meson.build
> @@ -31,6 +31,21 @@ if conf.has('WITH_SECRETS')
>      'name': 'virtsecretd',
>    }
>  
> +  virt_secret_init_encryption_conf = configuration_data()
> +
> +  virt_secret_init_encryption_conf.set('localstatedir', localstatedir)

---

> +  virt_secret_init_encryption_conf.set('name', 'Libvirt Secret Encryption Init')
> +  virt_secret_init_encryption_conf.set('service', 'virt-secret-init-encryption')
> +  virt_secret_init_encryption_conf.set('SERVICE', 'virt-secret-init-encryption'.to_upper())

^^^

None of the above substitutions are actually used in
'virt-secret-init-encryption.service.in'.

> +
> +  configure_file(
> +    input: 'virt-secret-init-encryption.service.in',
> +    output: '@0@.service'.format('virt-secret-init-encryption'),
> +    configuration: virt_secret_init_encryption_conf,
> +    install: true,
> +    install_dir: unitdir,
> +  )
> +
>    virt_daemon_units += {
>      'service': 'virtsecretd',
>      'name': 'secret',
> diff --git a/src/secret/virt-secret-init-encryption.service.in b/src/secret/virt-secret-init-encryption.service.in
> new file mode 100644
> index 0000000000..0a23d452e8
> --- /dev/null
> +++ b/src/secret/virt-secret-init-encryption.service.in
> @@ -0,0 +1,7 @@
> +[Unit]
> +Before=virtsecretd.service

libvirtd.service too

> +ConditionPathExists=!@localstatedir@/lib/libvirt/secrets/secrets-encryption-key
> +
> +[Service]
> +Type=oneshot
> +ExecStart=/usr/bin/sh -c 'umask 0066 && (dd if=/dev/urandom status=none bs=32 count=1 | systemd-creds encrypt --name=secrets-encryption-key - @localstatedir@/lib/libvirt/secrets/secrets-encryption-key)'
> diff --git a/src/secret/virtsecretd.service.extra.in b/src/secret/virtsecretd.service.extra.in
> index 1fc8c672f7..116458b22a 100644
> --- a/src/secret/virtsecretd.service.extra.in
> +++ b/src/secret/virtsecretd.service.extra.in
> @@ -1,2 +1,10 @@
>  # The contents of this unit will be merged into a base template.
>  # Additional units might be merged as well. See meson.build for details.
> +#
> +[Unit]
> +Requires=virt-secret-init-encryption.service
> +After=virt-secret-init-encryption.service

[1]