Last updated: 2026-06-25
HashiCorp Vault TLS/SSL Configuration Guide
This guide provides recommended TLS/SSL settings for HashiCorp Vault, a secrets management tool. Vault stores and controls access to sensitive data such as API keys, passwords, and certificates. TLS is critical for Vault because all secrets transit the network through its API.
Prerequisites
- HashiCorp Vault 1.19 (LTS) or later
- A valid SSL/TLS certificate
- Vault is built with Go's
crypto/tls, which provides strong TLS defaults
Certificate Setup
Vault needs a certificate that includes all hostnames and IP addresses clients will use to connect:
chmod 640 /etc/vault/ssl/privkey.pem
chown vault:vault /etc/vault/ssl/privkey.pem
chmod 644 /etc/vault/ssl/fullchain.pem
Listener Configuration
Vault's TLS settings are configured in the listener stanza of the Vault configuration file (/etc/vault.d/vault.hcl).
Basic TLS Setup
listener "tcp" {
address = "[::]:8200"
tls_cert_file = "/etc/vault/ssl/fullchain.pem"
tls_key_file = "/etc/vault/ssl/privkey.pem"
}
Setting
tls_disable = truedisables TLS entirely. Never do this in production. Vault will refuse to start in production mode without TLS unless explicitly disabled, and all secrets would transit the network in plaintext.
Minimum TLS Version
listener "tcp" {
address = "[::]:8200"
tls_cert_file = "/etc/vault/ssl/fullchain.pem"
tls_key_file = "/etc/vault/ssl/privkey.pem"
tls_min_version = "tls12"
}
Available values: tls10, tls11, tls12, tls13.
Cipher Suites
Vault uses Go's cipher suite names. Configure allowed cipher suites for TLS 1.2 (TLS 1.3 ciphers are not configurable in Go and are always secure):
listener "tcp" {
address = "[::]:8200"
tls_cert_file = "/etc/vault/ssl/fullchain.pem"
tls_key_file = "/etc/vault/ssl/privkey.pem"
tls_min_version = "tls12"
tls_cipher_suites = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
}
Client Certificate Authentication
To require clients to present a TLS certificate (mutual TLS):
listener "tcp" {
address = "[::]:8200"
tls_cert_file = "/etc/vault/ssl/fullchain.pem"
tls_key_file = "/etc/vault/ssl/privkey.pem"
tls_min_version = "tls12"
tls_client_ca_file = "/etc/vault/ssl/ca.pem"
tls_require_and_verify_client_cert = true
}
See RFC 8446 ยง4.3.2 for the TLS Certificate Request specification, and Wikipedia: Mutual authentication for a general overview.
Disable Client Cache Headers
For additional security, disable client-side caching of Vault responses:
listener "tcp" {
address = "[::]:8200"
tls_cert_file = "/etc/vault/ssl/fullchain.pem"
tls_key_file = "/etc/vault/ssl/privkey.pem"
tls_min_version = "tls12"
tls_disable_client_certs = false
custom_response_headers {
"default" = {
"Strict-Transport-Security" = ["max-age=63072000; includeSubDomains; preload"]
}
}
}
Cluster TLS
In high-availability (HA) deployments, Vault nodes communicate with each other through the cluster port. Configure TLS for cluster communication:
listener "tcp" {
address = "[::]:8200"
cluster_address = "[::]:8201"
tls_cert_file = "/etc/vault/ssl/fullchain.pem"
tls_key_file = "/etc/vault/ssl/privkey.pem"
tls_min_version = "tls12"
}
Vault automatically uses TLS for cluster communication when the listener has TLS enabled. For separate cluster certificates:
cluster_addr = "https://vault-node1.example.com:8201"
Complete Configuration
storage "raft" {
path = "/opt/vault/data"
node_id = "vault-node1"
}
listener "tcp" {
address = "[::]:8200"
cluster_address = "[::]:8201"
tls_cert_file = "/etc/vault/ssl/fullchain.pem"
tls_key_file = "/etc/vault/ssl/privkey.pem"
tls_min_version = "tls12"
tls_cipher_suites = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
custom_response_headers {
"default" = {
"Strict-Transport-Security" = ["max-age=63072000; includeSubDomains; preload"]
}
}
}
api_addr = "https://vault.example.com:8200"
cluster_addr = "https://vault-node1.example.com:8201"
ui = true
Vault as a CA (PKI Secrets Engine)
Vault can also act as a certificate authority using the PKI secrets engine. This is useful for issuing TLS certificates to other services:
vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki
vault write pki/root/generate/internal \
common_name="Internal CA" \
ttl=87600h
vault write pki/config/urls \
issuing_certificates="https://vault.example.com:8200/v1/pki/ca" \
crl_distribution_points="https://vault.example.com:8200/v1/pki/crl"
Client Configuration
Environment Variables
export VAULT_ADDR="https://vault.example.com:8200"
export VAULT_CACERT="/path/to/ca.pem"
For mutual TLS:
export VAULT_CLIENT_CERT="/path/to/client-cert.pem"
export VAULT_CLIENT_KEY="/path/to/client-key.pem"
CLI Usage
vault status -ca-cert=/path/to/ca.pem -address=https://vault.example.com:8200
Skip Verification (Development Only)
export VAULT_SKIP_VERIFY=true
Never use
VAULT_SKIP_VERIFYin production. This disables all certificate verification.
Security Notes
Vault uses Go's crypto/tls package, which has a different vulnerability history than OpenSSL:
- POODLE (CVE-2014-3566, 2014): SSL 3.0 has never been supported in Go's TLS implementation.
- BEAST (CVE-2011-3389, 2011): Mitigated by recommending TLS 1.2 as the minimum; AEAD-only ciphers eliminate the CBC padding oracle.
- CRIME (CVE-2012-4929, 2012): TLS compression is not supported in Go's
crypto/tls. - Lucky13 (2013): AEAD-only cipher list eliminates CBC padding timing side-channels entirely.
- FREAK (CVE-2015-0204, 2015): EXPORT-grade ciphers have never been supported in Go's
crypto/tls. - LOGJAM (CVE-2015-4000, 2015): DHE key exchange is not offered by default in Go; only ECDHE is used.
- Sweet32 (CVE-2016-2183, 2016): 3DES was removed from Go's default cipher list in Go 1.23 (August 2024) and is excluded from the recommended configuration.
- ROBOT (2017): Static RSA key exchange is not offered in Go's
crypto/tls; only ECDHE is used. - Downgrade attacks: Go's
crypto/tlsdoes not perform insecure version-fallback retries, and TLS 1.3 has built-in downgrade protection.
The following are not addressable through TLS configuration alone:
- Heartbleed (CVE-2014-0160, 2014): Not applicable. Go's
crypto/tlsis an independent TLS implementation and was never affected by Heartbleed. - BREACH (CVE-2013-3587, 2013): Vault exposes a REST API over HTTPS. If HTTP response compression is enabled by a reverse proxy, apply BREACH countermeasures at that layer; TLS configuration cannot prevent it.
- DROWN (CVE-2016-0800, 2016): Not applicable. Go's
crypto/tlsdoes not support SSLv2.
Verification
Start or restart Vault:
systemctl restart vault
Check Vault's status:
vault status
Test the TLS connection:
openssl s_client -connect vault.example.com:8200
Verify the certificate details:
curl --cacert /path/to/ca.pem https://vault.example.com:8200/v1/sys/health