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
<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.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.
# 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 pendingThe 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:
# 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 secretsin 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.
# 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
| Capability | OpenShift core | How it's covered / what fills it |
|---|---|---|
| Control-plane, etcd, kubelet certs | CORE | Cluster operators, auto-rotating. Don't touch. |
Internal service mTLS (.svc) | CORE | service-ca-operator annotations. |
| Secret storage primitive | CORE | base64 in etcd. Encryption at rest is opt-in. |
| Workload identity tokens | CORE | Bound, audience-scoped SA tokens (projected). |
| Public / browser-trusted certs | GAP | cert-manager + ACME, or a public CA issuer. |
| Private CA issuance for apps | GAP | cert-manager + Vault PKI / Venafi / Horizon. |
| Cert discovery & inventory | GAP | CLM platform (Venafi/CyberArk, Horizon). |
| Secret rotation & versioning | GAP | Vault, External Secrets Operator, cloud managers. |
| Dynamic / short-lived credentials | GAP | Vault dynamic secrets engines (DB, cloud, SSH). |
| HSM / key custody, BYOK | GAP | Vault + HSM seal, or a CLM vendor with HSM. |
| Keep secrets out of etcd entirely | GAP | Secrets 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?
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: ClusterIssuer6. Vendor Benchmark
Scored for an OpenShift team that already has secrets management and needs PKI. ● strong · ◐ partial · ○ absent.
| Dimension | HashiCorp Vault | Venafi → CyberArk | EverTrust Horizon | cert-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 creds | thousands of certs across many CAs; outages/audit are the pain | CLM without enterprise bloat, or EU/sovereign residency | certs 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: 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
Certificateresources whosedurationexceeds 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_secondsand alert at renewal-failed, not at expiry; the failure is the signal, the outage is too late.
# 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
.svcmTLS. - 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 K8SECSources: 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.
