Back to Blog
Platform Reference · OpenShift & Kubernetes PKI

PKI & Certificates on
Red Hat OpenShift

OpenShift ships a complete, auto-rotating PKI for itself — and nothing for your applications. This is the architecture of the three trust domains, why Kubernetes Secrets are weaker than they look, and how cert-manager becomes the fabric that makes any PKI vendor swappable.

Riad DAHMANIk8sec Security ResearchAugust 202616 min readOpenShiftcert-managerSecrets
Minimalist abstract hero: a glowing trajectory crossing nested trust-boundary rings into a core, representing PKI trust domains on OpenShift

The One-Sentence Model

OpenShift ships a complete, auto-rotating PKI for itself — control plane, etcd, kubelets — plus a small bonus CA for internal service traffic. It ships no PKI for your applications, no external trust, and no secrets lifecycle beyond a base64 blob in etcd. Every product in the benchmark below exists to fill one of those three holes.

The most common architectural mistake is treating "certificates on OpenShift" as a single problem. There are three, with different owners, rotation behaviour, and failure modes. Written for a team that already has secrets management and is missing the PKI half.

1. Three Trust Domains, Not One

DOMAIN 1 · CONTROL-PLANE PKI cluster operators · auto-rotates · you do nothing kube-apiserver signers etcd · kubelet CSR signers aggregator / front-proxy CA RISK · key custody signer keys on control-plane nodes — node root = mint any identity DOMAIN 2 · SERVICE CA free internal mTLS · most teams miss it service-ca-operator annotate a Service → serving-cert-secret-name COVERS · <svc>.<ns>.svc mTLS auto-rotated, cluster-internal only DOES NOT COVER ✗ any name outside .svc ✗ browser / public trust ✗ external mTLS to partners DOMAIN 3 · APPLICATION PKI THE GAP · nothing ships for this Route / Ingress certsdefault wildcard is self-signed Workload identityexternal mTLS, DB TLS — manual FILLED BY THE ADD-ON LAYER cert-manager Operator (GA) ↳ Vault PKI · Venafi/CyberArk ↳ EverTrust Horizon ↳ ACME / Let's Encrypt, private CA
Three trust domains, three owners, three rotation models. OpenShift covers the first two completely and ships nothing for the third — that is where the add-on layer plugs in.
Domain 1 · Control-plane PKI
Multiple independent CAs, each owned by a cluster operator, all auto-rotating. You inspect them; you never manage them. Manual edits get reverted.
Domain 2 · service-ca
Free internal PKI for <svc>.<ns>.svc mTLS. Annotate a Service, get a rotating cert. Most teams never turn it on and buy a vendor they didn't need.
Domain 3 · Application PKI
Browser-trusted certs, external mTLS, discovery, rotation, governance — the gap. Nothing ships for this; it is entirely yours to solve.

2. What OpenShift Core Actually Covers

Domain 1 — the cluster's own PKI (fully covered)

You inspect the trust material; you don't manage it. Rotation is automatic on each operator's own schedule.

inspect platform trust material
# the platform's trust material lives here
oc get secrets -n openshift-config
oc get configmap -n openshift-config-managed

# inspect any serving cert's real expiry
oc get secret <tls-secret> -n <ns> -o jsonpath='{.data.tls\.crt}' \
  | base64 -d | openssl x509 -noout -subject -issuer -dates

# pending node CSRs (kubelet cert rotation)
oc get csr -o wide | grep -i pending
The real risk here isn't expiry — it's key custody. The signer keys live on control-plane nodes. Root on a master means minting a valid kubelet or admin identity at will, which is why etcd / node compromise is a total-cluster event, not a single-service one.

Domain 2 — service-ca: the free internal PKI most teams never turn on

If you need mTLS between services inside the cluster, you likely don't need a vendor at all. Annotate the Service, get a rotating cert:

free rotating internal mTLS
# 1. Service gets a signed serving cert, auto-rotated, as a TLS secret
oc annotate service my-api \
  service.beta.openshift.io/serving-cert-secret-name=my-api-tls

# 2. Consumers get the CA to trust it
oc annotate configmap my-ca-bundle \
  service.beta.openshift.io/inject-cabundle="true"
#    -> ConfigMap now contains service-ca.crt

Valid only for <service>.<namespace>.svc names. Useless for anything a browser or external partner must trust.

Domain 3 — application certificates (not covered)

The default ingress wildcard is self-signed. Every externally trusted certificate, every external mTLS identity, and the entire lifecycle discipline around them is yours to solve.

3. How Secrets Actually Work — and Why They're Weak

