Bear Su's Blog

Traefik ForwardAuth 筆記

想要在 Traefik 設定呼叫外部服務來驗證請求是否可以轉發至後端。

示意圖


當請求送往 Traefik 的時候,會先將請求轉發至 Auth Service,透過 Auth Service 回傳的 HTTP Status Code 來決定能不能將請求轉送至 Backend。

Client <--> Traefik <--> Backend
               ^
               | Forward Auth
               v
             Auth Service

使用 Docker Compose 建立測試環境


假設本地環境為 Linux-like 作業系統,並已安裝好 Docker、Docker Compose、curl 工具。

建立目錄

mkdir traefik-forward-demo
cd traefik-forward-demo

新增 traefik 設定檔

新增 conf/traefik.yml,設定可參考 server configuration

api:
  insecure: true
providers:
  file:
    directory: "/etc/traefik"
    watch: true

新增 conf/dynamic.yml,設定可參考 File provider configuration。為了測試方便,我們分別建立可以驗證成功與失敗的 routers 與 middlewares。

http:
  routers:
    succ:
      rule: "Host(`succ-auth.docker.localhost`)"
      service: myip
      middlewares:
        - "succ-auth"
    fail:
      rule: "Host(`fail-auth.docker.localhost`)"
      service: myip
      middlewares:
        - "fail-auth"
  middlewares:
    succ-auth:
      forwardAuth:
        address: "http://httpbin/headers"
        trustForwardHeader: true
    fail-auth:
      forwardAuth:
        # Set a not found url to make auth fail
        address: "http://httpbin/headersx"
        trustForwardHeader: true
  services:
    myip:
      loadBalancer:
        passHostHeader: false
        servers:
        - url: "https://api.ipify.org"

新增 docker-compose.yml,建立 traefik container 與用來當作 Auth Service 的 httpbin container。

version: '3'

services:
  reverse-proxy:
    # The official v2 Traefik docker image
    image: traefik:v2.5
    ports:
      # The HTTP port
      - "80:80"
      # The Web UI (enabled by --api.insecure=true)
      - "8080:8080"
    volumes:
      # So that Traefik can listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock
      - ./conf:/etc/traefik
  httpbin:
    image: kennethreitz/httpbin
    environment: # Enable httpbin log
      - GUNICORN_CMD_ARGS=${GUNICORN_CMD_ARGS}

新增 .env,這樣可以讓 httpbin container 印出 access log。

GUNICORN_CMD_ARGS="--capture-output --error-logfile - --access-logfile - --access-logformat '%(h)s %(t)s %(r)s %(s)s Host: %({Host}i)s X-MY-ID: %({X-MY-ID}i)s'"

啟動測試環境


啟動 containers。

docker-compose up

在測試過程中可以觀察 httpbin 印出的 access log。

開啟另一個 terminal session 用來執行以下測試的指令。

測試驗證成功的請求


curl \
    -H Host:succ-auth.docker.localhost \
    -H X-MY-ID:hello@dream \
    "http://127.0.0.1"

如果成功,畫面將會輸出對外 IP。

172.25.0.1

由於 Auth Service 回傳 HTTP 狀態碼 200,所以請求會繼續往下送,轉發至 myip service。

測試驗證失敗的請求


curl \
    -H Host:fail-auth.docker.localhost \
    -H X-MY-ID:hello@dream \
    "http://127.0.0.1"

如果成功,畫面將會輸出對外 IP。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server.  If you entered the URL manually please check your spelling and try again.</p>

由於我們將 fail-auth middleware 驗證的端點指向 Auth Service 不存在的路徑,所以驗證的時候會回傳 HTTP 狀態碼 404,請求就不會繼續往 myip service 送,而是直接把 Auth Service 的回應返回至 client。

停止測試環境


於剛剛執行 docker-compute up 指令的 terminal session 輸入 crtl + c 停止 containers。

Ref



如果覺得這篇文章對您有所幫助,歡迎贊助我一杯咖啡 ☕️

祝您有美好的一天 ❤️