Configuration
Before deploying VAULT, define a group named vault in the inventory. There is no profile or mode parameter: the mode is derived entirely from the number of members in vault.
- Single node: no HA; suitable for development, testing, demos, and sandboxes.
- Three nodes: tolerates one member failure and provides HA access with an L2 VIP; suitable for production.
- Two nodes: functional but has no fault tolerance; treat it as a single-node setup.
| Members | Quorum | Tolerated Failures | Mode | Service Endpoint |
|---|---|---|---|---|
| 1 | 1 | 0 | Lab | vault.pigsty points to the member |
| 2 | 2 | 0 | Warning | Any member failure loses quorum |
| 3 | 2 | 1 | Production | vault.pigsty points to the VIP; HAProxy forwards to the active member |
VAULT uses OpenBao’s built-in Raft storage. Only one active member handles writes at a time; the remaining standby members forward requests to it.
Single Node
A single-node VAULT instance needs only one line of configuration:
Besides the IP address, the only required parameter is vault_seq. It determines the instance name vault-<seq> and which member performs initial cluster initialization: the one with the lowest vault_seq.
Single-node VAULT usually shares a machine with INFRA, ETCD, and PGSQL, so keys and data are not separated. Obtaining its disk exposes both encrypted data and the key. This is suitable for development and demos, but should not supply transparent-encryption keys in production.
Three Nodes
Three members tolerate one failure. Enable NODE’s L2 VIP on the vault group in production so the service endpoint is also highly available:
The resulting topology is:
When vip_enabled is true and there is more than one member, vault.yml generates /etc/haproxy/conf.d/vault.cfg on every member:
- Binds
<VIP>:8200in TCP mode with TLS passthrough. Clients and OpenBao still perform certificate validation. - Checks
GET /v1/sys/health: active returns200, standby429, sealed503, and uninitialized501. Only a member returning200receives traffic. - Health checks also use HTTPS and validate member certificates with
/etc/pki/ca.crt. - Members without the VIP must also bind
<VIP>:8200, requiringnet.ipv4.ip_nonlocal_bind=1. NODE’s tuned profiles set this. Withnode_tune: none, set it yourself or the playbook stops here.
With the VIP enabled, server certificate SANs include its address. Members must share the same node_cluster; otherwise NODE derives different VRRP authentication values and VIP failover does not work.
A three-member cluster can run without a VIP. Resolve vault.pigsty to one member; a standby forwards requests to the active member.
The cluster still tolerates one member failure, but the member named in DNS becomes a single point of failure for access.
Rerunning node.yml with haproxy_clean=true on vault nodes clears /etc/haproxy/conf.d/. Run ./vault.yml -l vault -t vault_haproxy to regenerate the VAULT endpoint.
Two Nodes
A two-member Raft cluster requires a quorum of two and tolerates no failures. Either member failing makes the whole cluster unavailable, potentially reducing availability below that of a single node.
VAULT permits two-member deployments but prints a warning. Treat this as a temporary state during scaling, not a permanent topology.
Raft supports larger clusters, but VAULT is designed and validated for one or three members.
Service Domain
All clients should use vault_domain, defaulting to vault.pigsty. The full address is:
Consumers such as pg_tde persist the KMS endpoint in their metadata. Using a domain allows migration from one to three members, or a change of VIP, by updating /etc/hosts without changing every consumer’s configuration.
NODE’s node_etc_hosts writes the mapping to each node’s /etc/hosts, without depending on INFRA DNS. Databases can therefore locate KMS at startup even if INFRA is unavailable.
Pigsty CA signs the server certificates. Every managed node has /etc/pki/ca.crt, which clients can use to verify VAULT’s identity.
Placement
In production, deploy VAULT on dedicated nodes or alongside control components such as ETCD and INFRA. Do not co-locate it with PostgreSQL or Silo data nodes that use its keys. Transparent encryption depends on separating keys from data: a leaked data disk, database backup, or object store should not expose its key in the same place.
VAULT needs few resources. Low disk latency matters most because each Raft log commit must be persisted.
Key Material
All VAULT trust roots are stored on the admin node in files/pki/vault/, alongside Pigsty CA. files/pki/ is ignored by Git by default:
| File | Contents | Notes |
|---|---|---|
unseal.key | 32-byte static seal key | Generated on first deployment and never overwritten; used by every member for auto-unseal |
init.json | Root token and five recovery shares, threshold three | Output of bao operator init; the root of administrative access |
backup.token | Token with read-only snapshot access | Used by vault-backup; valid for ten years |
backup/*.snap | Initial snapshot after initialization and final snapshot before whole-cluster removal | Mode 0600 |
vault-<seq>.crt / .key | Member server certificates and private keys | Signed by Pigsty CA; validity set by cert_validity |
A Raft snapshot and its matching unseal.key can recover the encrypted store. The root token and recovery keys in init.json are needed to regain administrative access afterward.
Losing unseal.key makes all snapshots unreadable. Keep files/pki/ and snapshots safely off-site.
Each member holds a copy of unseal.key. Before distributing it, Pigsty compares checksums. If an existing member key differs from the admin node’s key, the playbook stops immediately to avoid wrapping data with the wrong key.
Filesystem Layout
VAULT creates the following files and directories on each member:
| Path | Purpose | Permissions |
|---|---|---|
/etc/openbao/ | Configuration directory | 0750, root:openbao |
/etc/openbao/openbao.hcl | Main OpenBao configuration | 0640, root:openbao |
/etc/openbao/tls/ | CA certificate, server certificate, and private key | Directory 0750, files 0640, root:openbao |
/etc/openbao/unseal.key | Local copy of the static seal key | 0640, root:openbao |
/etc/openbao/backup.token | Local copy of the backup token | 0600, root:root |
/data/vault/raft/ | Raft data directory (configurable) | 0700, openbao:openbao |
/data/vault/backup/ | Seven local snapshots and the .backup.lock concurrency lock | 0700, root:root |
/var/log/openbao/ | audit.log, rotated daily with seven retained files | 0750, openbao:openbao |
/etc/systemd/system/openbao.service | systemd service definition | 0644, root:root |
/etc/profile.d/bao.sh | bao client environment variables | 0644, root:root |
/etc/logrotate.d/openbao | Audit log rotation | 0644, root:root |
/usr/local/bin/vault-backup | Snapshot script | 0755, root:root |
/etc/cron.d/vault-backup | Daily snapshot schedule | 0644, root:root |
/var/lib/node_exporter/textfile/vault.prom | Latest successful snapshot timestamp and size | Collected by node_exporter |
/etc/haproxy/conf.d/vault.cfg | HAProxy VIP endpoint (VIP enabled only) | 0644, root:root |
On INFRA nodes, /infra/targets/vault/<vault_cluster>-<vault_seq>.yml defines the member’s monitoring scrape target.
Was this page helpful?
Thanks—your feedback helps us improve this page.
What got in the way? (optional)