examlab .net 用最有效率的方法,考取最有價值的證照
本篇導覽 約 29 分鐘

服務帳戶管理

5,800 字 · 約 29 分鐘閱讀 ·

掌握 Google Cloud 中服務帳戶的安全與管理,包括金鑰、冒充 (Impersonation)、短期憑證與 Workload Identity Federation。

立即做 20 題練習 → 免費 · 不用註冊 · PCA

服務帳戶簡介 (Introduction to Service Accounts)

服務帳戶 (Service Account) 是一種特殊的 Google 帳戶,它屬於你的應用程式或虛擬機 (VM),而不是單個終端用戶。在 Professional Cloud Architect 的語境下,服務帳戶是安全、機器對機器通訊的核心。正確管理服務帳戶是打造安全環境與避免重大數據洩漏的關鍵差異所在。

白話文解釋 Service Accounts

類比 1 — 公司信用卡 (The Corporate Credit Card)

服務帳戶 想像成一張發給部門而非個人的 公司信用卡。它有特定的額度(權限),並用於支付特定的東西(存取資源)。如果部門主管離職,這張卡仍然有效。但是,如果這張卡被盜(金鑰洩露),任何人都可以在你註銷它之前使用它。

類比 2 — 機器人員工

服務帳戶就像是在你工廠裡工作的 機器人員工。它沒有個人生活,也沒有密碼;它只有一項任務(程式碼)和一個識別證(服務帳戶)。你不會給機器人整間工廠的鑰匙,你只會給它執行工作所需房間的鑰匙。

類比 3 — 代客泊車鑰匙 (The Valet Key)

服務帳戶冒充 (Service Account Impersonation) 就像是你汽車的 代客泊車鑰匙。你不會把包含家門鑰匙的整串鑰匙交給代客泊車員,而是給他們一把只能停車的特殊鑰匙。在 GCP 中,開發者「冒充」服務帳戶來執行任務,而無需看到實際的密碼或金鑰。

服務帳戶:應用程式或工作負載用來進行經過身份驗證的 API 呼叫的身份。它由其電子郵件地址識別:[email protected]


服務帳戶的類型

  1. 預設服務帳戶 (Default Service Accounts): 由 GCP 自動建立(例如 Compute Engine 預設服務帳戶)。警告: 這些帳戶預設通常具有廣泛的「編輯者 (Editor)」權限。
  2. 使用者管理(自訂)服務帳戶 (User-Managed Service Accounts): 由你建立。這是 最佳實踐 (Best Practice)。你可以精確定義它擁有的角色。
  3. Google 管理的服務帳戶 (Google-Managed Service Accounts): 由 Google 服務(如 Cloud Dataflow)使用,代表你執行操作。

服務帳戶金鑰對比冒充 (Service Account Keys vs. Impersonation)

  • 服務帳戶金鑰 (.json): 高風險。一旦洩露,在刪除前一直有效,且不會過期。請儘可能避免使用。
  • 冒充 (Impersonation): 高安全性。使用者或其他服務帳戶「扮演」某個服務帳戶。不需要下載金鑰,存取權限由 iam.serviceAccounts.getAccessToken 權限控管。
::promoted

架構師洞察: 對於 PCA 考試,如果被問及如何為 GKE 工作負載或 VM 提供資源存取權限,正確答案是 Workload Identity(針對 GKE)或 服務帳戶冒充,絕不是「下載 JSON 金鑰」。 ::


透過 Org Policy 停用服務帳戶金鑰建立

防止整個組織憑證外洩的最高槓桿控制,就是 在組織層級停用服務帳戶金鑰的建立。Org Policy 條件約束 iam.disableServiceAccountKeyCreation 會封鎖該節點(資料夾、專案或整個組織)下所有 iam.serviceAccountKeys.create 呼叫。第二個條件約束 iam.disableServiceAccountKeyUpload 則封鎖外部產生的公鑰上傳(即「自帶金鑰」流程)。兩者搭配可消除最常見的外洩管道:開發者下載長效 .json 並提交到 GitHub。