A Kubernetes Secret is base64-encoded, not encrypted. That's an encoding for binary-safe transport, never a security control. Four properties define the threat model:

  • Encryption at rest is OFF by default. Until you enable it, every Secret sits in etcd in cleartext — and in every etcd backup.
  • RBAC is per-namespace, not per-secret. get secrets in a namespace means all secrets in it. There is no per-key authorization.
  • No versioning, no rotation, no lease. A static Secret is static forever. Nothing expires it, rotates it, or tells you it leaked.
  • No access audit beyond the API log. You see the API call; you get no secret-level access trail.
enable etcd encryption at rest
# covers secrets, configmaps, routes, oauth tokens
oc patch apiserver cluster --type=merge \
  -p '{"spec":{"encryption":{"type":"aescbc"}}}'   # or aesgcm

# watch it converge — this rewrites resources, allow time
oc get openshiftapiserver \
  -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{end}'
Encryption at rest is not a secrets-management strategy. It defeats stolen-etcd and stolen-backup attacks. It does nothing about an attacker with API access, a pod that mounts the secret, or node root. That's what an external secrets store buys you: the secret is never in etcd at all.

4. Coverage Matrix — Core vs the Gap

CapabilityOpenShift coreHow it's covered / what fills it
Control-plane, etcd, kubelet certsCORECluster operators, auto-rotating. Don't touch.
Internal service mTLS (.svc)COREservice-ca-operator annotations.
Secret storage primitiveCOREbase64 in etcd. Encryption at rest is opt-in.
Workload identity tokensCOREBound, audience-scoped SA tokens (projected).
Public / browser-trusted certsGAPcert-manager + ACME, or a public CA issuer.
Private CA issuance for appsGAPcert-manager + Vault PKI / Venafi / Horizon.
Cert discovery & inventoryGAPCLM platform (Venafi/CyberArk, Horizon).
Secret rotation & versioningGAPVault, External Secrets Operator, cloud managers.
Dynamic / short-lived credentialsGAPVault dynamic secrets engines (DB, cloud, SSH).
HSM / key custody, BYOKGAPVault + HSM seal, or a CLM vendor with HSM.
Keep secrets out of etcd entirelyGAPSecrets Store CSI Driver — mounts straight from the vault.

5. The Integration Fabric: cert-manager

This is the key architectural point. Don't pick a PKI vendor and then work out how to wire it in — cert-manager is the wiring, and the vendor is just the trust anchor behind it. Red Hat's cert-manager Operator for Red Hat OpenShift is GA (Day-2, via OLM) and FIPS-designed from v1.14.0. Your decision reduces to: which issuer sits behind cert-manager?

the shape is identical regardless of vendor — only issuerRef changes
apiVersion: cert-manager.io/v1
kind: Certificate
metadata: {name: api-tls, namespace: my-app}
spec:
  secretName: api-tls          # cert lands here, auto-renewed
  duration: 720h               # short-lived by default
  renewBefore: 240h
  commonName: api.example.com
  dnsNames: [api.example.com]
  issuerRef:
    name: vault-issuer         # or venafi-issuer / horizon-clusterissuer
    kind: ClusterIssuer

6. Vendor Benchmark

Scored for an OpenShift team that already has secrets management and needs PKI. ● strong · ◐ partial · ○ absent.

DimensionHashiCorp VaultVenafi → CyberArkEverTrust Horizoncert-manager alone
General secrets mgmt● KV, dynamic creds, transit, leases◐ via CyberArk portfolio, not Venafi itself○ not its purpose○ none
PKI / CA issuance● full engine; great for short-lived internal certs● orchestrates across AD CS, EJBCA, public/cloud CAs● issuance + its own CA; multi-CA◐ only via an external issuer
Discovery & inventory○ knows only what it issued● flagship strength — network-wide discovery● automated discovery & inventory○ cluster-scoped only
Governance / policy / audit◐ strong audit, lighter cert policy● enterprise policy, approvals, compliance● policy, audit trails, reporting◐ Approver Policy add-on
OpenShift integration● certified CSI provider, Agent Injector● cert-manager issuer + Discovery Agent● horizon-issuer external issuer● native, GA Red Hat operator
Keeps secrets out of etcd● CSI mount or agent sidecar○ n/a○ n/a○ writes certs into Secrets
HSM / key custody● HSM auto-unseal (Enterprise)● BYOK / managed HSM● HSM partners○ none
Best when…one system for secrets and internal PKI + dynamic credsthousands of certs across many CAs; outages/audit are the painCLM without enterprise bloat, or EU/sovereign residencycerts are cluster-internal and you already have a CA
Procurement caution. Venafi TLS Protect → CyberArk Certificate Manager; Firefly → Workload Identity Manager; Venafi Kubernetes Agent → Discovery Agent. With the Palo Alto Networks acquisition of CyberArk completed Feb 2026, treat post-acquisition branding as unsettled — confirm current product names in vendor docs before writing them into a contract.

