Hashicorp Vault Setup
Here are steps for setting up a root and intermediate CA using Hashicorp Vault, on Ubuntu 24.
References
Lots of steps were taken from here: https://developer.hashicorp.com/vault/tutorials/secrets-management/pki-engine
Server Setup
Before installing Vault, perform steps from this page, to setup the server: Ubuntu Host Setup
Install Vault
Here are three lines to install vault.
First, we will setup the package source keys…
sudo wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
Now, add the package source entry…
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
Now, install vault…
sudo apt update && sudo apt install vault
Clustered Config
NOTE: If you are standing up a single node vault, skip this section.
Before starting the vault service, we need to setup the cluster configuration.
Open the config file at: /etc/vault.d/vault.hcl
We have created the following vault.hcl file for a cluster node that has an:
- IP = 192.168.75.24
- node_id = vault0204
# CopyrightHTTPS (c)listener
HashiCorp,listener Inc."tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/opt/vault/tls/tls.crt"
tls_key_file = "/opt/vault/tls/tls.key"
}
# SPDX-License-Identifier:Vault BUSL-1.1Configuration for Clustering.
# FullCreated configurationon options can be found at https://developer.hashicorp.com/vault/docs/configuration20250901
ui = true
cluster_name = "prod-vault"
# recommended with Integrated Storage
disable_mlock = true
# Advertise addresses (MUST be correct & reachable)
# Define the external API address that clients will use to communicate with this Vault node.
# set per node
api_addr = "https://vault-1.example.com:8200"
api_addr = "https://192.168.75.24:8200"
# Define the internal address used by Vault nodes to communicate with this Vault node.
# Vault ignores the scheme of this URL, so it doesn't matter if http or https.
# set per node (node's intra-cluster IP:8201)
cluster_addr = "https://192.168.75.24:8201"
#mlocklistener "tcp" {
address = true"0.0.0.0:8200"
tls_disable = 0
tls_cert_file = "/etc/vault.d/tls/vault.crt"
tls_key_file = "/etc/vault.d/tls/vault.key"
tls_client_ca_file = "/etc/vault.d/tls/ca.crt"
# Uncommentedoptional: this,require toclient disablecerts mlockfrom whenautomation:
using# Integrated Storage.
disable_mlocktls_require_and_verify_client_cert = true"true"
}
# Updated to use raft backend (Integrated Storage).
storage "raft" {
path = "/opt/vault/data"raft"
# unique on each node
node_id = "vault0204"
}
# HTTPAuto-join listenerpeers #listener(preferred "tcp"over manual joins)
retry_join {
# addressleader_api_addr = "127.0.0.1:https://vault-1.example.com:8200"
# tls_disable = 1
#}
# HTTPS listener
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_fileleader_ca_cert_file = "/opt/vault/etc/vault.d/tls/tls.ca.crt"
tls_key_file}
retry_join {
leader_api_addr = "https://vault-2.example.com:8200"
leader_ca_cert_file = "/opt/vault/etc/vault.d/tls/tls.key"ca.crt"
}
retry_join {
leader_api_addr = "https://vault-3.example.com:8200"
leader_ca_cert_file = "/etc/vault.d/tls/ca.crt"
}
}
# Recommended health endpoint behavior for LBs
# (defaults are fine; LB should treat 200 as active, 429 as standby, 503 sealed)
# See /v1/sys/health docs for details.
Once installed, we need to enable and start the vault services, with these lines:
sudo systemctl daemon-reload
sudo systemctl start vault
sudo systemctl enable vault
sudo systemctl status vault
You should be able to verify that the vault service is active by call this:
https://<host-ip>:8200/v1/sys/seal-status
NOTE: Use your VM’s IP, in the above.
If successful, the above call will return something like this:
{
"type":"shamir",
"initialized":false,
"sealed":true,
"t":0,
"n":0,
"progress":0,
"nonce":"",
"version":"1.17.6",
"build_date":"2024-09-24T19:48:40Z",
"migration":false,
"recovery_seal":false,
"storage_type":"file"
}
Vault Configuration
Edit the config file at: /etc/vault.d/vault.hcl
Specifically, you want to set the tls cert/key paths to your own domain certs.
As well, you may want to limit the listener to just a single address, since the default is for all adapters on the host.
Once done, save the config update and restart the service.
sudo systemctl restart vault.service
Vault User
The installer created a user called, vault, and the service runs under it.
But, the default keys are restricted to root permissions.
So, we need to fix access to certificates.
For this, we will create a group to make it easier to control and test access to certs and keys.
sudo groupadd pki
And, we will add the vault user to the group:
sudo usermod -a -G pki vault
Vault CLI Comms
For the vault command to communicate with the running service, we must set an env variable for it:
export VAULT_ADDR=https://your_domain:8200
NOTE: You may have to set the above to http, if you haven’t given vault a valid ssl cert, yet.
Initialize the Vault
In order for the vault service to manage secrets, you must initialize its store.
To do this, you need to run the following:
vault operator init -key-shares=3 -key-threshold=2
You can change the key shares and threshold based on your risk profile.
The vault CLI will respond with something like this:
Unseal Key 1: eZcJeydRrqeSMZ1zTN+VVll9TFT2KvJy7VlnxUgtvuz5
Unseal Key 2: ntmqCKq8rgNnKT1YSLCjVmCCZBAA3NwUeqxIyRpYD4Wm
Unseal Key 3: 3FK1+Hsorh4p8/L9mki3VskaEU2eQhLqGOI/pJkTHMbx
Initial Root Token: s.hY0ieybfDqCadz7JpL88uO3x
Save these values in a secure location, as this is the only time you will receive them.
Now, you can run the vault status command, and see it has changed to Initialized=true.
Run this to get vault status:
vault status
Now, you need to unseal the vault, so it can be used.
Notice the vault status showed an unseal progress of 0/2.
This means, that at least two more unseal tokens must be submitted for it to be available for access.
Enter enough tokens to unlock your vault with this command, and paste in one of the tokens when prompted:
vault operator unseal
Once the unseal threshold has been met, the Sealed state will become ‘false’.
Your vault is available for access.
Log into its UI, here: http://<host-ip>:8200/
You will be prompted to enter your root token, here:
If successful, you will see the root user’s dashboard:
Now, you should create a secrets engine, to store things.
The one that makes the most sense, first, is to make a KV store.
You should be able to make a kv secrets store (actually, a kv-v2 store) from the dashboard:
The above will create the secrets store at the path: /kv
You can change this if needed.
Once created, you will see the new empty store:
Starting the PKI Engine
NOTE: From here down, is steps for creating a Root CA.
If you are setting up an Intermediate CA, skip to ‘Configure Intermediate CA’.
For Vault to serve as a root CA, you have to add the PKI secrets engine.
To do this, enable the pki secrets engine:
For a Root CA, set the Max lease time to as long as possible, as the root CA will be offlined after generation.
Once initialized, it will look like this:
For a root CA, click Configure PKI to begin setup.
Choose the Generate Root option.
Set Type to Internal.
Set your Common name. Usually, this is a domain with a private TLD suffix.
Set the issuer name.
Set a TTL that is maxed out: 87600 hours.
Scroll down and fill in the issuer URLs, matching the origin for your root CA host:
When finished, click Done, to generate the root CA key and certificate.
You will see a page like this:
Copy out the root CA certificate, and save it to a file, named: ogsofttech.lan_ca.crt
Install it on all machines of the local network, so they will recognized the signed SSL certs of hosts.
Root CA Rotation
To make things easier, when it comes time to rotate your root CA key, add a role, now.
Click PKI.
Click Roles.
Click Create Role.
Give the new role a name that you will recognize as the root CA rotation role: CA_rotation_role
Leave the rest of the fields empty, and click Create.
Now, you have a working root CA key/cert for your network.
We will use it to sign the certificate of an Intermediate CA, that will do all the actual work.
And, we will offline the root CA.
Intermediate CA
To properly sign certificates, you will want to generate an Intermediate CA that will do all the actual issuing. And, you will offline the root CA, after the Intermediate CA is usable.
Repeat the above steps, down to:
Now, you are ready to generate an intermediate CA.
Configure Intermediate CA
For Vault to serve as an Intermediate CA, you have to add the PKI secrets engine.
To do this, enable the pki secrets engine:
For an Intermediate CA, set the Max lease time to 43800 hours, and enable the engine.
Once initialized, it will look like this:
For an Intermediate CA, click Configure PKI to begin setup.
Choose the Generate intermediate CSR option, and fill in the blanks.
Set Type to Internal.
Set your Common name to your domain with a suffix that it’s an Intermediate CA, like this:
ogsofttech.lan Int CA 01
Click Generate, to make the CSR.
Paste the CSR onto the clipboard, and save it as a file: pki_intermediate.csr.
Open the web UI for your root CA, and navigate to Secrets/PKI/Issuers, and click Sign Intermediate.
Paste the CSR content into the CSR field.
Set the domain name as the common name: ogsofttech.lan
Select pem_bundle from the Format dropdown:
Click Sign, to sign the CSR from the Intermediate CA.
Once signed, you’ll see this:
It contains the signed certificate for the Intermediate CA, the cert of the issuing CA, and the CA chain cert.
NOTE: Save all three in a known place, as this is the only time these will be available.
Download the certificate as: ogsofttech.lan-intca01.cert.pem
Open the UI for the Intermediate CA, and navigate to the Import a CA:
NOTE: You get to this, by clicking on the Issuers tab, and clicking Import.
Upload the certificate that you saved to: ogsofttech.lan-intca01.cert.pem
Click Import Issuer.
The Issuers tab will show two entries, one for the root, and one for the Int CA:
Issuing Role
Before you can issue certificates to hosts and such, you need to create an issuer role.
To do this, we need to identify the issuer’s Guid.
We can get this by clicking the terminal button, and running this:
read -field=default pki/config/issuers
Note the Guid that was returned.
Now, go to Secrets/PKI/Roles, and create a new role.
Give the role a name in this format: ogsofttech-dot-lan
Unclick the Use Default Issuer, and select the Guid that matches what we found above.
Set the TTL to 43800 hours.
At the bottom of the form…
In the Allowed Domains field, add our domain: ogsofttech.lan.
Check the “Allow Subdomains” checkbox.
And, click Create, to make our issuing role.
Now, you have a role that can create and sign certificates.
If not already done, you can offline your root CA, as it needs to be kept safe, and only needed to create a new Intermediate CA.
See this page for how to generation certificates: Generate Certificates with Hashicorp Vault
