建議的 Org Policy 組合

  • iam.disableServiceAccountKeyCreation → 在組織根節點 強制執行
  • iam.disableServiceAccountKeyUpload → 在組織根節點 強制執行
  • iam.disableServiceAccountCreation → 僅在沙盒資料夾強制執行(不可組織層級強制執行,否則無法部署工作負載)。
  • iam.automaticIamGrantsForDefaultServiceAccounts強制執行。此條件約束會停止新專案自動將 legacy Editor 角色授予 Compute 與 App Engine 預設 SA。

例外流程

在組織節點套用條件約束,然後在特定資料夾(如 legacy-batch-jobs/)建立 附帶豁免的子政策,供仍需下載金鑰的地端排程系統使用。豁免資料夾應同時受 VPC Service Controls 保護,並有 90 天金鑰輪換的硬性手冊。架構師應搭配 Cloud Asset Inventory 匯出(篩選 iam.googleapis.com/ServiceAccountKey 資產類型),讓豁免區內任何新金鑰於數分鐘內出現在 Security Command Center。

條件約束 iam.disableServiceAccountKeyCreation 只封鎖 金鑰,並不會刪除既有金鑰。在強制執行之前,請透過 Cloud Asset Inventory 跨所有專案執行 gcloud iam service-accounts keys list,並輪換或刪除所有逾 90 天的使用者管理金鑰。否則 legacy 金鑰會無限期有效,成為攻擊者的首要目標。


給外部工作負載用的 Workload Identity Federation

Workload Identity Federation (WIF) 讓在 GCP 外部執行的工作負載——AWS、Azure、GitHub Actions、地端 Kubernetes 或任何符合 OIDC 規範的身份提供者——能 不需下載服務帳戶金鑰 呼叫 Google Cloud API。外部 IdP 簽發一個 token(例如 AWS STS session、Azure managed identity token,或 GitHub Actions OIDC JWT),位於 sts.googleapis.comSecurity Token Service (STS) 將其交換為短效聯合 token,再用該 token 冒充 GCP 服務帳戶。

組成元件

  • Workload Identity Pool: 頂層容器,依信任邊界(例如每個 AWS 帳戶或每個 GitHub org 一個 pool)分組外部身份。
  • Workload Identity Pool Provider: 每個 IdP 對應一個 provider 設定。支援 awsoidcsaml 三種類型。Provider 定義 屬性對應 (attribute mapping)(如 google.subject = assertion.sub)與 屬性條件 (attribute condition)(CEL 表達式),用以閘控接受哪些外部 principal。
  • 服務帳戶綁定: 在目標 GCP 服務帳戶上授予 roles/iam.workloadIdentityUser,成員形如 principalSet://iam.googleapis.com/projects/PROJECT_NUM/locations/global/workloadIdentityPools/POOL/attribute.repository/my-org/my-repo

Provider 模式

  • AWS: 信任某個 AWS 帳戶;attribute condition 限制至特定 IAM role ARN。
  • Azure: OIDC provider 指向 https://login.microsoftonline.com/TENANT_ID/v2.0,並以 Azure AD application ID 進行條件過濾。
  • GitHub Actions: OIDC provider 指向 https://token.actions.githubusercontent.com,並以 assertion.repository == 'my-org/my-repo'assertion.ref == 'refs/heads/main' 過濾。

最終結果:GitHub Actions 部署到 GCP 時零儲存的 secret——沒有 GCP_SA_KEY GitHub secret、沒有輪換負擔,每次 workflow 執行只是一次 OIDC handshake。


GKE Workload Identity

對於在 GKE 內部 執行的工作負載,對應的機制是 GKE Workload Identity,它將 Kubernetes Service Account (KSA) 綁定到 Google Service Account (GSA),讓 pod 能以該 GSA 身份呼叫 Google API——同樣無需下載任何 JSON 金鑰。底層上,GKE metadata server 會攔截 pod 對 metadata.google.com 的呼叫,判別 pod 執行所使用的 KSA,然後為綁定的 GSA 鑄造短效 OAuth token。

