QCecuring - Enterprise Security Solutions

HashiCorp Vault PKI Engine: Complete Setup and Production Guide

PKI & Certificate Management 26 May, 2026 · 06 Mins read

Master HashiCorp Vault's PKI secrets engine for automated certificate management. Covers CA setup, short-lived certificates, cert-manager integration, and production deployment.


HashiCorp Vault’s PKI secrets engine transforms Vault into a fully functional certificate authority capable of issuing, renewing, and revoking X.509 certificates programmatically. For DevOps teams already using Vault for secrets management, the PKI engine provides a natural extension for certificate automation — eliminating manual CSR workflows and enabling short-lived certificates that reduce the blast radius of key compromise.

This guide covers everything from initial setup through production deployment, including integration patterns with Kubernetes cert-manager, Consul Connect, and CI/CD pipelines.

What Is the Vault PKI Secrets Engine?

The PKI secrets engine is a built-in Vault component that acts as a certificate authority. Unlike traditional CAs that require separate infrastructure, Vault PKI runs within your existing Vault cluster and leverages Vault’s access control, audit logging, and high-availability features.

Architecture Overview

┌─────────────────────────────────────────────────────────┐
│                    Vault Cluster                          │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  ┌──────────────┐    ┌──────────────────────────────┐   │
│  │  Root CA      │    │  Intermediate CA (Issuing)    │   │
│  │  (pki/)       │───▶│  (pki_int/)                   │   │
│  │  Offline use  │    │  Issues end-entity certs      │   │
│  └──────────────┘    └──────────────────────────────┘   │
│                              │                           │
│                              ▼                           │
│  ┌──────────────────────────────────────────────────┐   │
│  │              Roles (Certificate Profiles)          │   │
│  │  ┌─────────┐  ┌──────────┐  ┌───────────────┐   │   │
│  │  │ web-srv │  │ internal │  │ microservice  │   │   │
│  │  │ 1yr TTL │  │ 30d TTL  │  │ 24hr TTL      │   │   │
│  │  └─────────┘  └──────────┘  └───────────────┘   │   │
│  └──────────────────────────────────────────────────┘   │
│                              │                           │
└──────────────────────────────┼───────────────────────────┘

        ┌──────────────────────────────────────┐
        │           Consumers                    │
        │  cert-manager │ Consul │ Applications │
        └──────────────────────────────────────┘

Key Capabilities

FeatureDescription
Dynamic certificate issuanceGenerate certificates on-demand via API
Short-lived certificatesTTLs from minutes to years
Automatic rotationConsumers request new certs before expiry
CRL/OCSPBuilt-in revocation support
Multiple CAsSeparate root and intermediate hierarchies
Role-based accessFine-grained control over who can issue what
Audit loggingEvery operation logged through Vault’s audit system
Cross-signingSupport for CA migration scenarios

Setting Up Root and Intermediate CAs

Step 1: Enable the Root CA

# Enable the PKI engine for the root CA
vault secrets enable -path=pki pki

# Set maximum TTL for root CA (10 years)
vault secrets tune -max-lease-ttl=87600h pki

# Generate the root certificate
vault write pki/root/generate/internal \
  common_name="My Organization Root CA" \
  issuer_name="root-2026" \
  ttl=87600h \
  key_type=rsa \
  key_bits=4096

# Configure CA and CRL URLs
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"

Step 2: Enable the Intermediate CA

# Enable a separate PKI engine for the intermediate CA
vault secrets enable -path=pki_int pki

# Set maximum TTL (5 years)
vault secrets tune -max-lease-ttl=43800h pki_int

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

Step 3: Sign the Intermediate with the Root

# Sign the intermediate CSR with the root CA
vault write -format=json pki/root/sign-intermediate \
  csr=@intermediate.csr \
  format=pem_bundle \
  ttl=43800h \
  | jq -r '.data.certificate' > intermediate.cert.pem

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

