From 3e9076e777aff2f4b08330ed17e559fcfb6b3529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 17 May 2019 12:35:57 +0100 Subject: [PATCH] secrets: add support for running secret driver in embedded mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Reviewed-by: Michal Privoznik Signed-off-by: Daniel P. Berrangé --- docs/drivers.html.in | 1 + docs/drvsecret.html.in | 82 ++++++++++++++++++++++++++++++++++++++ src/secret/secret_driver.c | 58 ++++++++++++++++++++++----- 3 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 docs/drvsecret.html.in diff --git a/docs/drivers.html.in b/docs/drivers.html.in index 8743301ebd..34f98f60b6 100644 --- a/docs/drivers.html.in +++ b/docs/drivers.html.in @@ -8,6 +8,7 @@
  • Hypervisor drivers
  • Storage drivers
  • Node device driver
  • +
  • Secret driver
  • 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 @@ + + + + +

    Secret information management

    + +

    + The secrets driver in libvirt provides a simple interface for + storing and retrieving secret information. +

    + +

    Connections to SECRET driver

    + +

    + 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: +

    + +
    +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)
    +
    + +

    Embedded driver

    + +

    + 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. +

    + +
    +      secret:///embed?root=/some/dir
    +    
    + +

    + Under the specified root directory the following locations will + be used +

    + +
    +/some/dir
    +  |
    +  +- etc
    +  |   |
    +  |   +- secrets
    +  |
    +  +- run
    +      |
    +      +- secrets
    +    
    + +

    + 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. +

    + +

    + 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. +

    + + diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index a31005c731..210a16c3d3 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 */ + char *embeddedRoot; /* 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; @@ -475,7 +471,11 @@ secretStateInitialize(bool privileged, driver->secretEventState = virObjectEventStateNew(); driver->privileged = privileged; - if (privileged) { + if (root) { + driver->embeddedRoot = g_strdup(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 { @@ -550,19 +550,54 @@ secretConnectOpen(virConnectPtr conn, return VIR_DRV_OPEN_ERROR; } - if (!virConnectValidateURIPath(conn->uri->path, - "secret", - driver->privileged)) - return VIR_DRV_OPEN_ERROR; + if (driver->embeddedRoot) { + const char *root = virURIGetParam(conn->uri, "root"); + if (!root) + return VIR_DRV_OPEN_ERROR; + + if (STRNEQ(conn->uri->path, "/embed")) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("URI must be secret:///embed")); + return VIR_DRV_OPEN_ERROR; + } + + if (STRNEQ(root, driver->embeddedRoot)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Cannot open embedded driver at path '%s', " + "already open with path '%s'"), + root, driver->embeddedRoot); + 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->embeddedRoot) { + 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->embeddedRoot) { + secretDriverLock(); + driver->embeddedRefs--; + if (driver->embeddedRefs == 0) + virSetConnectSecret(NULL); + secretDriverUnlock(); + } return 0; } @@ -655,6 +690,7 @@ static virHypervisorDriver secretHypervisorDriver = { static virConnectDriver secretConnectDriver = { .localOnly = true, .uriSchemes = (const char *[]){ "secret", NULL }, + .embeddable = true, .hypervisorDriver = &secretHypervisorDriver, .secretDriver = &secretDriver, };