BlogSecrets

Short-lived TLS certificates from Vault PKI

Run an internal CA in Vault and issue certs that live for hours, not years — rotation becomes a non-event.

Nov 4, 2025·4 min readAdvanced·By the SecOpsLog team · command-tested

A three-year TLS certificate in a Kubernetes Secret is a time bomb with a calendar invite. When it expires, dashboards go red and nobody remembers who generated the CSR. Vault's PKI secrets engine flips the model: Vault is your private CA, apps request certificates with a TTL measured in hours or days, and renewal is an API call — not a ticket. Leases bind lifetime; when the lease ends, the cert is dead whether or not anyone rotated the file on disk.

You will enable PKI, generate an intermediate CA, define a role that caps TTLs and allowed domains, then issue a certificate and read the lease. For HA Vault, auth methods, and dynamic secrets beyond PKI, continue in Vault from dev to production.

Short-lived cert issuance with Vault PKI

The leaf private key is generated in Vault (or by the client, depending on API). The lease binds lifetime — when it expires, treat the cert as dead.

1Root /intermediateCA material in Vault2PKI roledomains + max TTL3App authenticatesAppRole / K8s / JWT4Issue certPOST pki/issue/…5Leaf + CA chainreturned once6App serves TLSreloads on renew7Lease endscert must be replaced

Enable PKI and build an intermediate

Production setups keep a root CA offline and only the intermediate in Vault. For a lab, a Vault-generated root is fine — just do not pretend that lab root is your company trust anchor. Tune max-lease-ttl on the mount so no role can accidentally mint multi-year leaves. Document the CA hierarchy in runbooks: which mount is authoritative, who can sign intermediates, and where CRL/OCSP endpoints live.

vault-pki-setup.sh
vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki
# lab only — generate a root; prefer importing an intermediate in prod
vault write -field=certificate pki/root/generate/internal \
common_name="Vault Lab Root" ttl=87600h > lab-root.pem
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"

A role that refuses wild requests

Roles are the policy. Cap max_ttl, list allowed_domains, and turn on enforce_hostnames. A role that allows * with a 90-day TTL recreates the old long-lived cert problem inside Vault. Separate roles per service class — shop-svc for app certs, ingress-edge for public hostnames — so a compromised AppRole cannot mint arbitrary domains.

pki-role.sh
vault write pki/roles/shop-svc \
allowed_domains="shop.svc.cluster.local,shop.example.com" \
allow_subdomains=true \
enforce_hostnames=true \
max_ttl="72h" \
ttl="24h"
bash — issue a leaf certificatelive
vault write pki/issue/shop-svc common_name=checkout.shop.svc.cluster.local ttl=24h
Key Value
certificate -----BEGIN CERTIFICATE-----
private_key -----BEGIN RSA PRIVATE KEY-----
ca_chain [lab root / intermediate]
lease_duration 24h
store privately; Vault will not show the private key again

Hand the cert to the workload safely

In Kubernetes, prefer the Vault Agent injector or External Secrets patterns that refresh before TTL. Writing a leaf key into a long-lived Secret without renewal automation just moves the expiry bomb. The injector sidecar renews at ~80% of lease lifetime and reloads the app — or writes to a projected volume the process watches.

Publish the issuing CA certificate to clients that need to trust internal services — ingress controllers, service meshes, and curl in CI. Vault exposes it at pki/ca/pem. Rotate the intermediate on a schedule and cross-sign during overlap so renewals never require a flag day.

Protect the CA like production data
Anyone who can call pki/root/generate or change the intermediate can mint trusted certs for your domains. Lock the policy, audit PKI paths, and keep break-glass separate from app roles. Root and intermediate private keys should never share the same Vault policy namespace as application issue roles.
Long-lived files vs Vault PKI
Static cert files
Years of validity
Manual CSR ballet
Expiry pages at 3am
Copy/paste private keys
Vault-issued
Hours/days TTL
API-driven issue
Lease-aware renewal
Policy-bound domains

Where this goes next

PKI is one engine. Wire Kubernetes auth so pods never see a long-lived Vault token, and pair short-lived TLS with NetworkPolicy so a compromised cert cannot be exfiltrated to an unexpected destination. The Vault from dev to production course covers HA, auth methods, dynamic secrets, and PKI done properly.

Go deeper in a courseVault from dev to productionHA, auth methods, dynamic secrets, and PKI done properly.View course

Related posts