OpenID Connect(OIDC)是一種現代的身份驗證協定,可以讓應用程式安全地驗證使用者身份。在 Kubernetes 叢集中使用 OIDC 可以簡化使用者管理,並提高安全性。本文將逐步說明如何在 KinD 叢集中組態 OIDC,並涵蓋從建立必要的 Secret 到組態 API 伺服器等所有關鍵步驟。過程中會使用 OpenUnison 作為 OIDC 提供者,並示範如何設定測試身份提供者、佈署 OpenUnison,以及更新 SAML2 Lab 中的依賴方設定。最後,還會探討如何使用 Impersonation 機制將集中式身份驗證整合到雲端託管的 Kubernetes 叢集中,解決雲端供應商不支援 OIDC 的問題。

組態 KinD 使用 OpenID Connect

建立 OpenUnison 的秘密(Secret)

當 OpenUnison 的 Operator 佈署完成後,需要建立一個 Secret 來儲存 OpenUnison 內部使用的密碼。請確保使用自己的值來替換這個 Secret 中的鍵值(並記得進行 base64 編碼):

kubectl create -f - <<EOF
apiVersion: v1
type: Opaque
metadata:
  name: orchestra-secrets-source
  namespace: openunison
data:
  K8S_DB_SECRET: cGFzc3dvcmQK
  unisonKeystorePassword: cGFzc3dvcmQK
kind: Secret
EOF

內容解密:

  • kubectl create 命令用於建立 Kubernetes 資源。
  • -f - 表示從標準輸入讀取資源定義。
  • apiVersionkind 指定了要建立的資源型別為 Secret。
  • metadata 部分定義了 Secret 的名稱和名稱空間。
  • data 部分包含了需要儲存的密碼,值需要進行 base64 編碼。
  • K8S_DB_SECRETunisonKeystorePassword 是 OpenUnison 使用的密碼。

設定測試身份提供者

  1. 前往 https://portal.apps.tremolo.io/ 並點選 Register 進行註冊。
  2. 登入測試身份提供者,點選 SAML2 Test Lab 徽章。
  3. 複製 SAML2 元資料 URL 並儲存。

建立 values.yaml 檔案

建立一個 values.yaml 檔案,用於提供佈署 OpenUnison 所需的組態資訊。可以參考本文 GitHub 倉函式庫中 chapter7 目錄下的範例檔案:

network:
  openunison_host: "k8sou.apps.XX-XX-XX-XX.nip.io"
  dashboard_host: "k8sdb.apps.XX-XX-XX-XX.nip.io"
  api_server_host: ""
  session_inactivity_timeout_seconds: 900
k8s_url: https://0.0.0.0:6443
cert_template:
  ou: "Kubernetes"
  o: "MyOrg"
  l: "My Cluster"
  st: "State of Cluster"
  c: "MyCountry"
image: "docker.io/tremolosecurity/openunison-k8s-login-saml2:latest"
myvd_config_path: "WEB-INF/myvd.conf"
k8s_cluster_name: kubernetes
enable_impersonation: false
dashboard:
  namespace: "kubernetes-dashboard"
  cert_name: "kubernetes-dashboard-certs"
  label: "k8s-app=kubernetes-dashboard"
  service_name: kubernetes-dashboard
certs:
  use_k8s_cm: false
  trusted_certs: []
monitoring:
  prometheus_service_account: system:serviceaccount:monitoring:prometheus-k8s
saml:
  idp_url: https://portal.apps.tremolo.io/idp-test/metadata/dfbe4040-cd32-470e-a9b6-809c840
  metadata_xml_b64: ""

內容解密:

  • network 部分定義了 OpenUnison 和 Dashboard 的主機名稱。
  • k8s_url 指定了 Kubernetes API 伺服器的 URL。
  • saml 部分組態了 SAML 身份提供者的相關資訊。

修改 values.yaml 檔案

