Skip to main content

    Using a Commercial CA With cert-manager in Kubernetes

    cert-manager is not Let's Encrypt only. How to issue paid DV, wildcard and OV certificates in Kubernetes with a commercial CA's ACME endpoint and EAB.

    MS
    My-SSL Team
    ·
    14 min read
    ·
    Published August 9, 2026
    ·
    Last updated August 9, 2026

    cert-manager issues certificates from any certificate authority that runs an ACME directory, not only from Let’s Encrypt. Commercial CAs run them too — Certum’s sits at https://acme.certum.pl/directory — and the one difference that matters is External Account Binding: a Key ID and HMAC key issued against the certificate you paid for, which cert-manager presents when it registers its ACME account. Where a CA has no ACME endpoint, or where the product is an OV or EV certificate whose organization has not been pre-validated, cert-manager cannot issue it at all and the certificate arrives as PEM files you turn into a kubernetes.io/tls Secret by hand. As of August 2026 that manual route means roughly two replacements a year per certificate, because the CA/Browser Forum capped TLS validity at 200 days on March 15, 2026.

    If you are still picking the certificate rather than installing one, decide the automation path first, because it quietly narrows the product list: the SSL certificates My-SSL issues through Certum include the domain-validated and wildcard products that go through an ACME endpoint as well as the organization-validated ones that need a person in the loop. Everyone already holding a certificate: skip to the Secret route further down.

    The two routes a commercial certificate takes into a Kubernetes cluster: an automated ACME path and a manual path that ends in a hand-built SecretTwo horizontal lanes end at the same place. The upper lane, labelled Path A, runs from the certificate authority’s ACME directory through a cert-manager ACME Issuer carrying External Account Binding credentials, then to a Certificate resource, and finally to a TLS Secret read by the Ingress. Renewal on this lane happens by itself. The lower lane, labelled Path B, runs from the CA portal where a human completes organization validation, to PEM files delivered by email, to a Secret created with kubectl, and then to the same Ingress. The organization validation step on the lower lane is highlighted because it is the step that cannot be automated, and renewal on that lane is a calendar entry rather than a controller.Same Ingress, two very different supply chainsPath A — ACME directory + External Account BindingCA ACMEdirectoryACME Issuerkid + HMACCertificateresourceSecretread by IngressRenewal: the controller does it. Nobody opens a ticket.Path B — buy it, validate it, install it yourselfCA portalorg validationPEM filescert + chain + keykubectlcreate secret tlsSecretread by IngressRenewal: a calendar reminder, roughly twice a year per certificate.The highlighted step on each lane is the one that decides which lane you are on.
    Nothing about Kubernetes decides which lane you get. Your CA does, and so does the validation level you bought.

    Can cert-manager use a commercial CA?

    Yes, wherever the CA publishes an ACME directory. cert-manager’s ACME Issuer takes a server URL and speaks RFC 8555 to whatever answers, so a paid directory is configured the same way as Let’s Encrypt with one block added. Tutorials default to Let’s Encrypt because it needs no account credentials, which makes the YAML three lines shorter — not because it is the only option.

    That framing has consequences beyond convenience. Plenty of teams assume cert-manager is a Let’s Encrypt client, conclude that a purchased certificate has no place in a cluster, and end up running two unrelated processes: a tidy automated one for public sites and a spreadsheet for the certificates their compliance team insisted on. The two do not have to be separate, and on most commercial CAs they are not.

    Certum documents an ACME v2 service at https://acme.certum.pl/directory, with http-01 available for single-domain, multi-domain and IP-address certificates and dns-01 for single-domain, multi-domain and wildcard ones. Registration wants the email address on the Certum account holding the order, and it hands back the two External Account Binding values that tie the ACME account to that order. If you already run Certbot against an ACME endpoint, the credentials are the same ones; only the client changes.

    What does not change is the boundary of what ACME can prove. The protocol demonstrates control of a domain name. It has no mechanism for confirming that a company is registered in Warsaw or that the person requesting the certificate works there, so anything above domain validation needs a step that happens somewhere other than your cluster.

    What you need before you configure anything

    Four things, and three of them come from the CA rather than the cluster: the ACME directory URL, the Key ID and HMAC key generated against your order, the email address on the CA account, and a working challenge route — an Ingress that can serve http-01 tokens, or DNS API credentials for dns-01. Wildcards force the DNS route; there is no HTTP challenge that can prove control of *.example.com.

    Collect the EAB values before you write any YAML. On most CAs they are shown once, in the order or product detail view, and regenerating them invalidates the pair — which is a bad thing to discover after an Issuer has already registered an account with the old ones. Treat them like an API key, because that is what they are.

    One thing you do not need: a CSR. cert-manager generates the key pair and the certificate signing request itself, inside the cluster, and the private key never leaves the Secret it writes. That is the opposite of the manual purchase flow, where you generate the CSR yourself and have to keep the matching key safe until the certificate comes back.

    How External Account Binding credentials travel from a certificate order to a cert-manager ACME IssuerFour stacked stages connected by downward arrows. The first stage is ordering the certificate in the certificate authority’s portal, which produces two credentials. The second stage shows those two credentials side by side: a Key ID, which is plain text and must not be encoded, and an HMAC key, which must be base64url encoded and is highlighted because getting its encoding wrong is the usual failure. The third stage stores the HMAC value in a Kubernetes Secret. The fourth stage is the cert-manager ACME Issuer, whose externalAccountBinding block references the Key ID and the Secret, so that the ACME account it registers is bound to the order that was paid for.Two credentials, one of which has to be encoded exactly right1. Order the certificate in the CA portalThe order is what the ACME account gets bound toKey ID (kid)plain text — never encode itHMAC keybase64url — encoded once, not twice2. Store the HMAC value in a Kubernetes Secretkubectl create secret generic … --from-literal3. ACME Issuer: externalAccountBinding.keyID + keySecretRefRegistration succeeds once, then the account key does the work
    The Key ID identifies the account and the HMAC key proves you own it, so a mistyped Key ID and a mis-encoded HMAC key fail in different ways.

    Setting up an ACME Issuer with External Account Binding

    Two objects do the work. A Secret holds the HMAC key, and a ClusterIssuer references it through an externalAccountBinding block alongside the Key ID. cert-manager registers an ACME account once, signs that registration with the HMAC key to prove the account belongs to your order, and stores its own account key in a second Secret named by privateKeySecretRef.

    Create the EAB Secret first. Use --from-literal so kubectl handles the transport encoding and you are not tempted to base64 the value yourself:

    kubectl create secret generic ca-eab-hmac \
      --namespace cert-manager \
      --from-literal=secret='<the base64url HMAC key from your CA>'

    Then the issuer. This one is written as a ClusterIssuer so certificates in any namespace can use it; swap the kind to Issuer if you want it scoped to one namespace instead.

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: commercial-ca
    spec:
      acme:
        server: https://acme.certum.pl/directory
        email: billing@example.com
        privateKeySecretRef:
          name: commercial-ca-account-key
        externalAccountBinding:
          keyID: "<the Key ID from your CA>"
          keySecretRef:
            name: ca-eab-hmac
            key: secret
        solvers:
          - dns01:
              cloudflare:
                apiTokenSecretRef:
                  name: cloudflare-api-token
                  key: api-token

    A few details in there are easy to get wrong. The keyID is plain text and must not be encoded. The key under keySecretRef is the field name inside the Secret, not the HMAC value. And keyAlgorithm, which older guides still show, has been deprecated since cert-manager v1.3.0 — the upstream library fixes the algorithm at HS256, so setting it does nothing.

    Check that registration worked before you request anything: kubectl describe clusterissuer commercial-ca should show a Ready condition and an ACME account URI. Then the Certificate itself is ordinary — nothing in it hints that the issuer is a paid one:

    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: example-com-tls
      namespace: web
    spec:
      secretName: example-com-tls
      issuerRef:
        name: commercial-ca
        kind: ClusterIssuer
      commonName: example.com
      dnsNames:
        - example.com
        - "*.example.com"

    cert-manager writes the result into a Secret of type kubernetes.io/tls with tls.crt and tls.key in it, which is the same shape an Ingress expects from a certificate you installed by hand. From the Ingress side the two paths are indistinguishable, and that is worth knowing: you can migrate a manually installed certificate to cert-manager by pointing a Certificate at the same secretName, with no change to the Ingress at all.

    Which validation levels can actually be automated?

    Domain validated certificates automate completely, wildcards and multi-domain certificates included, because everything the CA checks is something ACME can test. Organization validated certificates automate only where the CA supports it and has already vetted your company out of band. Extended validation is supported by fewer CAs still. The dividing line is not the certificate — it is whether a human has to look at a document.

    Which certificate validation levels a commercial ACME endpoint can issue automatically, and what has to happen first for each oneA three-column panel with a header row and three data rows. The columns are the validation level, whether it can be issued over ACME, and what must happen before the first automated issuance. Domain validated certificates, including wildcard and multi-domain, are issued fully over ACME once External Account Binding credentials exist. Organization validated certificates are issued over ACME only at certificate authorities that support it, and only after the organization has been vetted once in the portal; this row is highlighted because it is the row buyers most often get wrong. Extended validation certificates follow the same pre-validation rule but are supported by fewer authorities, so the practical answer for most buyers is that they arrive as files.ACME proves domain control. It cannot prove a company exists.Validation levelIssued over ACME?What has to happen firstDV, wildcard,multi-domainYes, end to endEAB credentials, plus a DNS-01challenge for wildcardsOV(organization)At some CAsThe CA vets your organizationonce, out of band, in the portalEV(extended)RarelySame pre-validation, supported byfewer CAs — usually arrives as filesBuy the validation level first, then find out which lane it puts you in — that order costs people a sprint.
    The organization vetting is a one-time human step either way. What differs is whether every renewal after it needs a human too.

    The pattern the CAs that do support OV over ACME have converged on is pre-validation. Your organization is vetted once, in the portal, the way it always was: company registry lookup, address confirmation, usually a phone call to a number the CA found independently. That validation is then stored against your account, and the ACME endpoint issues against it. A request naming an organization the CA has not already validated is rejected outright rather than queued for review. GlobalSign, DigiCert and Sectigo all document a version of this.

    Which means the honest planning question is not “can I automate OV” but “does my CA offer it, and did I buy the product that includes it”. Get that wrong and the certificate still arrives — it just arrives as an email attachment, and every renewal after it does too. If organization validation is a requirement rather than a preference, the OV SSL certificates we issue list the company documents the validation asks for, which is the part that sets your real lead time.

    There is a second reason teams end up on the manual path that has nothing to do with validation level: the certificate has to be usable outside the cluster. A certificate that also terminates on a hardware load balancer, a legacy Windows host, or a partner’s appliance needs a key you can export, and cert-manager deliberately keeps the key it generates inside the cluster. Distributing it defeats the point of having it there.

    When there is no ACME endpoint: the Secret route

    A certificate you bought and validated by hand goes into Kubernetes as a TLS Secret, and the Ingress reads it by name. Concatenate the leaf certificate with its intermediate chain, keep the private key you generated alongside the CSR, and create a Secret of type kubernetes.io/tls. cert-manager plays no part in this path, which also means nothing in the cluster will renew it for you.

    cat example.crt intermediate.crt > fullchain.crt
    
    kubectl create secret tls example-com-tls \
      --namespace web \
      --cert=fullchain.crt \
      --key=example.key

    Order matters inside fullchain.crt: leaf first, then each intermediate up the chain, and no root. Get it backwards and the Ingress will still start — the failure shows up later, on the clients whose trust stores cannot build the path themselves, which is usually mobile apps and older Java runtimes rather than desktop browsers. A quick openssl verify -untrusted intermediate.crt example.crt before you create the Secret is cheaper than that bug report.

    The Ingress side is one field:

    spec:
      tls:
        - hosts:
            - example.com
          secretName: example-com-tls

    Renewal is a replace, not an update in place: rebuild the Secret from the new files with kubectl create secret tls … --dry-run=client -o yaml | kubectl apply -f -. Controllers such as ingress-nginx watch the Secret they were pointed at and reload the certificate in memory when it changes, so no pod restart is needed and connections are not dropped. Workloads that mount the same Secret as a volume are the exception worth checking — the file on disk updates, but a process that read the certificate once at startup keeps serving the old one until something restarts it.

    One certificate can back several Ingresses, but the Secret has to exist in each namespace that references it, because Ingress cannot read a Secret from a namespace other than its own. Teams solve that with a replicator controller or by having cert-manager issue per namespace. On a wildcard certificate the copies multiply quickly, and every one of them is a place the old certificate can survive a renewal you thought you had finished.

    When does cert-manager renew, and what changed in 2026?

    With renewBefore unset and a certificate lasting more than 90 days, cert-manager renews two-thirds of the way through its duration rather than at a fixed number of days before expiry. On a 199-day certificate that lands around day 133, leaving about 66 days of slack — generous enough that a couple of failed attempts still resolve long before anything expires.

    The reason those numbers are 199 rather than 398 is CA/Browser Forum ballot SC-081v3, which cut the maximum TLS validity to 200 days on March 15, 2026, drops it to 100 days on March 15, 2027, and to 47 days on March 15, 2029. Certum issues 199 days over ACME as of March 13, 2026, one day inside the cap. The 199-day limit and what it changed is covered in its own right elsewhere on this site.

    How often a certificate has to be replaced as the maximum TLS validity period falls from 398 days to 47 daysFour horizontal bars drawn to scale, one per validity regime, each marked with the point two-thirds through its life where cert-manager renews by default. The first bar is 398 days, the maximum before March 2026, and needs roughly one replacement a year. The second bar is 199 days, the length Certum issues over ACME since March 13 2026 under the 200-day cap, and needs roughly two a year. The third bar is 100 days from March 2027 and needs roughly four. The fourth bar is 47 days from March 2029 and needs roughly eight. The bars shrink while the number of replacements per year grows, which is the argument for automating issuance rather than the calendar.The bar shrinks, the workload multipliesGold mark = where cert-manager renews when renewBefore is unset398 daysuntil Mar 2026≈1× / year199 daysnow≈2× / year100 daysfrom Mar 2027≈4× / year47 daysfrom Mar 2029≈8× / yearBars are drawn to scale. Dates follow the CA/Browser Forum schedule adopted in ballot SC-081v3.
    A yearly renewal survives being somebody’s reminder. Eight of them per certificate does not, which is the real deadline behind these dates.

    What that schedule does to a manual process is the part worth sitting with. One renewal a year is something a calendar reminder handles. Two is irritating. Eight, per certificate, across however many certificates you hold, is not a process any team sustains by hand — and 2029 is close enough that certificates bought in 2028 will already be renewing under it. Our guide to preparing for 47-day certificates goes through the wider inventory problem.

    Setting renewBefore explicitly is still worth doing on a paid issuer. Commercial CAs apply order and rate limits that Let’s Encrypt does not, and a renewal that fails because an order quota reset on the first of the month is easier to absorb with 60 days left than with ten. A value between a quarter and a third of the certificate’s life is a reasonable default:

    spec:
      renewBefore: 1440h  # 60 days

    There is a newer mechanism worth knowing about but not yet worth relying on. ACME Renewal Information, standardised as RFC 9773, lets the CA tell the client when to renew — useful during a mass revocation, when the CA needs everyone to re-issue early rather than on their own schedule. cert-manager put it behind the ACMEUseARI feature gate in v1.21, and as of August 2026 it is experimental. Pilot it; do not assume it is already deciding your renewals.

    What breaks most often

    Almost every failure on a commercial ACME issuer happens at account registration, before a single certificate is requested, and almost all of those are the HMAC key’s encoding. The second cluster of failures is challenges — specifically wildcards attempted over HTTP. Both fail loudly in the Issuer or Order status, so the diagnosis is quick once you know where to look.

    What you seeWhat it usually meansFix
    A base64 decode failure on the external account binding key dataThe HMAC key was encoded twice, or with standard base64 instead of base64urlRecreate the Secret with --from-literal and the value exactly as the CA displayed it
    urn:ietf:params:acme:error:externalAccountRequiredThe directory needs EAB and the Issuer has no externalAccountBinding blockAdd the block, then delete the account key Secret so registration is retried
    Invalid MAC, or invalid key IDCredentials from a different order, or regenerated after the Issuer registeredReissue the EAB pair in the CA portal and recreate both Secrets
    Order stuck pending on a *.example.com nameA wildcard is being attempted over http-01Move that solver to dns01; wildcards have no HTTP challenge
    Certificate renewed, browser still shows the old oneA pod mounted the Secret as a volume and read it once at startupRestart that workload, or run a controller that does it on Secret change

    Editing an Issuer that has already registered is the one operation with a non-obvious rule. cert-manager will not re-register an account that already has a stored key, so changing EAB credentials on a live Issuer appears to do nothing. Delete the Secret named in privateKeySecretRef and the next reconcile registers cleanly with the new values.

    Choosing between the two paths

    Take the ACME path whenever the CA offers one for the product you need and the private key can stay in the cluster. Take the Secret path when the validation level is not available over ACME, when the same certificate has to terminate somewhere outside Kubernetes, or when a policy requires the key to live in a store you control. Most clusters end up running both, and that is a reasonable outcome rather than a failure of design.

    What is worth avoiding is drifting into the Secret path by accident, because the automation question was never asked at purchase time. That is the expensive version: an OV wildcard bought on a three-year plan in an era of 199-day issuance, now generating a reissue every few months that somebody has to notice, download, concatenate, and apply across four namespaces. The certificate is fine. The process around it is what fails.

    A practical order of operations: confirm whether your CA runs an ACME directory and which of its products reach it, decide whether your compliance requirements genuinely need organization validation, and only then buy. Reversing those steps is how teams discover in week three that the certificate they already own cannot be automated. If the inventory side is the harder problem, our notes on managing certificates at scale cover tracking what you hold before the renewals start stacking up.

    Frequently Asked Questions

    Get instant answers to common questions about SSL certificates and our services.

    Still Have Questions?

    Our SSL experts are available 24/7 to help with any questions about certificates, installation, or technical issues.

    Buy the certificate that fits the path you can run

    Automation is decided at purchase, not at deployment. Our Certum certificate options and pricing set out the validation level, the domain coverage and the validation documents each product asks for, so you can check what a renewal will cost you in effort before the first one arrives.

    Related reading