Hashicorp Vault
Dokumentation für Hashicorp Vault - zentrale Secrets Management Lösung.
Overview
Hashicorp Vault ist ein Tool für das sichere Speichern und Verwalten von Secrets, Passwörtern, API-Keys, Zertifikaten und anderen sensiblen Daten.
Key Features:
- Sichere Speicherung von Secrets mit Verschlüsselung
- Dynamische Secrets (z.B. temporäre Datenbank-Credentials)
- Data Encryption as a Service
- Granulare Zugriffskontrolle via Policies
- Audit Logging aller Zugriffe
- Secret Rotation und Leasing
- Multi-Cloud und On-Premise Support
Architecture
┌─────────────────────────────┐
│ Hashicorp Vault │
│ │
│ ┌──────────────────────┐ │
│ │ Secrets Engines │ │
│ │ - KV (Key/Value) │ │
│ │ - Database │ │
│ │ - PKI │ │
│ │ - SSH │ │
│ └──────────────────────┘ │
│ │
│ ┌──────────────────────┐ │
│ │ Auth Methods │ │
│ │ - Token │ │
│ │ - LDAP/AD │ │
│ │ - AppRole │ │
│ │ - Kubernetes │ │
│ └──────────────────────┘ │
│ │
│ ┌──────────────────────┐ │
│ │ Audit Devices │ │
│ │ - File │ │
│ │ - Syslog │ │
│ └──────────────────────┘ │
└─────────────────────────────┘
▲
│ HTTPS API
│
┌────┴────────────┐
│ │
┌───▼───┐ ┌──────▼──────┐
│ CLI │ │ Web UI │
└───────┘ └─────────────┘
│ │
└────────┬────────┘
│
┌──────▼──────┐
│ Applications│
│ - Puppet │
│ - CI/CD │
│ - Scripts │
└─────────────┘Installation
Prerequisites
- Docker & Docker Compose installed
- Minimum 1GB RAM, 1 CPU core
- Storage for encrypted data
- TLS certificates for HTTPS (or Proxy like Traefik)
Docker Installation
Docker Compose Setup
Create docker-compose.yml:
version: '3.7'
networks:
vault:
traefik-net:
external: true
services:
vault-unseal:
image: ghcr.io/lrstanley/vault-unseal:0.7.2
networks:
- vault
volumes:
- /data/docker/vault/vault-unseal.yaml:/etc/vault-unseal.yaml
#command: sh -c "tail -f /dev/null"
command: "/usr/local/bin/vault-unseal -c /etc/vault-unseal.yaml"
vault:
image: hashicorp/vault:1.21 # Use a specific version in production, e.g., :1.17.0
# 1. Security: IPC_LOCK prevents memory swapping to disk
# This is critical for security in a persistent setup.
cap_add:
- IPC_LOCK
# 2. Ports: Vault API (8200) and Cluster Port (8201) exposed
#ports:
# - "8200:8200" # Vault API and UI
# - "8201:8201" # Raft Cluster Port (needed even for a single node)
# 3. Volumes: Ensure Persistence and Configuration Loading
volumes:
# Mount the HCL config file to the Vault config directory
- /data/docker/vault/config/vault.hcl:/vault/config/vault.hcl:ro
# Mount the named Docker volume for persistent storage
- /data/docker/vault/data:/vault/data
- /data/docker/vault/logs:/vault/logs
networks:
- traefik-net
- vault
deploy:
labels:
- "traefik.swarm.network=traefik-net"
- "traefik.enable=true"
- "traefik.http.routers.vault-iteas.rule=Host(`vault.iteas.cloud`)"
- "traefik.http.routers.vault-iteas.tls.certresolver=default"
- "traefik.http.services.vault-iteas.loadbalancer.server.port=8200"
# 4. Environment Variables
environment:
# Keep VAULT_ADDR for the Vault CLI inside the container
# This should be the address the container *knows* (localhost)
- VAULT_ADDR=http://127.0.0.1:8200
# IMPORTANT: Set VAULT_API_ADDR to the Traefik-exposed domain (HTTPS)
# This tells Vault what URL to use for external requests/UI links.
- VAULT_API_ADDR=https://vault.iteas.cloud
# 5. Command: Run Vault in Server Mode
# The container will use the vault.hcl config file.
#command: "server -config=/vault/config/vault.hcl"
#command: sh -c "tail -f /dev/null"
entrypoint: vault server -config /vault/config/vault.hcl
# 6. Health Check
# Ensures the service is actually running and responsive.
#healthcheck:
# test: ["CMD", "vault", "status"]
# interval: 10s
# timeout: 5s
# retries: 10Configuration
Create ./vault/config/vault.hcl:
# 1. Listener Configuration
# Vault must listen on the Docker bridge network interface (0.0.0.0)
# and expose its API on port 8200.
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = "true" # IMPORTANT: Disable TLS for a simple local test setup.
# In production, this MUST be set to "false" and proper
# certificates must be configured.
}
api_addr = "http://127.0.0.1:8200"
cluster_addr = "http://127.0.0.1:8201"
# 2. Storage Backend (Raft)
# Raft is the built-in storage engine and modern best practice.
# The path "/vault/data" is the persistent location inside the container.
storage "raft" {
path = "/vault/data"
node_id = "node1"
}
# 3. UI
ui = true
disable_mlock = "true"Create ./vault/vault-unseal.yaml:
---
# named environment that vault-unseal is running in, gets passed in when sending
# email alerts.
environment: dev
# delay between seal-checks of each vault node.
check_interval: 15s
# maximum delay between checks of each vault node. when an error occurs, we will
# add a backoff delay, up to this maximum.
max_check_interval: 30m
# list of vault nodes to check, must include http/https, and a port (unless 80/443).
vault_nodes:
- http://vault:8200
# unseal tokens necessary to unseal any of the given vaults in the above node
# list.
#
# WARNING: do not put enough tokens in this list that can be used to unseal a
# vault instance. I.e. if vault requires 3 of 5 tokens, DO NOT PUT 3 TOKENS HERE.
# the goal is to put less than the required amount, but have more instances of
# vault-unseal setup with the other missing tokens from the list. this ensures
# that if the server was compromised, they don't have all of the needed tokens.
#
# i.e. 1 instance of vault-unseal on each of the three nodes, each with two
# tokens. given A, B, and C tokens required, each instance should have the
# following tokens:
# * 1: AB
# * 2: BC
# * 3: AC
unseal_tokens:
- xyz
# skip tls checks for the given vault instance. useful if your instance doesn't
# have a certificate which has all of the server hostnames on it.
tls_skip_verify: false
# email notifications. setting this to false will disable all notifications.
email:
enabled: false
hostname: smtp.hostname.com
port: 25
username: your-username
password: your-password
# address to send from.
from_addr: your-alerts@hostname.com
# addresses to send to. the first will be the TO, the second and on will be CC'd
# onto the message.
send_addrs:
- your-alert-group@hostname.com
- example-user@hostname.com
# Skip TLS certificate validation.
tls_skip_verify: false
# Require TLS for SMTP connections.
# The default is opportunistic.
mandatory_tls: false
# notifications in vault-unseal queue up to prevent email spam (e.g. 20 alerts
# in one email). this is the max allotted time an event can be queued before
# the queue is sent as a notification.
notify_max_elapsed: 10m
# queue delay is the amount of time vault-unseal waits after the last received
# notification, before it sends all of them in bulk.
notify_queue_delay: 60s
allow_single_node: trueDirectory Structure
# Create directory structure
mkdir -p vault/{config,data,logs}Start Vault
# Start Vault container
docker-compose up -d
# Check logs
docker-compose logs -f vault
# Verify container is running
docker-compose psInitialize Vault
# Access Vault container
docker exec -it vault sh
# Set Vault address
export VAULT_ADDR='https://127.0.0.1:8200'
export VAULT_SKIP_VERIFY=true # Only for self-signed certs
# Initialize (ONLY ONCE!)
vault operator init -key-shares=1 -key-threshold=1
# Output example:
# Unseal Key 1: xxx
# Initial Root Token: s.xxxxxxxxxxxxxxxxxxxxxxxxSave Unseal Keys and Root Token
Die Unseal Keys und der Root Token müssen sicher gespeichert werden!
Ohne diese Keys kann Vault nicht entsperrt werden und alle Daten sind verloren.
Unseal Vault
Der Vault kann direkt via Web-UI oder CLI entsperrt werden.
# From host machine (requires vault CLI)
export VAULT_ADDR='https://vault.iteas.cloud'
vault operator unseal <key1>
# Or from inside container
docker exec -it vault sh
export VAULT_ADDR='https://127.0.0.1:8200'
export VAULT_SKIP_VERIFY=true
vault operator unseal <key1>
# Check status
vault statusVault CLI Access from Host
For convenience, install Vault CLI on the host machine: https://developer.hashicorp.com/vault/install
# Configure environment for linux
export VAULT_ADDR='https://vault.iteas.cloud'
# or for windows powershell
$env:VAULT_ADDR = 'https://vault.iteas.cloud'
# Verify
vault statusBasic Usage
Authentication
# Login with root token
vault login <root_token>
# Login with Microsoft OIDC
vault login -method=oidc -path=oidcSecrets Engines
Key/Value (KV) Secrets
# Enable KV v2 secrets engine
vault secrets enable -path=secret kv-v2
# Write a secret
vault kv put secret/myapp/config \
username="admin" \
password="SuperSecret123"
# Read a secret
vault kv get secret/myapp/config
# Read specific field
vault kv get -field=password secret/myapp/config
# List secrets
vault kv list secret/myapp
# Delete secret
vault kv delete secret/myapp/configDatabase Dynamic Secrets
# Enable database secrets engine
vault secrets enable database
# Configure database connection
vault write database/config/mysql \
plugin_name=mysql-database-plugin \
connection_url="{{username}}:{{password}}@tcp(mysql.iteas.tools:3306)/" \
allowed_roles="readonly,readwrite" \
username="vault" \
password="vault-password"
# Create role for dynamic credentials
vault write database/roles/readonly \
db_name=mysql \
creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}'; GRANT SELECT ON *.* TO '{{name}}'@'%';" \
default_ttl="1h" \
max_ttl="24h"
# Generate dynamic credentials
vault read database/creds/readonlyPolicies
Policies definieren, wer auf welche Secrets zugreifen darf.
Create Policy
Create app-policy.hcl:
# Read-only access to app secrets
path "secret/data/myapp/*" {
capabilities = ["read", "list"]
}
# Write access to specific path
path "secret/data/myapp/temp/*" {
capabilities = ["create", "update", "delete"]
}Apply policy:
vault policy write app-policy app-policy.hcl
# List policies
vault policy list
# Read policy
vault policy read app-policyTokens
# Create token with specific policy
vault token create -policy=app-policy
# Create renewable token
vault token create -policy=app-policy -renewable -ttl=720h
# Lookup token info
vault token lookup <token>
# Renew token
vault token renew <token>
# Revoke token
vault token revoke <token>Authentication Methods
Enable LDAP Auth
# Enable LDAP
vault auth enable ldap
# Configure LDAP
vault write auth/ldap/config \
url="ldaps://ldap.iteas.tools" \
userdn="ou=users,dc=iteas,dc=tools" \
groupdn="ou=groups,dc=iteas,dc=tools" \
binddn="cn=vault,ou=serviceaccounts,dc=iteas,dc=tools" \
bindpass="password"
# Map LDAP group to policy
vault write auth/ldap/groups/admins policies=admin-policy
vault write auth/ldap/groups/developers policies=dev-policy
# Login with LDAP
vault login -method=ldap username=johnEnable AppRole Auth
# Enable AppRole
vault auth enable approle
# Create role
vault write auth/approle/role/my-app \
token_policies="app-policy" \
token_ttl=1h \
token_max_ttl=4h
# Get Role ID
vault read auth/approle/role/my-app/role-id
# Generate Secret ID
vault write -f auth/approle/role/my-app/secret-id
# Login with AppRole
vault write auth/approle/login \
role_id="<role_id>" \
secret_id="<secret_id>"Security Best Practices
Enable Audit Logging
bashvault audit enable file file_path=/var/log/vault/audit.logUse Least Privilege Policies - Grant minimal necessary permissions
Enable TLS - Always use HTTPS for Vault API
Rotate Root Token
bashvault token revoke <old_root_token> vault operator generate-rootRegular Backups - Backup Vault data and unseal keys
Monitor Seal Status - Alert if Vault becomes sealed
Use Auto-Unseal - Consider cloud KMS for auto-unseal (AWS KMS, Azure Key Vault)
Token TTL Limits - Set reasonable token lifetimes
Secret Rotation - Regularly rotate credentials
Access Control - Use network policies to restrict access
Monitoring & Maintenance
Health Check
# Check Vault status
vault status
# Check seal status
vault operator seal-status
# Check leader (in HA setup)
vault operator raft list-peers
# Check Docker container health
docker-compose ps
docker-compose logs vault --tail=50Metrics
Vault exposes metrics via /v1/sys/metrics endpoint.
# Get metrics
curl -H "X-Vault-Token: $VAULT_TOKEN" \
https://vault.iteas.cloud/v1/sys/metricsBackup & Recovery
Backup
# Backup using raft snapshot (Raft storage only)
vault operator raft snapshot save backup.snapRestore
# Restore raft snapshot
vault operator raft snapshot restore backup.snap
# Unseal after restore
vault operator unseal <key1>Raft Snapshot zurückspielen
Wenn Vault mit Raft-Storage betrieben wird, kann ein Snapshot wie folgt wiederhergestellt werden:
1. Snapshot wiederherstellen (Vault muss laufen und unsealed sein):
# Vault authentifizieren
vault login <root_token>
# Snapshot mit -force zurückspielen
vault operator raft snapshot restore -force backup.snap2. Alternative: Restore während Vault sealed ist
Wenn Vault noch sealed ist, kann der Snapshot auch direkt zurückgespielt werden:
# Zunächst unseal durchführen
vault operator unseal <key>
# Nach Authentifizierung Snapshot restore
vault login <root_token>
vault operator raft snapshot restore -force backup.snap
# Nach erfolgreichem Restore wird Vault automatisch neu versiegelt
# Erneut unseal durchführen
vault operator unseal <key>Wichtige Hinweise:
- Der
-forceParameter überschreibt bestehende Daten - Nach dem Restore wird Vault automatisch sealed und muss erneut entsperrt werden
- Alle Vault-Knoten im Cluster müssen gestoppt sein, bevor ein Snapshot restored wird
- Bei HA-Setup: Restore auf dem Leader-Knoten durchführen
HA-Cluster Restore:
# 1. Alle Vault-Knoten stoppen
docker-compose stop vault-1 vault-2 vault-3
# 2. Nur ersten Knoten starten
docker-compose up -d vault-1
# 3. Unseal durchführen
vault operator unseal <key1>
# 4. Snapshot restore
vault login <root_token>
vault operator raft snapshot restore -force backup.snap
# 5. Erneut unseal
vault operator unseal <key1>
# 6. Andere Knoten starten (joinen automatisch)
docker-compose up -d vault-2 vault-3
# 7. Alle Knoten unsealen
vault operator unseal <key> # Auf jedem KnotenHigh Availability (HA)
Für Production-Umgebungen sollte Vault in HA-Konfiguration betrieben werden.
Raft Storage HA with Docker
Docker Compose HA Setup
Create docker-compose-ha.yml:
version: '3.8'
services:
vault-1:
image: hashicorp/vault:1.15
container_name: vault-1
restart: unless-stopped
ports:
- "8200:8200"
- "8201:8201"
environment:
VAULT_ADDR: 'https://0.0.0.0:8200'
VAULT_API_ADDR: 'https://vault-1.iteas.tools:8200'
VAULT_CLUSTER_ADDR: 'https://vault-1.iteas.tools:8201'
volumes:
- ./vault-1/config:/vault/config:ro
- ./vault-1/data:/vault/data
- ./vault-1/tls:/vault/tls:ro
cap_add:
- IPC_LOCK
command: server
networks:
- vault-network
vault-2:
image: hashicorp/vault:1.15
container_name: vault-2
restart: unless-stopped
ports:
- "8210:8200"
- "8211:8201"
environment:
VAULT_ADDR: 'https://0.0.0.0:8200'
VAULT_API_ADDR: 'https://vault-2.iteas.tools:8200'
VAULT_CLUSTER_ADDR: 'https://vault-2.iteas.tools:8201'
volumes:
- ./vault-2/config:/vault/config:ro
- ./vault-2/data:/vault/data
- ./vault-2/tls:/vault/tls:ro
cap_add:
- IPC_LOCK
command: server
networks:
- vault-network
vault-3:
image: hashicorp/vault:1.15
container_name: vault-3
restart: unless-stopped
ports:
- "8220:8200"
- "8221:8201"
environment:
VAULT_ADDR: 'https://0.0.0.0:8200'
VAULT_API_ADDR: 'https://vault-3.iteas.tools:8200'
VAULT_CLUSTER_ADDR: 'https://vault-3.iteas.tools:8201'
volumes:
- ./vault-3/config:/vault/config:ro
- ./vault-3/data:/vault/data
- ./vault-3/tls:/vault/tls:ro
cap_add:
- IPC_LOCK
command: server
networks:
- vault-network
networks:
vault-network:
driver: bridgeConfiguration for HA Node
Create ./vault-1/config/vault.hcl:
ui = true
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/vault/tls/vault.crt"
tls_key_file = "/vault/tls/vault.key"
}
storage "raft" {
path = "/vault/data"
node_id = "vault-1"
retry_join {
leader_api_addr = "https://vault-2:8200"
leader_ca_cert_file = "/vault/tls/ca.crt"
}
retry_join {
leader_api_addr = "https://vault-3:8200"
leader_ca_cert_file = "/vault/tls/ca.crt"
}
}
api_addr = "https://vault-1.iteas.tools:8200"
cluster_addr = "https://vault-1.iteas.tools:8201"Note: Create similar configs for vault-2 and vault-3 with respective node_id values.
Troubleshooting
Vault is Sealed
Symptom: vault status shows Sealed: true
Solution:
vault operator unseal <key1>
vault operator unseal <key2>
vault operator unseal <key3>Permission Denied
Symptom: Error: permission denied
Solution:
- Check token capabilities:
vault token capabilities <token> <path> - Review policy:
vault policy read <policy_name> - Verify token has correct policy attached
Connection Refused
Symptom: Cannot connect to Vault
Solution:
- Check Docker container:
docker-compose ps - Check container logs:
docker-compose logs vault - Verify listener address in config
- Check firewall:
firewall-cmd --list-all - Test connectivity:
curl -k https://vault.iteas.tools:8200/v1/sys/health - Check if container is running:
docker exec -it vault vault status
Token Expired
Symptom: Error: invalid token
Solution:
# Renew if renewable
vault token renew
# Or login again
vault login <method>Resources
Integration
Vault kann mit verschiedenen Tools und Plattformen integriert werden:
- Puppet/Ansible/Chef - Configuration Management
- Kubernetes - Service Account Auth
- CI/CD - Jenkins, GitLab CI, GitHub Actions
- Cloud Providers - AWS, Azure, GCP
- Databases - MySQL, PostgreSQL, MongoDB
- Applications - Custom applications via API
Siehe spezifische Integrations-Dokumentation:
Docker Management
Common Docker Commands
# Start Vault
docker-compose up -d
# Stop Vault
docker-compose stop
# Restart Vault
docker-compose restart
# View logs
docker-compose logs -f vault
# Access Vault shell
docker exec -it vault sh
# Remove container (data persists in volumes)
docker-compose down
# Remove container and volumes (WARNING: deletes data!)
docker-compose down -vAuto-Start on Boot
Ensure Docker is set to start on boot:
sudo systemctl enable dockerDocker Compose with restart: unless-stopped will automatically start containers on boot.
Updates
# Pull latest Vault image
docker-compose pull
# Recreate container with new image
docker-compose up -d
# Unseal after update
vault operator unseal <key1>
vault operator unseal <key2>
vault operator unseal <key3>Notes
ITeas Setup
Vault Server: https://vault.iteas.cloud
Installation Method: Docker mit Docker Compose
Storage Backend: File storage (single node) / Raft (High Availability)
Primary Integration: Puppet Hiera Backend
Docker Volumes:
- Configuration:
./vault/config - Data:
./vault/data - Logs:
./vault/logs