需要根據自己的佈署環境修改以下值:

  • openunison_host:使用 Docker 主機的 IP 位址。
  • dashboard_host:使用 Docker 主機的 IP 位址。
  • idp_url:使用從 SAML2 Lab 頁面取得的 SAML2 元資料 URL。

佈署 OpenUnison

使用修改後的 values.yaml 檔案執行 Helm 安裝命令:

helm install orchestra tremolo/openunison-k8s-login-saml2 --namespace openunison -f ./values.yaml

內容解密:

  • helm install 命令用於安裝 Helm Chart。
  • --namespace openunison 指定了佈署的名稱空間。
  • -f ./values.yaml 指定了使用的組態檔案。

更新 SAML2 Lab 中的依賴方

  1. 從 OpenUnison 取得 SAML2 元資料:curl --insecure https://k8sou.apps.192-168-2-131.nip.io/auth/forms/saml2_rp_metadata.jsp
  2. 將輸出的元資料複製到測試身份提供者的 Meta Data 欄位中,並點選 Update Relying Party。

設定測試使用者屬性

  1. 在測試身份提供者中新增所需的屬性。
  2. 點選 Update Test User Data 以儲存變更。

登入 OIDC 提供者

  1. 使用瀏覽器造訪 network.openunison_host,並完成登入流程。
  2. 登入後,您應該能夠看到 OpenUnison 的主畫面。

測試 OIDC 提供者

  1. 點選 Kubernetes Dashboard 連結。
  2. 由於 API 伺服器尚未信任 OpenUnison 發出的 Token,您可能會看到錯誤訊息。

圖表翻譯:

此圖示描述了使用 OpenID Connect 組態 KinD 的流程,包括建立 Secret、設定測試身份提供者、佈署 OpenUnison 以及更新 SAML2 Lab 中的依賴方等步驟。

將驗證整合到您的叢集中

設定 Kubernetes API 使用 OIDC

到目前為止,您已經將 OpenUnison 佈署為 OIDC 提供者並且正在執行,但是您的 Kubernetes 叢集尚未組態為使用它作為提供者。要組態 API 伺服器使用 OIDC 提供者,您需要將 OIDC 選項新增到 API 伺服器並提供 OIDC 證書,以便 API 能夠信任 OIDC 提供者。

由於我們使用的是 KinD,我們可以使用幾個 kubectldocker 命令新增所需的選項。

提供 OIDC 證書給 API 伺服器

要將 OIDC 證書提供給 API 伺服器,我們需要檢索證書並將其複製到 KinD 主伺服器。我們可以在 Docker 主機上使用兩個命令來完成此操作:

  1. 第一個命令從 OpenUnison 的 secret 中提取 TLS 證書。這與 OpenUnison 的 Ingress 物件參照的 secret 相同。我們使用 jq 工具從 secret 中提取資料,然後進行 base64 解碼:
kubectl get secret ou-tls-certificate -n openunison -o json | jq -r '.data["tls.crt"]' | base64 -d > ou-ca.pem

內容解密:

此命令用於從 Kubernetes 的 secret 中提取 OpenUnison 的 TLS 證書。首先,kubectl get secret 命令取得指定的 secret,然後透過 jq 解析 JSON 輸出,提取 tls.crt 欄位的值,最後進行 base64 解碼,將結果儲存到 ou-ca.pem 檔案中。

  1. 第二個命令將證書複製到主伺服器的 /etc/kubernetes/pki 目錄中:
docker cp ou-ca.pem cluster01-control-plane:/etc/kubernetes/pki/ou-ca.pem

內容解密:

此命令使用 Docker 的 cp 命令將本地的 ou-ca.pem 檔案複製到 KinD 主伺服器的 /etc/kubernetes/pki 目錄中,確保 API 伺服器能夠存取 OIDC 證書。

  1. 如前所述,要將 API 伺服器與 OIDC 整合,我們需要 OIDC 的值來設定 API 選項。要列出我們將使用的選項,請描述 openunison 名稱空間中的 api-server-config ConfigMap:
kubectl describe configmap api-server-config -n openunison

