Set up Vault as a PKI certificate authority with SSL automation and intermediate CA

Intermediate 45 min Apr 19, 2026 143 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Build a production-grade PKI infrastructure using HashiCorp Vault with root and intermediate certificate authorities. Enable automated SSL certificate generation and renewal for your applications with RBAC policies.

Prerequisites

  • Root or sudo access
  • Basic understanding of PKI concepts
  • Familiarity with SSL certificates
  • Command line experience

What this solves

HashiCorp Vault provides enterprise-grade PKI capabilities for managing SSL certificates at scale. This tutorial sets up Vault as a certificate authority with automated certificate issuance, renewal, and revocation. You'll configure a root CA, intermediate CA structure, and integrate Vault Agent for automatic certificate lifecycle management across your infrastructure.

Step-by-step installation

Update system packages and install dependencies

Start by updating your system and installing required packages for Vault installation.

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget gnupg software-properties-common
sudo dnf update -y
sudo dnf install -y curl wget gnupg2

Add HashiCorp repository and install Vault

Add the official HashiCorp repository and install Vault using the package manager.

curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
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
sudo apt update
sudo apt install -y vault
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo dnf install -y vault

Create Vault system user and directories

Create a dedicated system user for Vault and set up the required directory structure with proper permissions.

sudo useradd --system --home /etc/vault.d --shell /bin/false vault
sudo mkdir -p /opt/vault/data /etc/vault.d /var/log/vault
sudo chown -R vault:vault /opt/vault /etc/vault.d /var/log/vault
sudo chmod 750 /opt/vault/data /etc/vault.d
sudo chmod 755 /var/log/vault

Configure Vault server

Create the main Vault configuration file with storage backend, listener, and security settings.

storage "file" {
  path = "/opt/vault/data"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = 1
}

api_addr = "http://127.0.0.1:8200"
cluster_addr = "http://127.0.0.1:8201"
ui = true

Enable audit logging

audit { enabled = true type = "file" file_path = "/var/log/vault/audit.log" }

Disable mlock for development (enable in production)

disable_mlock = true

Set proper file permissions for configuration

Secure the Vault configuration file to prevent unauthorized access to sensitive settings.

sudo chown vault:vault /etc/vault.d/vault.hcl
sudo chmod 640 /etc/vault.d/vault.hcl

Create systemd service file

Configure Vault to run as a systemd service with proper security settings and automatic restart capabilities.

[Unit]
Description=HashiCorp Vault
Documentation=https://vaultproject.io/docs/
Requires=network-online.target
After=network-online.target

[Service]
Type=notify
User=vault
Group=vault
ProtectSystem=full
ProtectHome=read-only
PrivateTmp=yes
PrivateDevices=yes
SecureBits=keep-caps
AmbientCapabilities=CAP_IPC_LOCK
Capabilities=CAP_IPC_LOCK+ep
CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK
NoNewPrivileges=yes
ExecStart=/usr/bin/vault server -config=/etc/vault.d/vault.hcl
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
StartLimitInterval=60
StartLimitBurst=3
LimitNOFILE=65536
LimitMEMLOCK=infinity

[Install]
WantedBy=multi-user.target

Enable and start Vault service

Start Vault and enable it to automatically start on system boot.

sudo systemctl daemon-reload
sudo systemctl enable --now vault
sudo systemctl status vault

Initialize Vault

Initialize Vault with 5 key shares and a threshold of 3. Store the unseal keys and root token securely.

export VAULT_ADDR='http://127.0.0.1:8200'
vault operator init -key-shares=5 -key-threshold=3
Critical: Save the unseal keys and root token in a secure location. You'll need at least 3 unseal keys to unlock Vault after restarts.

Unseal Vault

Unseal Vault using 3 of the 5 unseal keys from the initialization step.

vault operator unseal [UNSEAL_KEY_1]
vault operator unseal [UNSEAL_KEY_2]
vault operator unseal [UNSEAL_KEY_3]

