Secret Vault

External Vault Integrations

Point Versus at the secrets manager you already run — HashiCorp Vault, CyberArk, or AWS Secrets Manager — so managed-device credentials are fetched on demand and never stored in Versus, resolved either in the cloud or in-network on a collector.

Not every organization wants device credentials living in a new place. If you already run HashiCorp Vault, CyberArk, or AWS Secrets Manager, Versus can read a managed device's credential straight from your existing secrets manager at connection time — so the credential is never stored in Versus. Versus keeps only the coordinates: which vault to talk to, and the path where the secret lives.

This is distinct from the Versus Vault, which stores secrets in Versus with envelope encryption. External Vault Integrations store nothing secret — they are a pointer plus an on-demand resolver. Use them when your policy says credentials must stay in the system of record you already operate.


What it is

Two records model an integration:

  • An External Vault Connection — a tenant's link to one external secrets manager: its address, auth method, and (for HashiCorp) the KV mount. The bootstrap credential Versus uses to authenticate to that vault is itself a reference into the Versus Vault (auth_ref), never stored in the connection.
  • An External Secret Reference — a pointer to one secret inside that vault: the secret_path and which fields hold the username and password. A device is bound to a reference; nothing about the secret's value is persisted.

When a workflow, discovery, or a device operation needs the credential, Versus (or a collector) resolves the reference on demand, uses it, and discards it. A resolved credential is cached in memory only, for a short TTL, and is never written to Postgres, never written to the Versus Vault, and never logged.

The feature is inert until you create a connection, and it rides the Secure Vault module entitlement — the same one that gates the Versus Vault. See Security & Compliance.

Supported providers

ProviderKeyStatus
HashiCorp Vault (KV v1/v2)hashicorpImplemented
CyberArk CCP / AIMcyberark_ccpImplemented
AWS Secrets Manageraws_smImplemented
CyberArk ConjurconjurRoadmap
Azure Key Vaultazure_kvRoadmap
GCP Secret Managergcp_smRoadmap
Delinea Secret ServerdelineaRoadmap

The roadmap providers are declared in the model so the UI and API accept them, but only HashiCorp, CyberArk CCP, and AWS Secrets Manager have working backends today. Selecting an unimplemented provider fails closed with a clear "not implemented yet" error rather than silently doing nothing.

How each provider maps

Because the three secrets managers are shaped differently, the connection's generic fields are reused per provider:

FieldHashiCorpCyberArk CCPAWS Secrets Manager
addresshttps://vault.corp:8200CCP base URL(unused)
namespaceEnterprise namespaceAppIDAWS region
mountKV engine mountSafe(unused)
auth_refVault token or {role_id, secret_id}optional client-cert PEM (mTLS)optional {aws_access_key_id, …}
secret_path (on the reference)KV pathObject namesecret name or ARN

For HashiCorp, auth_method is token or AppRole in the current release. For AWS, leaving auth_ref blank uses the ambient IAM role (task, instance, or IRSA) — the recommended path, so no static keys are stored anywhere. For CyberArk, the application is authorized by AppID plus allowed-machine/IP, with an optional client certificate for mutual TLS.


How resolution works

Versus reads a device's credential through a single facade. When a device is bound to an external secret reference, that path takes precedence over the Versus Vault enrollment and the legacy credential field — and it is fail-closed: if the external vault is unreachable or the path is wrong, the operation fails rather than falling back to a stale or different credential.

device operation needs credentials
        │
        ▼
device bound to an external secret? ──no──▶ Versus Vault enrollment / legacy credential
        │ yes
        ▼
resolve on the collector? ──yes──▶ dispatch carries only the path;
        │ no                        the collector reads it in-network (Mode C)
        ▼
cloud resolves via the provider ▶ TTL-cached in memory ▶ used ▶ discarded

A short cache TTL (default 60 seconds, per reference) means a rotation in your external vault is picked up automatically on the next connection — Versus never holds a credential long enough to go stale.

Cloud-side vs. collector-side — resolve_at

Where the secret is read is the most important decision, because it determines whether the plaintext ever touches Versus:

  • cloud — Versus resolves the secret in the application core. Suitable when the external vault is reachable from Versus (public endpoint, PrivateLink, etc.).
  • collector — the secret is read in your network by a collector, so it never traverses Versus. The dispatch to the collector carries only the non-secret KV path; the collector's local resolver reads it from your vault using the collector's own identity.
  • auto (default) — resolve on the collector when the device is bound to a site (and therefore reached through a collector), otherwise resolve in the cloud.

When a reference is collector-resolved, a stray attempt to resolve it cloud-side raises an error instead of quietly connecting with a legacy credential — the fail-closed guarantee holds in both directions.

Collector-side resolution (Mode C)

