Skip to content

Configuration

Choose a single-node or three-node VAULT topology and configure the HA VIP endpoint and service domain.

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.
MembersQuorumTolerated FailuresModeService Endpoint
110Labvault.pigsty points to the member
220WarningAny member failure loses quorum
321Productionvault.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:

vault: { hosts: { 10.10.10.10: { vault_seq: 1 } }, vars: { vault_cluster: vault } }

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:

vault:
  hosts:
    10.10.10.11: { vault_seq: 1 }   # Required identity parameter; instance name vault-1
    10.10.10.12: { vault_seq: 2 }   # Nonnegative integer, unique within the group
    10.10.10.13: { vault_seq: 3 }   # Keep immutable; the lowest seq performs initial initialization
  vars:
    vault_cluster: vault            # Cluster name for monitoring labels and instance prefixes
    node_cluster: vault             # Same node cluster name ensures consistent VRRP authentication
    vip_enabled: true               # Enable an L2 VIP for the vault node cluster
    vip_vrid: 129                   # VRRP router ID, 1-254; unique on the L2 network
    vip_address: 10.10.10.8         # VIP address; vault.pigsty should resolve here

all:
  vars:
    node_etc_hosts: [ '10.10.10.8 vault.pigsty' ]   # All nodes access vault through the VIP

The resulting topology is:

                  vault.pigsty -> 10.10.10.8 (VIP, node_etc_hosts)
                                   |
        +--------------------------+--------------------------+
        |    keepalived VIP + haproxy :8200 (check /v1/sys/health == 200)
   vault-1 10.10.10.11      vault-2 10.10.10.12      vault-3 10.10.10.13
   openbao :8200/:8201      openbao :8200/:8201      openbao :8200/:8201
        +------------- Raft (quorum 2, tolerates 1 failure) -----------+

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>:8200 in TCP mode with TLS passthrough. Clients and OpenBao still perform certificate validation.
  • Checks GET /v1/sys/health: active returns 200, standby 429, sealed 503, and uninitialized 501. Only a member returning 200 receives traffic.
  • Health checks also use HTTPS and validate member certificates with /etc/pki/ca.crt.
  • Members without the VIP must also bind <VIP>:8200, requiring net.ipv4.ip_nonlocal_bind=1. NODE’s tuned profiles set this. With node_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.

Three nodes without a VIP

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.

HAProxy configuration cleared

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:

https://vault.pigsty:8200

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.

./node.yml -t node_hosts           # Refresh /etc/hosts on all nodes after changing node_etc_hosts

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:

FileContentsNotes
unseal.key32-byte static seal keyGenerated on first deployment and never overwritten; used by every member for auto-unseal
init.jsonRoot token and five recovery shares, threshold threeOutput of bao operator init; the root of administrative access
backup.tokenToken with read-only snapshot accessUsed by vault-backup; valid for ten years
backup/*.snapInitial snapshot after initialization and final snapshot before whole-cluster removalMode 0600
vault-<seq>.crt / .keyMember server certificates and private keysSigned by Pigsty CA; validity set by cert_validity
Back up files/pki

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:

PathPurposePermissions
/etc/openbao/Configuration directory0750, root:openbao
/etc/openbao/openbao.hclMain OpenBao configuration0640, root:openbao
/etc/openbao/tls/CA certificate, server certificate, and private keyDirectory 0750, files 0640, root:openbao
/etc/openbao/unseal.keyLocal copy of the static seal key0640, root:openbao
/etc/openbao/backup.tokenLocal copy of the backup token0600, root:root
/data/vault/raft/Raft data directory (configurable)0700, openbao:openbao
/data/vault/backup/Seven local snapshots and the .backup.lock concurrency lock0700, root:root
/var/log/openbao/audit.log, rotated daily with seven retained files0750, openbao:openbao
/etc/systemd/system/openbao.servicesystemd service definition0644, root:root
/etc/profile.d/bao.shbao client environment variables0644, root:root
/etc/logrotate.d/openbaoAudit log rotation0644, root:root
/usr/local/bin/vault-backupSnapshot script0755, root:root
/etc/cron.d/vault-backupDaily snapshot schedule0644, root:root
/var/lib/node_exporter/textfile/vault.promLatest successful snapshot timestamp and sizeCollected by node_exporter
/etc/haproxy/conf.d/vault.cfgHAProxy 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.