HashiCorp Vault module

Writes certificate + key + chain into a Vault KV v2 secret path. Uses Vault's built-in version history for rollback — one of the few modules where rollback is a first-class operation rather than manual cleanup. Supports AppRole, JWT, and client-TLS authentication.

01Overview

  • Transport: Vault HTTP API.
  • Auth: AppRole (default — role_id + secret_id), JWT (e.g. OIDC from the backend pod), TLS client cert.
  • Target: KV v2 secret engine. Path template supports Go template variables ({{ .cn }}).
  • Payload: {"certificate": ..., "private_key": ..., "chain": ..., "fullchain": ...}. Field names customisable.
  • Rollback: supported — KV v2 keeps version history; rollback writes the previous version back as the current one.
  • Namespace: Enterprise Vault namespace is supported via the X-Vault-Namespace header.

02Prerequisites

  • Vault cluster reachable from the backend on its API port (typically 8200 HTTPS).
  • A KV v2 secret engine mounted (e.g. at secret/).
  • A policy granting create, update, read, and — for rollback — patch on the target path pattern. Sample policy for the default path secret/data/certs/+/...:
path "secret/data/certs/*" {
  capabilities = ["create", "update", "read", "patch"]
}
path "secret/metadata/certs/*" {
  capabilities = ["read", "list", "delete"]
}

03Create the module credential

  1. Settings → Distribution → CredentialsNewHashiCorp Vault.
  2. Pick the auth method:
    • AppRole: paste role_id + secret_id.
    • JWT: reference an OIDC token source (service-account token for in-cluster runs).
    • TLS cert: paste a PEM client certificate with the appropriate Vault cert-auth role.
  3. Save.

04Create a Vault target

  1. Settings → Distribution → TargetsNew. Module: HashiCorp Vault.
  2. Fields:
    • Addresshttps://vault.example.com:8200.
    • Namespace — optional; required for Vault Enterprise namespaces.
    • KV mount pathsecret (default).
    • Secret path template — e.g. certs/{{ .cn }}.
    • Field names — customize which JSON keys hold the cert, key, chain, fullchain (defaults: certificate, private_key, chain, fullchain).
    • TLS CA cert — PEM for a private-CA-signed Vault endpoint.
    • TLS skip verify — for bring-up only.
    • HTTP timeout — default 30 s.
    • Credential.
  3. Save → health check calls sys/health.

05Execution flow

  1. Auth with the configured method; acquire a short-lived Vault token.
  2. Render the secret path template against the cert's metadata.
  3. POST the JSON payload to /v1/<mount>/data/<path>. KV v2 bumps the version automatically.
  4. On success, record the new version in LastRollbackMeta for future rollback.

06Rollback

KV v2 keeps every version up to the engine's configured max_versions. Clicking Rollback on the distribution calls Vault's data/patch endpoint to re-write the previous version as the latest — the history record preserves the round trip. Make sure your max_versions is high enough to cover your rollback window (10 is the default; raise if your cadence is denser).

07Security notes

  • The private key lives in Vault after distribution — if that matters to your threat model, set include_private_key to off (cert-only delivery).
  • Vault's audit log captures every write; pair it with CertAutoPilot's audit trail for a full chain of custody.
  • The backend's Vault token is scoped to the policy above; it cannot read secrets outside that path pattern.

08Troubleshooting

"permission denied"

Policy is missing one of create/update/read on the target path, or the path pattern doesn't match. Test with vault token capabilities <token> secret/data/certs/example.com.

"namespace not found"

Either typo, or you hit a non-Enterprise Vault — namespaces are an Enterprise-only feature.

"kv v1 write format doesn't match"

The mount path points at a KV v1 engine. CertAutoPilot only supports KV v2. Remount or migrate.