DEV Community

Cover image for Kubernetes Ingress Playlist – Part 6: Securing the Kubernetes Ingress Using Cert-Manager with HTTPS

Kubernetes Ingress Playlist – Part 6: Securing the Kubernetes Ingress Using Cert-Manager with HTTPS

In the previous parts of our Kubernetes Ingress playlist, we covered installing the NGINX Ingress Controller, implementing host/path-based routing, and enabling authentication and self-signed TLS. Now, it's time to move a step ahead and automate certificate management using Cert-Manager — a powerful tool that simplifies issuing and renewing SSL/TLS certificates within your Kubernetes cluster.

In this part, we’ll:

  1. Deploy the simple-nodejs-app
  2. Install and configure Cert-Manager
  3. Automatically issue TLS certificates via Let’s Encrypt using ClusterIssuer
  4. Secure our NGINX Ingress endpoint with HTTPS

What is Cert-Manager?

Cert-Manager is a native Kubernetes certificate management controller that helps manage and automate the issuance, renewal, and use of TLS certificates. It supports multiple certificate issuers such as:

  1. Let’s Encrypt (ACME)
  2. HashiCorp Vault
  3. Self-signed certificates
  4. Venafi, and more

With Cert-Manager, you don’t need to manually generate and rotate certificates. It integrates seamlessly with Kubernetes and works great with Ingress resources.

As in previous parts, we’ll use the simple-nodejs-app exposed via a Kubernetes Service and secured via Ingress. The key difference this time is: we'll use Cert-Manager to get a real TLS certificate from Let’s Encrypt, making HTTPS truly production-ready.

Step 1: Install Cert-Manager using Helm

We will use helm to install cert manager. Following commands will install the Cert-Manager controller and its required CustomResourceDefinitions (CRDs).

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

helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.14.3 \
  --set installCRDs=true
Enter fullscreen mode Exit fullscreen mode

You will see output:

NAME: cert-manager
LAST DEPLOYED: Wed Aug  6 00:16:00 2025
NAMESPACE: cert-manager
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
cert-manager v1.14.3 has been deployed successfully!
Enter fullscreen mode Exit fullscreen mode

You can verify the installation

$ kubectl get pods --namespace cert-manager
NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-6c4645d66c-vlrd7              1/1     Running   0          4m23s
cert-manager-cainjector-55c5b94bfc-mnhln   1/1     Running   0          4m23s
cert-manager-webhook-549d7475d7-f9rzw      1/1     Running   0          4m23s
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a ClusterIssuer for Let’s Encrypt (Staging)

Cert-Manager needs an Issuer to request certificates from a Certificate Authority (CA) like Let’s Encrypt. We’ll create a ClusterIssuer, which issues certificates for the entire Kubernetes cluster. You can create a ClusterIssuer in any namespace — it's a cluster-wide resource, not namespace-scoped.

Create manifest (cluster_issuer.yaml)

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-nginx-cert
spec:
  # ACME issuer configuration
  # `email` - the email address to be associated with the ACME account (make sure it's a valid one)
  # `server` - the URL used to access the ACME server’s directory endpoint
  # `privateKeySecretRef` - Kubernetes Secret to store the automatically generated ACME account private key
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: newabog237@misehub.com
    privateKeySecretRef:
      name: letsencrypt-nginx-cert
    solvers:
      - http01:
          ingress:
            class: nginx
Enter fullscreen mode Exit fullscreen mode

Apply it and verify it:

$ kubectl apply -f cluster_issuer.yaml 
clusterissuer.cert-manager.io/letsencrypt-ngionx-cert created

$ kubectl get clusterissuer.cert-manager.io/letsencrypt-nginx-cert
NAME                     READY   AGE
letsencrypt-nginx-cert   True    4m20s
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a TLS-enabled Ingress

Cert-Manager will automatically provision a TLS certificate and store it in the simple-nodejs-tls-secret secret.

Create manifest file (nginx-ingress-with-cert-manager.yaml)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-nodejs-ingress
  namespace: simple-nodejs-app
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-nginx-cert"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - chinmayto.com
      secretName: simple-nodejs-tls-secret
  rules:
    - host: chinmayto.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: service-nodejs-app
                port:
                  number: 80
