GUACAMOLE-641: Merge documentation for vault support.

diff --git a/src/images/vault-ksm-001a-create-shared-folder.png b/src/images/vault-ksm-001a-create-shared-folder.png
new file mode 100644
index 0000000..afdd004
--- /dev/null
+++ b/src/images/vault-ksm-001a-create-shared-folder.png
Binary files differ
diff --git a/src/images/vault-ksm-001b-create-shared-folder.png b/src/images/vault-ksm-001b-create-shared-folder.png
new file mode 100644
index 0000000..1324ef1
--- /dev/null
+++ b/src/images/vault-ksm-001b-create-shared-folder.png
Binary files differ
diff --git a/src/images/vault-ksm-002-select-ksm.png b/src/images/vault-ksm-002-select-ksm.png
new file mode 100644
index 0000000..558e954
--- /dev/null
+++ b/src/images/vault-ksm-002-select-ksm.png
Binary files differ
diff --git a/src/images/vault-ksm-003a-create-application.png b/src/images/vault-ksm-003a-create-application.png
new file mode 100644
index 0000000..6f88813
--- /dev/null
+++ b/src/images/vault-ksm-003a-create-application.png
Binary files differ
diff --git a/src/images/vault-ksm-003b-create-application.png b/src/images/vault-ksm-003b-create-application.png
new file mode 100644
index 0000000..6e7e2ff
--- /dev/null
+++ b/src/images/vault-ksm-003b-create-application.png
Binary files differ
diff --git a/src/images/vault-ksm-004-generate-token.png b/src/images/vault-ksm-004-generate-token.png
new file mode 100644
index 0000000..349f49f
--- /dev/null
+++ b/src/images/vault-ksm-004-generate-token.png
Binary files differ
diff --git a/src/index.md b/src/index.md
index 9354335..9804098 100644
--- a/src/index.md
+++ b/src/index.md
@@ -39,6 +39,7 @@
 configuring-guacamole
 jdbc-auth
 ldap-auth
+vault
 duo-auth
 totp-auth
 header-auth
