[libvirt] [PATCH 6/7] secrets: add support for running secret driver in embedded mode

Daniel P. Berrangé posted 7 patches 11 weeks ago

[libvirt] [PATCH 6/7] secrets: add support for running secret driver in embedded mode

Posted by Daniel P. Berrangé 11 weeks ago
This enables support for running the secret driver embedded to the
calling application process using a URI:

   secret:///embed?root=/some/path

When using the embedded mode with a root=/var/tmp/embed, the
driver will use the following paths:

       configDir: /var/tmp/embed/etc/secrets
        stateDir: /var/tmp/embed/run/secrets

These are identical whether the embedded driver is privileged
or unprivileged.

This compares with the system instance which uses

       configDir: /etc/libvirt/secrets
        stateDir: /var/lib/libvirt/secrets

When an embedded instance of the secret driver is open, any other
embedded drivers will automatically use the embedded secret driver.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 docs/drivers.html.in       |  1 +
 docs/drvsecret.html.in     | 82 ++++++++++++++++++++++++++++++++++++++
 src/secret/secret_driver.c | 46 ++++++++++++++++-----
 3 files changed, 118 insertions(+), 11 deletions(-)
 create mode 100644 docs/drvsecret.html.in

diff --git a/docs/drivers.html.in b/docs/drivers.html.in
index 4539eedbcd..cb1ddc9212 100644
--- a/docs/drivers.html.in
+++ b/docs/drivers.html.in
@@ -8,6 +8,7 @@
       <li><a href="#hypervisor">Hypervisor drivers</a></li>
       <li><a href="storage.html">Storage drivers</a></li>
       <li><a href="drvnodedev.html">Node device driver</a></li>
+      <li><a href="drvsecret.html">Secret driver</a></li>
     </ul>
 
     <p>
