工作負載身分簡介
對於 GCP 專業雲端安全工程師 (PSE) 來說,管理機密資訊 (Secrets) 是風險最高的活動之一。傳統的應用程式驗證依賴於下載服務帳戶的 JSON 金鑰,並將其作為「機密 (Secrets)」掛載到容器中。這在安全性上是一場噩夢:金鑰經常被提交到 Git、在記錄中洩漏,或從遭到入侵的 Pod 中被盜。
工作負載身分 (Workload Identity) (針對 GKE) 和工作負載身分聯合 (Workload Identity Federation) (針對外部雲端) 代表了現代安全性的「黃金標準」。它們允許你的應用程式使用其「現有的」身分 (如 K8s 服務帳戶、AWS IAM 角色等) 向 Google Cloud 服務進行驗證,而無需任何靜態、長效的機密金鑰。
白話文解釋
1. 自動識別證製卡機 (工作負載身分)
想像一個高安全性的實驗室。與其給每個研究員一把永久的實體鑰匙,不如在入口處設置一台「自動識別證製卡機」。當一名研究員 (GKE Pod) 走近時,機器會驗證他們的實驗袍和 ID (K8s 服務帳戶),然後吐出一張臨時的、效期 1 小時的識別證。識別證過期後就失效了。這就是 GKE 元資料伺服器 (Metadata Server) 在運作。
2. 貨幣兌換處 (工作負載身分聯合)
想像你正從英國前往美國旅行。你無法在紐約使用英鎊,但你可以去貨幣兌換處。你出示有效的英鎊 (AWS 權杖),辦事員會根據預先商定的匯率 (屬性對應) 給你等值的美金 (Google 存取權杖)。你不需要「全球通用信用卡」(JSON 金鑰)。
3. 受信任的特使 (OIDC 聯合驗證)
想像兩個王國之間簽署了和平協議。A 王國不認識 B 王國的士兵,但他們信任 B 王國的國王。如果一名士兵攜帶有 B 王國國王簽署的信件 (OIDC 權杖),A 王國就會將他們視為賓客。Google Cloud 信任「簽發者」(如 AWS/Azure/Okta) 來聲明工作負載的身分。
針對 GKE 的工作負載身分 (Workload Identity)
這是運行在 GKE 上的應用程式存取 Google Cloud 服務的推薦方式。
運作方式
- 你建立一個具有所需 IAM 角色的 Google 服務帳戶 (GSA)。
- 你在 GKE 叢集中建立一個 Kubernetes 服務帳戶 (KSA)。
- 你透過授予 GSA 針對該 KSA 的
roles/iam.workloadIdentityUser角色,將兩者「繫結」在一起。 - GKE 元資料伺服器會攔截來自 Pod 的請求,並將 KSA 的權杖交換為 GSA 的存取權杖。
工作負載身分 (Workload Identity) 是一項 GKE 功能,它橋接了 Kubernetes 身分與 Google Cloud IAM 身分,消除了在叢集內管理服務帳戶金鑰的需求。
針對外部工作負載的工作負載身分聯合
這將「無金鑰」概念擴展到在 Google Cloud 之外運行的工作負載 (如 AWS、Azure、GitHub Actions、地端環境)。
關鍵組件
- 工作負載身分集區 (Workload Identity Pool): 外部身分的容器 (例如 "AWS-Production-Pool")。
- 工作負載身分提供者 (Workload Identity Provider): 定義 Google 與外部 IdP (如 AWS、Azure 或 OIDC/SAML) 之間的關係。
- 屬性對應 (Attribute Mapping): 將外部宣告 (Claims,例如
aws:PrincipalArn) 對應到 Google 內部屬性。
AWS/Azure 的聯合驗證
與其在 AWS Secrets Manager 中儲存 Google JSON 金鑰,你的 AWS Lambda 或 EC2 執行個體會使用其原生的 執行個體設定檔 (Instance Profile) 來請求 Google 權杖。
工作負載身分聯合是 PSE 唯一推薦用於 CI/CD 流程中 GitHub Actions 向 Google Cloud 進行驗證的方式。
將 K8s 服務帳戶對應到 GSA
繫結是雙向的:
- K8s 註解 (Annotation): KSA 必須使用 GSA 的電子郵件進行註解。
- IAM 繫結: GSA 必須有一個政策繫結,允許特定的 KSA (透過命名空間和名稱識別) 冒充它。
K8s 註解範例
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
iam.gke.io/gcp-service-account: [email protected]
name: my-app-ksa
namespace: default
KSA 與 GSA 的繫結是雙向的,PSE 場景題常考這一點。光是在 KSA 上加 iam.gke.io/gcp-service-account 註解並不足夠 — 你還必須在 GSA 上授予 roles/iam.workloadIdentityUser,成員為 serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]。任何一邊缺失,GKE Metadata Server 都會回傳靜默的 403。
消除對靜態 JSON 金鑰的需求
為什麼這是 PSE 的核心要求?
- 更換 (Rotation): 短期權杖每小時自動更換。
- 撤銷: 如果 Pod 遭到入侵,刪除 KSA 或 IAM 繫結會立即撤銷存取權。
- 合規性: 稽核更加清晰,因為沒有需要追蹤的「機密檔案」。
屬性對應與條件
在聯合驗證中,你可能不希望信任來自 AWS 帳戶的「每個」工作負載。
宣告對應 (Mapping Claims)
你將傳入的 AWS 宣告 (如 arn:aws:sts::123456789012:assumed-role/MyRole) 對應到 Google 屬性 (如 google.subject)。
條件式存取
你可以在身分提供者中新增 CEL 條件:
assertion.arn.startsWith('arn:aws:iam::123456789012:role/Production')
結果:只有帶有 'Production' 角色的 AWS 工作負載才能交換權杖。
在 Workload Identity Provider 上加 CEL attribute_condition (例如 assertion.arn.startsWith('arn:aws:iam::123456789012:role/Production'),或 GitHub Actions 場景的 assertion.repository == 'my-org/my-repo'),可在 STS 簽發聯合權杖之前就過濾掉不該進來的身分。這比只在 IAM 政策層做過濾更早收斂影響範圍,能擋住不該存取的 AWS 角色或被 fork 的儲存庫,避免它們進到 google.subject。
GKE 元資料伺服器保護
元資料伺服器是 GKE 工作負載身分的「核心」。
- GKE 沙箱 (GKE Sandbox): 對於高安全性環境,使用 GKE 沙箱將元資料伺服器與 Pod 的核心進一步隔離。
- 元資料隱藏 (Metadata Concealment): 在舊版 GKE 中用於向 Pod 隱藏預設的 GCE 元資料;工作負載身分取代並改進了這一功能。
如果你不啟用工作負載身分,Pod 可能會退而使用節點的預設服務帳戶,這通常擁有廣泛的「編輯者 (Editor)」權限。這是 PSE 考試中常見的陷阱。
排除身分權杖交換故障
- 檢查註解: KSA 是否已正確註解?
- 驗證 IAM 繫結: GSA 是否擁有針對該 KSA 的
roles/iam.workloadIdentityUser權限? - STS 記錄: 對於聯合驗證,檢查安全性權杖服務 (STS) 記錄,查看外部權杖是否被拒絕。
- 權杖格式: 確保 OIDC 提供者發送的是有效的 JWT (JSON Web Token)。
多雲端工作負載身分的最佳實務
- 每個環境一個集區: 為
Dev、Stage和Prod使用獨立的身分集區。 - 最小權限對應: 只對應 IAM 決策實際需要的屬性。
- 使用短期權杖: 將
expiresIn參數設定為任務所需的最小值。 - 監控權杖交換: 稽核
iam.googleapis.com/WorkloadIdentityPool資源的使用情況。
工作負載身分的 CLI 指令
建立工作負載身分集區
gcloud iam workload-identity-pools create "my-aws-pool" \
--location="global" \
--display-name="AWS Production Pool"
新增 AWS 提供者
gcloud iam workload-identity-pools providers create-aws "my-aws-provider" \
--workload-identity-pool="my-aws-pool" \
--account-id="123456789012" \
--location="global"
授予 KSA 冒充 GSA 的權限
gcloud iam service-accounts add-iam-policy-binding \
[email protected] \
--role="roles/iam.workloadIdentityUser" \
--member="serviceAccount:my-project.svc.id.goog[my-namespace/my-ksa]"
GKE 工作負載身分的成員格式為:
serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]
PSE 安全性最佳實務
- 禁用節點元資料: 確保所有節點集區都設定了
workload-metadata-configuration=GKE_METADATA。 - 使用受控識別 (Managed Identities): 在 Azure 中,使用「系統指派的受控識別」進行聯合驗證。
- 稽核權杖使用: 定期檢查成功與失敗的
GenerateAccessToken呼叫。 - 命名空間隔離: 如果 Pod 需要不同的 GSA 權限,切勿跨命名空間共用 KSA。
故障排除場景
場景:Pod 在呼叫 BigQuery 時收到 "403 Forbidden"。
診斷: KSA 已註解,但 GSA 缺少 BigQuery Data Viewer 角色,或者 GSA 沒有針對該 KSA 的工作負載身分繫結。
修正: 在 GSA 上執行 gcloud iam service-accounts get-iam-policy 並驗證 id.goog 成員繫結。
場景:GitHub Actions 無法向 Google Cloud 進行驗證。
診斷: 工作負載身分提供者中的 issuer 與 GitHub 的 OIDC URL 不匹配,或者 subject 對應不正確。
修正: 根據 GitHub 官方 OIDC 文件驗證提供者設定。
PSE 考試場景
場景 1:減少金鑰管理
「你的公司在 3 個雲端平台上有 500 個微服務。管理它們 Google Cloud 憑證最安全的方法是什麼?」 答案: 為所有 3 個雲端實施工作負載身分聯合 (Workload Identity Federation),以消除儲存、更換和管理 500 個 JSON 金鑰的需求。
場景 2:GKE 多租戶
「兩個不同的團隊在同一個 GKE 叢集但不同的命名空間中運行 Pod。你如何確保 A 團隊的 Pod 無法使用 B 團隊的權限?」 答案: 在每個命名空間中建立獨立的 KSA,並將它們繫結到不同的 GSA。使用 Kubernetes 網路政策 (Network Policies) 進一步隔離命名空間。
常見問題 (FAQ)
Q1:工作負載身分是否適用於 Autopilot 叢集? A1:是的,工作負載身分在 GKE Autopilot 中預設為啟用。
Q2:我可以與地端的 LDAP 伺服器進行聯合驗證嗎? A2:不能直接進行。你必須使用符合 OIDC 標準的包裝器 (如 Okta、Keycloak 或 Ping Identity) 作為橋樑。
Q3:工作負載身分聯合的費用是多少? A3:Google Cloud 不對聯合驗證服務本身收費,但適用標準的 API 使用費用。
總結檢查清單
- 解釋 GKE 工作負載身分中的權杖交換流程。
- 列出為 AWS 設定工作負載身分聯合的步驟。
- 定義「工作負載身分集區」及其用途。
- 為工作負載身分註解 KSA。
- 描述短期權杖優於 JSON 金鑰的安全性優勢。