2019年8月6日 星期二

透過 dex 取得 kubernetes 認證 (2)

用 PHP 實作 RP 這件事,對我來說其實分為兩個階段。

一開始我是希望能以 command line 的方式去進行 OIDC 認證,所以用 shell script 的方式取得 id_token。

後來是因為想弄一個可以管理 kubenretes 的 web 介面,希望在登入的部分是用 OIDC,也就是這個 web 就是一個 RP。因為對 golang 不熟,因此無法再從 example-app 來改,所以選擇用比較熟悉的 PHP 來做。

而在後面那個階段完成時,我才發現我第一階段做的 shell script,雖然可以 work ,但是有一些流程我其實沒搞清楚,所以先從第一階段開始說。

用瀏覽器的工具,可以觀察到從 example-app 到 dex 登入再回到 example-app 的流程裡,主要會有幾個頁面:

1. example-app 本身的登入頁面
2. dex 的登入頁面
3. dex 的 approval 頁面
4. 回到 example-app 顯示取得 id_token 的頁面

寫 script 的時候,以上動作都可以用 curl 辦到:
1. 從瀏覽器觀察到所傳遞的參數,設定給 curl ,就可以取得 dex login 頁面的 form 裡面參數 req
2. 將 req 參數及認證資訊 (也就是登入 ldap 的帳號密碼) 以 curl form post 的方式做登入
3. 再用 req 參數以 curl 傳到 approval 頁面,取得 id_token

問題就在第 3 步。整個 script 流程都沒瀏覽到 example-app,我以為這方式就用不到 example-app 了。實際上在第 3 步理,我傳給 curl 的參數裡有個 -L,也就是會 follow redirect link,在這一步 dex 會轉址回到 example-app,取得 id_token 是 example-app 這時才做的事,所以 script 取得的 id_token 其實是 example-app 處理後的結果。

也就是說,在 approval 之後, example-app 會自行連線到 dex 取得 id_token,而不是透過瀏覽器,所以從瀏覽器看不出來。到後面用 PHP 實作時,我才發現我錯誤的地方。

用 PHP/Laravel 實作的部分,比照 script 的做法
1. 因為是 GET method,直接把參數組一組 redirect 到 dex,就會進到 dex 登入頁面
2. 因為是 web 介面,不需要用程式做登入動作,所以 login 後會自動過 approval 然後轉址回指定的 Laravel 頁面,也就是 statciClients 設定的 redirectURIs
3. Laravel 收到的只有 url 裡的 code 參數,到這邊我才發現我之前理解上的錯誤

在翻過 example-app 原始碼,再去翻 dex 的原始碼,終於找到 RP 主動連線 dex 所傳遞的參數有哪些:
* code : 就是上面 url 裡的 code
* grant_type : 用 authorization_code
* client_id :  staticClients 裡設定的 id
* client_secret : staticClients 裡設定的 secret
* redirect_uri : staticClients 裡設定的 redirectURIs

把這些參數用 POST 的方式,用 guzzle 套件送到 dex server 的 /token ,以前面的例子來說, url 就是
https://dex.example.com:32200/token
這時候就可以取得 id_token 了

然後依照 id_token spec 去解出需要的資訊即可,這部分可以用這份簡報,參照 jwt.io 的線上 jwt decode (id_token 即為 JWT 格式的 token) ,就大概知道怎麼處理了。

從解出來的資訊,就可以取得 user 及 group (如果 SP 有提供,且 dex.yaml 有設定好的話),就可以透過 OIDC 認證取得使用者的身份了。

這篇處理了 web 的部分,下一篇將說明如何讓 command line tool (e.g. kubectl) 也能以取得的 token 來取得操作 kubernetes 權限。

沒有留言: