Support TLS for a migration is a multistep process. The target guest must be started using the "-object tls-creds-x509,endpoint=server,...". If that TLS object requires a passphrase an addition "-object security..." would also be created. The alias/id used for the TLS object is "objmigrate_tls0", while the alias/id used for the security object is "migrate-secret0". Once the domain is started, the "tls-creds" migration parameter must be set to the alias/id of the "tls-creds-x509" object. Once the migration completes, removing the two objects is necessary since the newly started domain could then become the source of a migration and thus would not be an endpoint. Handle the possibility of libvirtd stop/reconnect by saving the fact that a migration is using TLS was started in a "migrateTLS" boolean. Signed-off-by: John Ferlan <jferlan@xxxxxxxxxx> --- src/qemu/qemu_domain.c | 7 +- src/qemu/qemu_domain.h | 4 ++ src/qemu/qemu_migration.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 40c9dab..af84aac 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -766,7 +766,7 @@ qemuDomainSecretAESClear(qemuDomainSecretAES secret) } -static void +void qemuDomainSecretInfoFree(qemuDomainSecretInfoPtr *secinfo) { if (!*secinfo) @@ -1844,6 +1844,9 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf, virBufferEscapeString(buf, "<channelTargetDir path='%s'/>\n", priv->channelTargetDir); + if (priv->migrateTLS) + virBufferAddLit(buf, "<migrateTLS/>\n"); + return 0; } @@ -2112,6 +2115,8 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, if (qemuDomainSetPrivatePathsOld(driver, vm) < 0) goto error; + priv->migrateTLS = virXPathBoolean("boolean(./migrateTLS)", ctxt) == 1; + return 0; error: diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 85f7eb6..9ce8677 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -287,6 +287,7 @@ struct _qemuDomainObjPrivate { /* for migration's using TLS with a secret (not to be saved in our */ /* private XML). */ qemuDomainSecretInfoPtr migSecinfo; + bool migrateTLS; }; # define QEMU_DOMAIN_PRIVATE(vm) \ @@ -734,6 +735,9 @@ int qemuDomainMasterKeyCreate(virDomainObjPtr vm); void qemuDomainMasterKeyRemove(qemuDomainObjPrivatePtr priv); +void qemuDomainSecretInfoFree(qemuDomainSecretInfoPtr *secinfo) + ATTRIBUTE_NONNULL(1); + void qemuDomainSecretDiskDestroy(virDomainDiskDefPtr disk) ATTRIBUTE_NONNULL(1); diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 0db1616..0e95fd9 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1487,6 +1487,145 @@ qemuMigrationEatCookie(virQEMUDriverPtr driver, return NULL; } + +/* qemuMigrationCheckSetupTLS + * @driver: Pointer to driver + * @dconn: Connection pointer + * @vm: vm object + * @flags: migration flags + * + * Check if flags desired to use TLS and whether it's configured for the + * host it's being run on (src or dst depending on caller). If configured + * to use a secret for the TLS config, generate and save the migSecinfo. + * + * Returns 0 on success (or no TLS) + */ +static int +qemuMigrationCheckSetupTLS(virQEMUDriverPtr driver, + virConnectPtr dconn, + virDomainObjPtr vm, + unsigned int flags) +{ + int ret = -1; + qemuDomainObjPrivatePtr priv = vm->privateData; + virQEMUDriverConfigPtr cfg = NULL; + + if (flags & VIR_MIGRATE_TLS) { + cfg = virQEMUDriverGetConfig(driver); + + if (!cfg->migrateTLS) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("migration TLS not enabled for the host")); + goto cleanup; + } + + priv->migrateTLS = true; + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, + vm, driver->caps) < 0) + VIR_WARN("Failed to save migrateTLS for vm %s", vm->def->name); + + /* If there's a secret associated with the migrate TLS, then we + * need to grab it now while we have the connection. */ + if (cfg->migrateTLSx509secretUUID && + qemuDomainSecretMigratePrepare(dconn, priv, "migrate", + cfg->migrateTLSx509secretUUID) < 0) + goto cleanup; + } + + ret = 0; + + cleanup: + virObjectUnref(cfg); + return ret; +} + + +/* qemuMigrationAddTLSObjects + * @driver: pointer to qemu driver + * @priv: private qemu data + * @srcAlias: source alias to be used (migrate or nbd) + * @tlsCertDir: where to find certs + * @tlsListen: server or client + * @tlsVerify: tls verify + * @tlsAlias: alias to be generated for TLS object + * @secAlias: alias to be generated for a secinfo object + * @migParams: migration parameters to set + * + * Create the TLS objects for the migration and set the migParams value + * + * Returns 0 on success, -1 on failure + */ +static int +qemuMigrationAddTLSObjects(virQEMUDriverPtr driver, + virDomainObjPtr vm, + const char *srcAlias, + const char *tlsCertDir, + bool tlsListen, + bool tlsVerify, + char **tlsAlias, + char **secAlias, + qemuMonitorMigrationParamsPtr migParams) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + virJSONValuePtr tlsProps = NULL; + virJSONValuePtr secProps = NULL; + + if (qemuDomainGetTLSObjects(priv->qemuCaps, priv->migSecinfo, + tlsCertDir, tlsListen, tlsVerify, + srcAlias, &tlsProps, tlsAlias, + &secProps, secAlias) < 0) + return -1; + + /* Ensure the domain doesn't already have the TLS objects defined... + * This should prevent any issues just in case some cleanup wasn't + * properly completed (both src and dst use the same aliases) or + * some other error path between now and perform . */ + qemuDomainDelTLSObjects(driver, vm, *secAlias, *tlsAlias); + + /* Add the migrate TLS objects to the domain */ + if (qemuDomainAddTLSObjects(driver, vm, *secAlias, &secProps, + *tlsAlias, &tlsProps) < 0) + return -1; + + migParams->migrateTLSAlias = *tlsAlias; + + return 0; +} + + +/* qemuMigrationCheckSetupTLS + * @driver: Pointer to driver + * @cfg: Configuration pointer + * @vm: vm object + * @tlsAlias: alias to be free'd for TLS object + * @secAlias: alias to be free'd for a secinfo object + * + * Remove the TLS associated objects and memory + */ +static void +qemuMigrationDelTLSObjects(virQEMUDriverPtr driver, + virQEMUDriverConfigPtr cfg, + virDomainObjPtr vm, + char **tlsAlias, + char **secAlias) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + + if (!priv->migrateTLS) + return; + + qemuDomainDelTLSObjects(driver, vm, *secAlias, *tlsAlias); + qemuDomainSecretInfoFree(&priv->migSecinfo); + VIR_FREE(*tlsAlias); + VIR_FREE(*secAlias); + + priv->migrateTLS = false; + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, + vm, driver->caps) < 0) + VIR_WARN("Failed to save migrateTLS on vm %s", vm->def->name); +} + + static void qemuMigrationStoreDomainState(virDomainObjPtr vm) { @@ -3600,6 +3739,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, { virDomainObjPtr vm = NULL; virObjectEventPtr event = NULL; + virQEMUDriverConfigPtr cfg = NULL; int ret = -1; int dataFD[2] = { -1, -1 }; qemuDomainObjPrivatePtr priv = NULL; @@ -3613,6 +3753,8 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, bool stopProcess = false; bool relabel = false; int rv; + char *tlsAlias = NULL; + char *secAlias = NULL; qemuMonitorMigrationParams migParams = { 0 }; virNWFilterReadLockFilterUpdates(); @@ -3779,6 +3921,9 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, VIR_QEMU_PROCESS_START_AUTODESTROY) < 0) goto stopjob; + if (qemuMigrationCheckSetupTLS(driver, dconn, vm, flags) < 0) + goto stopjob; + if (qemuProcessPrepareHost(driver, vm, !!incoming) < 0) goto stopjob; @@ -3806,6 +3951,16 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, compression, &migParams) < 0) goto stopjob; + /* A set only parameter to indicate the "tls-creds-x509" object id */ + if (priv->migrateTLS) { + cfg = virQEMUDriverGetConfig(driver); + if (qemuMigrationAddTLSObjects(driver, vm, "migrate", + cfg->migrateTLSx509certdir, true, + cfg->migrateTLSx509verify, + &tlsAlias, &secAlias, &migParams) < 0) + goto stopjob; + } + if (STREQ_NULLABLE(protocol, "rdma") && virProcessSetMaxMemLock(vm->pid, vm->def->mem.hard_limit << 10) < 0) { goto stopjob; @@ -3891,6 +4046,8 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver, ret = 0; cleanup: + qemuMigrationDelTLSObjects(driver, cfg, vm, &tlsAlias, &secAlias); + virObjectUnref(cfg); qemuProcessIncomingDefFree(incoming); VIR_FREE(xmlout); VIR_FORCE_CLOSE(dataFD[0]); @@ -6185,6 +6342,15 @@ qemuMigrationFinish(virQEMUDriverPtr driver, qemuDomainCleanupRemove(vm, qemuMigrationPrepareCleanup); VIR_FREE(priv->job.completed); + /* If for some reason at this point in time something didn't properly + * remove the TLS objects, then make one last gasp attempt */ + if (priv->migrateTLS) { + char *tlsAlias = qemuAliasTLSObjFromSrcAlias("migrate"); + char *secAlias = qemuDomainGetSecretAESAlias("migrate", false); + + qemuMigrationDelTLSObjects(driver, cfg, vm, &tlsAlias, &secAlias); + } + cookie_flags = QEMU_MIGRATION_COOKIE_NETWORK | QEMU_MIGRATION_COOKIE_STATS | QEMU_MIGRATION_COOKIE_NBD; -- 2.9.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list