前文提及,SSL Termination 將 https 上傳解密的工作外包,與 Web APP 解耦。這不禁令我聯想到,在每次 BCP 演練,為了後端範圍外的 AD 身分驗證,不是要花很大功夫建一個替身,就是要處理網段隔離的問題,實在很傷腦筋,不如也利用類似技巧,請前面的 Traefik 外包處理,讓後面程式單純些。
這次要引入 Traefik 的 Middleware 概念:在 EntryPoint 與 Service 之間,我們有機會做很多事,諸如修改 Request、修改 Header、重新導向、增加驗證等。這些有的是 Traefik 內建,我們只需修改設定;或者有的是第三方外掛,要多一道下載引用的手續,但這方面 Traefik 做得很好,我們只感覺是在做「稍微複雜一點的設定」。
我們先來產一個金鑰對,後面用得到.如果是在 Windows:
ssh-keygen -t rsa -N "" -m pem -f key ssh-keygen -e -m pem -f key > key.pub
若是在 Linux 上:
openssl genrsa -out key openssl rsa -in key -pubout > key.pub
如此一來,不論哪個環境應該都會得到兩個文字檔,key 檔案的內容就是私鑰,而 key.pub 檔案的內容就是公鑰。我們可以借用 https://jwt.io 驗證它們的成對可用性:
既然都來 jwt.io 了,就順便在這產 JWT 給我們的服務外包驗證用。在右邊 PAYLOAD 那一欄把內容改一下:
左邊那一大塊 Encoded 就是跟據金鑰對與指定內容簽出來的 JWT,其中 iss 是 Issuer 的意思,未來可以比對用,不放也可以;exp 是 Expiration 的意思,這數字對應到一個時間點,如果使用 JWT 的當下跟這個比較的結果是逾期了,就拒絶存取。怎麼對應?這網頁也很貼心地幫我們,只要滑鼠移上去就可以看到。
拿到 JWT 之後怎麼用呢?讓我們回到 Traefik 這邊來,接續前文
,先確認後端 ok,從反向代理過來也 ok,再修改兩個設定檔:
#traefik.toml [providers.file] filename = "dynamic.toml" [[entryPoints]] address = ":443" [experimental.plugins.my-plugin] moduleName = "github.com/tnt-sbab/jwt-verifier" version = "v1.0.0"
#dynamic.toml [[http.routers]] rule = "Method(`GET`)" service = "my-service" tls = {} middlewares = ["my-middleware"] [[http.services.my-service.loadBalancer.servers]] url = "http://localhost:8000" [[tls.certificates]] certFile = "gss.com.tw-sha256.crt" keyFile = "gss.com.tw.key" [http.middlewares.my-middleware.plugin.my-plugin] PublicKey = """ -----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY----- """ Issuer = "traefik"
靜態設定檔 traefik.toml 增加第八行以後,參考 jwt-verifier 這個 plugin,命名為 my-plugin;動態設定檔 dynamic.toml 則增加第六行,以及第十五行以後,指明 my-plugin 的一個 Instance 命名為 my-middleware,公鑰內容要貼到第十八行的位置,Issuer 是 traefik。重新執行 traefik 後,應該之前確認的兩個 ok 都還 ok,並增加第三個 ok:
curl --resolve a.gss.com.tw:443:127.0.0.1 -H "Authorization: Bearer ..." https://a.gss.com.tw
如果 JWT 正確(包含公鑰、演算法、Issuer、Expiration)的話,我們就能以第三個 Request 得到正確回應,原本第二個(從反向代理免驗證過來)要關閉,做法是修改 dynamic.toml 第三行:
rule = "Method(`GET`) && HeaderRegexp(`Authorization`, `^Bearer `)"
就可以杜絶不論有沒有 JWT 都可以進來的怪象。那第一個合法路徑呢?就與 Traefik 無關了,請看你的 Web Application 如何限制來源為本機即可。