> On 13 Jul 2026, at 7:05 PM, Peter Krempa <[email protected]> wrote:
> 
> !-------------------------------------------------------------------|
>  CAUTION: External Email
> 
> |-------------------------------------------------------------------!
> 
> On Tue, Jun 23, 2026 at 06:26:04 +0000, Abhisek Panda wrote:
>> On the source host enable TLS-PSK based secure migration, if and only
>> if the VIR_MIGRATE_TLS flag is set and ca-cert.pem does not exist.
>> This is because the TLS X.509-based migration utilize the ca-cert.pem
>> file to verify the destination host. Subsequently, the source generates
>> a pre-shared key and transmits it to the destination via a migration
>> cookie. On the destination host, Libvirt unconditionally enables
>> PSK-based migration if it receives the key via the cookie.
>> 
>> Suggested-by: Tejus GK <[email protected]>
>> Signed-off-by: Abhisek Panda <[email protected]>
>> ---
>> include/libvirt/libvirt-domain.h | 13 ++++--
>> src/qemu/qemu_migration.c        | 74 ++++++++++++++++++++------------
>> 2 files changed, 56 insertions(+), 31 deletions(-)
>> 
>> diff --git a/include/libvirt/libvirt-domain.h 
>> b/include/libvirt/libvirt-domain.h
>> index 5b67f8f897..e8b5d8451c 100644
>> --- a/include/libvirt/libvirt-domain.h
>> +++ b/include/libvirt/libvirt-domain.h
>> @@ -1089,11 +1089,16 @@ 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 certificates and keys are present on the
>> +     * host, then TLS X.509 authentication scheme is used. However, if 
>> ca-cert.pem
>> +     * is missing on the source, then TLS PSK authentication scheme is used.
>> +     * In this case, the client must use a secure Libvirt to Libvirt 
>> communication
>> +     * channel because the pre-shared key is transmitted to the destination 
>> using the
> 
> The user ought to always use secure libvirt mode. No need to mention it
> explicitly.
> 
>> +     * migration cookie. If the certificate or the key file is corrupted or 
>> not
>> +     * properly configured on either source or destination, the migration 
>> will fail.
> 
> This will need to be updated after the changes I've suggested.
> 
>>      *
>> -     * Since: 3.2.0
>> +     * Since: 12.4.0
> 
> You can't change version info of an existing flag. This shows since when
> the flag exists.
> 
> 
>>      */
>>     VIR_MIGRATE_TLS = (1 << 16),
>> 
>> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
>> index 79b93fb6e9..bac5a953d1 100644
>> --- a/src/qemu/qemu_migration.c
>> +++ b/src/qemu/qemu_migration.c
>> @@ -3360,6 +3360,7 @@ qemuMigrationDstPrepareActive(virQEMUDriver *driver,
>>     qemuDomainJobPrivate *jobPriv = vm->job->privateData;
>>     qemuProcessIncomingDef *incoming = NULL;
>>     g_autofree char *tlsx509Alias = NULL;
>> +    g_autofree char *tlsPSKAlias = NULL;
>>     virObjectEvent *event = NULL;
>>     virErrorPtr origErr = NULL;
>>     int dataFD[2] = { -1, -1 };
>> @@ -3442,14 +3443,22 @@ 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,
>> -                                             &tlsx509Alias, NULL,
>> -                                             migParams) < 0)
>> -            goto error;
>> +        if (!mig->tlsPSK) {
>> +            if (qemuMigrationParamsEnableTLSx509(driver, vm, true,
>> +                                                 VIR_ASYNC_JOB_MIGRATION_IN,
>> +                                                 &tlsx509Alias, NULL,
>> +                                                 migParams) < 0)
>> +                goto error;
>> +        } else {
>> +            if (qemuMigrationParamsEnableTLSPSK(driver, vm, true,
>> +                                                VIR_ASYNC_JOB_MIGRATION_IN,
>> +                                                &tlsPSKAlias, migParams) < 
>> 0)
>> +                goto error;
>> +        }
>>     } else {
>>         if (qemuMigrationParamsDisableTLS(vm, migParams) < 0)
>>             goto error;
>> @@ -3556,6 +3565,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",
>> @@ -3567,6 +3583,9 @@ qemuMigrationDstPrepareFresh(virQEMUDriver *driver,
>>                       QEMU_MIGRATION_COOKIE_CAPS;
>>     }
>> 
>> +    if (flags & VIR_MIGRATE_TLS)
>> +        parseCookieFlags |= QEMU_MIGRATION_COOKIE_TLS_PSK;
>> +
>>     /* Let migration hook filter domain XML */
>>     if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
>>         g_autofree char *xml = NULL;
>> @@ -3613,14 +3632,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;
> 
> 
> Destination should always parse the PSK. If it's missing there's nothing
> to do but if the source sent it we should use it (to ensure
> always-secure mode).
> 
> 
>> 
>>     if (!(vm = virDomainObjListAdd(driver->domains, def,
>> @@ -5013,6 +5025,7 @@ qemuMigrationSrcRun(virQEMUDriver *driver,
>>     qemuDomainObjPrivate *priv = vm->privateData;
>>     g_autoptr(qemuMigrationCookie) mig = NULL;
>>     g_autofree char *tlsx509Alias = NULL;
>> +    g_autofree char *tlsPSKAlias = NULL;
>>     qemuMigrationIOThread *iothread = NULL;
>>     VIR_AUTOCLOSE fd = -1;
>>     unsigned long restore_max_bandwidth = priv->migMaxBandwidth;
>> @@ -5097,19 +5110,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,
>> -                                             &tlsx509Alias, hostname,
>> -                                             migParams) < 0)
>> -            goto error;
>> +        if (qemuMigrationCACertExists(driver)) {
> 
> Here this decision should happen based on whether the destination
> libvirt instance accepted PSK or not; deciding based on existance of the
> x509 key on the source will not allow ever using the PSK if the
> destionation doesn't have those set up.
> 
> 
>> +            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,
>> +                                                 &tlsx509Alias, hostname,
>> +                                                 migParams) < 0)
>> +                goto error;
>> +        } else {
>> +            if (qemuMigrationParamsEnableTLSPSK(driver, vm, false,
>> +                                                VIR_ASYNC_JOB_MIGRATION_OUT,
>> +                                                &tlsPSKAlias, migParams) < 
>> 0)
>> +                goto error;
>> +        }
>>     } else {
>>         if (qemuMigrationParamsDisableTLS(vm, migParams) < 0)
>>             goto error;
>> -- 
>> 2.43.7

Addressed in v3.


Reply via email to