HashiCorp Vault — Vault Architecture

5 minute read

Vault’s architecture is designed around a security-first model where all data is encrypted before it ever reaches storage. Understanding these internals helps you operate Vault confidently in production.


High-Level Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        Vault Server                              │
│                                                                   │
│  ┌───────────┐  ┌───────────────┐  ┌────────────┐               │
│  │   HTTP     │  │   System      │  │  Cluster   │               │
│  │   API      │  │   Backend     │  │  (HA)      │               │
│  │  :8200     │  │               │  │  :8201     │               │
│  └─────┬─────┘  └───────┬───────┘  └─────┬──────┘               │
│        │                 │                 │                       │
│  ┌─────▼─────────────────▼─────────────────▼──────────────────┐  │
│  │                     Core                                    │  │
│  │                                                             │  │
│  │  ┌──────────┐  ┌──────────────┐  ┌────────────────────┐   │  │
│  │  │ Auth     │  │ Secrets      │  │ Audit              │   │  │
│  │  │ Methods  │  │ Engines      │  │ Devices            │   │  │
│  │  │          │  │              │  │                    │   │  │
│  │  │ Token    │  │ KV           │  │ File               │   │  │
│  │  │ AppRole  │  │ Database     │  │ Syslog             │   │  │
│  │  │ OIDC     │  │ Transit      │  │ Socket             │   │  │
│  │  │ K8s      │  │ PKI          │  │                    │   │  │
│  │  │ AWS      │  │ AWS/Azure/GCP│  │                    │   │  │
│  │  └──────────┘  └──────────────┘  └────────────────────┘   │  │
│  │                                                             │  │
│  │  ┌─────────────────────────────────────────────────────┐   │  │
│  │  │                 Token Store                          │   │  │
│  │  └─────────────────────────────────────────────────────┘   │  │
│  │                                                             │  │
│  │  ┌─────────────────────────────────────────────────────┐   │  │
│  │  │                Policy Store                          │   │  │
│  │  └─────────────────────────────────────────────────────┘   │  │
│  └─────────────────────────┬───────────────────────────────┘  │
│                             │                                     │
│  ┌──────────────────────────▼──────────────────────────────┐     │
│  │                  Barrier (AES-256-GCM)                   │     │
│  │          All data encrypted before storage               │     │
│  └──────────────────────────┬──────────────────────────────┘     │
│                             │                                     │
│  ┌──────────────────────────▼──────────────────────────────┐     │
│  │               Storage Backend                            │     │
│  │                                                          │     │
│  │  ┌──────┐  ┌────────┐  ┌───────┐  ┌──────────────┐    │     │
│  │  │ Raft │  │ Consul │  │  S3   │  │ GCS / Azure  │    │     │
│  │  └──────┘  └────────┘  └───────┘  └──────────────┘    │     │
│  └──────────────────────────────────────────────────────────┘     │
└─────────────────────────────────────────────────────────────────┘

The Barrier

The barrier is Vault’s most critical architectural component. It provides an encryption layer between Vault and its storage backend.

How it works:

  1. Vault generates a master key during initialization
  2. The master key encrypts an encryption key
  3. The encryption key encrypts all data using AES-256-GCM
  4. Only encrypted data reaches the storage backend
  5. The storage backend never sees plaintext