Authenticate with root token

Log in to Vault using the root token to begin configuration.

vault auth [ROOT_TOKEN]

Configure PKI secrets engine

Enable PKI secrets engine for root CA

Enable the PKI secrets engine at the root CA path with extended TTL for long-lived root certificates.

vault secrets enable -path=pki-root -max-lease-ttl=87600h pki
vault write pki-root/config/urls \
    issuing_certificates="http://127.0.0.1:8200/v1/pki-root/ca" \
    crl_distribution_points="http://127.0.0.1:8200/v1/pki-root/crl"

Generate root certificate authority

Create the root CA certificate with a 10-year validity period. This will be your trust anchor.

vault write pki-root/root/generate/internal \
    common_name="Example.com Root CA" \
    country="US" \
    locality="San Francisco" \
    organization="Example Corporation" \
    ou="IT Department" \
    ttl=87600h \
    key_bits=4096 \
    exclude_cn_from_sans=true

Enable intermediate PKI secrets engine

Create a separate PKI mount for the intermediate CA with shorter TTL appropriate for day-to-day certificate signing.

vault secrets enable -path=pki-int -max-lease-ttl=8760h pki
vault write pki-int/config/urls \
    issuing_certificates="http://127.0.0.1:8200/v1/pki-int/ca" \
    crl_distribution_points="http://127.0.0.1:8200/v1/pki-int/crl"

Generate intermediate certificate signing request

Create a CSR for the intermediate CA that will be signed by the root CA.

vault write -format=json pki-int/intermediate/generate/internal \
    common_name="Example.com Intermediate CA" \
    country="US" \
    locality="San Francisco" \
    organization="Example Corporation" \
    ou="IT Department" \
    key_bits=4096 | jq -r '.data.csr' > pki_intermediate.csr

Sign intermediate certificate with root CA

Use the root CA to sign the intermediate certificate, creating the certificate chain.

vault write -format=json pki-root/root/sign-intermediate \
    csr=@pki_intermediate.csr \
    format=pem_bundle \
    ttl=8760h | jq -r '.data.certificate' > intermediate.cert.pem

Set intermediate certificate

Install the signed intermediate certificate back into the intermediate PKI engine.

vault write pki-int/intermediate/set-signed \
    certificate=@intermediate.cert.pem

Create PKI role for certificate issuance

Define a role that specifies which certificates can be issued and their parameters.

vault write pki-int/roles/example-com \
    allowed_domains="example.com" \
    allow_subdomains=true \
    allow_any_name=false \
    enforce_hostnames=true \
    allow_ip_sans=true \
    server_flag=true \
    client_flag=true \
    max_ttl="720h" \
    key_bits=2048

Configure RBAC and policies

Create certificate management policy

Define a policy that allows certificate creation and management operations.

# Allow reading PKI mounts
path "pki-int/cert/*" {
  capabilities = ["read"]
}

Allow listing certificates

path "pki-int/certs" { capabilities = ["list"] }

Allow certificate generation

path "pki-int/issue/example-com" { capabilities = ["create", "update"] }

Allow certificate revocation

path "pki-int/revoke" { capabilities = ["create", "update"] }

Allow reading CA certificate

path "pki-int/ca/pem" { capabilities = ["read"] }

Allow reading CRL

path "pki-int/crl/pem" { capabilities = ["read"] }
vault policy write pki-policy /tmp/pki-policy.hcl

Enable userpass authentication

Enable username/password authentication for user access to the PKI system.

vault auth enable userpass

Create PKI user with limited permissions

Create a user account with the PKI policy for certificate management operations.

vault write auth/userpass/users/pki-user \
    password="SecurePKIPassword123!" \
    policies="pki-policy"

Set up Vault Agent for certificate automation

Create Vault Agent configuration directory

Set up directories for Vault Agent configuration and certificate storage.