設定步驟

  1. 在叢集上啟用 Workload Identity:--workload-pool=PROJECT_ID.svc.id.goog
  2. 在 node pool 上啟用:--workload-metadata=GKE_METADATA。此設定會停用 legacy 的節點層級預設 SA 路徑。
  3. 在對應 namespace 建立 KSA:kubectl create sa my-app -n production
  4. 授予 IAM 綁定:
    gcloud iam service-accounts add-iam-policy-binding \
      my-gsa@PROJECT_ID.iam.gserviceaccount.com \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:PROJECT_ID.svc.id.goog[production/my-app]"
    
  5. 在 pod spec 中引用該 KSA:spec.serviceAccountName: my-app

為何對 PCA 重要

考試經常對比三種 GKE 模式:(1) 將 JSON 金鑰下載進 Kubernetes Secret(錯——etcd 中的長效憑證)、(2) 授予節點預設 SA 廣泛權限(錯——節點上每個 pod 都會繼承)、(3) Workload Identity(對——每 pod 最小權限、無儲存憑證)。永遠選第三個。

GKE Workload Identity 需要 node pool 使用 GKE_METADATA,而非 GCE_METADATA。如果 node pool 是在啟用 Workload Identity 之前建立、且仍使用 legacy metadata server,pod 會默默回落到 節點的 compute 預設服務帳戶——通常具有 Editor 權限。這是 PCA 案例研究中最常見的 GKE 權限提升失誤。


服務帳戶冒充與 Token Creator 角色

冒充 (Impersonation) 是 GCP 內部相當於 sudo 的機制:人類使用者(或另一個服務帳戶)暫時以某個服務帳戶身份執行特權操作,而完全不需要持有該 SA 的長效憑證。此機制由 目標服務帳戶上的 兩個角色控制:

  • roles/iam.serviceAccountTokenCreator——允許為該 SA 鑄造 OAuth 2.0 access token 與 OpenID Connect ID token。這是你授予給需要「以 SA 身份行事」的人類或 pipeline 的角色。
  • roles/iam.serviceAccountUser——允許將該 SA 附加 到資源(如 Compute Engine VM、Cloud Run service)。與 Token Creator 不同:此角色關心的是誰能部署以該 SA 執行的程式碼,而非誰能臨時鑄造 token。

冒充的實際樣貌

# 一次性 CLI 呼叫
gcloud storage ls gs://prod-bucket \
  --impersonate-service-account=prod-reader@PROJECT.iam.gserviceaccount.com

# 持久預設值
gcloud config set auth/impersonate_service_account \
  [email protected]

gcloud client 會呼叫 iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/prod-reader@...:generateAccessToken、收到預設 1 小時效期的 token,並以該 token 進行底層 API 呼叫。Audit log 會同時記錄呼叫者身份(如 [email protected])與被冒充的 SA,提供完整可追溯性。

冒充鏈

冒充可以串接:SA-A 冒充 SA-B 冒充 SA-C。每一跳都需要下一個 SA 上的 Token Creator。可用於職責分離——例如 CI 服務帳戶僅能冒充 staging 的「deploy」SA,後者通過人工核可閘門後才能冒充 production 的「promote」SA。

不要把 Token Creator (roles/iam.serviceAccountTokenCreator) 與 Service Account User (roles/iam.serviceAccountUser) 混為一談。Token Creator 讓主體能為臨時 API 呼叫鑄造 token(冒充流程)。Service Account User 讓主體能將 SA 附加到資源(部署流程)。真實世界許多權限提升都來自於只需要一個卻同時授予兩者——gcloud deploy 流程只需要 Service Account User;CLI 冒充只需要 Token Creator。


透過 IAM Credentials API 取得短期憑證

IAM Credentials API (iamcredentials.googleapis.com) 是 GCP 原生取得短期憑證的入口。每一次 WIF 交換、每一次冒充呼叫、每一次 gcloud auth print-access-token --impersonate-service-account 最終都會打到此 API。理解它的四個方法對考試至關重要:

  • generateAccessToken——回傳 OAuth 2.0 access token(預設 1h,透過 serviceAccounts.signJwt 或 org policy iam.allowServiceAccountCredentialLifetimeExtension 可延長至最多 12h)。
  • generateIdToken——回傳 OIDC ID token,用於對 Cloud Run、Cloud Functions、IAP 保護資源,或任何驗證 Google 簽署 JWT 的 audience 進行認證。
  • signBlob——以 SA 的 Google 管理金鑰簽署任意 byte string。供需鑄造自訂 JWT 的工具使用(如不暴露金鑰即為 GCS 產生 signed URL)。
  • signJwt——以 SA 的 Google 管理金鑰簽署 JWT payload。

