GUACAMOLE-2137 : OpenBao/Hashicorp Vault extension #1216
Open
adb014 wants to merge 22 commits into
Open
Conversation
Author
|
Rebased on staging/1.6.1 and the PR updated |
This was referenced Jun 2, 2026
…apache#1214 - It supports both OpenBao and Hashicorp Vault - Uses url like tokens of the form "vault://<mount>/<path>/<secret>" - Uses the path-help function of the vault to determine the vault type - Uses spring-vault to communicate with the vault - Adds support for both KV_1 and KV_2 Key-Value secret engines - Adds support for LDAP secret engine and static, dynamic and service accounts - Adds support of the SSH secret engine including both SSH one-time passwords and signed user certificates - Adds supports for the database secret engine, allowing Guacamole itself to obtain its username, password and if the database is configured with additional static values, the URI of the database server and the database itself - Adds the possiblity of including sub-tokens with the Vault tokens (ex: vault://kv1/users{GUAC_USERNAME}/password) - Gets the connectionGroup and User fallback functions in apache#1116 to actually work - Doesn't use a Base64 configuration string, but real Guacamole configuration options - Doesn't use a sanitize function on TextFields of the Form, but rather PasswordField types
…e statements. Remove unused GuacamoleExceptionSupplier
…introdcude in last commit
…same logic for safe use as a HashMap key
… that the Future isn't invalidated in the cache before its returned
…able or not regular files
- Use final on all local and method arguments where possible
- Comment all public methods and constructor
- Catch only specific exceptions
- Remove unused imports
- Remove code that can no longer be used
- No nested if block more than 2 levels deep
- Prefer getter functions to direct access to class variables
- Don't throw and catch exception in the same function, the the catch blocks
closer to where the exceptions are thrown
- Split HvClientProvider out from HvSecretService to reduce complexity and
increase readibility of both classes
- Create helper function for HvSecretService.prepareToken to regroup similar
logic and reduce CognitiveComplexity of prepareToken
- Split HvClient fallback logic into a seperate function, use an ordered List
of HvClients in this function to simplify the logic
Author
|
I converted this PR to a Draft as after having run the code through a SAST/linter and taking a deep breath after the Didn't last long in Draft form, 'cause I committed my changes a few hours after following testing |
added 5 commits
June 9, 2026 14:52
…ionGroup information can be updated for the UI
…ider class. Correct some comments
…irectoryService didn't unwrap HvConnectionGroup
Author
|
For discussion of my proposed TokenFilter change, please see regex101.com for an example of how the regular expression I propose functions |
added 2 commits
June 12, 2026 10:12
- Add ECDSA ec256 to Guacamole signed certifcates
- Add ability to get the Vault to issue the certificate
- Add URL query parameters to modify certificate type on a token
by token basis.
added 4 commits
June 15, 2026 16:09
…che key, to allow tokens from different secret records on the same connection
…cret engine for consistency with the vault itself
…ce to avoid casting warning
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was first based on #1143, but has now combined with #1116 as well, so I stole the Jira ticket of #1116. The main changes are
As this PR is fully documented in the markdown/jinja I won't do in to details of the working of this extension, but rather discuss the problems I encountered
Simplified token names:
The KSM extension uses token names like KEEPER_SERVER_USERNAME as only a single Keeper secret record with relatively well controls key values is used. This extension allows basically any mount path of the secret engine and path to the secret record within the Vault and so multiple secret records. Its therefore difficult to see how the KSM token naming method could be projected on to a Vault.
As in #1116 I chose to expose the Vault paths directly in the tokens, allowing the complete freedom. This means that the file
vault-token-mapping.ymlis probably not needed,Token paths:
In most cases the token name to use will be the path to the Vault secret record post-pending with the secret value to extract. This has several issues
Secret caching:
When obtaining a secret record from the Vault, the secrets in the record are associated between themselves. For example a dynamic LDAP account has a single use username and password. The structure of the base vault extension assumes a function getValue that returns a single secret value. We therefore need to cache the values for a single record to keep the association between common values.
In the getTokens method the VaultSecretService, this is not a problem as all tokens for a single connection are resolved at once and we can set a UUID as a key in the cache to ensure common values are kept together. It also prevents session stealing by timing issues in concurrent connections. For the secrets looked up for guacamole.propertes.vlt that basically only concern secrets without any user context this is no problem. The issue is with tokens looked up in vault-token-mapping.yml. These secrets are looked up individually, but they have a user context. To avoid secret stealing and try to keep common secrets together I used a cache key combining GUAC_USERNAME, USERNAME and the path to the Vault secret record.
By the nature of Vault tokens where the password rotation at each usage, this cache should only be very short term, in the order of a few seconds. I used caffiene for the cache
Spring-Vault :
Due to the Tomcat 9 dependency of Guacamole I was forced to use a version of spring-vault compatible with Java-11, so I'm left using version 2.3.4 of spring-vault, when spring-vault is currently working on version 4.x. This came with many issues, the main one being that the LifecycleAwareSessionManager class of spring-vault in version 2.3.4 is pretty much broken, so I had to reimplement my own SessionManager. The use of spring-vault in this pull-request is therefore more of a promise to be able to simplify the extension when Guacamole migrates to a newer Tomcat
SSH ed25519:
The SSH certificate signing reqires Guacamole to be able to generate temporary SSH certificates. I used apache SSHD for this. The Java 11 versions of apache SSHD don't include ed25519 directly and I had to include i2p as a crypto provider for ed25519. I removed the BouncyCastle Fips crypto provider from #1116, as it wasn't initially used and it prevented the use of ed25519 as FIPS-140 is a relatively old standard that doesn't include or allow elliptique curve crypto
LDAP Service accounts:
The LDAP service accounts in the Vault must be checked out and checked back in again after use. This presented two problems for this extension.
Non renewable or expired token
Even in recent spring-vault implementations of LifecycleAwareSessionManager, an expired or non renewable token will cause the SessionManager to just stop in expiry. I'd like to use VaultAgent for complex authentification methods via a token sink file. This essentially means that a reauthentication via a call to the function ClientAuthentication.login() of spring-vault should be used if the token is expired or non-renewable. I implemented this in my SessionManager