sudo mkdir -p /etc/vault-agent /opt/vault-agent/certs
sudo chown -R vault:vault /etc/vault-agent /opt/vault-agent
sudo chmod 750 /etc/vault-agent /opt/vault-agent

Configure Vault Agent for automatic certificate renewal

Create Vault Agent configuration for automated certificate lifecycle management.

vault {
  address = "http://127.0.0.1:8200"
  retry {
    num_retries = 5
  }
}

auto_auth {
  method "userpass" {
    mount_path = "auth/userpass"
    config = {
      username = "pki-user"
      password = "SecurePKIPassword123!"
    }
  }

  sink "file" {
    config = {
      path = "/opt/vault-agent/token"
    }
  }
}

template {
  source      = "/etc/vault-agent/cert.tpl"
  destination = "/opt/vault-agent/certs/server.crt"
  perms       = 0644
  command     = "systemctl reload nginx"
}

template {
  source      = "/etc/vault-agent/key.tpl"
  destination = "/opt/vault-agent/certs/server.key"
  perms       = 0600
  command     = "systemctl reload nginx"
}

Create certificate template files

Create templates that Vault Agent will use to generate certificate files.

{{- with secret "pki-int/issue/example-com" "common_name=web.example.com" "ttl=720h" }}
{{ .Data.certificate }}
{{ .Data.issuing_ca }}
{{- end }}
{{- with secret "pki-int/issue/example-com" "common_name=web.example.com" "ttl=720h" }}
{{ .Data.private_key }}
{{- end }}

Set proper permissions for Vault Agent files

Secure the Vault Agent configuration and template files.

sudo chown -R vault:vault /etc/vault-agent
sudo chmod 640 /etc/vault-agent/agent.hcl
sudo chmod 644 /etc/vault-agent/*.tpl

Create Vault Agent systemd service

Configure Vault Agent to run as a systemd service for automatic certificate renewal.

[Unit]
Description=Vault Agent
Requires=vault.service
After=vault.service

[Service]
Restart=on-failure
User=vault
Group=vault
ExecStart=/usr/bin/vault agent -config /etc/vault-agent/agent.hcl
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process

[Install]
WantedBy=multi-user.target

Enable and start Vault Agent

Start Vault Agent to begin automatic certificate management.

sudo systemctl daemon-reload
sudo systemctl enable --now vault-agent
sudo systemctl status vault-agent

Verify your setup

Test your PKI infrastructure by generating certificates and verifying the certificate chain.

# Check Vault status
vault status

Generate a test certificate

vault write pki-int/issue/example-com \ common_name="test.example.com" \ ttl="72h"

Verify certificate chain

openssl x509 -in /opt/vault-agent/certs/server.crt -text -noout

Check certificate expiration

openssl x509 -in /opt/vault-agent/certs/server.crt -enddate -noout

Verify Vault Agent is running

sudo systemctl status vault-agent

Check audit logs

sudo tail -f /var/log/vault/audit.log
Note: The first certificate generation may take a few minutes as Vault Agent authenticates and processes templates.

Common issues

SymptomCauseFix
Vault won't unsealMissing or incorrect unseal keysUse correct unseal keys from initialization
Permission denied errorsIncorrect file permissionssudo chown -R vault:vault /opt/vault
PKI role creation failsVault not authenticatedRun vault auth [ROOT_TOKEN]
Certificate generation failsPolicy doesn't allow operationVerify policy with vault policy read pki-policy
Vault Agent can't authenticateUser password incorrectReset password with vault write auth/userpass/users/pki-user password="NewPassword"
Template rendering failsCertificate expired or revokedCheck certificate status and regenerate

Next steps

Running this in production?

Want this handled for you? Setting this up once is straightforward. Keeping it patched, monitored, backed up and performant across environments is the harder part. See how we run infrastructure like this for European teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle infrastructure security hardening for businesses that depend on uptime. From initial setup to ongoing operations.