Skip to content

HashiCorp Vault KV Connector

Built-in vault connector for HashiCorp Vault KV secrets engine v2 using token auth (X-Vault-Token).

This connector is not the Authifi tenant secrets vault in packages/server/src/config/vault-config.ts — that is a separate product integration. See Secrets management for Authifi vault settings.

Local Vault with Docker

Run Vault in dev mode (in-memory, auto-unsealed, root token from env):

docker run -d --name vault-dev \
  -p 8200:8200 \
  -e VAULT_DEV_ROOT_TOKEN_ID=dev-root-token \
  -e VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 \
  hashicorp/vault:1.15 server -dev

Or use the Compose overlay:

docker compose -f docker/docker-compose.vault-dev.yml --profile vault-dev up -d

Enable KV v2 at mount secret

Dev images often ship with secret/ already mounted as KV v2. If not:

export VAULT_ADDR=http://127.0.0.1:8200
export VAULT_TOKEN=dev-root-token
vault secrets enable -version=2 -path=secret kv

HTTP equivalent: POST /v1/sys/mounts/secret with body {"type":"kv","options":{"version":"2"}}.

Root token → Floh connection field

Vault (Docker env) Floh connector field
VAULT_DEV_ROOT_TOKEN_ID token (secret)

Use a least-privilege token in production — not the dev root token.

address and allowPrivateNetworkEndpoint

Floh runs on Vault runs on Typical address allowPrivateNetworkEndpoint
Host (pnpm run dev) Host (-p 8200:8200) http://127.0.0.1:8200 Yes
Docker Compose (Floh + Vault) Service vault:8200 http://vault:8200 Yes
Production cluster Public ingress https://vault.example.com No

The address must be a bare base URL (no trailing slash, no embedded credentials). Floh validates it at connection resolution time and applies SSRF rules on every request unless the connection was validated with the private-network flag.

TLS recommendation for public addresses

For public (non-RFC1918) Vault endpoints, prefer https://. The connector validates address once at connection-config time and pins DNS only when the validator returns a resolved address — for arbitrary public hostnames DNS stays dynamic. An http:// public endpoint is therefore vulnerable to DNS rebinding between the config-time SSRF check and each subsequent request. TLS certificate validation on https:// defeats rebinding because a rebinding attacker cannot serve a valid certificate for the configured hostname. Private-network endpoints (loopback, RFC1918) are unaffected — allowPrivateNetworkEndpoint: true pins DNS to the resolved address.

Connection configuration

Create a connector instance via the Connectors API or UI with type vault.

Field Required Secret Purpose
address Yes No Vault API base URL.
token Yes Yes X-Vault-Token.
kvMount No No KV v2 mount path (default secret).
namespace No No Enterprise namespace (X-Vault-Namespace).
allowPrivateNetworkEndpoint No No Allow localhost / RFC1918 / Docker-internal address targets.

Commands

Command Description
test GET /v1/sys/health — fails if sealed or not initialized.
kvGet Read secret (path, optional version). Outputs data, version, createdTime.
kvPut Create/replace secret (path, data JSON object). Outputs version.
kvPatch Patch latest version (path, data JSON object).
kvDelete Soft-delete latest version at path.
kvList List keys under optional path prefix.

data must be a JSON object string (for example {"apiKey":"abc"}).

Minimal policy (HCL)

path "secret/data/myapp/*" {
  capabilities = ["create", "read", "update", "delete"]
}
path "secret/metadata/myapp/*" {
  capabilities = ["list", "read", "delete"]
}

Adjust secret if you use a different kvMount.

Manual QA checklist

  1. testok: true, not sealed.
  2. kvPut — write app/demo with {"env":"dev"}.
  3. kvGet — read back env.
  4. kvList — list under app/ (expect demo or demo/).
  5. kvPatch — merge another field; kvGet shows both.
  6. kvDelete — soft-delete; kvGet should fail or show deleted per policy.

Integration tests (Testcontainers)

From the repo root (Docker required):

pnpm --filter @floh/server run test:integration -- test/integration/vault-kv.test.ts

Troubleshooting

Symptom Likely cause
permission denied Token policy missing data or metadata path.
sealed / not initialized Cluster sealed or dev server not ready.
Connection blocked on 127.0.0.1 Set allowPrivateNetworkEndpoint to true.
no handler for route on kv ops Mount is KV v1 or wrong kvMount — enable KV v2.
Vault API request failed on kvList Check step diagnostics.httpStatus. 404: list a parent folder, not the leaf secret path (after kvPut at app/demo, list app or "", not app/demo). 403: add list on metadata/. Wrong kvMount vs where you wrote secrets.
Area Path
Connector definition packages/server/src/modules/connectors/handlers/vault.ts
Client, KV ops, policy packages/server/src/modules/connectors/handlers/vault-support/
Unit tests packages/server/test/unit/connectors/vault-*.test.ts
Integration tests packages/server/test/integration/vault-kv.test.ts
Dev Compose overlay docker/docker-compose.vault-dev.yml