效期治理

預設 1 小時的 access token 效期是刻意設計的安全邊界。如需更長效期(如 6 小時 Dataflow batch job),請設定 org policy 條件約束 constraints/iam.allowServiceAccountCredentialLifetimeExtension 並傳入 --lifetime=21600s。生產環境應避免此做法——刷新 token 幾乎總比延長效期好。透過 WIF 簽發的 token 有對應外部 IdP token TTL 的硬上限(如 GitHub OIDC token 約有效 15 分鐘;GCP token 不能比它更長)。


服務帳戶監控:Last-Authenticated Time 與洞察

無法觀測就無法保護。GCP 提供數種專為服務帳戶健康度設計的遙測介面:

Last-authenticated time

serviceAccounts.get 回應包含 lastAuthenticatedTime——以 7 天為粒度的最後一次成功驗證時間戳。可透過 Cloud Asset Inventory 或 gcloud iam service-accounts get-iam-policy 查詢。標準手冊:

  1. 透過 Cloud Asset Inventory feed 列舉組織內所有 SA。
  2. 過濾 lastAuthenticatedTime 早於 90 天前 disabled == false 的 SA。
  3. 停用(先不要刪除)這些 SA。等待 30 天。若無任何故障,再刪除。

Service Account Insights 與 IAM Recommender

Recommender API 會浮現如下洞察:

  • google.iam.serviceAccount.UnusedServiceAccountInsight——逾 90 天未驗證的 SA。
  • google.iam.policy.Recommender——SA 上授予過多角色(如過去 90 天授予了 Editor 但實際只用到 storage.objectViewer 中的權限)。

Audit logs

每一次 SA token 鑄造都記錄於 Cloud Audit Logs / Data Access logsiamcredentials.googleapis.com 服務名稱下。將其匯入 BigQuery 或 Chronicle,並針對以下情境告警:(a) 來自非預期來源 IP 的 Token Creator 呼叫、(b) 深度超過兩跳的冒充鏈、(c) lifetime > 3600sgenerateAccessToken 呼叫。

PCA 考試遇到「資安團隊想識別未使用的服務帳戶」的情境時,正確答案幾乎總是 「使用 Cloud Asset Inventory 提供的 lastAuthenticatedTime 欄位與 IAM Recommender 的 UnusedServiceAccountInsight——而不是「寫一個自訂腳本解析 audit log」。平台已經把活做掉了。


服務帳戶命名慣例

在擁有數百個專案與數千個 SA 的組織中,命名不是裝飾——它是事件回應時主要的歸屬機制。良好的命名慣例會把 用途環境擁有者 編碼進 SA 的 local part(@ 之前的部分)。

建議模式

<workload>-<role>-<env>@<project-id>.iam.gserviceaccount.com

範例:

  • checkout-api-runtime-prod@retail-checkout-prod.iam.gserviceaccount.com
  • dataflow-etl-writer-dev@analytics-etl-dev.iam.gserviceaccount.com
  • gh-actions-deployer-stg@platform-cicd-stg.iam.gserviceaccount.com

為何此事在維運上重要

  • 事件回應: 當 audit log 顯示 checkout-api-runtime-prod 上發生 Token Creator 呼叫時,回應者立即知道該呼叫對應到哪個團隊、環境與工作負載。
  • IaC 一致性: Terraform 模組可從工作負載名稱與環境變數導出 SA email,消除「綁錯 SA」這類拼字錯誤造成的 bug。
  • 政策自動化: Org Policy 自訂條件約束可要求 SA displayName 符合 regex,封鎖隨時間累積的隨手命名帳戶(test-sa-1tempfoo 等)。

Display name 與 description

建立時務必設定 --display-name--description。兩個欄位皆被索引並會出現在 Cloud Console 搜尋列;幾個月後即便目的已被遺忘,displayName="Checkout API runtime - production" 的 SA 仍能被找回。


