本頁說明如何解決 Google Kubernetes Engine (GKE) Autopilot 和 Standard 叢集中的安全性設定相關問題。
RBAC 和 IAM
通過驗證的 IAM 帳戶無法執行叢集內動作
當您嘗試在叢集中執行動作,但 GKE 找不到授權該動作的 RBAC 政策時,就會發生下列問題。GKE 會嘗試尋找授予相同權限的 IAM 允許政策。如果失敗,您會看到類似以下的錯誤訊息:
Error from server (Forbidden): roles.rbac.authorization.k8s.io is forbidden:
User "[email protected]" cannot list resource "roles" in
API group "rbac.authorization.k8s.io" in the namespace "kube-system": requires
one of ["container.roles.list"] permission(s).
如要解決這個問題,請使用 RBAC 政策授予嘗試執行的動作權限。舉例來說,如要解決先前範例中的問題,請在 kube-system
命名空間中,將具有 list
權限的角色授予 roles
物件。如需操作說明,請參閱使用角色型存取權控管授權叢集中的動作。
Workload Identity Federation for GKE
Pod 無法向 Google Cloud驗證
如果應用程式無法向 Google Cloud進行驗證,請確認下列設定是否正確:
確認您已在包含 GKE 叢集的專案中啟用 IAM 服務帳戶憑證 API。
確認叢集已啟用 GKE 適用的工作負載身分聯盟,方法是驗證叢集是否已設定工作負載身分集區:
gcloud container clusters describe CLUSTER_NAME \ --format="value(workloadIdentityConfig.workloadPool)"
將
CLUSTER_NAME
替換為 GKE 叢集的名稱。如果您尚未指定
gcloud
的預設區域或地區,執行這項指令時,可能也需要指定--region
或--zone
旗標。請確認應用程式執行的節點集區已設定 GKE 中繼資料伺服器:
gcloud container node-pools describe NODEPOOL_NAME \ --cluster=CLUSTER_NAME \ --format="value(config.workloadMetadataConfig.mode)"
更改下列內容:
- 將
NODEPOOL_NAME
替換為節點集區的名稱。 CLUSTER_NAME
改成 GKE 叢集名稱。
- 將
確認 Kubernetes 服務帳戶是否已正確註解:
kubectl describe serviceaccount \ --namespace NAMESPACE KSA_NAME
更改下列內容:
NAMESPACE
,並換成 GKE 叢集的命名空間。KSA
改為 Kubernetes 服務帳戶的名稱。
預期輸出內容應包含類似下列的註解:
iam.gke.io/gcp-service-account: GSA_NAME@PROJECT_ID.iam.gserviceaccount.com
確認 IAM 服務帳戶設定正確無誤:
gcloud iam service-accounts get-iam-policy \ GSA_NAME@GSA_PROJECT.iam.gserviceaccount.com
預期輸出內容應包含類似下列內容的繫結:
- members: - serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME] role: roles/iam.workloadIdentityUser
如果您有叢集網路政策,則必須允許叢集在
988
連接埠上輸出至127.0.0.1/32
(適用於執行 GKE 1.21.0-gke.1000 之前的版本),或在988
連接埠上輸出至169.254.169.252/32
(適用於執行 GKE 1.21.0-gke.1000 以上版本的叢集)。對於執行 GKE Dataplane V2 的叢集,您必須允許通訊埠80
上的169.254.169.254/32
輸出流量。kubectl describe networkpolicy NETWORK_POLICY_NAME
將
NETWORK_POLICY_NAME
替換為 GKE 網路政策的名稱。
存取 IAM 服務帳戶遭拒
新增 IAM 角色繫結後,Pod 可能無法立即透過 Workload Identity Federation for GKE 存取資源。在部署管道或宣告式 Google Cloud 設定中,如果同時建立 IAM 允許政策、角色繫結和 Kubernetes Pod 等資源,就更有可能發生存取失敗的情況。Pod 記錄檔中會顯示下列錯誤訊息:
HTTP/403: generic::permission_denied: loading: GenerateAccessToken("SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com", ""): googleapi: Error 403: Permission 'iam.serviceAccounts.getAccessToken' denied on resource (or it may not exist).
這個錯誤可能是因為 IAM 存取權變更傳播所致,也就是說,角色授予等存取權變更需要一段時間才能傳播至整個系統。角色授予作業通常約需兩分鐘才能完成,但有時可能需要七分鐘以上。詳情請參閱「存取權變更傳播」。
如要解決這個錯誤,請考慮在 Pod 嘗試存取 Google Cloud 資源之前新增延遲時間。
DNS 解析問題
本節說明如何找出並解決 Pod 至 Google Cloud API 的連線錯誤,這類錯誤是由 DNS 解析問題所導致。如果本節的步驟無法解決連線錯誤,請參閱「Pod 啟動時發生逾時錯誤」一節。
部分 Google Cloud 用戶端程式庫會解析 DNS 名稱 metadata.google.internal
,藉此連線至 GKE 和 Compute Engine 中繼資料伺服器。對於這些程式庫,叢集內 DNS 解析的健康狀態是工作負載向Google Cloud 服務驗證身分的重要依附元件。
偵測這個問題的方式取決於已部署應用程式的詳細資料,包括記錄設定。尋找錯誤訊息,確認是否需要設定 GOOGLE_APPLICATION_CREDENTIALS
、要求遭拒 (因為要求沒有憑證),或是找不到中繼資料伺服器。Google Cloud
舉例來說,下列錯誤訊息可能表示 DNS 解析發生問題:
ComputeEngineCredentials cannot find the metadata server. This is likely because code is not running on Google Compute Engine
如果 metadata.google.internal
的 DNS 解析發生問題,可以指示部分 Google Cloud 用戶端程式庫略過 DNS 解析,方法是將環境變數 GCE_METADATA_HOST
設為 169.254.169.254
:
apiVersion: v1
kind: Pod
metadata:
name: example-pod
namespace: default
spec:
containers:
- image: debian
name: main
command: ["sleep", "infinity"]
env:
- name: GCE_METADATA_HOST
value: "169.254.169.254"
這是中繼資料服務在 Google Cloud 運算平台一律可用的硬式編碼 IP 位址。
系統支援下列 Google Cloud 程式庫:
Pod 啟動時發生逾時錯誤
GKE 中繼資料伺服器需要幾秒鐘,才能開始接受新 Pod 的要求。如果應用程式和 Google Cloud 用戶端程式庫設定的逾時時間較短,在 Pod 生命週期的前幾秒內,嘗試使用 GKE 的 Workload Identity Federation 進行驗證可能會失敗。
如果發生逾時錯誤,請嘗試下列做法:
- 更新工作負載使用的 Google Cloud 用戶端程式庫。
- 變更應用程式程式碼,等待幾秒後再重試。
部署 initContainer,等待 GKE 中繼資料伺服器準備就緒,再執行 Pod 的主要容器。
舉例來說,以下資訊清單適用於含有
initContainer
的 Pod:apiVersion: v1 kind: Pod metadata: name: pod-with-initcontainer spec: serviceAccountName: KSA_NAME initContainers: - image: gcr.io/google.com/cloudsdktool/cloud-sdk:alpine name: workload-identity-initcontainer command: - '/bin/bash' - '-c' - | curl -sS -H 'Metadata-Flavor: Google' 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token' --retry 30 --retry-connrefused --retry-max-time 60 --connect-timeout 3 --fail --retry-all-errors > /dev/null && exit 0 || echo 'Retry limit exceeded. Failed to wait for metadata server to be available. Check if the gke-metadata-server Pod in the kube-system namespace is healthy.' >&2; exit 1 containers: - image: gcr.io/your-project/your-image name: your-main-application-container
控制層無法使用,導致 GKE 的工作負載身分聯盟失敗
叢集控制層無法使用時,中繼資料伺服器無法傳回 GKE 適用的 Workload Identity Federation。對中繼資料伺服器的呼叫會傳回狀態碼 500。
記錄檔探索工具中可能會顯示類似下列內容的記錄項目:
dial tcp 35.232.136.58:443: connect: connection refused
這項行為會導致 GKE 無法使用工作負載身分聯盟。
在區域叢集中,控制層在叢集維護期間可能會無法使用,這些維護工作包括輪替 IP、升級控制層 VM 或調整叢集或節點集區大小等情況。如要瞭解控制層的可用性,請參閱「選擇地區或區域控制層」。切換至區域叢集即可解決這個問題。
在叢集中使用 Istio 時,GKE 的 Workload Identity Federation 驗證失敗
應用程式啟動並嘗試與端點通訊時,您可能會看到類似下列的錯誤:
Connection refused (169.254.169.254:80)
Connection timeout
如果應用程式在 istio-proxy
容器準備就緒前嘗試建立網路連線,就可能發生這些錯誤。根據預設,Istio 和 Cloud Service Mesh 允許工作負載在啟動後立即傳送要求,無論攔截及重新導向流量的服務網格 Proxy 工作負載是否正在執行,對於使用 GKE 適用的工作負載身分聯盟的 Pod,這些在 Proxy 啟動前發生的初始要求可能無法送達 GKE 中繼資料伺服器。因此,API 驗證會失敗。
Google Cloud 如果未將應用程式設為重試要求,工作負載可能會失敗。
如要確認這個問題是否為錯誤原因,請查看記錄並檢查 istio-proxy
容器是否已順利啟動:
前往 Google Cloud 控制台的「Logs Explorer」頁面。
在查詢窗格中,輸入下列查詢:
(resource.type="k8s_container" resource.labels.pod_name="POD_NAME" textPayload:"Envoy proxy is ready" OR textPayload:"ERROR_MESSAGE") OR (resource.type="k8s_pod" logName:"events" jsonPayload.involvedObject.name="POD_NAME")
更改下列內容:
POD_NAME
:受影響工作負載的 Pod 名稱。ERROR_MESSAGE
:應用程式收到的錯誤 (connection timeout
或connection refused
)。
點選「執行查詢」
查看輸出內容,並檢查
istio-proxy
容器何時準備就緒。在以下範例中,應用程式嘗試發出 gRPC 呼叫。不過,由於
istio-proxy
容器仍在初始化,應用程式收到Connection refused
錯誤。Envoy proxy is ready
訊息旁邊的時間戳記表示istio-proxy
容器何時準備好處理連線要求:2024-11-11T18:37:03Z started container istio-init 2024-11-11T18:37:12Z started container gcs-fetch 2024-11-11T18:37:42Z Initializing environment 2024-11-11T18:37:55Z Started container istio-proxy 2024-11-11T18:38:06Z StatusCode="Unavailable", Detail="Error starting gRPC call. HttpRequestException: Connection refused (169.254.169.254:80) 2024-11-11T18:38:13Z Envoy proxy is ready
如要解決這個問題並避免再次發生,請嘗試下列任一工作負載設定選項:
在 Proxy 工作負載準備就緒前,請勿讓應用程式傳送要求。在 Pod 規格的
metadata.annotations
欄位中新增下列註解:proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
設定 Istio 或 Cloud Service Mesh,將 GKE 中繼資料伺服器的 IP 位址排除在重新導向範圍之外。在 Pod 規格的
metadata.annotations
欄位中新增下列註解:traffic.sidecar.istio.io/excludeOutboundIPRanges: 169.254.169.254/32
在開放原始碼 Istio 中,您可以選擇設定下列任一全域設定選項,為所有 Pod 減輕這個問題:
從重新導向中排除 GKE 中繼資料伺服器 IP 位址: 更新
global.proxy.excludeIPRanges
全域設定選項, 新增169.254.169.254/32
IP 位址範圍。防止應用程式傳送要求,直到 Proxy 啟動為止: 在 Istio 設定中加入
global.proxy.holdApplicationUntilProxyStarts
全域設定選項,值為true
。
gke-metadata-server
Pod 當機
gke-metadata-server
系統 DaemonSet Pod 可在節點上啟用 GKE 適用的工作負載身分聯盟。Pod 使用的記憶體資源與叢集中的 Kubernetes 服務帳戶數量成正比。
當 gke-metadata-server
Pod 的資源用量超出限制時,就會發生下列問題。Kubelet 會撤銷發生記憶體不足錯誤的 Pod。
如果叢集有超過 3,000 個 Kubernetes 服務帳戶,就可能發生這個問題。
如要找出問題,請按照下列步驟操作:
在
kube-system
命名空間中找出當機的gke-metadata-server
Pod:kubectl get pods -n=kube-system | grep CrashLoopBackOff
輸出結果會與下列內容相似:
NAMESPACE NAME READY STATUS RESTARTS AGE kube-system gke-metadata-server-8sm2l 0/1 CrashLoopBackOff 194 16h kube-system gke-metadata-server-hfs6l 0/1 CrashLoopBackOff 1369 111d kube-system gke-metadata-server-hvtzn 0/1 CrashLoopBackOff 669 111d kube-system gke-metadata-server-swhbb 0/1 CrashLoopBackOff 30 136m kube-system gke-metadata-server-x4bl4 0/1 CrashLoopBackOff 7 15m
說明當機的 Pod,確認原因是記憶體不足而遭驅逐:
kubectl describe pod POD_NAME --namespace=kube-system | grep OOMKilled
將
POD_NAME
替換為要檢查的 Pod 名稱。
如要還原 GKE 中繼資料伺服器的功能,請將叢集中的服務帳戶數量減少至 3,000 個以下。
啟用 GKE 適用的工作負載身分聯盟時,系統顯示「DeployPatch failed」錯誤訊息
GKE 會使用 Google Cloud代管的
Kubernetes Engine 服務代理程式
,在叢集中啟用 Workload Identity Federation for GKE。啟用 Google Kubernetes Engine API 時,系統會自動將 Kubernetes Engine 服務代理程式角色 (roles/container.serviceAgent
) 授予這個服務代理程式。 Google Cloud
如果您嘗試在專案的叢集上啟用 GKE 的工作負載身分聯合,但服務代理程式沒有 Kubernetes Engine 服務代理程式角色,作業就會失敗,並顯示類似以下的錯誤訊息:
Error waiting for updating GKE cluster workload identity config: DeployPatch failed
如要解決這個問題,請嘗試下列步驟:
檢查專案中是否有服務代理程式,以及設定是否正確:
gcloud projects get-iam-policy PROJECT_ID \ --flatten=bindings \ --filter=bindings.role=roles/container.serviceAgent \ --format="value[delimiter='\\n'](bindings.members)"
將
PROJECT_ID
替換為專案 ID。 Google Cloud如果服務代理程式設定正確,輸出內容會顯示服務代理程式的完整身分:
serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
如果輸出內容未顯示服務代理程式,您必須授予 Kubernetes Engine 服務代理程式角色。如要授予這個角色,請完成下列步驟。
取得 Google Cloud 專案編號:
gcloud projects describe PROJECT_ID \ --format="value(projectNumber)"
輸出結果會與下列內容相似:
123456789012
將角色授予服務代理:
gcloud projects add-iam-policy-binding PROJECT_ID \ --member=serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com \ --role=roles/container.serviceAgent \ --condition=None
將
PROJECT_NUMBER
替換為專案編號。 Google Cloud再次嘗試啟用 Workload Identity Federation for GKE。
後續步驟
如果無法在說明文件中找到問題的解決方法,請參閱「取得支援」一文,尋求進一步的協助, 包括下列主題的建議:
- 與 Cloud 客戶服務聯絡,建立支援案件。
- 在 StackOverflow 上提問,並使用
google-kubernetes-engine
標記搜尋類似問題,向社群尋求支援。你也可以加入#kubernetes-engine
Slack 頻道,取得更多社群支援。 - 使用公開問題追蹤工具回報錯誤或提出功能要求。