題幹與適用場景
一家公司在兩個雲和一個本地叢集執行多租戶微服務。每個環境由不同團隊管理,生產與預發布也必須隔離;支付服務需要呼叫報表服務,但不能把長期 API secret 或雲端廠商專屬角色散落到映像檔。請設計跨信任域的工作負載身分聯邦。
系統需要讓工作負載取得短期可驗證身分,並讓接收方只信任獲准的外部 trust domain、SPIFFE ID、audience 和業務動作。回答要涵蓋:SPIFFE ID 命名、SPIRE Server/Agent、節點與工作負載 attestation、X.509-SVID 或 JWT-SVID、foreign bundle 取得、授權映射、輪換、撤銷、快取、災備和從靜態憑證遷移。
本題有五條不變量:
- 身分來源必須能證明「哪個受控程序正在執行」,不能只證明某台機器有網路位址。
- 一個 trust domain 的 bundle 不能自動讓所有外部工作負載取得本地權限。
- SVID 過期或主體被撤銷後,接收方在聲明時限內停止接受。
- 私鑰在工作負載或受控 key manager 側生成,控制面不分發長期私鑰。
- 跨域聯邦只解決身分與信任材料交換,業務授權仍由資源服務執行。
面試官考察點
強回答會先畫出 trust domain、SPIFFE ID、SVID、SPIRE Server、Agent 和 Workload API 的邊界。SPIFFE 提供身分命名與可驗證文件規範;SPIRE 是執行節點和工作負載證明、簽發 SVID 的實作。身分不是權限,spiffe://prod.example/ns/payments/sa/worker 仍需要報表服務的 allow policy。
第二個訊號是聯邦模型。SPIFFE Federation 透過已配置且經 TLS 認證的 bundle endpoint 交換外部 trust domain 的公開信任材料;接收方必須預先知道 URL 代表哪個 domain,不能根據請求中的任意 domain 自動下載根。Workload API 可以返回 foreign bundles,驗證方按 SVID 的 trust domain 選擇對應 bundle。
第三個訊號是證明鏈。節點 attestation 證明 Agent 所在節點,workload attestation 再依據核心、kubelet、容器執行時等可信屬性匹配 registration selectors。只憑 namespace、標籤或客戶端自報身分不足以抵抗被盜的服務帳號。
最後要討論維運:聯邦 bundle 過期、根金鑰輪換、Agent 斷線、快取陳舊、控制面單點、跨雲時鐘偏差、舊服務無法載入 SVID,以及如何在不關閉驗證的情況下回滾。
回答前需要釐清的問題
- 哪些 trust domain 真的需要互信? 如果支付只呼叫報表,不應把三個域組成全互信網狀圖;先定義單向或最小互信邊。
- 使用 X.509-SVID 還是 JWT-SVID? mTLS 與連線級身分適合服務間長連線;跨雲 HTTP 或外部 OIDC 資源可能需要 JWT audience。兩者的驗證快取和洩露窗口不同。
- 誰管理外部 bundle endpoint? 同一公司可共享治理;跨公司則只能信任明確的公開材料、TLS 身分和審核後的 domain 映射。
- 撤銷目標是什麼? 例如 SVID 最長 15 分鐘、bundle 輪詢 60 秒、緊急撤銷要求五分鐘內阻斷新連線。
- 工作負載如何證明自己? Kubernetes ServiceAccount、雲端實例文件、TPM 或受控一次性 join token 的安全假設不同。
- 舊服務能否使用 SPIFFE? 若不能,是否由 sidecar 或 gateway 做受限轉換?轉換器本身的身分和權限必須單獨定義。
30 秒回答框架
「我會為每個環境建立獨立 trust domain,例如 production、staging 和 on-prem,給工作負載分配穩定且不含租戶秘密的 SPIFFE ID。每個域的 SPIRE Server 管理 registration entries,Agent 透過節點 attestation 啟動,再用本地程序屬性完成 workload attestation,工作負載透過 Workload API 取得短期 X.509-SVID 或 JWT-SVID。
支付域只配置報表域的 foreign bundle endpoint,並固定 domain、TLS 身分和允許的 trust-domain 映射。報表服務驗證簽章、SVID expiry、audience 和 peer bundle,再按完整 SPIFFE ID、環境、租戶上下文與動作執行授權。bundle 和 SVID 更新透過串流 API、短 TTL 與版本指標傳播;控制面不可用時保留有限的已驗證材料,但高風險新連線失敗關閉。遷移先雙軌執行舊憑證和 SVID,按服務灰度,確認稽核和撤銷目標後再刪除舊 secret。」
分步深入解答
第一步:劃分 trust domain 與身分命名
Trust domain 是身分命名空間和根信任邊界。生產、預發布、PCI 環境或不同管理組織應分別建立 domain,不要用一個全域根覆蓋所有風險。ID 可以採用:
spiffe://prod.example/ns/payments/sa/worker
spiffe://reports.partner/ns/analytics/sa/reader路徑應表達穩定的業務主體和治理範圍,不把 pod 名、IP 或短期部署雜湊當作長期授權主體。版本、租戶或區域等變化屬性可作為 attestation selector、策略輸入或 token claim;若把每次發布都編碼進 ID,輪換和授權維護會變成大規模遷移。
聯邦關係記錄為顯式邊:prod.example 可驗證 reports.partner 的 bundle,但只允許 audience reports-api 和方法 ReportRead。接收方不得因為兩個 domain 都使用 SPIFFE 就自動允許呼叫。
第二步:建立 Server、Agent 與 registration entries
SPIRE Server 保存 registration entries、簽發材料和節點授權關係;每個節點執行 Agent,Agent 暴露本地 Workload API。Server 只把某 Agent 有權管理的 registration entries 下發給它,減少單節點洩露的爆炸半徑。
註冊項應包含 SPIFFE ID、parent SPIFFE ID、selector 集合、允許的 SVID profile 和 audience。selector 要來自可信的編排器或節點屬性,例如 Kubernetes namespace、service account、容器映像摘要或雲端實例識別。不要只用使用者可修改的標籤,也不要把設定檔裡的任意字串當作 attestation 事實。
第三步:設計兩階段 attestation
節點啟動時,Agent 透過雲端實例文件、Kubernetes ServiceAccount、TPM 或一次性 join token 證明節點身分。Server 獨立驗證證明並簽發 Agent 身分。接著,工作負載透過本機 Unix domain socket 或受限端點呼叫 Workload API;Agent 透過程序 ID、核心、kubelet 或容器執行時取得 selector,與 registration entries 匹配後返回 SVID。
這個邊界解釋了為什麼 Workload API 可以沒有普通網路客戶端認證:Agent 必須透過 out-of-band 方式識別本地呼叫程序。socket 權限、namespace 隔離、宿主機核心與 kubelet 的信任假設必須納入威脅模型。若 Agent 無法確定呼叫者,不應發出預設高權限身分,而應返回 PermissionDenied。
第四步:選擇 SVID profile 與金鑰處理
X.509-SVID 適合 mTLS 和連線級服務身分;JWT-SVID 適合需要把 audience 帶入 HTTP 或外部 OIDC 交換的呼叫。JWT-SVID 的驗證方必須使用 subject trust domain 對應的 bundle,不得把任意 JWKS 當作同一根信任。
SVID 應短期有效並透過 Workload API 串流更新。私鑰由 workload 或 Agent 的 key manager 生成並留在受限記憶體或檔案描述符;Server 只簽發公鑰對應的憑證,不把長期私鑰寫入映像檔、環境變數或普通設定。多身分工作負載用 hint 或顯式選擇區分內部與外部 audience,避免預設身分被誤用。
第五步:安全建立跨域 bundle 聯邦
聯邦控制面先審核外部 domain、bundle endpoint、endpoint profile、TLS 憑證和允許的 SPIFFE ID 前綴。客戶端應預先知道 URL 代表的 trust domain;bundle endpoint 的 TLS 認證只證明傳輸端點,返回內容仍要按 domain、版本、簽章和有效期驗證。
取得 foreign bundle 後,把它放入版本化 trust store。驗證 peer 時根據 SVID 的 trust domain 選擇對應 bundle;沒有匹配 bundle 時拒絕。不要把 foreign bundle 作為本地簽發根,也不要因 endpoint 臨時重新導向就永久改變設定。輪詢、ETag、過期時間和最後成功版本都要可觀測。
第六步:把身分映射到資源授權
報表服務的 PEP 先驗證 mTLS peer 或 JWT-SVID,再把完整 SPIFFE ID、trust domain、audience、租戶和請求動作送給 PDP。允許策略示例:
allow if trust_domain == "prod.example"
and spiffe_id == "spiffe://prod.example/ns/payments/sa/worker"
and audience == "reports-api"
and action == "ReportRead"
and tenant == resource.tenant網路可達、SVID 有效和 domain 已聯邦都不等於業務允許。資源服務仍須檢查租戶歸屬、行級權限、審批與速率限制。若需要把 workload 身分換成雲端 IAM 或外部 OIDC,使用受限 broker,綁定 audience、scope、SVID TTL 和操作目的;不要把一張全能雲端角色憑證交給所有 workload。
第七步:輪換、撤銷與快取一致性
SVID 到期透過 Workload API 流更新,客戶端應原子替換憑證和金鑰,並讓新連線先使用新材料。trust bundle 輪換採用舊根與新根的有界重疊;只有所有驗證方載入新版本且舊 SVID/連線排空後才刪除舊根。緊急 compromise 不遵循正常重疊,應發布撤銷或 deny 版本並縮短接受窗口。
快取至少記錄 bundle version、issuer、trust domain、SVID expiry 與 policy version。聲明五分鐘撤銷目標,就必須讓連線建立、JWT 驗證和 sidecar 快取都在五分鐘內看到更新。長連線要按最大憑證年齡優雅 drain;只更新控制面資料庫而不處理現有連線不能算完成撤銷。
第八步:擴展、故障與遷移
SPIRE Server 的資源消耗會隨 registration entries 增長,單實例也是故障點。可以按區域或 trust domain 分片、使用多 Server HA、限制 Agent 看到的 entries,並監控簽發延遲、Agent 數、entry 數、Workload API 請求和 bundle lag。跨域聯邦應避免全網狀配置爆炸,優先透過受控邊界或 broker 連接。
控制面不可用時,已取得且未過期的 SVID 可支援低風險既有連線;不能無限期發放新身分。bundle 過期、Agent 無法證明節點、key manager 故障或域映射未知時,高風險新連線失敗關閉。遷移靜態 secret 時先雙寫認證、按服務池灰度、驗證稽核與撤銷,再刪除舊 secret;每一步都有回滾到仍受控的舊路徑,但不能回滾到關閉身分驗證。
高品質示範回答
「我會把 production、staging 和合作方拆成獨立 trust domain,用穩定的 SPIFFE ID 表示 workload。每個 domain 的 SPIRE Server 管 registration entries 和簽發根,Agent 先做節點證明,再透過本地 Workload API 依程序和編排器屬性完成 workload attestation。工作負載取得短期 X.509-SVID 做 mTLS,或按固定 audience 取得 JWT-SVID;私鑰只在 workload、Agent 或受控 key manager 一側。
支付域與報表域之間只配置一條經審核的 federation edge。客戶端預先綁定 endpoint 與 domain,驗證 TLS、bundle 版本和有效期;驗證 peer 時按 SVID 的 trust domain 選擇 foreign bundle,沒有匹配 bundle 就拒絕。報表服務先驗證 SVID、issuer、audience 和 expiry,再用完整 SPIFFE ID、租戶和動作做資源授權,聯邦本身不授予業務權限。
SVID 和 bundle 都透過串流更新、短 TTL、版本指標和有界舊材料支援輪換;長連線按憑證年齡 drain。控制面或證明失敗時不簽發未知身分,高風險呼叫失敗關閉。遷移舊 secret 採用雙軌、灰度、撤銷演練和稽核對帳,直到每個服務都能證明身分、授權和故障恢復邊界。」
常見錯誤
- 所有叢集共享一個 trust domain。 任何根或設定洩露都會擴大到全部環境;按管理與風險邊界拆分 domain。
- 把 SPIFFE ID 當成業務授權。 身分只回答「誰」,資源服務仍需檢查 audience、tenant、action 和資源歸屬。
- 只做節點 attestation。 同一節點上的惡意程序可能冒充服務;再用 workload selectors 識別呼叫程序。
- 用可變 pod 名或 IP 作為長期主體。 重建和漂移會破壞授權;使用穩定 ID,把版本屬性放入 selector 或策略。
- 把 federation endpoint 的 URL 當作信任根。 必須預配置 domain、驗證 TLS、bundle 內容、版本和有效期。
- foreign bundle 允許所有外部主體。 聯邦只提供驗證材料;策略要限定 ID 前綴、audience、動作與租戶。
- 把長期私鑰放進映像檔或環境變數。 映像、日誌和設定複製會洩露金鑰;在 workload 或 key manager 側生成並短期輪換。
- 無限期使用陳舊 bundle 或 SVID。 這會違背撤銷目標;記錄版本、TTL、連線年齡並在超時後拒絕。
- 控制面故障時預設放行。 未知身分不應取得新權限;按風險區分有限舊材料和失敗關閉。
- 只遷移 mTLS,不遷移稽核和授權。 加密通道不證明業務允許;記錄 peer ID、policy version、租戶與決策。
追問及應對
兩個 trust domain 需要雙向通信,是否必須互相導入 bundle?
不一定。若只有支付域呼叫報表域,可以建立單向驗證邊:報表信任支付的 foreign bundle,支付無需信任報表。只有報表也要發起呼叫時才添加反向邊,並分別配置 audience 與授權策略,避免把互信誤解為全權限。
為什麼不直接用雲端廠商的 workload identity?
雲端身分適合同一雲控制面,但多雲、本地和合作方會出現不同 issuer、SDK 與授權模型。SPIFFE 提供平台無關的命名、SVID 和 bundle 交換層;外部雲 IAM 仍可透過受限 OIDC federation broker 使用,不應把 SPIFFE 當成替代所有業務授權的萬能層。
Agent 的 Workload API 沒有普通客戶端認證安全嗎?
它依賴 out-of-band 程序識別,而不是把 socket 當作開放網路 API。必須限制 Unix socket 或 endpoint 權限、隔離宿主機和 namespace,並讓 Agent 根據核心、kubelet 或容器執行時返回的屬性匹配 registration entries。無法識別呼叫者就拒絕,不發預設高權限 SVID。
外部 bundle endpoint 暫時不可用怎麼辦?
保留帶版本和過期時間的最後可信 bundle。未過期且風險允許時可驗證既有連線;超過最大陳舊年齡或執行高風險新連線時失敗關閉。監控 bundle lag、最後成功版本和拒絕數,不能無限期接受舊根。
長連線如何處理 SVID 輪換和撤銷?
Workload API 串流提供新材料,客戶端原子更新並讓新連線先使用新憑證。連線按最大憑證年齡或撤銷窗口 drain;高風險操作在提交前再次檢查策略。僅替換磁碟檔案而不處理已建立連線,不能證明舊身分已失效。
如何證明 selector 沒有被攻擊者偽造?
selector 必須來自受信任的節點或編排器 API,並由 Server/Agent 驗證;使用者可修改的標籤只能作為非安全提示。結合映像摘要、service account、命名空間、程序屬性和節點證明,並對 registration 變更做審批和稽核。
遷移舊 API secret 時如何回滾?
先讓服務同時接受舊 secret 與 SVID,按服務池啟用 SVID 並記錄兩條路徑的成功率、授權和撤銷結果。故障時停止新發放、回到仍受控的舊 secret,修復後繼續灰度;舊 secret 的撤銷時間、清理證據和最終刪除必須有明確門檻,不能以關閉驗證作為回滾。