# Configure URLs for the intermediate
vault write pki_int/config/urls \
  issuing_certificates="https://vault.example.com:8200/v1/pki_int/ca" \
  crl_distribution_points="https://vault.example.com:8200/v1/pki_int/crl" \
  ocsp_servers="https://vault.example.com:8200/v1/pki_int/ocsp"

Step 4: Create Roles (Certificate Profiles)

Roles define the parameters for issued certificates:

# Role for web servers (1 year, RSA)
vault write pki_int/roles/web-server \
  allowed_domains="example.com" \
  allow_subdomains=true \
  max_ttl=8760h \
  key_type=rsa \
  key_bits=2048 \
  require_cn=true \
  allow_ip_sans=true \
  server_flag=true \
  client_flag=false

# Role for internal microservices (24 hours, ECDSA)
vault write pki_int/roles/microservice \
  allowed_domains="internal.example.com,svc.cluster.local" \
  allow_subdomains=true \
  allow_bare_domains=false \
  max_ttl=24h \
  key_type=ec \
  key_bits=256 \
  require_cn=false \
  allow_ip_sans=true \
  server_flag=true \
  client_flag=true \
  enforce_hostnames=true

# Role for client authentication (30 days)
vault write pki_int/roles/client-auth \
  allowed_domains="users.example.com" \
  allow_subdomains=true \
  max_ttl=720h \
  key_type=ec \
  key_bits=256 \
  client_flag=true \
  server_flag=false \
  no_store=true

Issuing Certificates

Via CLI

# Issue a certificate for a web server
vault write -format=json pki_int/issue/web-server \
  common_name="api.example.com" \
  alt_names="api-v2.example.com" \
  ip_sans="10.0.1.50" \
  ttl=720h

# Output includes: certificate, private_key, ca_chain, serial_number

Via API

# Issue certificate via HTTP API
curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
  --request POST \
  --data '{
    "common_name": "api.example.com",
    "ttl": "720h",
    "alt_names": "api-v2.example.com",
    "ip_sans": "10.0.1.50"
  }' \
  https://vault.example.com:8200/v1/pki_int/issue/web-server | jq

Via Application Code

package main

import (
    "fmt"
    "log"

    vault "github.com/hashicorp/vault/api"
)

func issueCertificate(client *vault.Client, commonName string, ttl string) (*vault.Secret, error) {
    secret, err := client.Logical().Write("pki_int/issue/microservice", map[string]interface{}{
        "common_name": commonName,
        "ttl":         ttl,
    })
    if err != nil {
        return nil, fmt.Errorf("failed to issue certificate: %w", err)
    }
    return secret, nil
}

func main() {
    config := vault.DefaultConfig()
    client, err := vault.NewClient(config)
    if err != nil {
        log.Fatal(err)
    }

    secret, err := issueCertificate(client, "payment-svc.internal.example.com", "24h")
    if err != nil {
        log.Fatal(err)
    }

    cert := secret.Data["certificate"].(string)
    key := secret.Data["private_key"].(string)
    ca := secret.Data["issuing_ca"].(string)

    // Write to files or configure TLS directly
    fmt.Printf("Certificate issued, serial: %s\n", secret.Data["serial_number"])
}

Short-Lived Certificates for Microservices

Short-lived certificates (hours to days) are a paradigm shift from traditional long-lived certificates. They reduce the need for revocation infrastructure because compromised certificates expire quickly.

Benefits of Short-Lived Certificates

AspectTraditional (1 year)Short-Lived (24 hours)
Compromise windowUp to 365 daysUp to 24 hours
Revocation dependencyCritical (CRL/OCSP)Minimal
Rotation complexityManual/scheduledAutomatic
Storage requirementsPersistentEphemeral
Audit trailSparseComprehensive

Implementing Auto-Rotation

# Python service with automatic certificate rotation
import threading
import time
import hvac
from datetime import datetime, timedelta