輸出結果如下:

Name: api-server-config
Namespace: openunison
Labels: <none>
Annotations: <none>
Data
====
oidc-api-server-flags:
---
-
--oidc-issuer-url=https://k8sou.apps.192-168-2-131.nip.io/auth/idp/k8sIdp
--oidc-client-id=kubernetes
--oidc-username-claim=sub
--oidc-groups-claim=groups
--oidc-ca-file=/etc/kubernetes/pki/ou-ca.pem

內容解密:

此命令用於檢索 api-server-config ConfigMap 中的資料,該資料包含了與 OIDC 整合所需的 API 伺服器選項。這些選項包括 OIDC 發行者 URL、客戶端 ID、使用者名稱宣告、群組宣告和 CA 檔案路徑等。

  1. 接下來,編輯 API 伺服器組態。OpenID Connect 是透過更改 API 伺服器的旗標來組態的。不同的發行版對這些更改的處理方式不同,因此請檢視您的供應商的檔案。對於 KinD,請進入控制平面並更新清單檔案:
docker exec -it cluster-auth-control-plane bash
apt-get update
apt-get install vim
vi /etc/kubernetes/manifests/kube-apiserver.yaml
  1. 尋找 --oidc-client--oidc-issuer-url 兩個選項,並用前面的命令輸出的 API 伺服器旗標替換它們。確保在前面新增空格和短橫線(-)。完成後應該如下所示:
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --oidc-issuer-url=https://k8sou.apps.192-168-2-131.nip.io/auth/idp/k8sIdp
- --oidc-client-id=kubernetes
- --oidc-username-claim=sub
- --oidc-groups-claim=groups
- --oidc-ca-file=/etc/kubernetes/pki/ou-ca.pem
- --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt

內容解密:

此步驟涉及編輯 kube-apiserver.yaml 清單檔案,以新增 OIDC 相關的旗標。這些旗標告訴 API 伺服器如何與 OIDC 提供者互動,包括驗證使用者和群組。

圖表翻譯:

此圖示呈現了 Kubernetes API 伺服器與 OIDC 提供者之間的互動流程。首先,API 伺服器會被組態為使用 OIDC 提供者的 URL 和客戶端 ID。然後,當使用者嘗試存取叢集時,API 伺服器會將其重定向到 OIDC 提供者進行驗證。驗證成功後,OIDC 提供者會發放一個 JWT 給使用者,使用者再將其呈現給 API 伺服器以取得存取許可權。

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 圖表翻譯:

rectangle "重定向" as node1
rectangle "驗證使用者" as node2
rectangle "呈現 JWT" as node3
rectangle "驗證 JWT" as node4

node1 --> node2
node2 --> node3
node3 --> node4

@enduml

圖表翻譯: 此圖示詳細展示了 Kubernetes API 伺服器如何與 OIDC 提供者協同工作來驗證使用者身份並授權存取叢集資源。首先,使用者嘗試存取叢集資源,API 伺服器將其重定向到 OIDC 提供者進行身份驗證。驗證成功後,OIDC 提供者發放 JWT,使用者再將 JWT 呈現給 API 伺服器,API 伺服器驗證 JWT 後授予存取許可權。

使用 kubectl 與您的 Token

要使用 kubectl 與叢集互動,您需要檢索您的 JWT 並將其新增到您的 Kubernetes 組態檔案中。

  1. 從 OpenUnison 控制台檢索您的 Token。導航到 OpenUnison 首頁並點選 “Kubernetes Tokens”。
  2. 複製 kubectl 命令並將其貼上到您的終端中。
  3. 為了安全起見,您可能希望在貼上命令之前備份原始組態檔案。
  4. 使用更新後的組態檔案,您應該能夠使用 kubectl 與叢集互動。

使用 KinD 組態 OpenID Connect

