A reference implementation for deploying and operating a highly available HashiCorp Vault cluster using Infrastructure as Code and standard platform-engineering practices.
This project packages a self-managed Vault deployment — Terraform for provisioning, Ansible for configuration and hardening, Docker for local development, and CI checks to keep it all honest — into something that can be stood up repeatably instead of hand-built once and forgotten.
Most public Vault examples stop at "here's a vault server -dev command."
Running Vault in production means dealing with unsealing, storage backends,
TLS, access policies, backups, and upgrades — the operational half of the
job that rarely makes it into a README. This repo is an attempt to write
that part down.
- Reproducible — the local profile stands up a real 3-node,
auto-unsealed Raft cluster from a clean checkout with one command
(
make deploy). The AWS/Azure profiles aren't there yet — see Roadmap. - HA by default — the reference topology is a multi-node Raft cluster
from the start, not bolted on as a "v2" feature. A load balancer in
front of it is still a
TODOinterraform/awsandterraform/azure. - Operable, not just deployable — runbooks and disaster-recovery procedures are first-class, not an afterthought.
- Cloud-agnostic core — Terraform modules are structured so the Vault and Ansible layers don't care whether the nodes came from AWS, Azure, or a local Docker Compose stack.
This is the topology make deploy actually stands up (local/CI). See
diagrams/architecture.md for the full
target production design — load balancer and cloud KMS auto-unseal
included, neither of which exist yet (see Roadmap):
vault CLI / apps
│
┌───────────────┬───────────────┐
│ │ │
vault-0 vault-1 vault-2
(leader) (follower) (follower)
│ │ │
└───────────────┴───────────────┘
│
Raft cluster
│
Transit auto-unseal
│
vault-unseal
(Shamir-unsealed once —
the root of trust)
vault-reference-platform/
├── terraform/
│ ├── aws/ # AWS provider implementation
│ ├── azure/ # Azure provider implementation
│ ├── local/ # Local/Docker provider for dev + CI
│ └── modules/ # Shared, provider-agnostic modules
├── ansible/
│ ├── playbooks/
│ ├── roles/
│ └── inventory/
├── docker/
│ ├── vault/ # Vault server image + config
│ ├── vault-unseal/ # Transit auto-unseal backend for the dev cluster
│ ├── tooling/ # CLI/dev tooling image
│ └── dev/ # docker-compose for local dev
├── scripts/
├── examples/
├── docs/
├── diagrams/
├── .github/workflows/
├── Makefile
├── LICENSE
└── CONTRIBUTING.md
git clone https://github.com/sethbergman/vault-reference-platform.git
cd vault-reference-platform
make deploy # 3-node Raft cluster, auto-unsealed, via Docker ComposeSee docs/deployment.md for cloud deployment via
Terraform + Ansible.
See docs/security.md for the threat model, auto-unseal
approach, TLS handling, and policy structure.
See docs/auto-unseal.md for how each profile
auto-unseals — Vault Transit locally/in CI, AWS KMS or Azure Key Vault in
the cloud profiles.
See docs/secret-rotation.md for bootstrapping
AppRole roles and rotating secret_ids on a recurring cadence via
scripts/bootstrap-approle.sh and scripts/rotate-secret-id.sh.
See docs/disaster-recovery.md for backup and
restore procedures.
See docs/operations.md for day-2 runbooks: health
checks, upgrades, capacity planning, and common incident response steps.
GitHub Actions runs six checks on every PR: terraform fmt/validate,
ansible-lint, shellcheck, and markdownlint, plus two jobs that
actually deploy the Docker Compose cluster and exercise it — one brings
up and auto-unseals the full 3-node Raft cluster and does a live
secret write/read, the other bootstraps an AppRole and proves
secret_id rotation end to end (issue, use, rotate, confirm the old
one is rejected). See
.github/workflows/ci.yml.
- v0.1 — local Docker Compose deployment, base Terraform + docs (done)
- v0.2 — HA cluster (done), auto-unseal (done), monitoring (open)
- v0.3 — CI security scanning, automated tests
- v1.0 — production-ready reference architecture
MIT — see LICENSE.
See CONTRIBUTING.md.