[libvirt] [PATCH v4 3/3] storage: Support "chap" authentication for iscsi pool

John Ferlan jferlan at redhat.com
Mon Jul 15 20:26:12 UTC 2013


Although the XML for CHAP authentication with plain "password"
was introduced long ago, the function was never implemented. This
patch replaces the login/password mechanism by following the
'ceph' (or RBD) model of using a 'username' with a 'secret' which
has the authentication information.

This patch performs the authentication during startPool() processing
of pools with an authType of VIR_STORAGE_POOL_AUTH_CHAP specified
for iSCSI pools.

There are two types of CHAP configurations supported for iSCSI
authentication:

  * Initiator Authentication
      Forward, one-way; The initiator is authenticated by the target.

  * Target Authentication
      Reverse, Bi-directional, mutual, two-way; The target is authenticated
      by the initiator; This method also requires Initiator Authentication

This only supports the "Initiator Authentication". (I don't have any
enterprise iSCSI env for testing, only have a iSCSI target setup with
tgtd, which doesn't support "Target Authentication").

"Discovery authentication" is not supported by tgt yet too. So this only
setup the session authentication by executing 3 iscsiadm commands, E.g:

% iscsiadm -m node --target "iqn.2013-05.test:iscsi.foo" --name \
  "node.session.auth.authmethod" -v "CHAP" --op update

% iscsiadm -m node --target "iqn.2013-05.test:iscsi.foo" --name \
  "node.session.auth.username" -v "Jim" --op update

% iscsiadm -m node --target "iqn.2013-05.test:iscsi.foo" --name \
  "node.session.auth.password" -v "Jimsecret" --op update
---
 src/storage/storage_backend_iscsi.c | 111 +++++++++++++++++++++++++++++++++++-
 1 file changed, 110 insertions(+), 1 deletion(-)

diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c
index ba4f388..d8df5d8 100644
--- a/src/storage/storage_backend_iscsi.c
+++ b/src/storage/storage_backend_iscsi.c
@@ -32,6 +32,8 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
+#include "datatypes.h"
+#include "driver.h"
 #include "virerror.h"
 #include "storage_backend_scsi.h"
 #include "storage_backend_iscsi.h"
@@ -39,6 +41,7 @@
 #include "virlog.h"
 #include "virfile.h"
 #include "vircommand.h"
+#include "virobject.h"
 #include "virrandom.h"
 #include "virstring.h"
 
@@ -655,9 +658,112 @@ virStorageBackendISCSICheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
     return ret;
 }
 
+static int
+virStorageBackendISCSINodeUpdate(const char *portal,
+                                 const char *target,
+                                 const char *name,
+                                 const char *value)
+{
+     virCommandPtr cmd = NULL;
+     int status;
+     int ret = -1;
+
+     cmd = virCommandNewArgList(ISCSIADM,
+                                "--mode", "node",
+                                "--portal", portal,
+                                "--target", target,
+                                "--op", "update",
+                                "--name", name,
+                                "--value", value,
+                                NULL);
+
+    if (virCommandRun(cmd, &status) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to update '%s' of node mode for target '%s'"),
+                       name, target);
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+    virCommandFree(cmd);
+    return ret;
+}
 
 static int
-virStorageBackendISCSIStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
+virStorageBackendISCSISetAuth(const char *portal,
+                              virConnectPtr conn,
+                              virStoragePoolDefPtr def)
+{
+    virSecretPtr secret = NULL;
+    unsigned char *secret_value = NULL;
+    virStoragePoolAuthChap chap;
+    int ret = -1;
+
+    if (def->source.authType == VIR_STORAGE_POOL_AUTH_NONE)
+        return 0;
+
+    if (def->source.authType != VIR_STORAGE_POOL_AUTH_CHAP) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("iscsi pool only supports 'chap' auth type"));
+        return -1;
+    }
+
+    if (!conn) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("iscsi 'chap' authentication requires connection"));
+        return -1;
+    }
+
+    chap = def->source.auth.chap;
+    if (chap.secret.uuidUsable)
+        secret = virSecretLookupByUUID(conn, chap.secret.uuid);
+    else
+        secret = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_ISCSI,
+                                        chap.secret.usage);
+
+    if (secret) {
+        size_t secret_size;
+        secret_value =
+            conn->secretDriver->secretGetValue(secret, &secret_size, 0,
+                                               VIR_SECRET_GET_VALUE_INTERNAL_CALL);
+        if (!secret_value) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("could not get the value of the secret "
+                             "for username %s"), chap.username);
+            goto cleanup;
+        }
+    } else {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("username '%s' specified but secret not found"),
+                       chap.username);
+        goto cleanup;
+    }
+
+    if (virStorageBackendISCSINodeUpdate(portal,
+                                         def->source.devices[0].path,
+                                         "node.session.auth.authmethod",
+                                         "CHAP") < 0 ||
+        virStorageBackendISCSINodeUpdate(portal,
+                                         def->source.devices[0].path,
+                                         "node.session.auth.username",
+                                         chap.username) < 0 ||
+        virStorageBackendISCSINodeUpdate(portal,
+                                         def->source.devices[0].path,
+                                         "node.session.auth.password",
+                                         (const char *)secret_value) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+cleanup:
+    virObjectUnref(secret);
+    VIR_FREE(secret_value);
+    return ret;
+}
+
+static int
+virStorageBackendISCSIStartPool(virConnectPtr conn,
                                 virStoragePoolObjPtr pool)
 {
     char *portal = NULL;
@@ -696,6 +802,9 @@ virStorageBackendISCSIStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                               NULL, NULL) < 0)
             goto cleanup;
 
+        if (virStorageBackendISCSISetAuth(portal, conn, pool->def) < 0)
+            goto cleanup;
+
         if (virStorageBackendISCSIConnection(portal,
                                              pool->def->source.initiator.iqn,
                                              pool->def->source.devices[0].path,
-- 
1.8.1.4




More information about the libvir-list mailing list