HashiCorp Vault — Storage Backends

3 minute read

The storage backend determines where Vault persists its encrypted data. Choosing the right backend is one of the most important production decisions you’ll make.


Storage Backend Overview

┌─────────────────────────────────────────────────────┐
│                  Vault Server                        │
│                                                       │
│              ┌────────────────┐                      │
│              │    Barrier     │  ← encrypts all data │
│              └───────┬────────┘                      │
│                      │                                │
│              ┌───────▼────────┐                      │
│              │ Storage Backend │  ← stores ciphertext│
│              └───────┬────────┘                      │
│                      │                                │
│          ┌───────────┼───────────┐                   │
│          │           │           │                    │
│     ┌────▼───┐ ┌────▼────┐ ┌───▼────┐              │
│     │  Raft  │ │ Consul  │ │  S3    │              │
│     │ (rec.) │ │         │ │        │              │
│     └────────┘ └─────────┘ └────────┘              │
└─────────────────────────────────────────────────────┘

💡 Key point: The storage backend only sees encrypted data. It does not need to provide its own encryption.


Comparison Matrix

Backend HA Support Consistency Operational Complexity Recommended
Raft (Integrated) ✅ Built-in Strong Low ✅ Yes
Consul ✅ External Strong Medium For Consul users
S3 ❌ Eventual Low Dev/backup only
GCS ❌ Eventual Low Dev/backup only
Azure Blob ❌ Eventual Low Dev/backup only
Filesystem ❌ N/A None Dev/test only
DynamoDB ✅ (with HA) Strong Medium AWS deployments

Raft is Vault’s integrated storage backend. It provides built-in consensus and HA without external dependencies.

# vault.hcl — Raft storage
storage "raft" {
  path    = "/opt/vault/data"
  node_id = "vault-1"
}
  • No external dependencies — No need to manage a separate Consul cluster
  • Built-in HA — Leader election and data replication handled by Vault
  • Simple operations — Backup with vault operator raft snapshot
  • Strong consistency — Raft consensus guarantees data consistency

Multi-Node Raft Cluster

# Node 1 — vault-1.hcl
storage "raft" {
  path    = "/opt/vault/data"
  node_id = "vault-1"

  retry_join {
    leader_api_addr = "https://vault-2.example.com:8200"
  }
  retry_join {
    leader_api_addr = "https://vault-3.example.com:8200"
  }
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_cert_file = "/opt/vault/tls/vault-cert.pem"
  tls_key_file  = "/opt/vault/tls/vault-key.pem"
}

api_addr     = "https://vault-1.example.com:8200"
cluster_addr = "https://vault-1.example.com:8201"

Raft Cluster Operations

# List raft peers
vault operator raft list-peers

# Expected output:
# Node       Address                  State       Voter
# ----       -------                  -----       -----
# vault-1    vault-1.example.com:8201 leader      true
# vault-2    vault-2.example.com:8201 follower    true
# vault-3    vault-3.example.com:8201 follower    true

# Take a snapshot (backup)
vault operator raft snapshot save backup.snap

# Restore from snapshot
vault operator raft snapshot restore backup.snap

# Remove a peer
vault operator raft remove-peer vault-3

Consul Storage

Consul was the original recommended backend before Raft was integrated:

# vault.hcl — Consul storage
storage "consul" {
  address = "127.0.0.1:8500"
  path    = "vault/"
  token   = "consul-acl-token"
}

When to Use Consul

  • You already operate a Consul cluster
  • You need Consul for service discovery alongside Vault
  • Your organization has Consul expertise

Consul vs Raft

Feature Raft Consul
External dependency None Consul cluster required
Operational complexity Low Higher (manage Consul + Vault)
Backup method raft snapshot Consul snapshot + Vault backup
HA mechanism Built-in leader election Consul session locks
Performance Excellent Depends on Consul cluster

Filesystem Storage

For development and testing only:

# vault.hcl — Filesystem storage (NO HA)
storage "file" {
  path = "/opt/vault/data"
}

⚠️ Warning: Filesystem storage does not support HA. Never use it in production.


Cloud Object Storage

Amazon S3

storage "s3" {
  bucket     = "my-vault-storage"
  region     = "us-east-1"
  access_key = "AKIA..."
  secret_key = "secret..."
}

Google Cloud Storage

storage "gcs" {
  bucket = "my-vault-storage"
}

Azure Blob Storage

storage "azure" {
  accountName = "myvaultstorage"
  accountKey  = "base64key..."
  container   = "vault-data"
}

⚠️ Warning: Cloud object storage backends do not support HA. Use them for dev/test or as backup targets, not for production clusters.


DynamoDB Storage (AWS)

DynamoDB supports HA when configured with a lock table:

storage "dynamodb" {
  ha_enabled = "true"
  region     = "us-east-1"
  table      = "vault-data"
}

Choosing the Right Backend

                    Need HA?
                   /        \
                 Yes         No
                /              \
    Have Consul?          ┌─────────────┐
    /         \           │ Use Raft    │
  Yes         No          │ (single     │
   │           │          │  node) or   │
   ▼           ▼          │ Filesystem  │
┌────────┐ ┌────────┐    └─────────────┘
│ Consul │ │  Raft  │
│ or     │ │ (rec.) │
│  Raft  │ │        │
└────────┘ └────────┘

For most deployments: Use Raft. It’s simpler, has no external dependencies, and is HashiCorp’s recommended backend.


Quick Reference

Backend HA Config Key Production Use
Raft ✅ storage "raft" ✅ Recommended
Consul ✅ storage "consul" ✅ If you have Consul
DynamoDB ✅ storage "dynamodb" ✅ AWS deployments
S3 ❌ storage "s3" ❌ Dev/backup only
GCS ❌ storage "gcs" ❌ Dev/backup only
Azure Blob ❌ storage "azure" ❌ Dev/backup only
Filesystem ❌ storage "file" ❌ Dev/test only

Next: Vault UI & CLI