Command Palette

Search for a command to run...

GitHubGitHub

HashiCorp Vault Installation Guide

Install Vault 2.2, initialise and unseal the server, enable the KV v2 and AWS secrets engines, configure AppRole authentication, audit logging and automatic unsealing.

Vault is a secrets management platform. It stores tokens, passwords, certificates and encryption keys, and issues short-lived credentials to the applications that need them.

System Requirements

  • A 64-bit operating system (Linux, macOS, Windows, FreeBSD)
  • 2 GB RAM for a small deployment, 8 GB or more for a production cluster
  • A persistent disk for the Raft data store
  • TLS certificates for the listener in production
  • Root/sudo privileges to install the system service

Installation Instructions

Ubuntu / Debian (apt)

# Add the HashiCorp signing key
wget -O - https://apt.releases.hashicorp.com/gpg \
  | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
 
# Add the repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" \
  | sudo tee /etc/apt/sources.list.d/hashicorp.list
 
# Install
sudo apt update
sudo apt install -y vault
 
vault version

Configuration

Development

# Start a development server with an in-memory store
vault server -dev
 
# The root token is printed at startup
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='<root-token-from-the-log>'

Production (Integrated Storage / Raft)

Create /etc/vault.d/vault.hcl:

ui = true
 
api_addr = "https://vault.example.com:8200"
cluster_address = "https://vault.example.com:8201"
 
# Integrated Storage
storage "raft" {
  path = "/opt/vault/data"
  node_id = "vault-node-1"
 
  retry_join {
    node_id = "vault-node-2"
    peer_addr = "https://vault-node-2.example.com:8201"
  }
}
 
listener "tcp" {
  address     = "0.0.0.0:8200"
  cluster_address = "0.0.0.0:8201"
  tls_cert_file   = "/etc/vault.d/cert.pem"
  tls_key_file    = "/etc/vault.d/key.pem"
  tls_client_ca_file = "/etc/vault.d/ca.pem"
  tls_min_version = "tls12"
 
  # Vault 2.x bounds the size of the token headers (default 8 KB)
  max_token_header_size = 8192
}
 
# Enable the audit device before you store anything
disable_mlock = true
# Create the data directory with the right ownership
sudo mkdir -p /opt/vault/data
sudo chown -R vault:vault /opt/vault
sudo chmod 750 /opt/vault
 
# Start the service
sudo systemctl enable --now vault
sudo systemctl status vault
sudo journalctl -u vault -f

Initialising and Unsealing

# Initialise with 5 key shares and a threshold of 3
vault operator init -key-shares=5 -key-threshold=3
 
# Save the unseal keys and the root token somewhere safe
# Unseal with any 3 of the 5 keys
vault operator unseal <key1>
vault operator unseal <key2>
vault operator unseal <key3>
 
# Check the status
vault status
 
# Log in with the root token
vault login <root-token>

Automatic Unsealing

seal "awskms" {
  region     = "eu-central-1"
  key_id     = "arn:aws:kms:eu-central-1:123456789012:key/abcd-1234"
  access_key = ""
  secret_key = ""
  iam_role_arn = "arn:aws:iam::123456789012:role/vault-unseal"
}

Secrets Engines

# Enable the KV v2 engine (the default path is "secret")
vault secrets enable -path=secret kv-v2
 
# Check what is enabled
vault secrets list
 
# Write and read a secret
vault kv put secret/myapp/config username=myuser password=mypassword
vault kv get secret/myapp/config
vault kv get -format=json secret/myapp/config | jq -r '.data.data.password'
 
# Enable the AWS dynamic credentials engine
vault secrets enable aws
vault write aws/config/root \
  region=eu-central-1 \
  access_key=$AWS_ACCESS_KEY_ID \
  secret_key=$AWS_SECRET_ACCESS_KEY
 
# Issue short-lived credentials
vault read aws/creds/my-role

Authentication

# Enable AppRole — designed for machine identities
vault auth enable approle
 
# Create a role
vault write auth/approle/role/my-role \
    secret_id_ttl=10m \
    token_num_uses=10 \
    token_ttl=20m \
    token_max_ttl=30m \
    secret_id_num_uses=40
 
# Fetch a role id and a secret id
vault read -field=role_id auth/approle/role/my-role/role-id
vault write -f -field=secret_id auth/approle/role/my-role/secret-id
 
# Log in
vault write auth/approle/login role_id=<role-id> secret_id=<secret-id>
# Enable AWS IAM authentication for EC2, EKS and ECS workloads
vault auth enable aws
vault write auth/aws/config \
    type=iam \
    role_arn="arn:aws:iam::123456789012:role/vault-auth"
 
vault write auth/aws/role/my-role \
    bound_iam_principal_arn="arn:aws:iam::123456789012:role/my-app" \
    policies=my-policy \
    ttl=1h

Policies

Create app-policy.hcl:

path "secret/data/myapp/*" {
  capabilities = ["read", "list"]
}
 
path "auth/approle/login" {
  capabilities = ["create", "update"]
}
vault policy write app-policy app-policy.hcl

Audit Logging

Enable at least one audit device before you store any secrets — audit logs are the only record of who accessed what.

# File audit device
vault audit enable file file_path=/var/log/vault/audit.log
 
# Syslog audit device
vault audit enable syslog facility=local tag=vault
 
# List the active devices
vault audit list
# Rotate the root token and create a scoped one instead
vault token create -policy=app-policy -ttl=1h -explicit-max-ttl=4h

Upgrading

# 1. Back up the data directory
sudo systemctl stop vault
sudo tar -czf /var/backups/vault-$(date +%F).tar.gz -C /opt/vault data
sudo systemctl start vault
 
# 2. Upgrade the package
sudo apt update && sudo apt install --only-upgrade vault
 
# 3. Restart and check the seal status
sudo systemctl restart vault
vault status

Troubleshooting

Best Practices

  1. Use Integrated Storage (Raft) for production instead of the file backend.
  2. Enable automatic unsealing with a cloud KMS and never store unseal keys with the server.
  3. Enable audit devices before you store any secrets and ship the logs off-host.
  4. Use short-lived, scoped tokens — never hand out the root token to applications.
  5. Prefer dynamic credentials over static secrets; Vault issues AWS, database and SSH credentials on demand.
  6. Run at least three nodes in a cluster, spread across failure domains.
  7. Use TLS on the listener and a tls_min_version of tls12 or higher.
  8. Back up the Raft store and test the restore regularly.
  9. Use the Vault Agent to inject secrets into applications without them ever being written to disk.

Next Steps