預設 Compute SA 對比自訂服務帳戶

每個 GCP 專案都會自動產生一個 Compute Engine 預設服務帳戶[email protected])與一個 App Engine 預設服務帳戶[email protected])。從歷史上看,兩者在專案建立時都會被授予 Editor 角色——這是個幾乎涵蓋專案內所有資源類型寫入權限的廣泛角色。任何未明確指定 --service-account 旗標啟動的 VM、Cloud Function 或 App Engine instance 都會繼承這個 Editor 等級的身份。

為何預設值很危險

  • 一台被入侵的 VM 即取得專案內的 Editor 權限——對 GCS、BigQuery、Pub/Sub、Compute 等皆有讀寫權限。
  • 從一台 VM 橫向移動到另一台變得簡單,因為它們共用同一個身份。
  • 事後移除 Editor 授權往往會默默地破壞工作負載(App Engine 部署 pipeline、legacy 備份腳本等)。

修復做法

  1. 強制執行 Org Policy iam.automaticIamGrantsForDefaultServiceAccounts,讓新專案跳過自動 Editor 授權。
  2. 針對既有專案,透過 Cloud Asset Inventory 稽核仍持有 roles/editor 的預設 SA,並以範圍緊縮的自訂 SA 取代。
  3. 針對每個新工作負載(VM、GKE node pool、Cloud Run service、Cloud Function),依上文命名慣例建立 自訂 SA 並明確附加。永遠不要倚賴預設值。

遷移食譜

  • 建立自訂 SA,只授予該工作負載實際會用到的角色(透過 Policy Analyzer 的「已使用權限」報告驗證)。
  • 更新工作負載的 Terraform/Deployment Manager 設定,指定 service_account.email
  • 重新部署。觀察 24 小時內的 audit log 是否出現 PERMISSION_DENIED 錯誤。逐一補上缺漏的權限——除非你已驗證預定義角色中每個權限都有需要,否則絕不直接授予預定義角色。
  • 穩定後從預設 SA 移除 Editor 授權。若沒有工作負載仍在使用預設 SA,則完全停用之。

考試三條快速記憶事實: (1) 預設 Compute SA 在未強制執行 automaticIamGrantsForDefaultServiceAccounts 時會取得 Editor。(2) GKE Workload Identity 需要叢集設定 --workload-pool 並且 node pool 設定 --workload-metadata=GKE_METADATA。(3) Workload Identity Federation 使用 sts.googleapis.com 的 STS 交換外部 IdP token;SA 綁定使用 principalSet:// 與角色 roles/iam.workloadIdentityUser


橫向移動防範 (Lateral Movement Prevention)

一個被入侵的服務帳戶很少是攻擊的終點——它通常是開始。攻擊者串接 iam.serviceAccounts.getAccessTokeniam.serviceAccounts.actAsiam.serviceAccounts.signBlob,從低價值 SA 樞紐至高價值 SA。架構師必須明確設計對此的防範。

需控制的樞紐點

  • Token Creator 圖譜: 盤點組織內每一個 roles/iam.serviceAccountTokenCreator 綁定。若 SA-A 在 SA-B 上有 Token Creator、SA-B 在 SA-C 上有 Token Creator,則 SA-A 可在兩跳內抵達 SA-C。打斷長鏈。
  • 跨環境 SA 上的 actAs 絕不在 prod SA 上將 Service Account User 授予 dev SA 或 dev 使用者。這是真實世界外洩報告中最常見的權限提升路徑。
  • 跨專案綁定: 一個 project-shared-tools 中的 SA 對 project-prod-data 持有 roles/owner 是巨大爆炸半徑。配合 VPC Service Controls 與 IAM Conditions 依請求上下文縮限。