diff --git a/src/vault.md b/src/vault.md
new file mode 100644
index 0000000..a90bac9
--- /dev/null
+++ b/src/vault.md
@@ -0,0 +1,373 @@
+Retrieving secrets from a vault
+===============================
+
+Guacamole supports reading secrets such as connection-specific passwords from a
+key vault, automatically injecting those secrets into connection configurations
+using [parameter tokens](parameter-tokens) or Guacamole configuration
+properties via an additional, vault-specific configuration file analogous to
+`guacamole.properties`. This support is intended with multiple vault providers
+in mind and currently supports [Keeper Secrets Manager (KSM)](https://www.keepersecurity.com/secrets-manager.html).
+
+:::{important}
+This chapter involves modifying the contents of `GUACAMOLE_HOME` - the
+Guacamole configuration directory. If you are unsure where `GUACAMOLE_HOME` is
+located on your system, please consult [](configuring-guacamole) before
+proceeding.
+:::
+
+(vault-downloading)=
+
+Downloading the vault extension
+-------------------------------
+
+The vault extension is available separately from the main `guacamole.war`. The
+link for this and all other officially-supported and compatible extensions for
+a particular version of Guacamole are provided on the release notes for that
+version. You can find the release notes for current versions of Guacamole here:
+<http://guacamole.apache.org/releases/>.
+
+The vault extension is packaged as a `.tar.gz` file containing directories
+specific to vault implementations (currently only `ksm/` for the KSM
+implementation). Each vault-specific directory contains a `.jar` file (the
+actual Guacamole extension). The Guacamole extension `.jar` will ultimately
+need to be placed within `GUACAMOLE_HOME/extensions`.
+
+(installing-vault-support)=
+
+Installing key vault support
+----------------------------
+
+Guacamole extensions are self-contained `.jar` files which are located within
+the `GUACAMOLE_HOME/extensions` directory. To install the KSM vault extension,
+you must:
+
+1. Create the `GUACAMOLE_HOME/extensions` directory, if it does not already
+   exist.
+
+2. Copy `ksm/guacamole-vault-ksm-1.5.0.jar` within `GUACAMOLE_HOME/extensions`.
+
+3. Configure Guacamole to use KSM to retrieve secrets, as described below.
+
+:::{important}
+You will need to restart Guacamole by restarting your servlet container in
+order to complete the installation. Doing this will disconnect all active
+users, so be sure that it is safe to do so prior to attempting installation. If
+you do not configure the vault support properly, Guacamole will not start up
+again until the configuration is fixed.
+:::
+
+(adding-guac-to-ksm)=
+
+### Adding Guacamole to KSM
+
+Allowing an application like Guacamole to access secrets via KSM involves
+creating an application in KSM. A KSM application is simply a means of
+assigning permissions, narrowing exactly which secrets the application in
+question should be able to access.
+
+1. Log into your vault via the Keeper Security website and create at least one
+   shared folder to house any secrets that should be made available to Apache
+   Guacamole. These folders will be used when registering Apache Guacamole with
+   KSM and functions to define exactly which secrets the application may access.
+   **Secrets that are not within these shared folders will not be accessible by
+   Guacamole.**
+
+   The option for creating a shared folder is within a submenu that appears
+   when you click on "Create New":
+
+   ![Submenu for creating new objects, including shared folders.](images/vault-ksm-001a-create-shared-folder.png)
+
+   No special options need to be selected for the shared folder except for
+   providing a reasonable name for the folder:
+
+   ![Shared folder creation dialog.](images/vault-ksm-001b-create-shared-folder.png)
+
+2. Navigate to KSM by selecting the "Secrets Manager" tab in the navigation
+   sidebar on the left side of the screen:
+
+   !["Secrets Manager" selected within the navigation sidebar.](images/vault-ksm-002-select-ksm.png)
+
+3. Click "Create Application" on the right ride of the toolbar near the top of
+   the screen:
+
+   !["Create Application" button in the KSM toolbar.](images/vault-ksm-003a-create-application.png)
+
+   The dialog that appears will prompt you to provide a name for the
+   application that will access the vault, as well as the shared folder(s) that
+   this application will have access to. Enter a reasonable name for the
+   application, such as "Apache Guacamole", and select the shared folder(s) you
+   created for Guacamole to access:
+
+   ![KSM application creation dialog.](images/vault-ksm-003b-create-application.png)
+
+   Guacamole only needs read-only access permissions to secrets, which should
+   already be selected by default.
+
+   :::{warning}
+   You should only check the "Lock external WAN IP" box if your Guacamole
+   server has a static IP _and_ you will be using the KSM CLI tool directly on
+   that server. **If you will be running the KSM CLI tool on a separate machine
+   with a different public IP address, you must not check this box.**
+   :::
+
+4. Once satisfied with the application name and parameters, click "Generate
+   Token" to generate a one-time token:
+
+   ![Application creation confirmation dialog showing the generated one-time token.](images/vault-ksm-004-generate-token.png)
+
+5. Copy the provided one-time token using [the KSM CLI tool](https://docs.keeper.io/secrets-manager/secrets-manager/secrets-manager-command-line-interface/init-command)
+   to obtain the base64-encoded configuration that must be provided to
+   Guacamole with [the `ksm-config` property](guac-vault-config). **This token
+   can only be used once, but the base64 configuration can be used indefinitely
+   unless manually revoked within KSM:**
+
+   ```console
+   $ ./ksm init default US:_-L2NIxWdMatbyYwBnYROLlJVjeg4BzO3xZWoiDkh4U
+
+   ewogICJjbGllbnRJZCI6ICJTR1ZzYkc4Z2RHaGxjbVVoSUZSb1pYTmxJSEJ5YjNCbGNuUnBaWE1n
+   YUdGMlpTQmlaV1Z1SUcxaGJuVmhiR3g1SUhKbFpHRmpkR1ZrTGlCWGFIay9Qdz09IiwKICAicHJp
+   dmF0ZUtleSI6ICJWRzhnWlc1emRYSmxJSFJvWVhRZ1lXTjBkV0ZzSUhObGJuTnBkR2wyWlNCMllX
+   eDFaWE1nWVhKbElHNXZkQ0JsZUhCdmMyVmtJSFpwWVNCdmRYSWdiV0Z1ZFdGc0xpQlVhR1Y1SUcx
+   aGVTQnViM1FnUVV4TUlHSmxJSE5sYm5OcGRHbDJaU0IyWVd4MVpYTXNJR0oxZENCaGRDQnNaV0Z6
+   ZENCdmJtVWdjMlZsYlhNZ2RHOGdZbVV1IiwKICAiYXBwS2V5IjogIlYyVnNZMjl0WlNFZ1JXNXFi
+   M2tnUVhCaFkyaGxJRWQxWVdOaGJXOXNaU0U9IiwKICAiaG9zdG5hbWUiOiAia2VlcGVyc2VjdXJp
+   dHkuY29tIiwKICAic2VydmVyUHVibGljS2V5SWQiOiAiMTAiCn0K
+   $   
+   ```
+
+(guac-vault-config)=
+
+### Configuring Guacamole for KSM
+
+Guacamole requires only a single configuration property to configure secret
+retrieval from KSM, `ksm-config`, which must be provided the base64
+configuration value retrieved from KSM using the one-time token [obtained when
+Guacamole was registered with KSM as an application as described above](adding-guac-to-ksm).
+All other configuration properties are optional.
+
+`ksm-config`
+: The base64-encoded configuration information generated for the application
+  you created within KSM to represent Apache Guacamole. The easiest way to
+  obtain this value is using [the KSM CLI tool](https://docs.keeper.io/secrets-manager/secrets-manager/secrets-manager-command-line-interface/init-command).
+  as described above. *This value is required.*
+
+`ksm-allow-unverified-cert`
+: Whether unverified server certificates should be accepted. If set to `true`,
+  the server certificate for connections to the KSM service will be accepted even
+  if they cannot be verified. **Unless you are a developer testing changes to
+  the KSM vault support itself, it is unlikely that you need to set this
+  property.**
+
+(completing-vault-install)=
+
+### Completing the installation
+
+Guacamole will only reread `guacamole.properties` and load newly-installed
+extensions during startup, so your servlet container will need to be restarted
+before the newly-installed vault support will take effect. Restart your servlet
+container and give the vault support a try.
+
+:::{important}
+You only need to restart your servlet container. *You do not need to restart
+guacd*.
+
+guacd is completely independent of the web application and does not deal with
+`guacamole.properties` or the authentication system in any way. Since you are
+already restarting the servlet container, restarting guacd as well technically
+won't hurt anything, but doing so is completely pointless.
+:::
+
+If Guacamole does not come back online after restarting your servlet container,
+check the logs. Problems in the configuration of installed vault support
+extensions may prevent Guacamole from starting up, and any such errors will be
+recorded in the logs of your servlet container.
+
+(vault-connection-secrets)=
+
+Retrieving connection secrets from a vault
+------------------------------------------
+
+Secrets for connection parameters are provided using [parameter
+tokens](parameter-tokens) that can be either automatically or manually defined.
+Automatic tokens are [defined dynamically by Guacamole when the connection is
+used](vault-dynamic-secrets) based on other configuration values within the
+connection, such as the connection's `hostname` or `username`. Manual tokens
+are injected by Guacamole based on secrets that are [statically mapped using an
+additional configuration file](vault-static-secrets).
+
+(vault-dynamic-secrets)=
+
+### Automatic injection of secrets based on connection parameters
+
+Parameter tokens containing the values of secrets within a record are
+automatically injected for connections whose parameter values match specific
+criteria, such as having a particular `username` or `hostname`. This happens
+whenever a connection is used and is fully dynamic, affecting only the state of
+the connection from the perspective of the user accessing it.
+
+:::{important}
+There are limitations to the degree that secrets can be automatically applied
+based on connection parameters:
+
+* In all cases, only unique records are considered. If multiple records match
+  the criteria that applies to a particular token in the context of a
+  connection, the token will not be injected for that connection.
+
+* Automatic injection of secrets cannot currently be used with balancing
+  connection groups, as the underlying connection that the balancing
+  implementation will choose cannot be known before token values must be made
+  available.
+
+If automatic injection of secrets cannot work for your use case, consider using
+[manually-specified secrets via `ksm-token-mapping.yml`](vault-static-secrets).
+:::
+
+Parameter tokens injected from KSM records take the form
+{samp}`$\{KEEPER_{CRITERIA}_{SECRET}\}`, where `CRITERIA` determines how the
+applicable record is located based on the connection's parameters and `SECRET`
+determines what value is retrieved from that record.
+
+The following `CRITERIA` names are supported:
+
+`USER`
+: The record whose "login" field contains a username that matches the value of
+  the `username` parameter of the connection. If the record has no "login" field,
+  a "text" or "password" custom field will be used if the label of that field
+  contains the word "username" (case-insensitive).
+
+`SERVER`
+: The record whose "login" field contains a hostname that matches the value of
+  the `hostname` parameter of the connection. If the record has no "login" field,
+  a "text" or "password" custom field will be used if the label of that field
+  contains the word "hostname", "address", or "IP address" (case-insensitive,
+  ignoring any spaces between "IP" and "address").
+
+`GATEWAY`
+: Identical to `SERVER`, except that the value of the `gateway-hostname`
+  parameter is used. This is only applicable to RDP connections.
+
+`GATEWAY_USER`
+: Identical to `USER`, except that the value of the `gateway-username`
+  parameter is used. This is only applicable to RDP connections.
+
+The following `SECRET` types are supported:
+
+`USERNAME`
+: The username specified by the record's "login" field. If the field is a
+  custom field, the label must contain the word "username" (case-insensitive)
+  and must be a "text" or "hidden" field.
+
+`PASSWORD`
+: The password specified by the record's "password" or "hidden" field. If the
+  field is a custom field, the label must contain the word "password"
+  (case-insensitive).
+
+`KEY`
+: The private key associated with the record. If the record has a dedicated
+  key pair field, the private key from this field is used. If not, and the
+  record has a single `.pem` file attached, the content of that attachment is
+  used. Lacking any key pair field or attachment, any custom field that is a
+  "password" or "hidden" field will be used as long as it contains the phrase
+  "private key" in its label (case-insensitive, ignoring any space(s) between
+  "private" and "key").
+
+`PASSPHRASE`
+: The passphrase associated with the record's private key, if the record type
+  has dedicated fields for these. If the record has no dedicated passphrase
+  field, a "password" or "hidden" custom field will be used as long as it
+  has the word "passphrase" in its label (case-insensitive).
+
+For example, the `${KEEPER_USER_PASSWORD}` token would retrieve the password
+for the user specified by the `username` parameter, and `${KEEPER_SERVER_KEY}`
+would retrieve the private key for the server specified by the `hostname`
+parameter.
+
+(vault-static-secrets)=
+
+### Manual definition of secrets
+
+Parameter tokens can be manually defined by placing a YAML file within
+`GUACAMOLE_HOME` called `ksm-token-mapping.yml`. This file must contain a set
+of name/value pairs where each name is the name of a token to define and each
+value is [a reference to a secret in KSM using "Keeper Notation"](https://docs.keeper.io/secrets-manager/secrets-manager/about/keeper-notation).
+
+For example, the following `ksm-token-mapping.yml` defines two parameter
+tokens, `${WINDOWS_ADMIN_PASSWORD}` and `${LINUX_SERVER_KEY}`, each pulling
+their values from different parts of different records in KSM:
+
+```yaml
+WINDOWS_ADMIN_PASSWORD: keeper://odei1zeejoL7Ceiv3eig0a/field/password
+LINUX_SERVER_KEY: keeper://Chah0VuPh0ohyeuL4che1o/file/idrsa.pem
+```
+
+Token substitution of other parameter tokens like `${GUAC_USERNAME}` is
+performed *on the reference to the secret* to allow the reference to vary by
+values that may be relevant to the connection. The values of substituted tokens
+are URL-encoded before being placed into the reference in "Keeper Notation". In
+addition, the following tokens are available for use within the secret
+reference:
+
+`${CONNECTION_GROUP_NAME}`
+: The human-readable name of the connection group being used. Secrets using
+  this token are only available if a user is directly connecting to a balancing
+  connection group, not manually connecting to a connection within a group.
+
+`${CONNECTION_GROUP_ID}`
+: The unique identifier of the connection group being used. Secrets using this
+  token are only available if a user is directly connecting to a balancing
+  connection group, not manually connecting to a connection within a group.
+
+`${CONNECTION_NAME}`
+: The human-readable name of the connection being used. Secrets using this
+  token are only available if a user is directly connecting to a connection, not
+  connecting via a balancing group.
+
+`${CONNECTION_ID}`
+: The unique identifier of the connection being used. Secrets using this token
+  are only available if a user is directly connecting to a connection, not
+  connecting via a balancing group.
+
+`${CONNECTION_HOSTNAME}`
+: The value of the `hostname` parameter of the connection being used. Secrets
+  using this token are only available if a user is directly connecting to a
+  connection, not connecting via a balancing group.
+
+`${CONNECTION_USERNAME}`
+: The value of the `username` parameter of the connection being used. Secrets
+  using this token are only available if a user is directly connecting to a
+  connection, not connecting via a balancing group.
+
+`${USERNAME}`
+: The username of the current user, as stored with the user object representing
+  that user in the system storing the relevant connection or connection group.
+  This is not necessarily the same as `${GUAC_USERNAME}`, which is the username
+  provided by the user as part of their credentials when they authenticated.
+
+For example, to automatically define a token called `${LINUX_SERVER_KEY}` that
+selects a private key from among several within the same record by searching
+for a file named after the current user, the following YAML could be used:
+
+```yaml
+LINUX_SERVER_KEY: keeper://Chah0VuPh0ohyeuL4che1o/file/${USERNAME}.pem
+```
+(guacamole-properties-ksm)=
+
+Retrieving configuration properties from a vault
+------------------------------------------------
+
+Secrets for Guacamole configuration properties are provided through [an
+additional file within `GUACAMOLE_HOME` called `guacamole.properties.ksm`](guacamole-properties-ksm).
+This file is _identical_ to `guacamole.properties` except that the values of properties
+are [references to KSM secrets in "Keeper Notation"](https://docs.keeper.io/secrets-manager/secrets-manager/about/keeper-notation).
+Secrets can be used for any Guacamole configuration property that isn't
+required to configure the KSM support.
+
+For example, the following `guacamole.properties.ksm` defines both the
+`mysql-username` and `mysql-password` properties using values from a single
+record in KSM that contains a username/password pair:
+
+```
+mysql-username: keeper://iel4yeic5ahxae7Eereec7/field/login
+mysql-password: keeper://iel4yeic5ahxae7Eereec7/field/password
+```
+