HashiCorp Vault — Root & Intermediate CA

2 minute read

Build a proper two-tier PKI hierarchy: a root CA that signs an intermediate CA, which in turn issues end-entity certificates.


Step 1 — Generate Root CA

# Generate root CA (key stays inside Vault)
vault write pki/root/generate/internal \
    common_name="My Organization Root CA" \
    issuer_name="root-2024" \
    ttl=87600h \
    key_bits=4096

Expected output:

Key              Value
---              -----
certificate      -----BEGIN CERTIFICATE-----
                 MIIFaz...
                 -----END CERTIFICATE-----
expiration       1895587200
issuer_id        abc123
issuer_name      root-2024
issuing_ca       -----BEGIN CERTIFICATE-----...
key_id           def456
serial_number    12:34:56:78:...

Configure CA URLs

vault write pki/config/urls \
    issuing_certificates="$VAULT_ADDR/v1/pki/ca" \
    crl_distribution_points="$VAULT_ADDR/v1/pki/crl"

Step 2 — Generate Intermediate CA

# Generate CSR for intermediate CA
vault write -format=json pki_int/intermediate/generate/internal \
    common_name="My Organization Intermediate CA" \
    issuer_name="intermediate-2024" \
    key_bits=4096 | jq -r '.data.csr' > /tmp/pki_int.csr

Step 3 — Sign Intermediate with Root

# Root CA signs the intermediate CSR
vault write -format=json pki/root/sign-intermediate \
    issuer_ref="root-2024" \
    csr=@/tmp/pki_int.csr \
    format=pem_bundle \
    ttl=26280h | jq -r '.data.certificate' > /tmp/intermediate.cert.pem

Step 4 — Import Signed Intermediate

# Import the signed certificate back into the intermediate mount
vault write pki_int/intermediate/set-signed \
    certificate=@/tmp/intermediate.cert.pem

Configure Intermediate URLs

vault write pki_int/config/urls \
    issuing_certificates="$VAULT_ADDR/v1/pki_int/ca" \
    crl_distribution_points="$VAULT_ADDR/v1/pki_int/crl"

Verify the Hierarchy

# Read root CA
vault read -field=certificate pki/ca/pem > /tmp/root-ca.pem

# Read intermediate CA
vault read -field=certificate pki_int/ca/pem > /tmp/int-ca.pem

# Verify chain
openssl verify -CAfile /tmp/root-ca.pem /tmp/int-ca.pem
# /tmp/int-ca.pem: OK

Using an External Root CA

If your organization already has a root CA:

# 1. Generate CSR from Vault
vault write -format=json pki_int/intermediate/generate/internal \
    common_name="Vault Intermediate CA" | jq -r '.data.csr' > vault-int.csr

# 2. Sign the CSR with your external CA (outside Vault)
# openssl, cfssl, or your CA tooling

# 3. Import the signed cert
vault write pki_int/intermediate/set-signed \
    certificate=@signed-intermediate.pem

Complete Setup Script

#!/bin/bash
# setup-pki.sh — Complete PKI hierarchy setup

set -e

echo "=== Setting up Root CA ==="
vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki

vault write pki/root/generate/internal \
    common_name="My Org Root CA" \
    issuer_name="root-2024" \
    ttl=87600h

vault write pki/config/urls \
    issuing_certificates="$VAULT_ADDR/v1/pki/ca" \
    crl_distribution_points="$VAULT_ADDR/v1/pki/crl"

echo "=== Setting up Intermediate CA ==="
vault secrets enable -path=pki_int pki
vault secrets tune -max-lease-ttl=26280h pki_int

vault write -format=json pki_int/intermediate/generate/internal \
    common_name="My Org Intermediate CA" \
    issuer_name="intermediate-2024" | jq -r '.data.csr' > /tmp/pki_int.csr

vault write -format=json pki/root/sign-intermediate \
    issuer_ref="root-2024" \
    csr=@/tmp/pki_int.csr \
    format=pem_bundle \
    ttl=26280h | jq -r '.data.certificate' > /tmp/intermediate.cert.pem

vault write pki_int/intermediate/set-signed \
    certificate=@/tmp/intermediate.cert.pem

vault write pki_int/config/urls \
    issuing_certificates="$VAULT_ADDR/v1/pki_int/ca" \
    crl_distribution_points="$VAULT_ADDR/v1/pki_int/crl"

echo "=== PKI Hierarchy Ready ==="
rm -f /tmp/pki_int.csr /tmp/intermediate.cert.pem

Quick Reference

Command Description
vault write pki/root/generate/internal ... Generate root CA
vault write pki_int/intermediate/generate/internal ... Generate intermediate CSR
vault write pki/root/sign-intermediate ... Sign intermediate
vault write pki_int/intermediate/set-signed ... Import signed cert

Next: Issuing Certificates