[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [RFC] secrets API, was Re: [PATCH 0/9] Add support for (qcow*) volume encryption



Hello,
based on your comments, here is a proposal for a "secret management" API.

Rather than add explicit accessors for attributes of secrets, and hard-code the "secrets are related to storage volumes" association in the API, the proposed uses XML to manipulate the association as well as other attributes, like it is used in other areas of libvirt.

The user would allocate an ID for the secret using virSecretAllocateID(), set attributes of the secret using XML, e.g.
  <secret ephemeral='no' private='yes'>
    <volume>/var/lib/libvirt/images/mail.img</volume>
    <description>LUKS passphrase for the main hard drive of our mail server</description>
  </secret>
Then, the secret value can be either generated and stored by libvirt, or supplied by the user using virSecretSetValue().  

A simple API is provided for enumeration of all secrets.  Very large deployments manage secret IDs automatically, so it probably is not necessary to provide specialized lookup functions (e.g. allowing the volume key -> secret ID lookup in less than O(number of secrets)).

The <encryption> element used in volume and domain specifications remains, but it never contains any secrets directly, only something like
  <secret type='passphrase' secret_id='c1f11a6d-8c5d-4a3e-ac7a-4e171c5e0d4a' />

More detailed documentation is in the patch.

Does that look OK?

Thank you,
    Mirek
diff --git a/docs/formatsecret.html.in b/docs/formatsecret.html.in
new file mode 100644
index 0000000..0960d86
--- /dev/null
+++ b/docs/formatsecret.html.in
@@ -0,0 +1,46 @@
+<html>
+  <body>
+    <h1>Secret attributes XML format</h1>
+
+    <ul id="toc"></ul>
+
+    <h2><a name="SecretAttributes">Secret attributes XML</a></h2>
+
+    <p>
+      Secrets stored by libvirt may have attributes associated with them, using
+      the <code>secret</code> element.  The <code>secret</code> element has two
+      optional attributes, each with values '<code>yes</code>' and
+      '<code>no</code>', and defaulting to '<code>no</code>':
+    </p>
+    <dl>
+      <dt><code>ephemeral</code></dt>
+      <dd>This secret must only be kept in memory, never stored persistently.
+      </dd>
+      <dt><code>private</code></dt>
+      <dd>The value of the secret must not be revealed to any caller of libvirt,
+        nor to any other node.
+      </dd>
+    </dl>
+    <p>
+      The top-level <code>secret</code> element may contain the following
+      elements:
+    </p>
+    <dl>
+      <dt><code>volume</code></dt>
+      <dd>Key of a volume this secret is associated with.  It is safe to delete
+        the secret after the volume is deleted.
+      </dd>
+      <dt><code>description</code></dt>
+      <dd>A human-readable description of the purpose of the secret.
+      </dd>
+    </dl>
+
+    <h2><a name="example">Example</a></h2>
+
+    <pre>
+      &lt;secret ephemeral='no' private='yes'&gt;
+         &lt;volume&gt;/var/lib/libvirt/images/mail.img&lt;/volume&gt;
+         &lt;description&gt;LUKS passphrase for the main hard drive of our mail server&lt;/description&gt;
+      &lt;/secret&gt;</pre>
+  </body>
+</html>
diff --git a/docs/formatstorageencryption.html.in b/docs/formatstorageencryption.html.in
index d4043f3..daa4d64 100644
--- a/docs/formatstorageencryption.html.in
+++ b/docs/formatstorageencryption.html.in
@@ -4,7 +4,7 @@
 
     <ul id="toc"></ul>
 
-    <h2><a name="StorageEncryption">Storage encryption XML</a></h2>
+    <h2><a name="StorageEncryption">Storage volume encryption XML</a></h2>
 
     <p>
       Storage volumes may be encrypted, the XML snippet described below is used
@@ -17,9 +17,20 @@
       attribute <code>format</code>.  Currently defined values
       of <code>format</code> are <code>unencrypted</code>
       and <code>qcow</code>.  Each value of <code>format</code> implies some
-      expectations about the content of the <code>encryption</code>tag.  Other
+      expectations about the content of the <code>encryption</code> tag.  Other
       format values may be defined in the future.
     </p>
+    <p>
+      The <code>encryption</code> tag can currently contain a sequence of
+      <code>secret</code> tags, each with mandatory attributes <code>type</code>
+      and <code>secret_id</code>.  The only currently defined value of
+      <code>type</code> is <code>passphrase</code>.  <code>secret_id</code>
+      refers to a secret known to libvirt.  libvirt can use a secret value
+      previously set using <code>virSecretSetValue()</code>, or, if supported
+      by the particular volume format and driver, automatically generate a
+      secret value at the time of volume creation, and store it using the
+      specified <code>secret_id</code>.
+    <p>
     <h3><a name="StorageEncryptionUnencrypted">"unencrypted" format</a></h3>
     <p>
       Specifying an <code>&lt;encryption type="unencrypted"/&gt;</code> is
@@ -29,23 +40,19 @@
     <p>
       The <code>qcow</code> format specifies that the built-in encryption
       support in <code>qcow</code>- or <code>qcow2</code>-formatted volume
-      images should be used.  The passphrase can be either left unspecified
-      (e.g. when creating a volume), or can be defined using
-      a <code>secret</code> tag with a mandatory
-      attribute <code>format="passphrase"</code>.  The tag contains the
-      passphrase, encoded using base64.
+      images should be used.  A single <code>&lt;secret
+      type='passphrase'&gt;</code> element is expected.
     </p>
 
     <h2><a name="example">Example</a></h2>
 
     <p>
-      Here is a simple example, specifying use of the <code>qcow</code> format
-      with passphrase <code>silly</code>.
+      Here is a simple example, specifying use of the <code>qcow</code> format:
     </p>
 
     <pre>
       &lt;encryption format='qcow'&gt;
-         &lt;secret type='passphrase'&gt;c2lsbHk=&lt;/secret&gt;
+         &lt;secret type='passphrase' secret_id='c1f11a6d-8c5d-4a3e-ac7a-4e171c5e0d4a' /&gt;
       &lt;/encryption&gt;</pre>
   </body>
 </html>
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index f9f5c46..af3ae57 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1458,6 +1458,95 @@ void virEventRegisterImpl(virEventAddHandleFunc addHandle,
                           virEventAddTimeoutFunc addTimeout,
                           virEventUpdateTimeoutFunc updateTimeout,
                           virEventRemoveTimeoutFunc removeTimeout);
+
+/**
+ * virSecretAllocateID:
+ * @conn: virConnect connection
+ *
+ * Allocates a secret ID (a printable string) without associating a secret
+ * value with the ID.
+ *
+ * Returns the secret ID on success, or NULL on failure.  The caller must
+ * free() the secret ID.
+ */
+char *virSecretAllocateID(virConnectPtr conn, const char *comment, int flags);
+
+/**
+ * virSecretSetXML:
+ * @conn: virConnect connection
+ * @secret_id: A secret ID
+ * @xml: XML containing attributes of the secret.
+ *
+ * Replaces all attributes of the secret specified by @secret_id by attributes
+ * specified in @xml (any attributes not specified in @xml are
+ * discarded). Allocates @secret_id if it was not previously allocated.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int virSecretSetXML(virConnectPtr conn, const char *secret_id, const char *xml);
+
+/**
+ * virSecretGetXML:
+ * @conn: virConnect connection
+ * @secret_id: A secret ID
+ *
+ * Returns XML describing attributes of the secret on success, NULL on
+ * failure.  The caller must free() the XML.
+ */
+char *virSecretGetXML(virConnectPtr conn, const char *secret_id);
+
+/**
+ * virSecretSetValue:
+ * @conn: virConnect connection
+ * @secret_id: A secret ID
+ * @secret: The secret
+ * @secret_size: Size of the secret
+ *
+ * Associates a secret value with @secret_id.  Allocates @secret_id if it was
+ * not previously allocated.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int virSecretSetValue(virConnectPtr conn, const char *secret_id,
+                      const void *secret, size_t secret_size);
+
+/**
+ * virSecretGetValue:
+ * @conn: virConnect connection
+ * @secret_id: A secret ID
+ * @secret: Pointer where the secret is stored
+ * @secret_size: Place for storing size of the secret
+ *
+ * Returns the secret value associated with @secret_id on success, NULL on
+ * failure.  The caller must free() the secret value.
+ */
+void *virSecretGetValue(virConnectPtr conn, const char *secret_id,
+                        size_t *secret_size);
+
+/**
+ * virSecretDelete:
+ * @conn: virConnect connection
+ * @secret_id: A secret ID
+ *
+ * Deletes the secret with @secret_id (including the secret value and all
+ * attributes).
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+void *virSecretDelete(virConnectPtr conn, const char *secret_id);
+
+/**
+ * virSecretListSecrets:
+ * @conn: virConnect connection
+ * @ids: Pointer to an array to store the IDs
+ * @maxids: size of the array.
+ *
+ * List the defined secret IDs, store pointers to names in @ids.
+ *
+ * Returns the number of IDs provided in the array, or -1 on failure.
+ */
+int virSecretListSecrets(virConnectPtr conn, char **ids, size_t maxids);
+
 #ifdef __cplusplus
 }
 #endif

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]