--- /dev/null
+<?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>
struct _virSecretDriverState {
virMutex lock;
bool privileged; /* readonly */
+ char *embeddedRoot; /* readonly */
+ int embeddedRefs;
virSecretObjListPtr secrets;
char *stateDir;
char *configDir;
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;
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 {
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;
}
static virConnectDriver secretConnectDriver = {
.localOnly = true,
.uriSchemes = (const char *[]){ "secret", NULL },
+ .embeddable = true,
.hypervisorDriver = &secretHypervisorDriver,
.secretDriver = &secretDriver,
};