How to setup Letsencrypt with Kubernetes microk8s using default Ingress?

5/7/2021

Recently, I tried to setup letsencrypt using microk8s and the default ingress controller on a bare-metal server.

I found a few guides online that were very useful but it seems as if there must have been a recent update to microk8s that changed the way the ingress controller is configured.

To save you guys time, I wrote out exactly what I did.

Here are some useful resources if you get stuck or to get a better understanding.

https://cert-manager.io/docs/installation/kubernetes/

https://cert-manager.io/docs/tutorials/acme/ingress/

This link was really useful for troubleshooting

https://cert-manager.io/docs/faq/acme/

-- Emmanuel Mendoza
cert-manager
kubernetes
lets-encrypt
microk8s
nginx-ingress

2 Answers

5/7/2021

This guide is to set up Letsencrypt with Kubernetes using Microk8s and the default Ingress controller.

Versions used:

microk8s version 1.21/stable

cert-manager v1.3.1

Pre-requisite: Forward ports 80 & 443 to your server. Set up a domain name that points to your server.

Install microk8s

snap install microk8s --classic --channel=1.21/stable

Enable dns and ingress

sudo microk8s enable dns ingress

We'll create a test webserver deployment/service using the nginx webserver image to test web traffic

webserver-depl-svc.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webserver-depl
spec:
  selector:
    matchLabels:
      app: webserver-app
  template:
    metadata:
      labels:
        app: webserver-app
    spec:
      containers:
        - name: webserver-app
          image: nginx:1.8
---
apiVersion: v1
kind: Service
metadata:
  name: webserver-svc
spec:
  selector:
    app: webserver-app
  ports:
  - name: webserver-app
    protocol: TCP
    port: 80
    targetPort: 80

apply the config file

sudo microk8s kubectl apply -f webserver-depl-svc.yaml

now to configure the default ingress to serve the test webserver

ingress-routes.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-routes
spec:
  rules:
#change yourdomain.com to your domain
  - host: yourdomain.com
    http:
      paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: webserver-svc
              port:
                number: 80

Apply the ingress routes

sudo microk8s kubectl apply -f ingress-routes.yaml

When you visit yourdomain.com, you should see the default "welcome to nginx!" splash screen.

Now to install cert-manager https://cert-manager.io/docs/installation/kubernetes/

sudo microk8s kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.3.1/cert-manager.yaml

The next command should show 3 pods to confirm cert-manager is installed and running

sudo microk8s kubectl get pods --n=cert-manager

Now to create the certificate issuer config. A detail to notice is that the class used in this config is public as opposed to nginx. This may be microk8s specific. https://cert-manager.io/docs/tutorials/acme/ingress/

letsencrypt-staging.yaml

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
#change to your email
    email: youremail@gmail.com
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-staging
    solvers:
    - http01:
        ingress:
          class: public

letsencrypt-prod.yaml

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
#change to your email
    email: youremail@gmail.com
    privateKeySecretRef:
       name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: public

Apply both issuer configs

sudo microk8s kubectl apply -f letsencrypt-staging.yaml

sudo microk8s kubectl apply -f letsencrypt-prod.yaml

now to update ingress-routes.yaml to use the staging certificate.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-routes
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-staging"
spec:
  tls:
  - hosts:
#change to your domain
    - yourdomain.com
    secretName: tls-secret
  rules:
#change to your domain
  - host: yourdomain.com
    http:
      paths:
        - path: /
        pathType: Prefix
        backend:
          service:
            name: webserver-svc
            port:
              number: 80

Apply the update

sudo microk8s kubectl apply -f ingress-routes.yaml

Run the next command to confirm Ready=True

sudo microk8s kubectl get certificate

If it returned true, that means HTTP-01 challenge was successful. You can see more detail at the end of output running the next command

sudo microk8s kubectl describe certificate tls-secret

Now to change ingress-routes.yaml to use the production certificate.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-routes
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
#change to your domain
    - yourdomain.com
    secretName: tls-secret
  rules:
#change to your domain
  - host: yourdomain.com
    http:
      paths:
        - path: /
        pathType: Prefix
        backend:
          service:
            name: webserver-svc
            port:
              number: 80

Apply the update

sudo microk8s kubectl apply -f ingress-routes.yaml

Now the moment of truth. Run the next command to confirm a certificate was generated. Ready=True

sudo microk8s kubectl get certificate

Run the next command and look at the final output to verify the certificate was issued.

sudo microk8s kubectl describe certificate tls-secret

Now if you visit your domain. You should see the little lock of success! :-)

-- Emmanuel Mendoza
Source: StackOverflow

12/15/2021

Update December 2021: I had to update ingress-routes.yaml to get this to work:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-routes
spec:
  rules:
#change yourdomain.com to your domain
  - host: yourdomain.com
    http:
      paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: webserver-svc
              port:
                number: 80
-- KNOX
Source: StackOverflow