diff --git a/docs/drvsecret.html.in b/docs/drvsecret.html.in
new file mode 100644
index 0000000000..9a05fe1f09
--- /dev/null
+++ b/docs/drvsecret.html.in
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <body>
+    <h1>Secret information management</h1>
+
+    <p>
+      The secrets driver in libvirt provides a simple interface for
+      storing and retrieving secret information.
+    </p>
+
+        <h2><a id="uris">Connections to SECRET driver</a></h2>
+
+    <p>
+    The libvirt SECRET driver is a multi-instance driver, providing a single
+    system wide privileged driver (the "system" instance), and per-user
+    unprivileged drivers (the "session" instance). A connection to the secret
+    driver is automatically available when opening a connection to one of the
+    stateful primary hypervisor drivers. It is none the less also possible to
+    explicitly open just the secret driver, using the URI protocol "secret"
+    Some example connection URIs for the driver are:
+    </p>
+
+<pre>
+secret:///session                      (local access to per-user instance)
+secret+unix:///session                 (local access to per-user instance)
+
+secret:///system                       (local access to system instance)
+secret+unix:///system                  (local access to system instance)
+secret://example.com/system            (remote access, TLS/x509)
+secret+tcp://example.com/system        (remote access, SASl/Kerberos)
+secret+ssh://root@example.com/system   (remote access, SSH tunnelled)
+</pre>
+
+    <h3><a id="uriembedded">Embedded driver</a></h3>
+
+    <p>
+      Since 6.0.0 the secret driver has experimental support for operating
+      in an embedded mode. In this scenario, rather than connecting to
+      the libvirtd daemon, the secret driver runs in the client application
+      process directly. To open the driver in embedded mode the app use the
+      new URI path and specify a virtual root directory under which the
+      driver will create content.
+    </p>
+
+    <pre>
+      secret:///embed?root=/some/dir
+    </pre>
+
+    <p>
+      Under the specified root directory the following locations will
+      be used
+    </p>
+
+    <pre>
+/some/dir
+  |
+  +- etc
+  |   |
+  |   +- secrets
+  |
+  +- run
+      |
+      +- secrets
+    </pre>
+
+    <p>
+      The application is responsible for recursively purging the contents
+      of this directory tree once they no longer require a connection,
+      though it can also be left intact for reuse when opening a future
+      connection.
+    </p>
+
+    <p>
+      The range of functionality is intended to be on a par with that
+      seen when using the traditional system or session libvirt connections
+      to QEMU. Normal practice would be to open the secret driver in embedded
+      mode any time one of the other drivers is opened in embedded mode so
+      that the two drivers can interact in-process.
+    </p>
+  </body>
+</html>
diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c
index d248121327..c791bde2f9 100644
--- a/src/secret/secret_driver.c
+++ b/src/secret/secret_driver.c
@@ -55,6 +55,8 @@ typedef virSecretDriverState *virSecretDriverStatePtr;
 struct _virSecretDriverState {
     virMutex lock;
     bool privileged; /* readonly */
+    bool embedded; /* readonly */
+    int embeddedRefs;
     virSecretObjListPtr secrets;
     char *stateDir;
     char *configDir;
@@ -456,12 +458,6 @@ secretStateInitialize(bool privileged,
                       virStateInhibitCallback callback G_GNUC_UNUSED,
                       void *opaque G_GNUC_UNUSED)
 {
-    if (root != NULL) {
-        virReportError(VIR_ERR_INVALID_ARG, "%s",
-                       _("Driver does not support embedded mode"));
-        return -1;
-    }
-
     if (VIR_ALLOC(driver) < 0)
         return VIR_DRV_STATE_INIT_ERROR;
 
@@ -474,8 +470,12 @@ secretStateInitialize(bool privileged,
 
     driver->secretEventState = virObjectEventStateNew();
     driver->privileged = privileged;
+    driver->embedded = root != NULL;
 
-    if (privileged) {
+    if (root) {
+        driver->configDir = g_strdup_printf("%s/etc/secrets", root);
+        driver->stateDir = g_strdup_printf("%s/run/secrets", root);
+    } else if (privileged) {
         driver->configDir = g_strdup_printf("%s/libvirt/secrets", SYSCONFDIR);
         driver->stateDir = g_strdup_printf("%s/libvirt/secrets", RUNSTATEDIR);
     } else {
@@ -552,19 +552,42 @@ secretConnectOpen(virConnectPtr conn,
         return VIR_DRV_OPEN_ERROR;
     }
 
-    if (!virConnectValidateURIPath(conn->uri->path,
-                                   "secret",
-                                   driver->privileged))
-        return VIR_DRV_OPEN_ERROR;
+    if (driver->embedded) {
+        if (STRNEQ(conn->uri->path, "/embed")) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("URI must be secret:///embed"));
+            return VIR_DRV_OPEN_ERROR;
+        }
+    } else {
+        if (!virConnectValidateURIPath(conn->uri->path,
+                                       "secret",
+                                       driver->privileged))
+            return VIR_DRV_OPEN_ERROR;
+    }
 
     if (virConnectOpenEnsureACL(conn) < 0)
         return VIR_DRV_OPEN_ERROR;
 
+    if (driver->embedded) {
+        secretDriverLock();
+        if (driver->embeddedRefs == 0)
+            virSetConnectSecret(conn);
+        driver->embeddedRefs++;
+        secretDriverUnlock();
+    }
+
     return VIR_DRV_OPEN_SUCCESS;
 }
 
 static int secretConnectClose(virConnectPtr conn G_GNUC_UNUSED)
 {
+    if (driver->embedded) {
+        secretDriverLock();
+        driver->embeddedRefs--;
+        if (driver->embeddedRefs == 0)
+            virSetConnectSecret(NULL);
+        secretDriverUnlock();
+    }
     return 0;
 }
 
@@ -657,6 +680,7 @@ static virHypervisorDriver secretHypervisorDriver = {
 static virConnectDriver secretConnectDriver = {
     .localOnly = true,
     .uriSchemes = (const char *[]){ "secret", NULL },
+    .embeddable = true,
     .hypervisorDriver = &secretHypervisorDriver,
     .secretDriver = &secretDriver,
 };
-- 
2.23.0

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list