Vault’s TLS certificate is actually managed by Vault itself, not by an external CA, which is a common misconception.
Let’s get Vault running in a way that’s actually safe for production, meaning it’s secured with TLS and can actually save its state somewhere persistent.
First, we need to generate some TLS certificates. Vault needs to serve over HTTPS, and for production, you absolutely don’t want to use the self-signed certificates it can generate on its own. You’ll want certificates signed by a CA that your clients trust. For this example, we’ll assume you have a CA and have generated a server certificate and key.
# Assuming you have your CA cert (ca.pem), server cert (server.pem), and server key (server.key)
# For testing, you can generate self-signed certs, but this is NOT for production:
# openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.pem -days 365 -nodes -subj "/CN=vault.example.com"
# openssl x509 -outform pem -in server.pem -out ca.pem # This is NOT a real CA, just for demo self-signing
Next, we need to configure Vault to use these certificates and point it to a durable storage backend. For production, you should never use the default in-memory storage. That means all your secrets vanish when Vault restarts. A common and robust choice is Consul.
Here’s a basic vault.hcl configuration file you’d place in /etc/vault.d/vault.hcl:
storage "consul" {
address = "127.0.0.1:8500"
path = "vault/"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert = "/etc/vault.d/server.pem"
tls_key = "/etc/vault.d/server.key"
tls_disable = 0 # Ensure TLS is enabled
}
api_addr = "https://vault.example.com:8200"
cluster_addr = "https://vault.example.com:8201" # For HA setups
ui = true
Let’s break down what’s happening here:
storage "consul": This tells Vault to use Consul as its storage backend.addressis where Consul is running, andpathis the KV prefix within Consul where Vault will store its data.listener "tcp": This configures the network listener.addressis the interface and port Vault will bind to.tls_certandtls_key: These point to your server’s TLS certificate and private key.tls_disable = 0: This explicitly enables TLS. A value of1would disable it, which is a grave security error.
api_addr: This is the address that clients will use to communicate with Vault. It must be an HTTPS URL if you’ve enabled TLS.cluster_addr: For high-availability (HA) setups, this is the address that Vault nodes use to communicate with each other. It also needs to be HTTPS.ui = true: This enables the built-in web UI, which is super handy.
Before starting Vault, ensure Consul is running and accessible at 127.0.0.1:8500. If you’re using a different address, update the storage block accordingly.
To start Vault with this configuration, you would typically run:
vault server -config=/etc/vault.d/vault.hcl
If you’re setting up Vault as a systemd service (which you absolutely should for production), your service file (/etc/systemd/system/vault.service) would look something like this:
[Unit]
Description=HashiCorp Vault
Documentation=https://www.vaultproject.io/docs/
After=network.target
[Service]
Environment=VAULT_ADDR=https://vault.example.com:8200
Environment=VAULT_TLS_CACERT=/etc/vault.d/ca.pem # If your client needs to trust the server cert's CA
User=vault
Group=vault
ExecStart=/usr/local/bin/vault server -config=/etc/vault.d/vault.hcl
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Notice VAULT_ADDR and VAULT_TLS_CACERT in the Environment section. VAULT_ADDR should match your api_addr and VAULT_TLS_CACERT is essential if you’re using a custom CA that clients (including the vault CLI) need to trust.
After starting Vault, you’ll need to initialize it and unseal it.
# On a machine that can reach the Vault server
export VAULT_ADDR='https://vault.example.com:8200'
# Initialize Vault (only do this once)
vault operator init > init.txt
# Take the keys from init.txt and unseal Vault
# You'll need at least M/N unseal keys, where M is the threshold
vault operator unseal <unseal_key_1>
vault operator unseal <unseal_key_2>
# ... and so on until the threshold is met
The VAULT_ADDR environment variable is critical for the vault CLI to know where to send commands. The api_addr in the vault.hcl config is what the Vault server tells other Vault servers (in an HA cluster) or clients about itself, while VAULT_ADDR is what your client uses to connect to Vault. They often, but not always, match.
The cluster_addr is used by Vault nodes to discover and communicate with each other for replication and consensus. If your nodes are running on different IPs or hostnames, this must reflect that. It’s also crucial that cluster_addr uses HTTPS when TLS is enabled on the listener, otherwise, the cluster communication will be unencrypted.
When Vault starts, it binds to the IP address specified in listener.tcp.address. If you use 0.0.0.0, it binds to all available network interfaces. For stricter security, you might bind to a specific IP address (e.g., 192.168.1.100). Also, ensure that the api_addr and cluster_addr are resolvable by your clients and other Vault nodes, respectively. If you’re using hostnames like vault.example.com, make sure your DNS is configured correctly.
After you’ve initialized and unsealed Vault, you’ll need to set the root token. The root token is printed to the console after a successful initialization and is also stored in the init.txt file. You’ll use this token to authenticate your initial login.
# From init.txt
export VAULT_TOKEN='<your-root-token>'
vault status
The VAULT_TOKEN environment variable is how your CLI session authenticates. You’ll want to use Vault’s authentication methods (like AppRole, Kubernetes, etc.) to generate dynamic tokens for applications and users instead of using the root token directly for day-to-day operations.
The most surprising part about the TLS configuration is that Vault itself can act as a Certificate Authority (CA) for its own internal services and even issue certificates to clients. This is often overlooked because most production setups integrate with existing corporate CAs for their primary TLS certificates. However, Vault’s built-in CA capabilities are powerful for managing secrets related to PKI, but also for securing inter-service communication within a Vault cluster or with trusted clients.
The next thing you’ll want to explore is setting up Vault in High Availability mode to ensure resilience.