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(a)redhat.com>
---
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