How to Install an ACME SSL Certificate in Kubernetes Using Cert-Manager?

1 Star2 Stars3 Stars4 Stars5 Stars (1 votes, average: 5.00 out of 5)
Loading...
ACME SSL Installation Kubernetes

Summary

When your cluster is handling traffic over an unsecured TLS channel, all traffic sent between your users and services is readable in plain text. If you are running NGINX Ingress or Traefik without automation for certificate management, then you are one expired certificate away from a production outage.

Cert-manager eliminates this problem forever, automatically issuing, renewing and binding ingress to Kubernetes without human interaction.

What Do You Need Before You Start?

There are five things you must have before you can get a single command to run successfully.

  • A working Kubernetes Cluster installed with Kubernetes v1.23 or above.
  • The kubectl utility is set up and logged in to your cluster.
  • One of the two most popular options is to use an ingress controller such as NGINX Ingress or Traefik.
  • Your domain’s DNS A record is resolved to your ingress controller’s public address
  • An EAB Credentials: ACME Directory URL, an EAB Key Identifier (KID), and an EAB HMAC Key

These are required to make cert-manager’s HTTP-01 challenge succeed. It will fail silently. Before proceeding, check DNS propagation using dig or nslookup.

Steps to Configure cert-manager & ACME service in Kubernetes

Step 1: Install Cert-Manager in Kubernetes

Install cert-manager using Helm. It is the recommended method for production clusters because it gives you version control, upgrade paths, and CRD management in one command.

Run these four commands in sequence:

kubectl create namespace cert-manager

helm repo add jetstack https://charts.jetstack.io

helm repo update

helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--version v1.14.4 \
--set installCRDs=true

After installation, confirm all three pods are running:

kubectl get pods -n cert-manager

You must see exactly three pods: cert-manager, cert-manager-webhook, and cert-manager-cainjector.

If any pod is in CrashLoopBackOff or Pending, the webhook will block certificate issuance downstream. Fix pod health before moving forward.

Step 2: Create a Kubernetes Secret for EAB Credentials

External Account Binding (EAB) credentials are used to verify cert-manager to your Commercial CA DigiCert, Sectigo, or GlobalSign. These credentials need to be stored in a Kubernetes Secret, and not hardcoded in YAML manifests.

Make a secret using this one-line command. To create a new secret, use the following command:

kubectl create secret generic acme-eab-secret \
--namespace cert-manager \
--from-literal=eab-kid="YOUR_EAB_KID" \
--from-literal=eab-hmac-key="YOUR_EAB_HMAC_KEY"

Substitute your own EAB_KID and YOUR_EAB_HMAC_KEY with your CA’s values from their dashboard. Whitespace from a browser or PDF is not valid for HMAC. You should first copy it into a plain text editor, then paste it back in.

Step 3: Define a ClusterIssuer or Issuer

A ClusterIssuer is the cert-manager resource that connects your cluster to your CA’s ACME endpoint. It works across all namespaces. Use it for shared infrastructure. A regular Issuer is scoped to a single namespace, and it is for tenant isolation.

Create a file named clusterissuer.yaml with this configuration:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: acme-issuer
spec:
  acme:
    server: https://your.acme-server.com/v2/DV
    email: [email protected]
    privateKeySecretRef:
      name: acme-private-key
    externalAccountBinding:
      keyID: YOUR_EAB_KID
      keySecretRef:
        name: acme-eab-secret
        key: eab-hmac-key
    solvers:
    - http01:
        ingress:
          class: nginx

Apply it:

kubectl apply -f clusterissuer.yaml

Three fields require your direct attention: server is your CA’s ACME directory URL, email is the address that receives expiry warnings, and ingress.class must match your actual ingress controller.

Use “traefik” for Traefik, and “nginx” for NGINX Ingress Controller. A mismatched ingress class is the single most common reason HTTP-01 challenges fail.

Step 4: Create a Certificate Resource

A Certificate resource tells cert-manager exactly which domains to secure and where to store the resulting TLS secret.

Create a file named certificate.yaml:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-ssl-cert
  namespace: default
spec:
  secretName: my-ssl-cert-tls
  issuerRef:
    name: acme-issuer
    kind: ClusterIssuer
  commonName: yourdomain.com
  dnsNames:
  - yourdomain.com
  - www.yourdomain.com

Apply it:

kubectl apply -f certificate.yaml

Cert-manager immediately contacts your CA, serves the ACME challenge token through your ingress, and, upon validation, stores the signed certificate as a Kubernetes TLS secret named my-ssl-cert-tls.

This entire process takes under 60 seconds on a correctly configured cluster.

Step 5: Reference the Certificate in Your Ingress

The ingress resource is where TLS termination actually happens. Update your ingress YAML to reference the TLS secret cert-manager created:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  namespace: default
  annotations:
    cert-manager.io/cluster-issuer: acme-issuer
spec:
  tls:
  - hosts:
    - yourdomain.com
    - www.yourdomain.com
    secretName: my-ssl-cert-tls
  rules:
  - host: yourdomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: your-service
            port:
              number: 80

Apply it:

kubectl apply -f ingress.yaml

The annotation cert-manager.io/cluster-issuer: acme-issuer is what triggers automatic certificate management. Without it, cert-manager ignores this ingress entirely. The annotation is the bridge between your ingress and your issuer. Never omit it.

Step 6: Verify Certificate and Auto-Renewal

Now we need to make sure that cert-manager has finished getting the certificate.

Run this command to check if cert-manager completed issuance:

kubectl describe certificate my-cert

We are looking for the message that says “Certificate issued successfully“.

If we see anything like Issuing, Failed, or Pending, that means the ACME challenge did not finish. In that case, we should first check the logs of the ingress controller and the DNS resolution.

To see when the certificates will be renewed:

kubectl get certificaterequests

Cert-manager will renew the certificates automatically thirty days before they expire. We do not need to renew the certificates.

If we want to test the renewal, we can force cert-manager to renew the certificate away by running:

kubectl cert-manager renew my-ssl-cert

This way, cert-manager can renew the certificates without any downtime.

FAQs

Can I use DNS-01 Validation of HTTP-01?

Yes, you can. The DNS-01 validation is used in conjunction with Cert-manager. It supports DNS providers like Cloudflare, AWS Route 53 and Google Cloud DNS. This is very useful when a port is not accessible to the public (80 is the default port).

Does cert-manager do well in production?

Yes, it is. Cert-manager is being used extensively in production. It automates the management of SSL/TLS certificates for private and public cloud deployments of Kubernetes.

Can I obtain a certificate with ACME on Kubernetes?

Yes, it’s possible to obtain a certificate with ACME. It should be validated with DNS-01, not HTTP-01 challenges. In order to make it work, your DNS server provider should be able to manage the DNS through APIs. Then, you configure the proper DNS resolver for cert-manager.

Conclusion

With cert-manager, Kubernetes security is simplified by automating the management of certificates: issuance, deployment and renewal. After setup, all your apps continue to be secured with valid TLS certificates without any additional administrative burden or risk of unknown certificates expiring.

For a trusted ACME-compatible SSL certificate for your Kubernetes environment, contact us today to order an SSL certificate and receive expert deployment and configuration assistance.