On Wed, Jul 29, 2026 at 08:58:58 +0000, Abhisek Panda wrote:
> Enable TLS-PSK based secure migration, if and only if the
> VIR_MIGRATE_TLS flag is set and the destination host lacks necessary
> X.509 credentials (ca-cert.pem, server-cert.pem and server-key.pem).
> 
> Suggested-by: Tejus GK <[email protected]>
> Signed-off-by: Abhisek Panda <[email protected]>
> ---
>  include/libvirt/libvirt-domain.h | 11 +++--
>  src/qemu/qemu_migration.c        | 83 +++++++++++++++++++++-----------
>  2 files changed, 64 insertions(+), 30 deletions(-)
> 
> diff --git a/include/libvirt/libvirt-domain.h 
> b/include/libvirt/libvirt-domain.h
> index 5b67f8f897..70d955fd31 100644
> --- a/include/libvirt/libvirt-domain.h
> +++ b/include/libvirt/libvirt-domain.h
> @@ -1089,9 +1089,14 @@ typedef enum {
>      VIR_MIGRATE_POSTCOPY = (1 << 15),
>  
>      /* Setting the VIR_MIGRATE_TLS flag will cause the migration to attempt
> -     * to use the TLS environment configured by the hypervisor in order to
> -     * perform the migration. If incorrectly configured on either source or
> -     * destination, the migration will fail.
> +     * to use either the TLS X.509 or TLS pre-shared key (PSK) authentication
> +     * mechanisms. If valid X.509 certificates and keys exist on the 
> destination host,
> +     * then Libvirt will use TLS X.509 authentication. Otherwise, Libvirt 
> falls back to
> +     * TLS PSK authentication. If the certificate or the key file is 
> corrupted or not
> +     * properly configured on either source or destination, the migration 
> will fail.
> +     *
> +     * Note: Since 12.6.0, Libvirt supports the TLS pre-shared key (PSK) 
> authentication
> +     * mechanism along with the TLS X.509 authentication scheme.

Per
<https://lists.libvirt.org/archives/list/[email protected]/message/PLXLRIV33ZGREYCL745JXCF34TOLARGE/>

freeze is on monday, so the version statement might need to be bumped.

Once again I'm sorry about the review delay, but there's a lot of other
stuff I need to deal with.



>       *
>       * Since: 3.2.0
>       */
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index 943478fe68..5e381b96e9 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -3508,14 +3508,28 @@ qemuMigrationDstPrepareActive(virQEMUDriver *driver,
>      /* Save original migration parameters */
>      qemuDomainSaveStatus(vm);
>  
> -    /* Migrations using TLS need to add the "tls-creds-x509" object and
> +    /* Migrations using TLS need to add the "tls-creds-x509" object if the 
> cert files are
> +     * present on the host, else fallback to adding the "tls-creds-psk" 
> object. Additionally,
>       * set the migration TLS parameters */
>      if (flags & VIR_MIGRATE_TLS) {
> -        if (qemuMigrationParamsEnableTLSx509(driver, vm, true,
> -                                             VIR_ASYNC_JOB_MIGRATION_IN,
> -                                             &tlsAlias, NULL,
> -                                             migParams) < 0)
> -            goto error;
> +        if (!mig->tlsPSK) {
> +            if (qemuMigrationParamsEnableTLSx509(driver, vm, true,
> +                                                 VIR_ASYNC_JOB_MIGRATION_IN,
> +                                                 &tlsAlias, NULL,
> +                                                 migParams) < 0)
> +                goto error;
> +        } else {
> +            ret = qemuMigrationPersistPSK(driver, vm, mig->tlsPSK);
> +            if (ret < 0) {
> +                virSecureEraseString(mig->tlsPSK);
> +                g_clear_pointer(&mig->tlsPSK, g_free);
> +                goto error;

As noted before this belongs to the common cleanup. Also at a failure at
this point the key was not used yet so there's no need to consider it a
secret.


> +            }
> +            if (qemuMigrationParamsEnableTLSPSK(driver, vm, true,
> +                                                VIR_ASYNC_JOB_MIGRATION_IN,
> +                                                &tlsAlias, migParams) < 0)
> +                goto error;
> +        }

For future proofing (enabling PSK tls even without explicit flag) the
logic should be:

1) if PSK exists enable TLS psk

2) if VIR_MIGRATE_TLS and x509 certs exist enable x509

3) otherwise do nothing



