This is a text-only version of the following page on https://raymii.org:
---
Title : Password protect web services in Kubernetes (k3s/traefik) with basic auth
Author : Remy van Elst
Date : 15-07-2024 20:11
URL : https://raymii.org/s/tutorials/Password_protect_web_services_in_Kubernetes_k3s_traefik_with_basic_auth.html
Format : Markdown/HTML
---
Now that I have a [high-available local kubernetes cluster](/s/tutorials/High_Available_k3s_kubernetes_cluster_with_keepalived_galera_and_longhorn.html) and am [experimenting with deploying apps](/s/snippets/Using_nodeSelector_to_deploy_a_Kubernetes_Helm_chart_only_on_x86_or_amd64_nodes_not_arm64.html), it's also time to look into securing those apps using certificates and passwords. In this case I'm going to set up password authentication, like a `.htaccess` file in `Apache2`, to protect the `Longhorn` dashboad, which by default requires no authentication. This means deploying an `Ingress`, a `Middleware` and a `Secret`.
Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:
I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go check it out!
Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.
You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $200 credit for 60 days. Spend $25 after your credit expires and I'll get $25!
Longhorn is a distributed replicated storage solution for Kubernetes and in
[my high-available k3s cluster](/s/tutorials/High_Available_k3s_kubernetes_cluster_with_keepalived_galera_and_longhorn.html)
I use it to make sure `PersistentVolumes` are replicated among nodes, thus
making sure that when a `Node` fails, any deployment on there with a
`PersistentVolume` can start up on another node without issues. By default
`k3s` creates these volumes as local folders on a node, so when a node fails,
the volume is also gone (until that node is back up). Longhorn resolves this
by replicating the volumes among nodes and making them available to
Kubernetes.
In my [previous guide](/s/tutorials/High_Available_k3s_kubernetes_cluster_with_keepalived_galera_and_longhorn.html)
you can read on how to install and configure Longhorn. In that guide we
`Exposed` the dashboard with the following command:
kubectl expose service longhorn-frontend --type=LoadBalancer --port=8877 --target-port 8000 --name=longhorn-frontend-ext --namespace longhorn-system
If you open your browser and go to your `http://HA-IP:8877` you should be
greeted by the dashboard and you can do anything without ever logging in or
creating a token. This is not secure so lets fix it by adding a password
(and in an upcoming article, `https` and certificates).
Here you can see a screenshot of my Longhorn dashboard while volumes are being
rebuilt after a Node failure:
![longhorn dashboard](/s/inc/img/longhorn-1.png)
A bit of set up is required, so lets get started!
I'm using k3s/kubernetes version `v1.30.2+k3s1`.
### DNS hostname
I recently wrote [a small guide](/s/tutorials/Kubernetes_k3s_Ingress_for_different_domains_like_virtual_hosts.html)
on how to expose a `Service` on a hostname (domain name) instead of an
`ip:port` combo. In this guide I'll assume that you also have set up such a
domain for your `k3s` cluster.
I'll be using the following domain in this guide:
longhorn.k3s.homelab.mydomain.org
### Routers, Middlewares and Services in traefik
I'm not that familiar with `traefik` but after diving into their documentation,
for `traefik` version 2, I think I have a better understanding of the terms used.
- A `Router` is comparable to a `frontend` (like in `haproxy`)
- A `Service` is comparable to a `backend`
- A `Middleware` sits in between the two and can modify the request, headers, do redirects and such stuff. You can have multiple `Middlewares`.
![traefik flow](/s/inc/img/longhorn-3.png)
[image source](https://web.archive.org/web/20240714174204/https://www.virtuozzo.com/company/blog/kubernetes-traefik-ingress-controller/)
One of the functions that a `Middleware` can provide is `basic-auth`, in our case the password protection.
### Adding basic auth password protection
We must create a `Middleware` resource for `traefik` which handles the
password authentication. My kubernetes distribution,`k3s`, comes with
`traefik`, if you use `nginx`, this guide won't work for you.
`Middleware` is a [Custom Resource Definition](https://web.archive.org/web/20240712170016/https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-middleware) of the traefik [middlewares]
(https://web.archive.org/web/20240712004522/https://doc.traefik.io/traefik/middlewares/http/overview/).
The username and password itself are generated like you would do for a
`.htpasswd` file in `Apache2`. On your local admin workstation, install the required tools
to generate such passwords:
apt install apache2-utils
Navigate to your kubernetes folder, then to the `longhorn` folder. In my
[high available cluster guide](/s/tutorials/High_Available_k3s_kubernetes_cluster_with_keepalived_galera_and_longhorn.html)
I created such a folder structure for deployment and it should contain a
`longhorn.yaml` file.
Generate the file `longhorn-auth-file` with a password in it for user `admin`:
htpasswd -c longhorn-auth-file admin
If you ever want to add a user, omit the `-c` option and rerun the command
with a different username. You must update the kubernetes `Secret` as well
with the new content.
In a Kubernetes `Secret` the string (in our case generated by `htpasswd`) must
be base64-encoded. Do that for the file we just generated:
base64 longhorn-auth-file
Output:
dXNlcjok[...]Cgo=
If you think you are never going to need more than 1 user, you could pipe the
username/password:
htpasswd -nb admin password | openssl base64
That will result in the same string, but is less flexible because you cannot
add users later on.
Create a file for your `Ingress` for the dashboard:
vim longhorn-ingress.yaml
The content consist out of multiple pieces of yaml, separated by three dashes
(`---`). I'll be covering them piece by piece, but they all go into one
file.
First is the `Secret`:
apiVersion: v1
kind: Secret
metadata:
name: longhorn-basic-auth-secret
namespace: longhorn-system
data:
users: |2
dXNlcjok[...]Cgo=
---
The `|2` is yaml syntax, [this stackoverflow post](http://web.archive.org/web/20240714155936/https://stackoverflow.com/questions/51139902/why-does-ruby-yaml-sometimes-add-2-after-pipe-char/51140867#51140867)
explains what happens (Block Scalar Header and newline trimming).
You must paste the base64 string below the `|2` line, indented with 2 spaces
below `users:`.
The `Secret` is named `longhorn-basic-auth-secret` and that name will be used
for the next part, the `Middleware`:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: longhorn-basic-auth-middleware
spec:
basicAuth:
secret: longhorn-basic-auth-secret
realm: "Longhorn Dashboard"
---
This basically [wraps the traefik middleware configuration]
(https://web.archive.org/web/20240712005049/https://doc.traefik.io/traefik/middlewares/http/basicauth/).
It contains the users and a `realm`, which is what will show up in the basic
auth prompt. Note that as I said earlier, this will only work for the `traefik` service.
Last part of the file is the `Ingress`
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: longhorn-ui-ingress
namespace: longhorn-system
annotations:
spec.ingressClassName: traefik
traefik.ingress.kubernetes.io/router.middlewares: longhorn-system-longhorn-basic-auth-middleware@kubernetescrd
spec:
rules:
- host: longhorn.k3s.homelab.mydomain.org
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: longhorn-frontend
port:
number: 80
This is a fairly standard `Ingress`, except for the following `annotations`:
spec.ingressClassName: traefik
traefik.ingress.kubernetes.io/router.middlewares: longhorn-system-longhorn-basic-auth-middleware@kubernetescrd
This last line **must** have the following format:
-@kubernetescrd
The character `@` is not allowed in the `Middleware` name. If you want multiple `Middlewares`,
you must separate them with a comma.
Apply the file:
kubectl apply -n longhorn-system -f longhorn-ingress.yaml
Output:
secret/longhorn-basic-auth-secret created
middleware.traefik.io/longhorn-basic-auth created
ingress.networking.k8s.io/longhorn-ui-ingress created
Open your browser and navigate to the domain you set up in the `Ingress` file
and you should be prompted by a login prompt:
![internet explorer](/s/inc/img/longhorn-2.png)
You might notice my URL starting with `https`, but that is part of an article
that is still in the works.
---
License:
All the text on this website is free as in freedom unless stated otherwise.
This means you can use it in any way you want, you can copy it, change it
the way you like and republish it, as long as you release the (modified)
content under the same license to give others the same freedoms you've got
and place my name and a link to this site with the article as source.
This site uses Google Analytics for statistics and Google Adwords for
advertisements. You are tracked and Google knows everything about you.
Use an adblocker like ublock-origin if you don't want it.
All the code on this website is licensed under the GNU GPL v3 license
unless already licensed under a license which does not allows this form
of licensing or if another license is stated on that page / in that software:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Just to be clear, the information on this website is for meant for educational
purposes and you use it at your own risk. I do not take responsibility if you
screw something up. Use common sense, do not 'rm -rf /' as root for example.
If you have any questions then do not hesitate to contact me.
See https://raymii.org/s/static/About.html for details.