
September 10, 2026
13 min read
By Kokil Thapa | Last reviewed: September 2026
Manual TLS certificate management breaks down fast once you run more than a handful of services. The HashiCorp Vault PKI Secrets Engine solves that by turning Vault into a private certificate authority that issues short-lived certs on demand. I've handled Let's Encrypt and Certbot on Ubuntu servers for years, and I still reach for Vault PKI when internal microservices, staging clusters, or client portals need automated, policy-controlled certificates without exposing a root key. This guide walks through setup, issuance, rotation, and the production patterns that actually hold up.
pki/, configure root or intermediate CAs, define roles with TTL and domain rules, then call pki/issue/<role> to generate TLS certificates dynamically without storing private keys in application repos.What is the HashiCorp Vault PKI Secrets Engine and when should you use it?
The PKI secrets engine is one of Vault's built-in engines. It generates X.509 certificates signed by a CA you control inside Vault. Unlike static secrets stored in HashiCorp Vault secrets management, PKI certs are dynamic. Vault creates a fresh key pair, signs the cert, returns both, and can revoke them through CRLs or OCSP.
You reach for Vault PKI when public CAs are wrong for the job. Internal service mesh traffic, database TLS between app servers, mTLS for APIs, and staging environments all fit. Public Let's Encrypt certs work for browser-facing sites. They do not help when service A in a private VPC must trust service B with a cert signed by your own root.
On production Laravel and API deployments I maintain, TLS often terminates at Apache or Nginx with Certbot. Vault PKI sits behind that layer for east-west traffic, webhook callbacks between internal services, and CI pipelines that need ephemeral certs. The two approaches complement each other rather than compete.
Vault PKI also integrates cleanly with the broader secrets stack. Pair it with External Secrets Operator and Vault on Kubernetes, or with Vault dynamic secrets for databases so both TLS certs and DB credentials rotate from one control plane.
How do you enable and configure the Vault PKI secrets engine?
Start with a running Vault cluster in dev or production mode. The PKI engine mounts at a path like pki/ or pki_int/. Production setups almost always use a two-tier CA: a root with a long TTL kept mostly offline, and an intermediate that signs day-to-day leaf certs.
Step 1: Enable the engine and generate a root CA
Enable PKI at the root path. Generate a self-signed root with a 10-year TTL. Tune max lease TTL so intermediate CAs can be issued beneath it.
vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki
vault write pki/root/generate/internal \
common_name="My Org Root CA" \
ttl=87600h \
key_type=rsa \
key_bits=4096
vault write pki/config/urls \
issuing_certificates="https://vault.example.com/v1/pki/ca" \
crl_distribution_points="https://vault.example.com/v1/pki/crl"
The config/urls step matters for clients that fetch the issuing CA or CRL over HTTP. Without it, chain validation fails in browsers and strict TLS libraries.
Step 2: Create an intermediate CA
Mount a second PKI engine for the intermediate. Generate a CSR inside Vault, sign it with the root, then import the signed cert back.
vault secrets enable -path=pki_int pki
vault secrets tune -max-lease-ttl=43800h pki_int
vault write pki_int/intermediate/generate/internal \
common_name="My Org Intermediate CA" \
key_type=rsa \
key_bits=4096
vault write pki/root/sign-intermediate \
csr=@pki_intermediate.csr \
format=pem_bundle \
ttl=43800h
vault write pki_int/intermediate/set-signed certificate=@signed_intermediate.pem
After this, disable or restrict direct use of the root path. All leaf issuance should flow through pki_int/. That limits blast radius if the intermediate key is ever compromised.
Step 3: Define a role with sane defaults
Roles are where policy lives. Set allowed domains, max TTL, key type, and whether clients can request arbitrary SANs.
vault write pki_int/roles/web-server \
allowed_domains="example.com,*.example.com" \
allow_subdomains=true \
max_ttl=720h \
key_type=rsa \
key_bits=2048 \
require_cn=true \
generate_lease=true
A max_ttl of 720 hours (30 days) is a reasonable starting point for internal services. Public-facing certs from Let's Encrypt cap at 90 days. Shorter TTLs reduce the window if a cert leaks.
How do you issue and renew TLS certificates with Vault PKI?
Issuing a cert is a single API call once roles exist. Vault returns the certificate, private key, issuing CA chain, and lease metadata.
Issue a certificate from the CLI
vault write pki_int/issue/web-server \
common_name="api.example.com" \
ttl=168h \
ip_sans="10.0.1.50"
vault write -format=json pki_int/issue/web-server \
common_name="app.example.com" > cert.json
Parse cert.json in your deploy script. Write certificate, private_key, and issuing_ca to disk. Reload the web server. On Ubuntu with Apache, that means systemctl reload apache2 after dropping files into /etc/ssl/private/.
Automate renewal before expiry
Vault tracks leases when generate_lease=true. Renew with vault lease renew or re-issue before TTL expires. A common pattern I've seen on client projects:
- Cron or systemd timer runs every 24 hours.
- Script authenticates to Vault with AppRole or a short-lived token.
- Script requests a new cert if the current one expires within seven days.
- Script writes PEM files and reloads the reverse proxy.
- Script logs success or alerts on failure.
Do not store the Vault token in the cron script itself. Pull it from environment variables injected by systemd, or use AppRole with secret_id delivered at boot from cloud metadata. That aligns with CI/CD secrets management best practices and keeps credentials out of Git.
For Kubernetes workloads, cert-manager with a Vault issuer avoids custom cron entirely. The Kubernetes secrets management article covers the broader pattern. Vault PKI becomes one issuer backend among several.
Revoke compromised certificates
Revocation is first-class in Vault PKI. Use serial number or certificate PEM:
vault write pki_int/revoke serial_number=03:ab:cd:...
vault write pki_int/tidy tidy_cert_store=true tidy_revoked_certs=true
Run tidy periodically. Revoked cert metadata accumulates and slows CRL generation on busy clusters.
How does Vault PKI compare to Let's Encrypt and manual OpenSSL?
Teams often ask whether Vault PKI replaces Let's Encrypt. Usually it does not. Each tool fits a different trust boundary.
| Criteria | HashiCorp Vault PKI | Let's Encrypt (Certbot) | Manual OpenSSL CA |
|---|---|---|---|
| Best for | Internal services, mTLS, private networks | Public HTTPS sites with valid browser trust | One-off certs, legacy scripts |
| Trust in browsers | Only if you distribute your root CA | Yes, publicly trusted | No, unless manually installed |
| Automation | API-driven, dynamic TTL, lease tracking | ACME protocol, 90-day certs | Manual CSR and sign steps |
| Policy control | Fine-grained roles, audit log, revocation | Domain validation only | Whatever your script enforces |
| Operational cost | Vault cluster to run and harden | Free certs, minimal infra | Low setup, high drift risk |
| Key storage | Keys never leave Vault | Keys on server filesystem | Keys often on disk or USB |
For public law-firm portals and eCommerce sites I ship, Let's Encrypt via Certbot on Apache remains the default for visitor-facing TLS. Vault PKI handles service-to-service calls, internal admin panels, and staging mirrors. A domain registration and hosting setup typically covers the public layer. Vault covers what happens inside the VPC.
What production pitfalls should you avoid with Vault PKI?
Vault PKI is powerful. It is also easy to misconfigure in ways that only surface at 2 a.m. when certs expire.
Root CA exposure
Never issue leaf certificates directly from the root CA in production. Generate the root, sign one intermediate, then seal or tightly ACL the root mount. If the root key leaks, every cert in your organisation is suspect. Rotating a root means redeploying trust stores everywhere.
Overly permissive roles
A role with allowed_domains="*" and long TTLs defeats the purpose of policy-bound issuance. Scope each role to the service that needs it. A Laravel API role should allow only api.internal.example.com. A wildcard role for staging might allow *.staging.example.com with a 72-hour max TTL.
Missing CRL or OCSP distribution
Clients that validate revocation need reachable CRL or OCSP endpoints. Configure pki/config/urls on both root and intermediate mounts. Test from a host outside the Vault cluster. Firewall rules blocking port 443 to Vault break revocation checks silently.
No monitoring on expiry
Even with auto-renewal, monitor cert expiry externally. Use blackbox probes or OpenTelemetry checks against your endpoints. Vault lease renewal can fail if tokens expire, policies change, or the intermediate hits its own TTL ceiling. I treat cert expiry alerts the same way I treat disk-space alerts on production servers managed through Linux system administration contracts.
Storing issued private keys insecurely
Vault returns the private key to the caller. That is by design. The caller must write it to a restricted path like /etc/ssl/private/ with mode 600 and root ownership. Do not commit PEM files to Git. Use strong passphrases only when your stack requires PKCS#12 bundles. Prefer raw PEM on servers with proper filesystem permissions.
Official references help during audits and onboarding. The HashiCorp Vault PKI secrets engine documentation covers every endpoint. The Vault PKI API reference lists request fields for automation. For baseline X.509 behaviour, the RFC 5280 specification defines profile rules your roles should respect.
How do you integrate Vault PKI with applications and CI pipelines?
Most teams do not issue certs by hand. They wire Vault PKI into deploy pipelines and runtime platforms.
Laravel and PHP applications
A Laravel app behind Nginx does not call Vault directly at runtime in most setups. The deploy step requests a cert, writes PEM paths into the server config, and reloads the proxy. Your Deployer or GitLab CI job authenticates with VAULT_TOKEN or AppRole credentials stored in CI variables. That matches how I deploy sister sites on shared EC2 with GitLab CI and Deployer 7. Secrets stay in Vault and CI, not in the repo.
For outbound mTLS to a payment gateway or internal API, Laravel's HTTP client accepts a cert option. Load PEM content from environment variables injected at deploy time. Never hardcode paths that only exist on one developer laptop.
Kubernetes with cert-manager
Install cert-manager and configure a ClusterIssuer pointing at Vault. Pods receive TLS secrets as Kubernetes secrets. Combine with Sealed Secrets for GitOps for non-PKI credentials. The PKI path handles rotation. Sealed Secrets handles static config.
Multi-cloud and hybrid setups
Vault runs well on a dedicated cluster reachable from all environments. Avoid mounting a separate PKI engine per cloud unless regulatory boundaries require it. A single intermediate CA with role-based separation is easier to audit. See multi-cloud secrets management for the broader identity and policy model.
Client portals with document upload and payment flows, like those built for Mijar Law Associates, need TLS at every layer. Public users hit Let's Encrypt at the edge. Background workers talking to Redis or PostgreSQL over TLS pull certs from Vault PKI on a short TTL.
Key Takeaways
- Mount the HashiCorp Vault PKI Secrets Engine with a root CA for signing only, and an intermediate CA for daily leaf issuance.
- Define PKI roles with strict domain lists, short max TTLs, and
generate_lease=trueso renewals are trackable. - Keep Let's Encrypt for public browser trust; use Vault PKI for internal mTLS, service mesh, and staging environments.
- Automate issuance and renewal through CI, cron, or cert-manager — never store private keys in Git or Ansible plaintext.
- Configure CRL/OCSP URLs, enable audit logging, and monitor cert expiry independently of Vault lease renewal.
- Revoke and tidy compromised or expired certificates regularly to keep CRL size manageable.
People Also Ask
What is the difference between Vault PKI and Vault KV secrets?
KV stores static key-value pairs you manage manually. PKI generates dynamic X.509 certificates with key pairs, signed by a CA inside Vault. PKI certs expire on a TTL and can be renewed or revoked. KV secrets persist until you overwrite or delete them.
Can Vault PKI replace Let's Encrypt for public websites?
Not without distributing your root CA to every visitor's browser or operating system. Let's Encrypt chains to publicly trusted roots. Vault PKI chains to a private root. Use Vault PKI for internal traffic and Let's Encrypt for public HTTPS.
How long should TLS certificate TTL be in Vault PKI?
Internal services commonly use 24 hours to 30 days. Shorter TTL limits exposure if a cert leaks. Balance that against renewal frequency and outage risk if automation fails. Start with 168 hours (7 days) and tighten once renewal is proven.
Does Vault store the private key after issuing a certificate?
Vault generates the key pair during issuance and returns the private key to the caller. It does not retain the leaf private key for later retrieval. If you lose the key, request a new certificate. CA private keys remain inside Vault unless exported during setup.
Build a cert lifecycle your team can maintain
The HashiCorp Vault PKI Secrets Engine turns certificate management from a quarterly scramble into an API call with policy, audit, and revocation built in. Start with a two-tier CA, scope your roles tightly, and automate renewal before you point production traffic at it. Pair public Let's Encrypt certs at the edge with Vault PKI inside your network, and you cover both trust models without duplicating effort.
If you need help hardening TLS across Laravel apps, Kubernetes clusters, or enterprise application deployments, the patterns above are the same ones I apply on production systems. Read how to handle secrets in CI/CD pipelines safely for the pipeline side, or Ansible Vault for secrets if you are still migrating off encrypted files. When you want hands-on setup on your infrastructure, contact us and we can map a PKI rollout to your stack.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