>      } else {
>          if (qemuMigrationParamsDisableTLS(vm, migParams) < 0)
>              goto error;
> @@ -3622,6 +3636,13 @@ qemuMigrationDstPrepareFresh(virQEMUDriver *driver,
>      g_autofree char *xmlout = NULL;
>      unsigned int cookieFlags = 0;
>      bool taint_hook = false;
> +    unsigned int parseCookieFlags = QEMU_MIGRATION_COOKIE_LOCKSTATE |
> +                                    QEMU_MIGRATION_COOKIE_NBD |
> +                                    QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG |
> +                                    QEMU_MIGRATION_COOKIE_CPU_HOTPLUG |
> +                                    QEMU_MIGRATION_COOKIE_CPU |
> +                                    QEMU_MIGRATION_COOKIE_CAPS |
> +                                    
> QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS;
>  
>      VIR_DEBUG("name=%s, origname=%s, protocol=%s, port=%hu, "
>                "listenAddress=%s, nbdPort=%d, nbdURI=%s, flags=0x%x",
> @@ -3633,6 +3654,11 @@ qemuMigrationDstPrepareFresh(virQEMUDriver *driver,
>                        QEMU_MIGRATION_COOKIE_CAPS;
>      }
>  
> +    if (flags & VIR_MIGRATE_TLS) {
> +        parseCookieFlags |= QEMU_MIGRATION_COOKIE_TLS_PSK;
> +        cookieFlags |= QEMU_MIGRATION_COOKIE_TLS_PSK;

Always parse PSK on destination. There's no need to gate this on VIR_MIGRATE_TLS




> +    }
> +
>      /* Let migration hook filter domain XML */
>      if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
>          g_autofree char *xml = NULL;
> @@ -3679,14 +3705,7 @@ qemuMigrationDstPrepareFresh(virQEMUDriver *driver,
>       * domain list. Parsing/validation may fail and there's no
>       * point in having the domain in the list at that point. */
>      if (!(mig = qemuMigrationCookieParse(driver, NULL, *def, origname, NULL,
> -                                         cookiein, cookieinlen,
> -                                         QEMU_MIGRATION_COOKIE_LOCKSTATE |
> -                                         QEMU_MIGRATION_COOKIE_NBD |
> -                                         
> QEMU_MIGRATION_COOKIE_MEMORY_HOTPLUG |
> -                                         QEMU_MIGRATION_COOKIE_CPU_HOTPLUG |
> -                                         QEMU_MIGRATION_COOKIE_CPU |
> -                                         QEMU_MIGRATION_COOKIE_CAPS |
> -                                         
> QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS)))
> +                                         cookiein, cookieinlen, 
> parseCookieFlags)))
>          goto cleanup;
>  
>      if (!(vm = virDomainObjListAdd(driver->domains, def,
> @@ -5112,6 +5131,9 @@ qemuMigrationSrcRun(virQEMUDriver *driver,
>      if (storageMigration)
>          cookieFlags |= QEMU_MIGRATION_COOKIE_NBD;
>  
> +    if (flags & VIR_MIGRATE_TLS)
> +        cookieFlags |= QEMU_MIGRATION_COOKIE_TLS_PSK;
> +
>      if (virLockManagerPluginUsesState(driver->lockManager) &&
>          !cookieout) {
>          virReportError(VIR_ERR_INTERNAL_ERROR,
> @@ -5163,19 +5185,26 @@ qemuMigrationSrcRun(virQEMUDriver *driver,
>      qemuDomainSaveStatus(vm);
>  
>      if (flags & VIR_MIGRATE_TLS) {
> -        const char *hostname = NULL;
> -
> -        /* We need to add tls-hostname whenever QEMU itself does not
> -         * connect directly to the destination. */
> -        if (spec->destType == MIGRATION_DEST_CONNECT_HOST ||
> -            spec->destType == MIGRATION_DEST_FD)
> -            hostname = spec->dest.host.name;
> -
> -        if (qemuMigrationParamsEnableTLSx509(driver, vm, false,
> -                                             VIR_ASYNC_JOB_MIGRATION_OUT,
> -                                             &tlsAlias, hostname,
> -                                             migParams) < 0)
> -            goto error;
> +        if (mig->flags & QEMU_MIGRATION_COOKIE_TLS_PSK) {
> +            if (qemuMigrationParamsEnableTLSPSK(driver, vm, false,
> +                                                VIR_ASYNC_JOB_MIGRATION_OUT,
> +                                                &tlsAlias, migParams) < 0)
> +                goto error;
> +        } else {
> +            const char *hostname = NULL;
> +
> +            /* We need to add tls-hostname whenever QEMU itself does not
> +             * connect directly to the destination. */
> +            if (spec->destType == MIGRATION_DEST_CONNECT_HOST ||
> +                spec->destType == MIGRATION_DEST_FD)
> +                hostname = spec->dest.host.name;
> +
> +            if (qemuMigrationParamsEnableTLSx509(driver, vm, false,
> +                                                 VIR_ASYNC_JOB_MIGRATION_OUT,
> +                                                 &tlsAlias, hostname,
> +                                                 migParams) < 0)
> +                goto error;
> +        }

Same note as before. If the PSK got through the handshake, you can
always enable it rather than gating it behind VIR_MIGRATE_TLS.

x509 needs to be gated behind VIR_MIGRATE_TLS but only if PSK is not
agreed upon



>      } else {
>          if (qemuMigrationParamsDisableTLS(vm, migParams) < 0)
>              goto error;
> -- 
> 2.43.7
> 

Reply via email to