k3s HTTPS with Let’s Encrypt
Tags: k3s, k8s, letsencrypt
Published: 2019-07-05 14:29:33

---
title: k3s HTTPS with Let’s Encrypt
published: true
tags: k3s,k8s,letsencrypt
canonical_url: https://pascalw.me/blog/2019/07/02/k3s-https-letsencrypt.html
---

[K3s](https://k3s.io/) is a Certified Kubernetes distribution designed for production workloads in unattended, resource-constrained, remote locations or inside IoT appliances.
It provides a ready to go Kubernetes instance packaged a single binary.

This guide will show you how to easily set up k3s with HTTPS via Let’s Encrypt.

(READMORE)

K3s comes with [Traefik](https://traefik.io/) out of the box. Traefik itself supports automatic HTTPS via Let’s Encrypt, but setting this up with k3s turned out to be pretty cumbersome. Instead using the excellent [cert-manager](https://github.com/jetstack/cert-manager) add-on, it's a breeze!

## 0: Setup k3s.

This guide assumes you have a working k3s instance and `kubectl` configured to talk to your k3s instance. If you haven't already just follow the [docs](https://github.com/rancher/k3s/blob/master/README.md) and you'll be up and running in minutes.

## 1. Install Helm

[Helm](https://helm.sh/) is a package manager for Kubernetes. It consists of a local client and a server component.
Installing Helm is quite [straightfoward](https://helm.sh/docs/using_helm/#installing-helm).

Install the client:

 ```sh
$ brew install kubernetes-helm
 ```

Create the service account so Helm can interact with your k3s instance:

```sh
$ kubectl create serviceaccount tiller --namespace=kube-system
```

Grant it admin privileges:

```sh
$ kubectl create clusterrolebinding tiller-admin --serviceaccount=kube-system:tiller --clusterrole=cluster-admin
```

Note: granting admin privileges to Helm might not be a good idea depending on how your cluster is setup. Read [here](https://helm.sh/docs/using_helm/#role-based-access-control) for more details.

Install Helm on k3s:

```sh
$ helm init --service-account=tiller
```
<p></p>

## 2. Install cert-manager

Alright, so now we have Helm installed let's move on to installing `cert-manager`.
`cert-manager` is a Kubernetes add-on to automate the management and issuance of TLS certificates from various issuing sources, amongst which Let’s Encrypt.

Start with installing `cert-manager`s CRDs:

```sh
$ kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.8/deploy/manifests/00-crds.yaml
```

Add the `cert-manager` Helm repo:

```sh
$ helm repo add jetstack https://charts.jetstack.io && helm repo update
```

Install `cert-manager`:

```sh
$ helm install \
  --name cert-manager \
  --namespace cert-manager \
  --version v0.8.1 \
  jetstack/cert-manager
```

This might take a minute or so. Verify the installation by checking all `cert-manager` pods are running:

```sh
$ kubectl get all -n cert-manager
```

<p></p>

## 3. Configure cert-manager

With  `cert-manager` installed we need to configure it to use Let’s Encrypt, by creating a *certificate issuer*:

```sh
$ cat <<EOF > letsencrypt-prod-issuer.yaml
apiVersion: certmanager.k8s.io/v1alpha1
kind: Issuer
metadata:
 name: letsencrypt-prod
spec:
 acme:
   # The ACME server URL
   server: https://acme-v02.api.letsencrypt.org/directory
   # Email address used for ACME registration, update to your own.
   email: user@example.com
   # Name of a secret used to store the ACME account private key
   privateKeySecretRef:
     name: letsencrypt-prod
   # Enable the HTTP-01 challenge provider
   http01: {}
EOF
```

And apply it:

```sh
$ kubectl apply -f letsencrypt-prod-issuer.yaml
```

By now, `cert-manager` is ready to provision Let’s Encrypt certificates as we need it.

## 4. Deploy a service with automatic HTTPS

To try this out let's deploy a simple service. You should have a DNS name pointed to your k3s cluster for this to work. The example below uses `bootcamp.k3s.example.org`, be sure to update this to your own hostname!

Create the manifest:

```yaml
$ cat <<EOF > k8s-bootcamp.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: k8s-bootcamp
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: k8s-bootcamp
  template:
    metadata:
      labels:
        app: k8s-bootcamp
    spec:
      containers:
      - name: k8s-bootcamp
        image: gcr.io/google-samples/kubernetes-bootcamp:v1
---
apiVersion: v1
kind: Service
metadata:
  name: k8s-bootcamp
  namespace: default
spec:
  ports:
  - name: http
    targetPort: 8080
    port: 80
  selector:
    app: k8s-bootcamp
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: k8s-bootcamp
  annotations:
    kubernetes.io/ingress.class: "traefik"
    certmanager.k8s.io/issuer: "letsencrypt-prod"
    certmanager.k8s.io/acme-challenge-type: http01

spec:
  tls:
  - hosts:
    # Change this to your own hostname
    - bootcamp.k3s.example.org
    secretName: bootcamp-k3s-example-org-tls
  rules:
  # Change this to your own hostname
  - host: bootcamp.k3s.example.org
    http:
      paths:
      - path: /
        backend:
          serviceName: k8s-bootcamp
          servicePort: http
EOF
```

And apply it:

```sh
$ kubectl apply -f k8s-bootcamp.yaml
```

Wait a minute or so and your endpoint should become available with a Let’s Encrypt certificate! 🎉