On Thu, Nov 27, 2025 at 12:52:29 +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 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 <[email protected]>
> ---
>  libvirt.spec.in                         |  4 ++++
>  src/meson.build                         |  1 +
>  src/secret/meson.build                  | 24 ++++++++++++++++++++++++
>  src/secret/secret-init-encryption.in    | 10 ++++++++++
>  src/secret/virtsecretd.service.extra.in |  8 ++++++++
>  5 files changed, 47 insertions(+)
>  create mode 100644 src/secret/secret-init-encryption.in
> 
> diff --git a/libvirt.spec.in b/libvirt.spec.in
> index 62af7fb517..dba8a71311 100644
> --- a/libvirt.spec.in
> +++ b/libvirt.spec.in
> @@ -1880,13 +1880,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
> @@ -2238,6 +2241,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/secret/meson.build b/src/secret/meson.build
> index 3b859ea7b4..c02d1064a9 100644
> --- a/src/secret/meson.build
> +++ b/src/secret/meson.build
> @@ -31,6 +31,30 @@ if conf.has('WITH_SECRETS')
>      'name': 'virtsecretd',
>    }
>  
> +  secret_init_encryption_unit = {
> +    'service': 'virt-secret-init-encryption',
> +    'name': 'Libvirt Secret Encryption Init',
> +    'input': 'secret-init-encryption.in',
> +  }

You can put these values directly inline rather than have this extra
object.


> +  unit_conf = configuration_data()

Preferrably use a more descriptive name for the variable.

e.g. virt_secret_init_encryption_conf

> +  unit_conf.set('runstatedir', runstatedir)
> +  unit_conf.set('sbindir', sbindir)
> +  unit_conf.set('localstatedir', localstatedir)
> +  unit_conf.set('sysconfdir', sysconfdir)
> +  unit_conf.set('initconfdir', initconfdir)
> +  unit_conf.set('name', secret_init_encryption_unit['name'])
> +  unit_conf.set('service', secret_init_encryption_unit['service'])
> +  unit_conf.set('SERVICE', secret_init_encryption_unit['service'].to_upper())

The secret-init-encryption.in uses only 'localstatedir' replacement,
anything else isn't used here.


> +  configure_file(
> +    input: secret_init_encryption_unit['input'],
> +    output: '@[email protected]'.format(secret_init_encryption_unit['service']),
> +    configuration: unit_conf,
> +    install: true,
> +    install_dir: unitdir,
> +  )
> +
>    virt_daemon_units += {
>      'service': 'virtsecretd',
>      'name': 'secret',


> diff --git a/src/secret/secret-init-encryption.in 
> b/src/secret/secret-init-encryption.in

Please rename this to 'virt-secret-init-encryption.service.in'

> new file mode 100644
> index 0000000000..29da6dbcce
> --- /dev/null
> +++ b/src/secret/secret-init-encryption.in
> @@ -0,0 +1,10 @@
> +[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)'
> +
> +[Install]
> +WantedBy=multi-user.target

What does this actually do?


> 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

This will likely be needed also for the monolithic daemon's unit
(libvirtd.service) as that can also start the secret driver in those
setups.

Reply via email to