class CertificateManager:
    def __init__(self, vault_url, vault_token, role, common_name):
        self.client = hvac.Client(url=vault_url, token=vault_token)
        self.role = role
        self.common_name = common_name
        self.cert = None
        self.key = None
        self.expiry = None
        self._renewal_thread = None

    def issue_certificate(self):
        response = self.client.secrets.pki.generate_certificate(
            name=self.role,
            common_name=self.common_name,
            mount_point="pki_int",
            extra_params={"ttl": "24h"}
        )
        self.cert = response["data"]["certificate"]
        self.key = response["data"]["private_key"]
        # Renew at 70% of lifetime
        ttl_seconds = response["data"]["expiration"] - time.time()
        self.expiry = datetime.now() + timedelta(seconds=ttl_seconds * 0.7)
        return self.cert, self.key

    def start_auto_renewal(self):
        def renew_loop():
            while True:
                sleep_time = (self.expiry - datetime.now()).total_seconds()
                if sleep_time > 0:
                    time.sleep(sleep_time)
                self.issue_certificate()
                print(f"Certificate renewed at {datetime.now()}")
        
        self._renewal_thread = threading.Thread(target=renew_loop, daemon=True)
        self._renewal_thread.start()

Integration with cert-manager

The Vault PKI engine integrates natively with Kubernetes cert-manager through the Vault issuer:

Configure Vault Authentication for cert-manager

# Enable Kubernetes auth in Vault
vault auth enable kubernetes

# Configure Kubernetes auth
vault write auth/kubernetes/config \
  kubernetes_host="https://kubernetes.default.svc" \
  kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

# Create policy for cert-manager
vault policy write cert-manager - <<EOF
path "pki_int/sign/web-server" {
  capabilities = ["create", "update"]
}
path "pki_int/issue/web-server" {
  capabilities = ["create"]
}
EOF

# Bind the policy to cert-manager's service account
vault write auth/kubernetes/role/cert-manager \
  bound_service_account_names=cert-manager \
  bound_service_account_namespaces=cert-manager \
  policies=cert-manager \
  ttl=1h

Deploy cert-manager Vault Issuer

# vault-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: vault-issuer
spec:
  vault:
    path: pki_int/sign/web-server
    server: https://vault.example.com:8200
    caBundle: <base64-encoded-vault-ca>
    auth:
      kubernetes:
        role: cert-manager
        mountPath: /v1/auth/kubernetes
        serviceAccountRef:
          name: cert-manager
---
# certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: api-tls
  namespace: production
spec:
  secretName: api-tls-secret
  duration: 24h
  renewBefore: 8h
  issuerRef:
    name: vault-issuer
    kind: ClusterIssuer
  commonName: api.example.com
  dnsNames:
    - api.example.com
    - api.internal.svc.cluster.local
  privateKey:
    algorithm: ECDSA
    size: 256

Consul Connect Integration

Vault PKI can serve as the CA for Consul’s service mesh:

# Consul server configuration
connect {
  enabled = true
  ca_provider = "vault"
  ca_config {
    address = "https://vault.example.com:8200"
    token = "vault-consul-token"
    root_pki_path = "pki"
    intermediate_pki_path = "pki_int"
    leaf_cert_ttl = "72h"
    rotation_period = "2160h"
    intermediate_cert_ttl = "8760h"
    private_key_type = "ec"
    private_key_bits = 256
  }
}

CRL and OCSP Configuration

Certificate Revocation List (CRL)

# Enable auto-tidy for CRL management
vault write pki_int/config/auto-tidy \
  enabled=true \
  tidy_cert_store=true \
  tidy_revoked_certs=true \
  tidy_expired_issuers=true \
  safety_buffer="72h" \
  interval_duration="12h"

# Manually revoke a certificate
vault write pki_int/revoke \
  serial_number="39:dd:2e:90:b7:23:1f:8d:d3:7d:31:c5:1b:da:84:c0:ac:b8:03:49"

# Fetch current CRL
curl -s https://vault.example.com:8200/v1/pki_int/crl/pem > crl.pem
openssl crl -in crl.pem -text -noout

OCSP Responder

Vault 1.12+ includes a built-in OCSP responder:

# OCSP is automatically available at:
# GET /v1/pki_int/ocsp/<base64-encoded-request>
# POST /v1/pki_int/ocsp (with DER-encoded request body)

# Test OCSP response
openssl ocsp \
  -issuer intermediate-ca.pem \
  -cert server.pem \
  -url https://vault.example.com:8200/v1/pki_int/ocsp \
  -resp_text

Policies and Access Control

Least-Privilege Policy Examples

# Policy for web team - can only issue web server certificates
path "pki_int/issue/web-server" {
  capabilities = ["create", "update"]
}

path "pki_int/sign/web-server" {
  capabilities = ["create", "update"]
}

# Policy for platform team - can manage roles and issue any cert
path "pki_int/roles/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}

path "pki_int/issue/*" {
  capabilities = ["create", "update"]
}

path "pki_int/sign/*" {
  capabilities = ["create", "update"]
}

path "pki_int/revoke" {
  capabilities = ["create", "update"]
}

# Policy for monitoring - read-only access to CRL and CA chain
path "pki_int/cert/*" {
  capabilities = ["read", "list"]
}

path "pki_int/ca/pem" {
  capabilities = ["read"]
}

path "pki_int/crl/pem" {
  capabilities = ["read"]
}

Performance Tuning

High-Volume Certificate Issuance

For environments issuing thousands of certificates per hour:

# Disable certificate storage for high-volume roles (reduces storage I/O)
vault write pki_int/roles/ephemeral-service \
  allowed_domains="svc.cluster.local" \
  allow_subdomains=true \
  max_ttl=1h \
  no_store=true \
  generate_lease=false

# Tune the mount for performance
vault secrets tune \
  -max-lease-ttl=8760h \
  -default-lease-ttl=24h \
  -listing-visibility=unauth \
  pki_int/

Performance Benchmarks

ConfigurationIssuance RateNotes
Default (RSA 2048, storage enabled)~200 certs/secSuitable for most deployments
no_store=true, RSA 2048~500 certs/secNo revocation tracking
no_store=true, ECDSA P-256~800 certs/secFastest option
With HSM backend~50-100 certs/secHSM becomes bottleneck

Storage Backend Considerations

# Consul storage (recommended for HA)
storage "consul" {
  address = "127.0.0.1:8500"
  path    = "vault/"
  # Tune for PKI workloads
  max_parallel = 128
}

# Integrated Raft storage (simpler operations)
storage "raft" {
  path = "/opt/vault/data"
  # Performance tuning
  performance_multiplier = 1
}

Production Deployment Considerations

High Availability

# Vault HA configuration for PKI workloads
listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_cert_file = "/opt/vault/tls/vault.crt"
  tls_key_file  = "/opt/vault/tls/vault.key"
}

# Enable performance standby nodes for read-heavy PKI operations
# (Enterprise feature)
seal "awskms" {
  region     = "us-east-1"
  kms_key_id = "alias/vault-unseal"
}

Monitoring and Alerting

# Prometheus metrics to monitor
- vault_secret_kv_count{mount_point="pki_int"}  # Certificate count
- vault_secret_lease_creation_count              # Issuance rate
- vault_core_handle_request_duration             # Latency
- vault_expire_num_leases                        # Active leases

# Alert rules
groups:
  - name: vault-pki
    rules:
      - alert: HighCertIssuanceLatency
        expr: vault_core_handle_request_duration{mount_point="pki_int"} > 2
        for: 5m
      - alert: IntermediateCAExpiringSoon
        expr: vault_pki_cert_expiry_seconds{issuer="intermediate"} < 2592000
        for: 1h

Backup and Disaster Recovery

# Export the intermediate CA for disaster recovery
vault read -format=json pki_int/cert/ca > intermediate-ca-backup.json

# Snapshot the entire Vault (includes PKI state)
vault operator raft snapshot save vault-backup-$(date +%Y%m%d).snap

# Test restore procedure regularly
vault operator raft snapshot restore vault-backup.snap

When Vault PKI Is Enough vs. When You Need More

