<p>Recently, I tried to setup letsencrypt using microk8s and the default ingress controller on a bare-metal server.</p>
<p>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.</p>
<p>To save you guys time, I wrote out exactly what I did.</p>
<p>Here are some useful resources if you get stuck or to get a better understanding.</p>
<p><a href="https://cert-manager.io/docs/installation/kubernetes/" rel="noreferrer">https://cert-manager.io/docs/installation/kubernetes/</a></p>
<p><a href="https://cert-manager.io/docs/tutorials/acme/ingress/" rel="noreferrer">https://cert-manager.io/docs/tutorials/acme/ingress/</a></p>
<p>This link was really useful for troubleshooting</p>
<p><a href="https://cert-manager.io/docs/faq/acme/" rel="noreferrer">https://cert-manager.io/docs/faq/acme/</a></p>

<p><strong>This guide is to set up Letsencrypt with Kubernetes using Microk8s and the default Ingress controller.</strong></p>
<p><strong>Versions used:</strong></p>
<p><em>microk8s version 1.21/stable</em></p>
<p><em>cert-manager v1.3.1</em></p>
<p><strong>Pre-requisite:</strong> Forward ports 80 &amp; 443 to your server. Set up a domain name that points to your server.</p>
<p>Install microk8s</p>
<pre><code>snap install microk8s --classic --channel=1.21/stable
</code></pre>
<p>Enable dns and ingress</p>
<pre><code>sudo microk8s enable dns ingress
</code></pre>
<p>We'll create a test webserver deployment/service using the nginx webserver image to test web traffic</p>
<p><em><strong>webserver-depl-svc.yaml</strong></em></p>
<pre><code>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
</code></pre>
<p>apply the config file</p>
<pre><code>sudo microk8s kubectl apply -f webserver-depl-svc.yaml
</code></pre>
<p>now to configure the default ingress to serve the test webserver</p>
<p><em><strong>ingress-routes.yaml</strong></em></p>
<pre class="lang-yaml prettyprint-override"><code>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
</code></pre>
<p>Apply the ingress routes</p>
<pre><code>sudo microk8s kubectl apply -f ingress-routes.yaml
</code></pre>
<p>When you visit <em>yourdomain.com</em>, you should see the default &quot;welcome to nginx!&quot; splash screen.</p>
<p>Now to install cert-manager <a href="https://cert-manager.io/docs/installation/kubernetes/" rel="nofollow noreferrer">https://cert-manager.io/docs/installation/kubernetes/</a></p>
<pre><code>sudo microk8s kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.3.1/cert-manager.yaml
</code></pre>
<p>The next command should show 3 pods to confirm cert-manager is installed and running</p>
<pre><code>sudo microk8s kubectl get pods -n=cert-manager
</code></pre>
<p>Now to create the certificate issuer config. A detail to notice is that the class used in this config is <em>public</em> as opposed to <em>nginx</em>. This may be microk8s specific. <a href="https://cert-manager.io/docs/tutorials/acme/ingress/" rel="nofollow noreferrer">https://cert-manager.io/docs/tutorials/acme/ingress/</a></p>
<p><em><strong>letsencrypt-staging.yaml</strong></em></p>
<pre><code>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
</code></pre>
<p><em><strong>letsencrypt-prod.yaml</strong></em></p>
<pre><code>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
</code></pre>
<p>Apply both issuer configs</p>
<pre><code>sudo microk8s kubectl apply -f letsencrypt-staging.yaml

sudo microk8s kubectl apply -f letsencrypt-prod.yaml
</code></pre>
<p>now to update <em><strong>ingress-routes.yaml</strong></em> to use the staging certificate.</p>
<pre><code>apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ingress-routes
  annotations:
    cert-manager.io/cluster-issuer: &quot;letsencrypt-staging&quot;
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
</code></pre>
<p>Apply the update</p>
<pre><code>sudo microk8s kubectl apply -f ingress-routes.yaml
</code></pre>
<p>Run the next command to confirm Ready=True</p>
<pre><code>sudo microk8s kubectl get certificate
</code></pre>
<p>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</p>
<pre><code>sudo microk8s kubectl describe certificate tls-secret
</code></pre>
<p>Now to change <em><strong>ingress-routes.yaml</strong></em> to use the production certificate.</p>
<pre><code>apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-routes
  annotations:
    cert-manager.io/cluster-issuer: &quot;letsencrypt-prod&quot;
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
</code></pre>
<p>Apply the update</p>
<pre><code>sudo microk8s kubectl apply -f ingress-routes.yaml
</code></pre>
<p>Now the moment of truth. Run the next command to confirm a certificate was generated. Ready=True</p>
<pre><code>sudo microk8s kubectl get certificate
</code></pre>
<p>Run the next command and look at the final output to verify the certificate was issued.</p>
<pre><code>sudo microk8s kubectl describe certificate tls-secret
</code></pre>
<p>Now if you visit your domain. You should see the little lock of success! :-)</p>