組態 KinD 叢集並驗證 OpenID Connect 身份驗證

  1. 首先,您需要將 KinD 叢集組態為使用 OpenID Connect(OIDC)進行身份驗證。具體步驟包括生成相關憑證和組態叢集的 API 伺服器。

  2. 在主機控制檯中執行匯出的命令,該命令會生成一個臨時憑證並組態 kubectl 使用該憑證連線到 KinD 叢集:

    export TMP_CERT=$(mktemp) && echo -e "
    

–BEGIN CERTIFICATE

–\n…\n

–END CERTIFICATE

–" > $TMP_CERT kubectl config set-cluster kubernetes –certificate-authority=$TMP_CERT –embed-certs=true kubectl config set-credentials mlbiamext –auth-provider=oidc –auth-provider-arg=idp-issuer-url=https://your-idp-issuer-url.com –auth-provider-arg=client-id=kubernetes-client –auth-provider-arg=refresh-token=your-refresh-token kubectl config set-context kubernetes –cluster=kubernetes –user=mlbiamext kubectl config use-context kubernetes

#### 內容解密:
- `export TMP_CERT=$(mktemp)`:建立一個臨時檔案來儲存憑證。
- `kubectl config set-cluster`:組態叢集資訊,包括使用臨時憑證作為憑證授權單位。
- `kubectl config set-credentials`:設定使用 OIDC 身份驗證的使用者憑證,包括 IdP 發行者 URL、客戶端 ID 和重新整理令牌。
- `kubectl config set-context` 和 `kubectl config use-context`:切換到新組態的上下文。

3. 驗證您是否能夠使用 `kubectl get nodes` 檢視叢集節點:
```bash
kubectl get nodes

輸出結果應該顯示叢集中的節點狀態、角色和版本等資訊。

內容解密:

  • 此步驟驗證了 kubectl 是否能夠正確連線到 KinD 叢集並取得節點資訊。
  1. 登出 OpenUnison 並觀察 kubectl 命令的行為。幾分鐘後,由於令牌過期,kubectl 命令將無法執行:
    $ kubectl get nodes
    Unable to connect to the server: failed to refresh token: oauth2: cannot fetch token: 401 Unauthorized
    

    內容解密:

    • 當 OIDC 令牌過期後,kubectl 無法重新整理令牌,導致命令執行失敗,表明身份驗證機制正常運作。

整合集中式身份驗證與雲端託管叢集

為何需要 Impersonation

許多雲端供應商提供了託管的 Kubernetes 服務,但它們通常不支援 OpenID Connect。在這種情況下,需要使用 Impersonation 機制來整合集中式身份驗收與授權。

Impersonation 的工作原理

Kubernetes Impersonation 允許反向代理代表使用者向 API 伺服器發出請求,而無需直接使用使用者的憑證。反向代理會新增 Impersonate-UserImpersonate-Group HTTP 標頭,以指示 API 伺服器請求是由誰發出的。

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title Impersonation 的工作原理

rectangle "id_token" as node1
rectangle "Impersonate-User, Impersonate-Group" as node2

node1 --> node2

@enduml

圖表翻譯: 此圖示展示了使用者透過反向代理與 Kubernetes API 伺服器互動的流程。使用者首先向反向代理提供 id_token,反向代理再新增 Impersonate-UserImpersonate-Group 標頭,將請求轉發給 API 伺服器。

在 Kubernetes Dashboard 中使用 Impersonation

在 Kubernetes Dashboard 中同樣可以使用 Impersonation。Dashboard 本身不應具有特權身份,而是透過反向代理傳遞 Impersonation 標頭來與 API 伺服器互動。

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 在 Kubernetes Dashboard 中使用 Impersonation

rectangle "id_token" as node1
rectangle "Impersonate-User, Impersonate-Group" as node2
rectangle "帶有 Impersonation 標頭的請求" as node3

node1 --> node2
node2 --> node3

@enduml

圖表翻譯: 此圖示展示了使用者透過反向代理與 Kubernetes Dashboard 互動,並進一步與 API 伺服器互動的流程。Dashboard 將反向代理新增的 Impersonation 標頭傳遞給 API 伺服器。