ucloud k8s部署traefik的forward-auth
作者:morya
時間:2020-0915
協議:創作共享2.0
traefik是一個開源邊界路由器。 opensource edge router
流程圖
失敗流程
sequenceDiagram user ->> traefik: curl -H X-Uid:10 api.domain.cn traefik ->> authsvc: curl -H X-Uid:10 my-forward-auth/auth authsvc -->> traefik: 401 auth failed traefik -->> user: 401 auth failed
成功流程
sequenceDiagram user ->> traefik: curl -H X-Uid:100 api.domain.cn/whoami traefik ->> authsvc: curl -H X-Uid:100 my-forward-auth/auth authsvc -->> traefik: 200 auth succ traefik ->> api: curl -H X-Uid:100 -H X-Secret:blaa -H X-Auth-User:somebody whoami api -->> traefik: query response traefik -->> user: query response
部署traefik
The Traefik Chart from Helm's default charts repository is still using Traefik v1.7.
helm默認的repo中traefik charts是1.7,traefik當前已經是v2.2版本。 date:2020-0803
helm repo add traefik https://containous.github.io/traefik-helm-chart
調整配置 (適配ucloud uk8s平台)
# values.yaml
service:
enabled: true
type: LoadBalancer
# Additional annotations (e.g. for cloud provider specific config)
annotations:
"service.beta.kubernetes.io/ucloud-load-balancer-type": "outer"
# 代表ULB網絡類型,outer為外網,inner為內網;outer為默認值,此處可省略。
"service.beta.kubernetes.io/ucloud-load-balancer-vserver-protocol": "tcp"
# 表示ULB協議類型,tcp與udp等價,表示ULB4;http與httpS等價,表示ULB7;tcp為默認值,此處可省略。
"service.beta.kubernetes.io/ucloud-load-balancer-eip-paymode": traffic
# 支持traffic、bandwidth、sharebandwidth,默認為bandwidth
"service.beta.kubernetes.io/ucloud-load-balancer-eip-bandwidth": "145"
# bandwidth下默認為10Mpbs,建議顯式聲明帶寬大小,避免費用超標。
"service.beta.kubernetes.io/ucloud-load-balancer-eip-chargetype": "dynamic" # 付費模式,支持month,year,dynamic,默認為month
"service.beta.kubernetes.io/ucloud-load-balancer-eip-quantity": "1" # 付費時長,默認為1,chargetype為dynimic時無效
# Additional entries here will be added to the service spec. Cannot contains
# type, selector or ports entries.
spec:
externalTrafficPolicy: Local
安裝traefik
helm install traefik traefik/traefik --values=values.yaml
配置traefik
- 構建和部署auth-svc
- 配置crd
- 配置middleware-forward-auth
- 配置ingress-route
auth-svc
代碼
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"strconv"
)
var (
flagListen = flag.String("listen", ":80", "listen address")
)
func onAuth(w http.ResponseWriter, req *http.Request) {
uid, _ := strconv.ParseInt(req.Header.Get("X-Uid"), 10, 64)
if uid != 100 {
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprint(w, "auth failed")
return
}
h := w.Header()
h.Add("X-Secret", "blaa")
h.Add("X-Auth-User", "somebody")
fmt.Fprint(w, "auth pass")
}
func main() {
flag.Parse()
log.SetOutput(os.Stderr)
log.SetFlags(log.LstdFlags | log.Lshortfile)
http.HandleFunc("/auth", onAuth)
http.ListenAndServe(*flagListen, nil)
}
部署auth-svc
apiVersion: v1
kind: Service
metadata:
name: my-forward-auth
namespace: dev
labels:
app: my-forward-auth
spec:
ports:
- port: 80
targetPort: 80
selector:
app: my-forward-auth
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-forward-auth
namespace: dev
spec:
selector:
matchLabels:
app: my-forward-auth
replicas: 1
template:
metadata:
labels:
app: my-forward-auth
spec:
containers:
- name: my-forward-auth
image: somebody/my-forward-auth
imagePullPolicy: Always
command:
- '/app'
- '-listen=:80'
ports:
- containerPort: 80
配置crd
配置middleware
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: forward-auth
spec:
forwardAuth:
address: http://my-forward-auth.dev/auth ## 如果traefik和auth在不同namespace,需明確指定
trustForwardHeader: true
authResponseHeaders:
- X-Auth-User
- X-Secret
kubectl apply -f middleware.yaml
配置IngressRoute
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: my-forward-auth-test
namespace: default
spec:
entryPoints:
- web
# - websecure
routes:
- kind: Rule
match: Host(`api.domain.cn`) && PathPrefix(`/`)
middlewares:
- name: forward-auth
namespace: default # IngressRoute 和 forward-auth 不一定在一個namespace
services:
- kind: Service
namespace: dev2 ## 自定義名字空間
name: whoami ## 此處服務需要自己實現
port: 80
kubectl apply -f ingress-route.yaml
部署api服務
apiVersion: v1
kind: Service
metadata:
name: whoami
labels:
app: whoami
spec:
ports:
- port: 80
targetPort: 80
selector:
app: whoami
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
spec:
selector:
matchLabels:
app: whoami
replicas: 1
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: containous/whoami
ports:
- containerPort: 80
關鍵特征
- 鑒權中間件服務,僅通過GET請求接收traefik轉送的auth
- 請求不攜帶body
- 原始請求的HEADERS一概攜帶到middleware來
- 如果經過多層forward-auth-middleware auth01,auth02附帶的headers會傳遞到后續service中
- 原始請求的關鍵信息 URI 等,通過
X-Forwarded-xxx攜帶到middleware中X-Forwarded-Uri: /api/auth/login/somebodyX-Forwarded-Method: POST