Enter fullscreen mode Exit fullscreen mode

Apply it and verify:

$ kubectl apply -f nginx-ingress-with-cert-manager.yaml 
ingress.networking.k8s.io/simple-nodejs-ingress created

$ kubectl get ingress -n simple-nodejs-app
NAME                    CLASS   HOSTS           ADDRESS                                                                         PORTS     AGE
simple-nodejs-ingress   nginx   chinmayto.com   a4374e0452f8c4e0c99602307d9cb013-4fe3550df37ae3d7.elb.us-east-1.amazonaws.com   80, 443   43s

$ kubectl get secret -n simple-nodejs-app
NAME                       TYPE                DATA   AGE
simple-nodejs-tls-secret   kubernetes.io/tls   2      23s
Enter fullscreen mode Exit fullscreen mode

This will also create a certificate, describe it to get event log:

$ kubectl get certificate -n simple-nodejs-app
NAME                       READY   SECRET                     AGE
simple-nodejs-tls-secret   True    simple-nodejs-tls-secret   64s

$ kubectl describe certificate -n simple-nodejs-app
Name:         simple-nodejs-tls-secret
Namespace:    simple-nodejs-app
Labels:       <none>
Annotations:  <none>
API Version:  cert-manager.io/v1
Kind:         Certificate
Metadata:
  Creation Timestamp:  2025-08-05T19:25:19Z
  Generation:          1
  Owner References:
    API Version:           networking.k8s.io/v1
    Block Owner Deletion:  true
    Controller:            true
    Kind:                  Ingress
    Name:                  simple-nodejs-ingress
    UID:                   60ff8b31-a5d0-43ef-a01d-d50c308870ab
  Resource Version:        14728
  UID:                     17601f42-7597-44c8-be5e-096434d8be46
Spec:
  Dns Names:
    chinmayto.com
  Issuer Ref:
    Group:      cert-manager.io
    Kind:       ClusterIssuer
    Name:       letsencrypt-nginx-cert
  Secret Name:  simple-nodejs-tls-secret
  Usages:
    digital signature
    key encipherment
Status:
  Conditions:
    Last Transition Time:  2025-08-05T19:25:42Z
    Message:               Certificate is up to date and has not expired
    Observed Generation:   1
    Reason:                Ready
    Status:                True
    Type:                  Ready
  Not After:               2025-11-03T18:27:11Z
  Not Before:              2025-08-05T18:27:12Z
  Renewal Time:            2025-10-04T18:27:11Z
  Revision:                1
Events:
  Type    Reason     Age    From                                       Message
  ----    ------     ----   ----                                       -------
  Normal  Issuing    3m26s  cert-manager-certificates-trigger          Issuing certificate as Secret does not exist
  Normal  Generated  3m25s  cert-manager-certificates-key-manager      Stored new private key in temporary Secret resource "simple-nodejs-tls-secret-vcvkp"
  Normal  Requested  3m25s  cert-manager-certificates-request-manager  Created new CertificateRequest resource "simple-nodejs-tls-secret-1"
  Normal  Issuing    3m3s   cert-manager-certificates-issuing          The certificate has been successfully issued
Enter fullscreen mode Exit fullscreen mode

Now access https://chinmayto.com in your browser and inspect the certificate. It should be signed by Let’s Encrypt. Even if you try to access http://chinmayto.com it gets redirected to https.

Note: If by any reason certificate status is not READY, try to get reason by describing it. If there is an issue issuing certificate, describe the challenge to troubleshoot.

Conclusion

Using Cert-Manager, we’ve automated the entire TLS certificate lifecycle within our Kubernetes cluster. Instead of relying on self-signed certs or manual renewals, Cert-Manager:

  1. Automatically provisions and renews certificates
  2. Integrates with Ingress resources for seamless HTTPS
  3. Supports both staging and production issuers

This boosts security, ensures reliability, and simplifies operational overhead. It’s a production-grade solution for securing Kubernetes services via Ingress and a must-have for modern cloud-native applications.

References

GitHub Repo: https://github.com/chinmayto/kubernetes-ingress-nginx/tree/main/Part_06

Top comments (0)