HashiCorp Vault Integration
Integrate Horizon Epoch with HashiCorp Vault for secure credential management.
Overview
Vault integration supports:
- Static secrets (KV v2)
- Dynamic database credentials
- PKI certificates for mTLS
- Multiple authentication methods
Prerequisites
- HashiCorp Vault server (1.x or later)
- Vault CLI (for setup)
- Network access from Horizon Epoch to Vault
Authentication Methods
Token Authentication
Simplest method, suitable for development:
from horizon_epoch import Config
config = Config(
vault_addr="https://vault.example.com:8200",
vault_token="hvs.xxx..."
)
export VAULT_ADDR="https://vault.example.com:8200"
export VAULT_TOKEN="hvs.xxx..."
AppRole Authentication
Recommended for applications:
config = Config(
vault_addr="https://vault.example.com:8200",
vault_auth_method="approle",
vault_role_id="xxx-xxx-xxx",
vault_secret_id="${VAULT_SECRET_ID}" # From env or file
)
Setup in Vault:
# Enable AppRole
vault auth enable approle
# Create policy
vault policy write horizon-epoch - <<EOF
path "secret/data/horizon-epoch/*" {
capabilities = ["read"]
}
path "database/creds/horizon-epoch-*" {
capabilities = ["read"]
}
EOF
# Create role
vault write auth/approle/role/horizon-epoch \
token_policies="horizon-epoch" \
token_ttl=1h \
token_max_ttl=4h
Kubernetes Authentication
For Kubernetes deployments:
config = Config(
vault_addr="https://vault.example.com:8200",
vault_auth_method="kubernetes",
vault_role="horizon-epoch"
)
AWS IAM Authentication
For AWS environments:
config = Config(
vault_addr="https://vault.example.com:8200",
vault_auth_method="aws",
vault_role="horizon-epoch-ec2"
)
KV Secrets (Static)
Store database credentials in KV v2:
# Store secret
vault kv put secret/horizon-epoch/postgres \
username=epoch_user \
password=secret123
config.add_postgres(
name="mydb",
host="db.example.com",
database="production",
vault_path="secret/data/horizon-epoch/postgres"
)
Dynamic Database Credentials
Vault can generate short-lived database credentials:
# Configure database secrets engine
vault secrets enable database
vault write database/config/postgres \
plugin_name=postgresql-database-plugin \
allowed_roles="horizon-epoch-*" \
connection_url="postgresql://{{username}}:{{password}}@db:5432/production" \
username="vault" \
password="vault-password"
vault write database/roles/horizon-epoch-readonly \
db_name=postgres \
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
default_ttl="1h" \
max_ttl="24h"
config.add_postgres(
name="mydb",
host="db.example.com",
database="production",
vault_role="database/creds/horizon-epoch-readonly"
)
PKI Certificates
For mTLS authentication:
# Enable PKI
vault secrets enable pki
# Configure PKI (simplified)
vault write pki/root/generate/internal \
common_name="Horizon Epoch CA"
vault write pki/roles/horizon-epoch-client \
allowed_domains="epoch.internal" \
allow_subdomains=true \
max_ttl="720h"
config.add_postgres(
name="mydb",
host="db.example.com",
vault_pki_role="pki/issue/horizon-epoch-client",
sslmode="verify-full"
)
Configuration File
# epoch.toml
[vault]
addr = "https://vault.example.com:8200"
auth_method = "approle"
role_id = "xxx-xxx-xxx"
secret_id_file = "/run/secrets/vault-secret-id"
[storage.postgres.production]
host = "db.example.com"
database = "production"
vault_path = "secret/data/horizon-epoch/postgres"
[storage.postgres.readonly]
host = "db.example.com"
database = "production"
vault_role = "database/creds/horizon-epoch-readonly"
Troubleshooting
Permission Denied
Error: permission denied on path "secret/data/..."
- Check policy is attached to token/role
- Verify path is correct (KV v2 uses
secret/data/prefix) - Check Vault audit log for details
Token Expired
Error: Vault token expired
- Token TTL may be too short
- Enable token renewal in config
- Use AppRole for automatic re-authentication
Connection Failed
Error: failed to connect to Vault
- Verify VAULT_ADDR is correct
- Check network connectivity
- Verify TLS certificates if using HTTPS
Certificate Issues
Error: x509: certificate signed by unknown authority
config = Config(
vault_addr="https://vault.example.com:8200",
vault_ca_cert="/path/to/ca.crt"
)
Best Practices
- Use AppRole or Kubernetes auth in production
- Enable audit logging in Vault
- Use dynamic credentials when possible
- Set appropriate TTLs - short enough for security, long enough for operations
- Rotate static secrets regularly
Next Steps
- AWS Secrets - Alternative cloud-native solution
- mTLS Authentication - Certificate-based auth
- Credential Providers - Overview of all providers