防禦控制

  • IAM Conditions: 以來源 IP(request.auth.access_levels)、時間(request.time)或目標資源(resource.name.startsWith)限制 Token Creator 授權。
  • VPC Service Controls: 將高價值 SA 與其存取的資料置於 perimeter 內。即便攻擊者從 perimeter 外取得 SA 的 token,API 呼叫仍會以 VPC_SERVICE_CONTROLS_VIOLATION 失敗。
  • Policy Analyzer: 執行 gcloud asset analyze-iam-policy 詢問「哪些身份能 act as prod-database-admin@?」並狠狠地刪減答案集合。
  • 及時 (just-in-time) 提權: 接入 PAM 系統(或以 Cloud Functions + Cloud Scheduler 自建一套),僅在工單核可後 30 分鐘的窗口內授予敏感 SA 上的 Token Creator。

將服務帳戶附加到 Compute、Cloud Run 與 Cloud Functions

最後一個實務問題是:SA 實際 如何 抵達工作負載。每個運算介面都有自己的附加模型,每個模型也都有自己的陷阱。

Compute Engine (GCE)

  • 建立 instance 時指定 [email protected]--scopes=cloud-platform。位於 169.254.169.254 的 metadata server 會將 SA 的 access token 暴露給 VM 內的程序。
  • 陷阱: legacy --scopes 機制(如 --scopes=https://www.googleapis.com/auth/devstorage.read_only)會進一步限制 SA token 可做的事,但它 不是 可依賴的安全邊界。永遠透過 SA 上的 IAM 角色縮限範圍,並使用 --scopes=cloud-platform 將所有限制交給 IAM。
  • 呼叫者需在 SA 上具備 roles/iam.serviceAccountUser 才能附加。

Cloud Run(含 Cloud Run Jobs)

  • 於部署時透過 --service-account 指定。每個 revision 可使用不同 SA,便於進行身份的藍綠遷移。
  • Cloud Run runtime 透過相同的 metadata server 端點暴露 token,因此 SDK 自動探查(google.auth.default())可無縫運作。
  • 陷阱: 若未指定 SA,service 會使用 Compute 預設 SA——也就是上文討論過的危險 Editor 重裝預設值。請永遠明確指定。

Cloud Functions(1st 與 2nd gen)

  • 1st gen:部署時的 --service-account 旗標。Runtime SA 預設為 App Engine 預設 SA([email protected]),歷史上具有 Editor。
  • 2nd gen(基於 Cloud Run 的 Cloud Functions):模型同 Cloud Run。
  • 陷阱: Cloud Functions 還有一個 build-time SA(Cloud Build 用以打包函式)。請同時設定:--service-account(runtime)與 --build-service-account(build)。常見設定錯誤是只授予 runtime SA 對的角色,然後 build 因為令人困惑的 GCS 權限錯誤而失敗。

三者共通規則

部署主體需要在被附加的 SA 上具備 roles/iam.serviceAccountUser。沒有此角色,部署會回傳 PERMISSION_DENIED: Permission iam.serviceAccounts.actAs denied on service account ...。這是僅次於 GKE metadata server 議題的第二常見 PCA 考試陷阱。


常見問題 — 服務帳戶管理 (FAQ — Service Account Management)

Q1. 使用者 (User) 和服務帳戶 (Service Account) 有什麼區別?

使用者代表「人」(身份);服務帳戶代表「工作負載」(機器身份)。使用者透過密碼和 MFA 登入;服務帳戶則使用金鑰或附加的元數據。

Q2. 使用「Compute Engine 預設服務帳戶」安全嗎?

通常不安全。它預設被授予「編輯者 (Editor)」角色,這對於大多數生產工作負載來說範圍太廣了。請務必建立自訂服務帳戶。

Q3. 如何阻止洩露的金鑰被使用?

立即在 IAM 控制台中刪除該金鑰。如果整個服務帳戶都遭到破壞,請刪除該服務帳戶本身(儘管這可能會中斷你的應用程式)。

Q4. 什麼是「Workload Identity」?

這是 GKE 應用程式存取 Google Cloud 服務的推薦方式。它將 Kubernetes 服務帳戶 連結到 Google 服務帳戶,從而消除了管理 Secret 的需求。

Q5. 服務帳戶可以有自己的 IAM 策略嗎?

可以。你可以決定「誰」可以使用該服務帳戶。這被稱為服務帳戶的「資源層級 IAM 策略」。

官方資料來源

更多 PCA 主題