┌────────────────┐      ┌────────────────┐      ┌────────────────┐
│   Unseal Keys  │─────▶│  Master Key    │─────▶│ Encryption Key │
│  (Shamir's)    │      │                │      │  (AES-256-GCM) │
└────────────────┘      └────────────────┘      └────────┬───────┘
                                                          │
                                              Encrypts all data
                                                          │
                                                          ▼
                                                ┌────────────────┐
                                                │ Storage Backend│
                                                │ (sees only     │
                                                │  ciphertext)   │
                                                └────────────────┘

💡 Key insight: Even if someone gains access to your storage backend (Raft files, Consul data, S3 bucket), they cannot read any secrets without the unseal keys.


Storage Backend

The storage backend provides durable persistence for Vault’s encrypted data. It does not need to provide encryption — the barrier handles that.

Backend HA Support Description
Raft (Integrated) ✅ Built-in consensus, recommended for most deployments
Consul ✅ HashiCorp’s service mesh, mature HA support
S3 ❌ AWS object storage, no HA
GCS ❌ Google Cloud Storage, no HA
Azure Blob ❌ Azure object storage, no HA
Filesystem ❌ Local disk, dev/test only

Raft is the recommended storage backend for production. It provides built-in HA without external dependencies.

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

Secrets Engines

Secrets engines are pluggable components mounted at specific paths. Each engine handles a different type of secret.

# List enabled secrets engines
vault secrets list

# Output:
# Path          Type         Description
# ----          ----         -----------
# cubbyhole/    cubbyhole    per-token private storage
# identity/     identity     Identity store
# secret/       kv           key/value secret storage
# sys/          system       system endpoints

How mounting works:

# Enable a database secrets engine at "database/"
vault secrets enable database

# Enable another KV engine at "team-a/"
vault secrets enable -path=team-a kv-v2

Each mount point is an isolated namespace — secret/myapp and team-a/myapp are completely separate.


Auth Methods

Auth methods verify client identity and return a Vault token with attached policies.

┌────────────┐     ┌─────────────┐     ┌───────────┐
│   Client    │────▶│ Auth Method │────▶│  Vault    │
│             │     │             │     │  Token    │
│ Credentials │     │ • Token     │     │           │
│ (password,  │     │ • AppRole   │     │ + Policies│
│  JWT, etc.) │     │ • OIDC      │     │ + TTL     │
└────────────┘     │ • K8s SA    │     │ + Metadata│
                    └─────────────┘     └───────────┘
# Enable userpass auth method
vault auth enable userpass

# Create a user
vault write auth/userpass/users/sushil \
    password="my-password" \
    policies="dev-team"

# Login
vault login -method=userpass username=sushil password="my-password"

Audit Devices

Audit devices log every Vault operation. Vault requires at least one working audit device in production — if all audit devices fail, Vault stops responding to prevent unaudited access.

# Enable file audit device
vault audit enable file file_path=/var/log/vault/audit.log

# Enable syslog audit device
vault audit enable syslog tag="vault" facility="AUTH"

Audit log entry example:

{
  "type": "request",
  "auth": {
    "token_type": "service",
    "policies": ["default", "dev-team"]
  },
  "request": {
    "operation": "read",
    "path": "secret/data/myapp",
    "remote_address": "10.0.1.50"
  },
  "response": {
    "data": {
      "data": {
        "db_password": "hmac-sha256:abc123..."
      }
    }
  }
}

⚠️ Important: Sensitive values in audit logs are HMAC-hashed, not stored in plaintext. You can verify a specific value against the hash if needed.


The Request Lifecycle

When a client makes a request, here’s the complete flow:

Client Request
      │
      ▼
┌─────────────────┐
│ 1. HTTP Listener │  ← Parse request, check TLS
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ 2. Audit Request │  ← Log the request to audit devices
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ 3. Authenticate  │  ← Validate token, check expiry
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ 4. Authorize     │  ← Check policies for path + capability
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ 5. Route         │  ← Direct to correct secrets engine
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ 6. Process       │  ← Secrets engine handles the request
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│ 7. Audit Response│  ← Log the response to audit devices
└────────┬────────┘
         │
         ▼
    Client Response

Ports and Networking

Port Purpose Protocol
8200 Client API & UI HTTPS (TLS required in production)
8201 Cluster communication (HA) HTTPS (mutual TLS)
# vault.hcl — listener configuration
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"
}

Quick Reference

Component Purpose
Barrier Encrypts all data with AES-256-GCM before storage
Storage Backend Persists encrypted data (Raft recommended)
Secrets Engines Generate, store, or encrypt secrets (pluggable)
Auth Methods Verify client identity, issue tokens
Audit Devices Log every operation (HMAC-protected)
Token Store Manages all Vault tokens and their properties
Policy Store Stores and evaluates access control policies

Next: Seal & Unseal