Collector-side resolution is the collector plane's Mode C. A collector can resolve credentials in three modes, and one collector can run several at once:

ModeWhere the secret livesUsed for
ASealed on the collector's local disk (AES-256-GCM)Versus-managed credentials kept in-network
BDelivered decrypted inside the signed dispatch envelopeCloud-held credentials, in memory only
CRead live from your external vault, in-networkExternal Vault Integrations

A CompositeResolver routes each credential request to the right mode by tenant, provider, and target, so a single collector can inject an F5 credential via Mode A while resolving another device's credential from your HashiCorp Vault via Mode C — neither path sees the other's secrets. The collector's HashiCorp backend authenticates with AppRole (role_id/secret_id → short-lived client token, cached until just before expiry), reads the KV v2 path, and re-composes the exact {username, password} blob a provider driver expects — so the driver cannot tell whether the bytes came from the local sealed vault or your external one. Every mode still enforces its own scope: composition never widens access. See Collector Security and Collector Fleet.

Dynamic secrets and rotate-on-close

If your HashiCorp Vault exposes a dynamic-secret engine (database, LDAP, etc.), mark the reference dynamic and give it a dynamic_role (for example database/creds/f5-lab). Each resolution then mints ephemeral credentials and a lease — never cached — and the lease id rides back with the result. When a Privileged Session Management broker closes a session, it revokes the lease, so the credential is dead after use. This is rotate-on-close: the device credential a session used is invalidated the moment the session ends.


Using it as an operator

1. Create a connection

POST /api/extvault/connections/
Authorization: Bearer eyJhbGc…
Content-Type: application/json

{
  "name": "Corp HashiCorp Vault",
  "provider": "hashicorp",
  "address": "https://vault.corp.example:8200",
  "mount": "secret",
  "kv_version": 2,
  "auth_method": "approle",
  "auth_ref": "vault://root/extvault/corp-hashicorp/approle",
  "resolve_at": "auto",
  "network": "collector_lan",
  "tls_verify": true
}

auth_ref is a vault:// reference into the Versus Vault, where the bootstrap token or {role_id, secret_id} JSON is stored — it is write-only from the API's point of view and never returned. network records how the vault is reached (public, privatelink, or collector_lan).

2. Test the connection

POST /api/extvault/connections/{id}/test/

This authenticates and runs a cheap reachability check, updating the connection's state (draft → active, or error) and last_ok_at / last_error. It never returns secret material — only { "ok": true, "detail": "authenticated to … (mount=secret)" }.

3. Add a secret reference

POST /api/extvault/secrets/
Content-Type: application/json

{
  "connection": "…connection-id…",
  "name": "F5 lab pair",
  "secret_path": "network/f5/aegon-lab",
  "username_key": "username",
  "password_key": "password",
  "cache_ttl_s": 60
}

username_key / password_key name the fields inside the stored secret (defaulting to username / password). Pin a specific KV v2 version with secret_version, or leave it blank for the latest. Set dynamic: true with a dynamic_role for a dynamic engine.

4. Verify the path resolves

POST /api/extvault/secrets/{id}/test/

Resolves the secret once to confirm the path and keys are correct. The response returns the username (a username is not itself the secret) and a boolean password_found — it never echoes the password:

200 OK
{
  "ok": true,
  "username": "svc-f5-lab",
  "password_found": true,
  "detail": "resolved network/f5/aegon-lab (username='svc-f5-lab', password present)"
}

5. Bind it to a device

Set the device's credential source to the reference. From then on, every device operation — discovery, F5 BIG-IP automation, certificate deployment, a workflow step — resolves the credential on demand, subject to resolve_at. You can also bind a connection to a collector so its Mode-C policy is configured to match.


What Versus stores — and doesn't

Stored in VersusNever stored in Versus
Connection metadata (address, mount, auth method)The external vault's bootstrap secret (kept as a Versus Vault reference)
The secret's path and field namesThe device credential value (resolved on demand, memory-cached only)
Resolution audit events (who / what / where / outcome)Dynamic-secret leases (minted per use, never cached)

Every resolution emits a secret-free audit event — connection, provider, path, purpose, and success/failure — and, where available, records it on the Versus Vault's tamper-evident hash-chained audit trail. Auditing is best-effort and never breaks resolution. Connections and references are tenant-scoped with row-level security, so one tenant can never see or resolve another's.


How it fits the platform

External Vault Integrations sit alongside the Versus Vault as an alternative credential source, chosen per device. The rest of the platform is unaware of the difference: providers, workflows, and certificate lifecycle ask for a device's credential the same way regardless of where it comes from. Combined with collector-side (Mode C) resolution, a bank or regulated enterprise can automate its estate with Versus while keeping every privileged credential inside its own secrets manager and network. See Platform Architecture for the layers involved.


Related