Vault PKI Excels At

  • Internal certificate issuance for microservices
  • Short-lived certificates with automatic rotation
  • Integration with HashiCorp ecosystem (Consul, Nomad, Terraform)
  • Teams already operating Vault for secrets management
  • DevOps-driven certificate workflows

Consider a Dedicated PKI Solution When

RequirementVault PKIDedicated PKI Platform
Public CA integrationLimitedNative
Certificate discoveryNoYes
Multi-protocol (SCEP, CMP, EST)No (API only)Yes
Compliance reportingBasic audit logsPurpose-built reports
Non-technical user workflowsNo UI for cert opsSelf-service portals
Cross-platform agent deploymentVault agent onlyMulti-platform agents
Certificate visibility dashboardMinimalComprehensive
Hybrid (public + private) managementSeparate toolsUnified

For organizations that need both Vault’s secrets management and comprehensive certificate lifecycle management, platforms like QCecuring can integrate with Vault while providing the broader visibility, compliance reporting, and multi-protocol support that Vault alone doesn’t offer.

Hybrid Architecture

Many production environments use Vault PKI for internal/ephemeral certificates while using a dedicated CLM platform for longer-lived certificates, public CA integration, and compliance:

┌─────────────────────────────────────────────────────┐
│              Certificate Lifecycle Platform           │
│  (Public certs, compliance, discovery, reporting)    │
└─────────────────────────┬───────────────────────────┘

          ┌───────────────┼───────────────┐
          ▼               ▼               ▼
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│  Public CAs   │  │  Vault PKI   │  │  Cloud CAs   │
│  (DigiCert,   │  │  (Internal,  │  │  (AWS PCA,   │
│   Let's       │  │   ephemeral) │  │   GCP CAS)   │
│   Encrypt)    │  │              │  │              │
└──────────────┘  └──────────────┘  └──────────────┘

Key Takeaways

  • Vault PKI is ideal for DevOps teams already using Vault — it provides certificate automation without additional infrastructure.
  • Always use a two-tier CA hierarchy with an offline or tightly controlled root CA and an online intermediate for day-to-day issuance.
  • Short-lived certificates reduce risk — configure TTLs of 24 hours or less for service-to-service communication and let automation handle renewal.
  • cert-manager integration makes Vault PKI seamless in Kubernetes environments, handling issuance and renewal declaratively.
  • Use no_store=true for high-volume roles where you don’t need revocation tracking — this dramatically improves performance.
  • Monitor your intermediate CA expiration — a forgotten intermediate CA renewal will break all certificate issuance.
  • Vault PKI has limits — it lacks certificate discovery, multi-protocol support, and compliance dashboards that dedicated PKI platforms provide.
  • Plan for scale — test your Vault cluster’s certificate issuance rate under load before relying on it for production workloads with thousands of services.

Vault PKI Architecture Review

Get expert guidance on your Vault PKI deployment architecture, performance tuning, and security hardening.

Schedule Review

Related Insights

Code Signing

Code Signing in Linux: Complete Guide to Signing Packages, Binaries, and Containers

Learn how to sign Linux artifacts including RPM/DEB packages, kernel modules, container images, Git commits, and AppImages. Covers GPG, cosign, Sigstore, and CI/CD integration.

By Shivam sharma

26 May, 2026 · 08 Mins read

Code SigningDeveloper SecurityDevOps & Automation

PKI & Certificate Management

Small Business PKI Solutions: Practical Guide to Certificate Management at Scale

Compare PKI solutions for small businesses including Let's Encrypt, Smallstep, EJBCA, and managed services. Covers implementation roadmaps, cost analysis, and compliance for SMBs.

By Shivam sharma

26 May, 2026 · 06 Mins read

PKI & Certificate ManagementEnterprise SecurityBuyer's Guide

Ready to Secure Your Enterprise?

Experience how our cryptographic solutions simplify, centralize, and automate identity management for your entire organization.

Stay ahead on cryptography & PKI

Get monthly insights on certificate management, post-quantum readiness, and enterprise security. No spam.

We respect your privacy. Unsubscribe anytime.