7. Advanced Techniques

Once cert-manager is the fabric and service-ca covers the inside, the maturity curve is about making certificates short-lived and self-healing so a human never touches one.

Dynamic, short-lived PKI with Vault

Instead of long-lived certs and calendar-driven panic, issue 24-hour certs from a Vault PKI role and let cert-manager renew them continuously. A leaked cert is a problem for hours, not months.

Vault PKI role → cert-manager ClusterIssuer (short-lived)
# Vault: a role that only mints tightly-scoped, short-TTL leaf certs
vault write pki_int/roles/openshift-apps \
  allowed_domains="apps.internal" allow_subdomains=true \
  max_ttl="24h" ttl="24h" key_usage="DigitalSignature,KeyEncipherment"

# cert-manager consumes it; every Certificate renewBefore keeps it fresh
# (issuerRef.kind: ClusterIssuer -> vault-issuer)

Workload identity beyond X.509: SPIFFE/SPIRE

For service-to-service authn that outgrows service-ca, SPIRE issues SPIFFE SVIDs — short-lived, automatically-rotated identities keyed to workload attestation (namespace, SA, image), not to a hostname. It composes with cert-manager via the SPIRE controller-manager and gives you mTLS whose identity survives IP and DNS churn.

Govern issuance, don't just automate it

  • cert-manager approver-policy — gate which issuers a namespace may use and which SANs it may request, so a compromised tenant can't mint *.yourbank.com.
  • Policy at admission — a Kyverno rule that rejects Certificate resources whose duration exceeds your ceiling (e.g. > 90 days) makes "short-lived" an enforced invariant, not a suggestion.
  • Expiry as an SLO — scrape cert-manager's certmanager_certificate_expiration_timestamp_seconds and alert at renewal-failed, not at expiry; the failure is the signal, the outage is too late.
Prometheus: alert on certs failing to renew (not on expiry)
# fires while there is still time to fix it
- alert: CertRenewalFailing
  expr: (certmanager_certificate_expiration_timestamp_seconds - time()) < 7*24*3600
  for: 1h
  labels: {severity: warning}
  annotations:
    summary: "Cert {{ $labels.name }} in {{ $labels.namespace }} renews in < 7d and is not refreshing"

8. Recommendation

You have secrets management without embedded PKI — the cleanest possible starting point, because the PKI layer slots in beside it rather than replacing it.

  • Install the cert-manager Operator first, regardless of vendor. It's GA, Red Hat-supported, and becomes the abstraction that makes the vendor swappable. Deciding later means rework.
  • Turn on service-ca for everything internal. Free, auto-rotating, already installed. Don't buy a vendor to solve .svc mTLS.
  • Enable etcd encryption today — one patch, immediate win against stolen-etcd/backup.
  • Then choose by which pain is real. Issuance + short-lived internal certs and consolidation with secrets → Vault (most mature Red Hat integration). "We don't know how many certs we have and one expired last quarter" → that's discovery/governance → Venafi/CyberArk or Horizon (the lighter, EU-sovereign option).
  • Add the Secrets Store CSI Driver to bypass etcd entirely — the strongest control available, and it composes with Vault.

Vault and a CLM platform aren't mutually exclusive: large estates run Vault as the issuing engine and short-lived-credential source, with the CLM platform as the governance and discovery plane above it.

Managed platforms hand you a beautiful PKI — for themselves. The certificates that actually face your users and partners live in Domain 3, and OpenShift ships nothing there on purpose. Get cert-manager in as the fabric first; the vendor behind it is a decision you can change later. The one thing you cannot defer is deciding who owns Domain 3 — because right now, by default, nobody does.

— k8sec Security Research

Map every certificate and secret before one expires on you.

K8SEC correlates cluster PKI, service-ca coverage, etcd encryption state, and the Domain-3 gap so you can see what's trusted, what's rotating, and what's about to break.

Explore K8SEC

Sources: Red Hat documentation (cert-manager Operator GA, FIPS design v1.14.0+, tested issuers; service-ca-operator; etcd encryption). Vault/OpenShift integration per Red Hat (certified CSI provider, Agent Injector). Venafi→CyberArk→Palo Alto acquisition chain and product renames per vendor sources (Palo Alto completed the CyberArk acquisition 11 Feb 2026). EverTrust Horizon issuer per EverTrust docs. Secret/etcd threat framing cross-checked against the CIS Kubernetes Benchmark.

On this page

Contents

The one-sentence modelThree trust domainsWhat core coversHow Secrets really workCoverage matrixThe integration fabricVendor benchmarkAdvanced techniquesRecommendationFinal word