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.