Securing your ingress with cert-manager & let's encrypt

In line with my previous article regarding external-dns component in a kubernetes cluster : https://yodamad.hashnode.dev/set-up-external-dns-on-a-kubernetes-cluster, here is a quick one explaining how to secure your nginx ingresses with a certificate to enable security in your environment.

This article is covering how to set up & configure the different elements to automatically generate a certificate provided by let's encrypt organism when deploying a new ingress in our cluster. Once it's done, every time an ingress will be deployed, with the right annotations, automatically a certificate will be generated to secure with TLS the HTTP endpoint.

Prerequisites for this article are :

  • A Kubernetes cluster running with an nginx ingress controller (and, optionally, external-dns) installed

  • kubectl installed on your laptop

  • helm installed, optionally

First, we have to install cert-manager component. This component is in charge to manage certificates in a cluster. A complete description is available here

# Install it with helm
$ 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.11.0 \
  --set installCRDs=true

# or install it kubectl 
$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml

We can control that everything goes well by checking that the new components related to cert-manager are known by the cluster

$ kubectl get crd | grep cert-manager
certificaterequests.cert-manager.io
certificates.cert-manager.io
challenges.acme.cert-manager.io
clusterissuers.cert-manager.io
issuers.cert-manager.io
orders.acme.cert-manager.io

$ kubectl explain Certificate
$ kubectl explain CertificateRequest
$ kubectl explain Challenge

Now, we need to create the component that will do the process to claim and generate a certificate regarding a certificate provider such as let's encrypt. This is done by creating a ClusterIssuer component. This will cover the whole cluster. NB: If you want to restrict this feature to a dedicated namespace, you can use an Issuer instead.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-production
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: <your_email_to_receive_notifications>
    privateKeySecretRef:
      name: letsencrypt-production
    solvers:
      - http01:
          ingress:
            class: nginx

Here, each ingress will be detected and a certificate will be generated to secure them if TLS is configured. You can fine-grain the ingresses to handle using ingressTemplate solver approach describes in the official documentation. Now, let's modify the Ingress defined in the previous article:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hashnode
  annotations:
    kubernetes.io/ingress.class: nginx
    # Add this for detection
    # Replace cluster-issuer by issuer if you define an Issuer rather than a ClusterIssuer
    cert-manager.io/cluster-issuer: letsencrypt-production
spec:
  rules:
  - host: demo.hashnode.mydns.fr
    http:
      paths:
      - backend:
          service:
            name: hashnode
            port:
              number: 80
        pathType: Prefix
        path: /
  # Add this part to enable TLS
  tls:
    - hosts:
      - demo.hashnode.mydns.fr
      secretName: nginx-demo-tls
kubectl apply -f hashnode-demo.yaml -n hashnode

Once applied, we can see that

  • ingress controller is exposing 443 port

  • a certificate has been generated

$ kubectl get svc --all-namespaces | grep ingress-nginx-controller
ingress-nginx       ingress-nginx-controller             LoadBalancer   10.3.106.101   57.128.40.102   80:30542/TCP,443:30552/TCP   2d11h

$ kubectl get certificates -A
NAMESPACE   NAME             READY   SECRET           AGE
hashnode    nginx-demo-tls   True    nginx-demo-tls   81m

Now we can check that our website is secured with a valid certificate

And we can have a quick look at the certificate

So, in conclusion, with a few steps, we are now able to secure our endpoints for valid certificates generated by an official organism.

All sources are still available in my GitLab repository.

8
Subscribe to my newsletter

Read articles from Matthieu Vincent directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Matthieu Vincent
Matthieu Vincent

TechAdvocate DevSecOps / Cloud platform Lead Architect @ Sopra Steria Speaker @ Devoxx, Snowcamp, Breizhcamp, GitLab Connect and internally Co-Founder of Volcamp IT Conference @ Clermont-Fd (https://volcamp.io) GitLab Hero