How HashiCorp Vault Secrets Management Works
This page explains what Qualytics does with the six Secrets Management fields, which values are right for each kind of Vault secret, how the connection fields reference the secret, and what the network must allow. The step-by-step setup lives in the how-tos: Prepare Vault and Configure the Connection.
The Four Steps
Each time Qualytics opens the connection, including connection tests, syncs, profiles, and scans, it performs these steps:
- Log in. Qualytics sends a
POSTto the Login URL with the Credentials Payload as the request body. - Extract the token. The Token JSONPath is applied to the login response to read the client token.
- Fetch the secret. Qualytics sends a
GETto the Secret URL with the token in the header named by Token Header Name. - Substitute. The Data JSONPath is applied to the fetch response to obtain a flat object of key/value pairs. Every
${key}in the connection's fields is replaced with the matching value.
Secrets are never cached between uses. That is what makes a credential changed in Vault take effect automatically, and it is also why Vault must stay reachable for as long as the datastore is in use. The one thing Qualytics remembers is a failure to reach Vault: after a connection or name resolution failure, it does not contact that host again for five minutes, and a test or operation in that window fails right away with a message saying how long ago the failure was and when the next try happens.
The Six Fields
| Field | Example for an AppRole login and a KV version 2 secret | Notes |
|---|---|---|
| Login URL | https://vault.example.com/v1/auth/approle/login |
A full URL with scheme and host. With a namespace: https://vault.example.com/v1/<namespace>/auth/approle/login. |
| Credentials Payload | {"role_id": "<role_id>", "secret_id": "<secret_id>"} |
Any valid JSON the login endpoint accepts. The namespace never goes here; it goes in the URLs. |
| Token JSONPath | $.auth.client_token |
Correct for every Vault auth method. Other products put the token elsewhere; check their login response. |
| Secret URL | https://vault.example.com/v1/secret/data/qualytics/postgres |
A full URL: scheme, host, then the API path shown on the secret's Paths tab in the Vault UI. With a namespace: https://vault.example.com/v1/<namespace>/secret/data/qualytics/postgres. |
| Token Header Name | X-Vault-Token |
Vault's header. Other products use their own, for example Authorization. The extracted token is sent as the header value exactly as returned, with nothing added. |
| Data JSONPath | $.data.data |
Depends on the engine serving the secret; see below. The form pre-fills $.data, which is right only for KV version 1 and the database secrets engine. |
Any Vault auth method that answers a POST with a token works, not only AppRole: user and password, LDAP, Okta, GitHub, and others all return the token at $.auth.client_token. AppRole is the usual choice for a service like Qualytics because it does not depend on a person's account.
Header value is sent verbatim
Qualytics puts the value the Token JSONPath extracted into the header unchanged. A product that expects Authorization: Bearer <token> but returns only the bare token in its login response will reject the fetch, because no Bearer prefix is added. Such a product needs a login endpoint, or a gateway in front of it, that returns the complete header value.
Choosing the Data JSONPath
The Data JSONPath must point at the object that holds the key/value pairs, and that object sits at a different depth depending on the engine that serves the secret.
| Engine | How to recognize it | Fetch response shape | Data JSONPath |
|---|---|---|---|
| KV version 2 (the default for new mounts) | The API path contains /data/, for example /v1/secret/data/qualytics/postgres |
{"data": {"data": {"username": "...", "password": "..."}, "metadata": {...}}} |
$.data.data |
| KV version 1 | No /data/ segment, for example /v1/kv/qualytics/postgres |
{"data": {"username": "...", "password": "..."}} |
$.data |
| Database secrets engine (dynamic credentials) | The path starts with /v1/database/creds/ |
{"data": {"username": "...", "password": "..."}} |
$.data |
With $.data on a KV version 2 secret, Qualytics receives an object whose only keys are data and metadata, so every ${key} reference fails with a message listing exactly those two keys.
Referencing the Secret
Type ${key} in a text or file field under Connection Properties or Authentication, where key is a name inside the secret. The Type selector and the Port field take no reference: the type is checked against its allowed values and the port must be a number before any secret is read, so a reference in either makes the test or save fail. For a secret holding username and password, the Username field is ${username} and the Password field is ${password}.
- The syntax is a dollar sign with braces.
$.usernameis JSONPath, not a reference, and is sent to the target system as literal text. - Key names are case sensitive and must match the secret exactly.
- A key name must start with a letter or underscore and contain only letters, digits, and underscores. A key such as
service-accountcannot be referenced even though Vault accepts it. In a file field, in Private Key Password, or in the Hive Client Principal,${service-account}is rejected when you save or test, with a message saying that secret token names may only contain letters, digits, and underscores. In any other field it is left in place as literal text and reaches the data source unchanged, so the failure shows up there as a login error. Name the keyservice_accountinstead. - A field can mix literal text and references, for example
jdbc:postgresql://${host}:5432/app. - Substitution applies to the connection's own fields. The six Secrets Management fields are used as typed.
File fields
A file field can hold a reference too, so a file kept in your secrets manager never has to be uploaded. Every connection file field takes one: the Hive Native and Hive Keytab and krb5.conf, the BigQuery and Google Cloud Storage Service Account Key, and the Snowflake Private Key.
- Click Type a value instead next to the file field to switch it from an upload to a text box, and enter
${key}, wherekeyholds the file's contents. Upload a file instead switches back, and each mode keeps its own value while you switch. - A Keytab is a binary file. An upload encodes it for you, but a reference is used as stored, so store the keytab in your secrets manager as its base64 form. The text files, such as krb5.conf and a service account key, are stored as they are.
- On a secret field the typed value is masked as a single line, with the usual eye toggle to reveal it.
- A connection saved with a reference reopens with the reference visible in the text box, so you can see which key it points at. A field whose value is never returned, such as a service account key, shows as a saved secret instead.
- A reference that cannot be resolved is rejected when you save, with the keys the secret does hold listed in the message. A reference on a connection with no secrets manager set up is rejected the same way.
- A Snowflake private key may be stored as the key text or as its base64 form. An encrypted private key supplied by reference is not accepted, because its passphrase is never stored. For an uploaded encrypted key, Private Key Password can be a
${key}reference on its own: Qualytics resolves it and decrypts the key before saving. - A BigQuery service account key by reference is read each time the connection is used, so a key changed in the secrets manager takes effect on the next operation.
Namespaces
On Vault Enterprise and HCP Vault every mount, role, policy, and secret lives inside a namespace. Qualytics sends no namespace header, so the namespace must be part of both URL paths, right after /v1/.
- Secret in namespace
team-a:https://vault.example.com/v1/team-a/secret/data/qualytics/postgres - AppRole enabled in namespace
team-a:https://vault.example.com/v1/team-a/auth/approle/login - AppRole enabled in the root namespace:
https://vault.example.com/v1/auth/approle/login, and its policy must then name the secret path with the namespace prefix,team-a/secret/data/qualytics/postgres
To see which namespace a role is in, open Access in the Vault UI with the namespace selector set to the namespace in question. If approle/ is listed there, that namespace belongs in the Login URL. The Paths tab of a secret already includes the namespace in the API path it shows.
A missing namespace does not look like a namespace problem
Logging in against the wrong namespace returns invalid role or secret ID, the same message as a wrong secret ID, because Vault does not reveal whether a role exists. Check the namespace before minting new credentials.
Network Requirements
Qualytics must reach Vault over HTTPS from the addresses shown in the banner below every connection form; see Finding the addresses to allow. Two things to confirm with your network team:
- The firewall allows those addresses to reach Vault's host and port: 443 for most installations, 8200 for a default standalone one.
- Vault's hostname resolves from inside the Qualytics deployment. A name that only resolves on an office network, or a
.localname, often does not.
A connection test that waits about two minutes and then fails with a gateway timeout is a timeout for the whole request, which includes reaching Vault, reading the secret, and then connecting to the data source. When the timeout happens before Vault has answered, the form values have not been evaluated yet, so changing them does not help until the network path exists. Troubleshooting explains how to tell which stage stalled.