Adrian Goins recently gave a Kubernetes masterclass on how to secure and control the edge with K3s and Traefik, demonstrating how to access K3s' Traefik Proxy dashboard, you can sign up to watch the replay at: https://more.suse.com/ MC_Secure_Edge_K3s_Traefik.html
Rancher Desktop creates a single node K3s cluster and I'm curious if I can access the Traefik Proxy dashboard when using Rancher Desktop. I asked this question in Adrian's class and he said it should work, so I got to work.
Note: The environment used in this article is a Linux operating system, such as Mac or Windows, and parameters need to be adjusted as appropriate.
This article refers to some courses published by Adrian on GitHub: https://github.com/traefik-workshops/k3s-and-traefik-proxy
First, clone Adrian's repo:
> git clone https://github.com/traefik-workshops/k3s-and-traefik-proxy.git
> cd k3s-and-traefik-proxy/
Lesson 1: Expose the Traefik Dashboard
NOTE: None of the files in 01-Expose-the-Dashboard are currently used in Adrian's courses.
set the cluster IP to variable
Adrian recommends checking the cluster IP address in the kubeconfig file, Rancher Desktop will create a ~/.kube/config file on the host:
> grep server ~/.kube/config
server: https://127.0.0.1:6443
> export CLUSTERIP=127.0.0.1
At this point, Adrian continues his course, but there is currently a problem with Rancher Desktop on Linux: Privileged ports (ports lower than 1024) are not accessible. Please refer to https://github.com/rancher-sandbox/rancher-desktop/issues/576
Instead, Rancher Desktop users on Linux must know which Ingress ports the HTTP (80) and HTTPS (443) ports are forwarded to:
> kubectl get service -n kube-system traefik
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik LoadBalancer 10.43.146.37 192.168.5.15 80:30876/TCP,443:30614/TCP 26
We save the Ingress port into a variable so it can be used throughout the class:
> export CLUSTERHTTP=`kubectl get service -n kube-system traefik -o json | jq '.spec.ports[0].nodePort'`
> export CLUSTERHTTPS=`kubectl get service -n kube-system traefik -o json | jq '.spec.ports[1].nodePort'`
switch the current Namespace to kube-system
> kubectl config set-context --current --namespace kube-system
Context "rancher-desktop" modified.
Create Service
> kubectl expose deploy/traefik -n kube-system --port=9000 --target-port=9000 --name=traefik-dashboard
service/traefik-dashboard exposed
Create Ingress
> kubectl create ingress traefik-dashboard --rule="dashboard.traefik.$CLUSTERIP.sslip.io/*=traefik-dashboard:9000"
ingress.networking.k8s.io/traefik-dashboard created
Access Dashboard
Unlike the Adrian step, we need to include the HTTP Ingress port in the URL:
> curl -si http://dashboard.traefik.$CLUSTERIP.sslip.io:$CLUSTERHTTP/dashboard/ | head -n 1
HTTP/1.1 200 OK
> echo http://dashboard.traefik.$CLUSTERIP.sslip.io:$CLUSTERHTTP/dashboard/
http://dashboard.traefik.127.0.0.1.sslip.io:30876/dashboard/
Annotations
> kubectl annotate ingress traefik-dashboard traefik.ingress.kubernetes.io/router.entrypoints=web
ingress.networking.k8s.io/traefik-dashboard annotated
Lesson 2: Securing the Dashboard with Middleware
> cd 02-Secure-the-Dashboard-With-Middleware
create user file
Note that Adrian has provided user file settings based on the workshop:
> cat users
user@example.com:$apr1$nWlieTS.$pbESld2QB5uYuUTAfFICr.
admin@example.com:$apr1$XMtXkoUy$IwIKiM./ujfaYf6/MsCaf1
Create dashboard dashboard-users Secret from users file
> kubectl create secret generic dashboard-users --from-file=users
secret/dashboard-users created
Create Middleware from middleware-auth.yaml
> cat middleware-auth.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: dashboard-auth
spec:
basicAuth:
secret: dashboard-users
> kubectl apply -f middleware-auth.yaml
middleware.traefik.containo.us/dashboard-auth created
Applying Middleware to Ingress
> kubectl annotate ingress traefik-dashboard \
traefik.ingress.kubernetes.io/router.middlewares=kube-system-dashboard-auth@kubernetescrd
ingress.networking.k8s.io/traefik-dashboard annotated
Note that if you've been accessing the dashboard in your browser, you should now be prompted for a username and password:
Test Middleware
> curl -si http://dashboard.traefik.$CLUSTERIP.sslip.io:$CLUSTERHTTP/dashboard/ | head -n 1
HTTP/1.1 401 Unauthorized
> curl -si -u 'admin@example.com:admin1234' http://dashboard.traefik.$CLUSTERIP.sslip.io:$CLUSTERHTTP/dashboard/ | head -n 1
HTTP/1.1 200 OK
Create Middleware to add /dashboard prefix
> cat middleware-rewrite.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: dashboard-rewrite
spec:
addPrefix:
prefix: /dashboard
> kubectl apply -f middleware-rewrite.yaml
middleware.traefik.containo.us/dashboard-rewrite created
Apply second Middleware to Ingress
> kubectl annotate ingress traefik-dashboard \
traefik.ingress.kubernetes.io/router.middlewares=kube-system-dashboard-rewrite@kubernetescrd,kube-system-dashboard-auth@kubernetescrd \
--overwrite=true
ingress.networking.k8s.io/traefik-dashboard annotated
access dashboard without /dashboard/
> curl -si http://dashboard.traefik.$CLUSTERIP.sslip.io:$CLUSTERHTTP/ | head -n 1
HTTP/1.1 401 Unauthorized
Fix Dashboard
> kubectl create ingress traefik-dashboard-api --rule="dashboard.traefik.$CLUSTERIP.sslip.io/api/*=traefik-dashboard:9000"
ingress.networking.k8s.io/traefik-dashboard-api created
> kubectl annotate ingress traefik-dashboard-api \
traefik.ingress.kubernetes.io/router.middlewares=kube-system-dashboard-auth@kubernetescrd
ingress.networking.k8s.io/traefik-dashboard-api annotated
3: Custom Resources
> cd ../03-Use-the-IngressRoute-Custom-Resource/
Change Ingress to IngressRoutes
Remove the previously created Ingress:
> kubectl delete ingress/traefik-dashboard ingress/traefik-dashboard-api
ingress.networking.k8s.io "traefik-dashboard" deleted
ingress.networking.k8s.io "traefik-dashboard-api" deleted
To create a new IngressRoute, we need to change the IP address:
> cat ingressroute.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard-secure
spec:
entryPoints:
- web
routes:
- kind: Rule
match: Host("dashboard.traefik.10.68.0.70.sslip.io")
services:
- name: traefik-dashboard
port: 9000
middlewares:
- name: dashboard-auth
- name: dashboard-rewrite
- kind: Rule
match: Host("dashboard.traefik.10.68.0.70.sslip.io") && PathPrefix("/api")
services:
- name: traefik-dashboard
port: 9000
middlewares:
- name: dashboard-auth
> sed -i "s/10\.68\.0\.70/${CLUSTERIP}/" ingressroute.yaml
> cat ingressroute.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard-secure
spec:
entryPoints:
- web
routes:
- kind: Rule
match: Host("dashboard.traefik.127.0.0.1.sslip.io")
services:
- name: traefik-dashboard
port: 9000
middlewares:
- name: dashboard-auth
- name: dashboard-rewrite
- kind: Rule
match: Host("dashboard.traefik.127.0.0.1.sslip.io") && PathPrefix("/api")
services:
- name: traefik-dashboard
port: 9000
middlewares:
- name: dashboard-auth
> kubectl apply -f ingressroute.yaml
ingressroute.traefik.containo.us/traefik-dashboard-secure created
IngressRoute
> kubectl get ingressroute traefik-dashboard -o yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
annotations:
helm.sh/hook: post-install,post-upgrade
creationTimestamp: "2022-02-11T16:01:09Z"
generation: 1
labels:
app.kubernetes.io/instance: traefik
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: traefik
helm.sh/chart: traefik-10.9.100
name: traefik-dashboard
namespace: kube-system
resourceVersion: "657"
uid: 7993457e-7cde-478b-82c9-76acc5eebbd9
spec:
entryPoints:
- traefik
routes:
- kind: Rule
match: PathPrefix(`/dashboard`) || PathPrefix(`/api`)
services:
- kind: TraefikService
name: api@internal
What is TraefikService?
> kubectl patch ingressroute/traefik-dashboard-secure --type=json --patch-file patch-dashboard-service.yaml
ingressroute.traefik.containo.us/traefik-dashboard-secure patched
> kubectl delete service traefik-dashboard
service "traefik-dashboard" deleted
> curl -si -u 'admin@example.com:admin1234' http://dashboard.traefik.$CLUSTERIP.sslip.io:$CLUSTERHTTP/ | head -n 1
HTTP/1.1 200 OK
Lesson 4: Securing the Dashboard with TLS
> cd ../04-Secure-the-Dashboard-With-TLS/
set cert-manager
I'm using the latest version of cert-manager, currently 1.7.1:
> kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.7.1/cert-manager.yaml
customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
...
...
...
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
> kubectl get pods -n cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-cainjector-d6cbc4d9-j8q8x 1/1 Running 0 70s
cert-manager-6d8d6b5dbb-ts2mq 1/1 Running 0 70s
cert-manager-webhook-85fb68c79b-ql658 1/1 Running 0 70s
Create ClusterIssuer
> cat clusterissuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned
spec:
selfSigned: {}
> kubectl apply -f clusterissuer.yaml
clusterissuer.cert-manager.io/selfsigned created
generate certificate for dashboard
We need to change the IP address:
> cat certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: dashboard
spec:
subject:
organizations:
- Traefik Academy
commonName: dashboard.traefik.10.68.0.70.sslip.io
issuerRef:
kind: ClusterIssuer
name: selfsigned
secretName: dashboard-crt
> sed -i "s/10\.68\.0\.70/${CLUSTERIP}/" certificate.yaml
> cat certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: dashboard
spec:
subject:
organizations:
- Traefik Academy
commonName: dashboard.traefik.127.0.0.1.sslip.io
issuerRef:
kind: ClusterIssuer
name: selfsigned
secretName: dashboard-crt
> kubectl apply -f certificate.yaml
certificate.cert-manager.io/dashboard created
> kubectl get secret | grep tls
k3s-serving kubernetes.io/tls 2 87m
dashboard-crt
Add certificate to IngressRoute
> cat patch-dashboard-tls.yaml
- op: replace
path: /spec/entryPoints
value:
- websecure
- op: add
path: /spec/tls
value:
secretName: dashboard-crt
> kubectl patch ingressroute/traefik-dashboard-secure \
--type=json \
--patch-file patch-dashboard-tls.yaml
ingressroute.traefik.containo.us/traefik-dashboard-secure patched
> echo https://dashboard.traefik.$CLUSTERIP.sslip.io:$CLUSTERHTTPS/
https://dashboard.traefik.127.0.0.1.sslip.io:30614/
Add HTTP redirect
> cat middleware-scheme.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: redirect-permanent
spec:
redirectScheme:
permanent: true
scheme: https
Need to add HTTPS port in middleware-scheme.yaml and change IP address in ingressroute.yaml:
> echo " port: \"${CLUSTERHTTPS}\"" >> middleware-scheme.yaml
> cat middleware-scheme.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: redirect-permanent
spec:
redirectScheme:
permanent: true
scheme: https
port: "30614"
> kubectl apply -f middleware-scheme.yaml
middleware.traefik.containo.us/redirect-permanent created
> cat ingressroute.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard-http
spec:
entryPoints:
- web
routes:
- kind: Rule
match: Host("dashboard.traefik.10.68.0.70.sslip.io")
services:
- name: api@internal
kind: TraefikService
middlewares:
- name: redirect-permanent
> sed -i "s/10\.68\.0\.70/${CLUSTERIP}/" ingressroute.yaml
> cat ingressroute.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard-http
spec:
entryPoints:
- web
routes:
- kind: Rule
match: Host("dashboard.traefik.127.0.0.1.sslip.io")
services:
- name: api@internal
kind: TraefikService
middlewares:
- name: redirect-permanent
> kubectl apply -f ingressroute.yaml
ingressroute.traefik.containo.us/traefik-dashboard-http created
> curl -si http://dashboard.traefik.$CLUSTERIP.sslip.io:$CLUSTERHTTP/ | head -n 1
HTTP/1.1 301 Moved Permanently
If we remove the head command, we can see where it was moved:
> curl -si http://dashboard.traefik.$CLUSTERIP.sslip.io:$CLUSTERHTTP/
HTTP/1.1 301 Moved Permanently
Location: https://dashboard.traefik.127.0.0.1.sslip.io:30614/
Date: Fri, 11 Feb 2022 17:40:15 GMT
Content-Length: 17
Content-Type: text/plain; charset=utf-8
The location should include the Ingress port for HTTPS:
> echo http://dashboard.traefik.$CLUSTERIP.sslip.io:$CLUSTERHTTP/
http://dashboard.traefik.127.0.0.1.sslip.io:30876/
If we open the URL in a web browser, it should redirect to an HTTPS site. If not, you may need to clear your web browser's cache.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。