头图

图片

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.


Rancher
1.2k 声望2.5k 粉丝

Rancher是一个开源的企业级Kubernetes管理平台,实现了Kubernetes集群在混合云+本地数据中心的集中部署与管理。Rancher一向因操作体验的直观、极简备受用户青睐,被Forrester评为“2020年多云容器开发平台领导厂商...