This patch allow libvirt-cim to use non-root's ssh key in migration
to avoid exposing root's ssh login on server. In some case server are
forbidden to expose or provide any root ssh login, and still use ssh
encryption between two migration nodes with key of special account
created for virtual machine management. This patch provide it.
The patch added three additonal paremeters in vs migration and migratable
method, they are DestinationHostParams, SSH_Key_Src, SSH_Key_Dest.
DestinationHostParams is the addtional string which would be appended after
the uri if it was set, so with this parameter user could add additional
parameter in libvirt remote uri, such as "?keyfile=/tmp/tempkey.rsa". Because
libvirt woulkd ignore the private key file parameter, if the key's directory
was not owned by the user, and libvirt-cim runs as root, so SSH_Key_Src and
SSH_Key_Dest were provided to allow a copying of keyfile to a directory that
owned by root, at runtime. if SSH_Key_Src and SSH_Key_Dest were set,
libvirt-cim would run shell command "cp -f [SSH_Key_Src] [SSH_Key_Dest]".
Typically cim client with authority to do a migration, could specify these
three additonal parameters with ssh migration method set, as
DestinationHostParams="?keyfile=/root/temp_migration_key.rsa"
SSH_Key_Src="/home/VController/.ssh/id_rsa"
SSH_Key_Dest="/root/temp_migration_key.rsa"
then, the migration would complete with VController's key pairs, instead of
root's, avoided turning on root's ssh logins.
Test was done when SELinux was shutdown.
V2:
Rebased and Better documentation.
Signed-off-by: Wenchao Xia <xiawenc(a)linux.vnet.ibm.com>
---
src/Virt_VSMigrationService.c | 96 +++++++++++++++++++++++++++++++++++++++--
1 files changed, 92 insertions(+), 4 deletions(-)
diff --git a/src/Virt_VSMigrationService.c b/src/Virt_VSMigrationService.c
index 76e3d25..b03450c 100644
--- a/src/Virt_VSMigrationService.c
+++ b/src/Virt_VSMigrationService.c
@@ -150,6 +150,7 @@ static CMPIStatus get_migration_uri(CMPIInstance *msd,
static char *dest_uri(const char *cn,
const char *dest,
+ const char *dest_params,
uint16_t transport)
{
const char *prefix;
@@ -157,6 +158,7 @@ static char *dest_uri(const char *cn,
const char *param = "";
char *uri = NULL;
int rc;
+ int param_labeled = 0;
if (STARTS_WITH(cn, "Xen"))
prefix = "xen";
@@ -197,16 +199,75 @@ static char *dest_uri(const char *cn,
goto out;
}
- if (!STREQC(param, ""))
+ if (!STREQC(param, "")) {
rc = asprintf(&uri, "%s/%s", uri, param);
+ param_labeled = 1;
+ }
- if (rc == -1)
+ if (rc == -1) {
uri = NULL;
+ goto out;
+ }
+ if (dest_params) {
+ if (param_labeled == 0) {
+ rc = asprintf(&uri, "%s?%s", uri, dest_params);
+ } else {
+ rc = asprintf(&uri, "%s%s", uri, dest_params);
+ }
+ if (rc == -1) {
+ uri = NULL;
+ goto out;
+ }
+ }
out:
return uri;
}
+/* libvirt need private key specified must be placed in a directory owned by
+ root, because libvirt-cim now runs as root. So here the key would be copied,
+ up layer need to delete that key after migration. This method could allow
+ libvirt-cim borrow a non-root ssh private key, instead of using root's private
+ key, avoid security risk. */
+static int ssh_key_cp(const char *src, const char *dest)
+{
+ char *cmd = NULL;
+ int rc;
+ int ret = 0;
+ FILE *stream = NULL;
+ char buf[256];
+
+ rc = asprintf(&cmd, "cp -f %s %s", src, dest);
+ if (rc == -1) {
+ cmd = NULL;
+ ret = -1;
+ goto out;
+ }
+
+ CU_DEBUG("excuting system cmd [%s].", cmd);
+ stream = popen(cmd, "r");
+ if (stream == NULL) {
+ CU_DEBUG("Failed to open pipe to run command");
+ ret = -2;
+ goto out;
+ }
+ usleep(10000);
+
+ buf[255] = 0;
+ while (fgets(buf, sizeof(buf), stream) != NULL) {
+ CU_DEBUG("Exception got: %s.", buf);
+ ret = -3;
+ goto out;
+ }
+
+ out:
+ if (stream != NULL) {
+ pclose(stream);
+ }
+ free(cmd);
+ return ret;
+}
+
static CMPIStatus get_msd_values(const CMPIObjectPath *ref,
const char *destination,
const CMPIArgs *argsin,
@@ -217,6 +278,14 @@ static CMPIStatus get_msd_values(const CMPIObjectPath *ref,
CMPIInstance *msd;
uint16_t uri_type;
char *uri = NULL;
+ const char *dest_params = NULL;
+ const char *ssh_hack_src = NULL;
+ const char *ssh_hack_dest = NULL;
+ int ret;
+
+ cu_get_str_arg(argsin, "DestinationHostParams", &dest_params);
+ cu_get_str_arg(argsin, "SSH_Key_Src", &ssh_hack_src);
+ cu_get_str_arg(argsin, "SSH_Key_Dest", &ssh_hack_dest);
s = get_msd(ref, argsin, &msd);
if (s.rc != CMPI_RC_OK)
@@ -230,7 +299,7 @@ static CMPIStatus get_msd_values(const CMPIObjectPath *ref,
if (s.rc != CMPI_RC_OK)
goto out;
- uri = dest_uri(CLASSNAME(ref), destination, uri_type);
+ uri = dest_uri(CLASSNAME(ref), destination, dest_params, uri_type);
if (uri == NULL) {
cu_statusf(_BROKER, &s,
CMPI_RC_ERR_FAILED,
@@ -238,6 +307,19 @@ static CMPIStatus get_msd_values(const CMPIObjectPath *ref,
goto out;
}
+ if ((ssh_hack_src) && (ssh_hack_dest)) {
+ CU_DEBUG("hacking ssh keys src %s, dest %s.",
+ ssh_hack_src, ssh_hack_dest);
+ ret = ssh_key_cp(ssh_hack_src, ssh_hack_dest);
+ if (ret < 0) {
+ cu_statusf(_BROKER, &s,
+ CMPI_RC_ERR_FAILED,
+ "Failed to copy ssh key files");
+ goto out;
+ }
+ }
+
+ CU_DEBUG("Migrate tring to connect remote host with uri %s.", uri);
*conn = virConnectOpen(uri);
if (*conn == NULL) {
CU_DEBUG("Failed to connect to remote host (%s)", uri);
@@ -1537,7 +1619,7 @@ static CMPIStatus migrate_vs_host(CMPIMethodMI *self,
const char *dhost = NULL;
CMPIObjectPath *system;
const char *name = NULL;
-
+
cu_get_str_arg(argsin, "DestinationHost", &dhost);
cu_get_ref_arg(argsin, "ComputerSystem", &system);
@@ -1608,6 +1690,9 @@ static struct method_handler vsimth = {
.handler = vs_migratable_host,
.args = {{"ComputerSystem", CMPI_ref, false},
{"DestinationHost", CMPI_string, false},
+ {"DestinationHostParams", CMPI_string, true},
+ {"SSH_Key_Src", CMPI_string, true},
+ {"SSH_Key_Dest", CMPI_string, true},
{"MigrationSettingData", CMPI_instance, true},
{"NewSystemSettingData", CMPI_instance, true},
{"NewResourceSettingData", CMPI_instanceA, true},
@@ -1632,6 +1717,9 @@ static struct method_handler mvsth = {
.handler = migrate_vs_host,
.args = {{"ComputerSystem", CMPI_ref, false},
{"DestinationHost", CMPI_string, false},
+ {"DestinationHostParams", CMPI_string, true},
+ {"SSH_Key_Src", CMPI_string, true},
+ {"SSH_Key_Dest", CMPI_string, true},
{"MigrationSettingData", CMPI_instance, true},
{"NewSystemSettingData", CMPI_instance, true},
{"NewResourceSettingData", CMPI_instanceA, true},
--
1.7.1