このページでは、Google Kubernetes Engine(GKE)Autopilot クラスタと Standard クラスタのセキュリティ構成に関連する問題を解決する方法について説明します。
さらにサポートが必要な場合は、Cloud カスタマーケアにお問い合わせください。RBAC と IAM
認証された IAM アカウントがクラスタ内アクションを実行できない
クラスタでアクションを実行しようとしたときに、GKE がアクションを認可する RBAC ポリシーを見つけられないと、次の問題が発生します。GKE は、同じ権限を付与する IAM 許可ポリシーを見つけようとします。失敗した場合、次のようなエラー メッセージが表示されます。
Error from server (Forbidden): roles.rbac.authorization.k8s.io is forbidden:
User "example-account@example-project.iam.gserviceaccount.com" 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
Namespace 内の roles
オブジェクトに対する list
権限を持つロールを付与します。手順については、ロールベース アクセス制御を使用してクラスタ内のアクションを認可するをご覧ください。
GKE 用 Workload Identity 連携
Pod が Google Cloud で認証されない
アプリケーションが Google Cloud で認証されない場合は、次の設定が正しく構成されていることを確認してください。
GKE クラスタを含むプロジェクトで IAM Service Account Credentials API が有効になっていることを確認します。
Workload Identity プールが設定されていることを確認して、クラスタで GKE 用 Workload Identity 連携が有効になっていることを確認します。
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 クラスタの Namespace に置き換えます。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
クラスタ ネットワーク ポリシーを使用している場合は、バージョン 1.21.0-gke.1000 より前の GKE を実行しているクラスタのポート
988
で、127.0.0.1/32
への下り(外向き)が許可されていることを確認します。また、GKE バージョン 1.21.0-gke.1000 以降を実行しているクラスタのポート988
で、169.254.169.252/32
への下り(外向き)が許可されていることを確認します。GKE Dataplane V2 を実行しているクラスタでは、ポート80
で169.254.169.254/32
への下り(外向き)を許可する必要があります。kubectl describe networkpolicy NETWORK_POLICY_NAME
NETWORK_POLICY_NAME
は、GKE ネットワーク ポリシーの名前に置き換えます。
IAM サービス アカウントのアクセスが拒否される
IAM ロール バインディングを追加した直後に、GKE 用 Workload Identity 連携を使用して Pod がリソースにアクセスできない場合があります。アクセス障害は、IAM 許可ポリシー、ロール バインディング、Kubernetes Pod などのリソースが一緒に作成されるデプロイ パイプラインや宣言型の Google Cloud 構成で発生する可能性が高くなります。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 のアクセス権の変更の伝播が原因で発生することがあります。つまり、ロールの付与などのアクセス権の変更がシステム全体に伝播されるまでに時間がかかるということです。ロールの付与の場合、通常は反映に 2 分ほどかかりますが、7 分以上かかることもあります。詳細については、アクセス権の変更の伝播をご覧ください。
このエラーを解決するには、Pod が作成された後に Google Cloud リソースにアクセスする前に遅延を追加することを検討してください。
DNS 解決に関する問題
一部の Google Cloud クライアント ライブラリは、DNS 名 metadata.google.internal
を解決することで GKE と Compute Engine のメタデータ サーバーに接続するように構成されています。これらのライブラリの場合、Google Cloud サービスに対するワークロードの認証には、正常なクラスタ内の DNS 解決が重要な依存関係となります。
この問題を検出する方法は、デプロイしたアプリケーションの詳細(ロギング構成など)によって異なります。次のようなエラー メッセージがないか確認します。
- GOOGLE_APPLICATION_CREDENTIALS の構成を求めるエラー メッセージ、または
- Google Cloud サービスへのリクエストが、認証情報がリクエストになかったために拒否されたことを示すエラー メッセージ。
metadata.google.internal
の DNS 解決で問題が発生した場合は、環境変数 GCE_METADATA_HOST
を 169.254.169.254
に設定することで、一部の Google Cloud クライアント ライブラリで DNS 解決をスキップするように指示できます。
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 でリクエストの受信を開始できるようになるまでに数秒かかります。Pod が有効になってから最初の数秒間に GKE 用 Workload Identity 連携を使用して認証を試みると、タイムアウトが短いアプリケーションと Google Cloud クライアント ライブラリで認証に失敗する可能性があります。
タイムアウト エラーが発生した場合は、次のことを試してください。
- ワークロードが使用する Google Cloud クライアント ライブラリを更新します。
- 数秒待ってから再試行するようにアプリケーション コードを変更します。
Pod のメインコンテナを実行する前に、GKE メタデータ サーバーの準備が完了するまで待機する initContainer をデプロイします。
たとえば、次のマニフェストは
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 用 Workload Identity 連携が失敗する
クラスタ コントロール プレーンが利用できない場合、メタデータ サーバーは GKE 用 Workload Identity 連携を返すことができません。メタデータ サーバーを呼び出すと、ステータス コード 500 が返されます。
ログ エクスプローラに、次のようなログエントリが表示されます。
dial tcp 35.232.136.58:443: connect: connection refused
この動作により、GKE 用 Workload Identity 連携が使用できなくなります。
IP のローテーション、コントロール プレーン VM のアップグレード、クラスタまたはノードプールのサイズ変更などのクラスタ メンテナンス時に、ゾーンクラスタでコントロール プレーンが使用できない場合があります。コントロール プレーンの可用性については、リージョンまたはゾーンのコントロール プレーンの選択をご覧ください。リージョン クラスタに切り替えると、この問題は解消されます。
Istio を使用するクラスタで GKE 用 Workload Identity 連携の認証が失敗する
アプリケーションの起動時にエンドポイントとの通信を試みると、次のようなエラーが表示されることがあります。
Connection refused (169.254.169.254:80)
Connection timeout
これらのエラーは、istio-proxy
コンテナの準備が整う前にアプリケーションがネットワーク接続を試行した場合に発生することがあります。デフォルトでは、Istio と Cloud Service Mesh は、トラフィックをインターセプトしてリダイレクトするサービス メッシュ プロキシ ワークロードが実行されているかどうかに関係なく、ワークロードが起動するとすぐにリクエストを送信できるようにします。GKE 用 Workload Identity 連携を使用する Pod の場合、プロキシの起動前に発生するこれらの初期リクエストは、GKE メタデータ サーバーに到達しない可能性があります。その結果、Google Cloud APIs への認証が失敗します。リクエストを再試行するようにアプリケーションを構成しない場合、ワークロードが失敗する可能性があります。
この問題がエラーの原因であることを確認するには、ログを表示して、istio-proxy
コンテナが正常に起動されたかどうかを確認します。
Google Cloud コンソールで、[ログ エクスプローラ] ページに移動します。
クエリペインに次のクエリを入力します。
(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
この問題を解決し、再発しないようにするには、次のワークロードごとの構成オプションのいずれかをお試しください。
プロキシ ワークロードの準備が整うまで、アプリケーションがリクエストを送信しないようにします。Pod 仕様の
metadata.annotations
フィールドに次のアノテーションを追加します。proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
GKE メタデータ サーバーの IP アドレスをリダイレクトから除外するように Istio または Cloud Service Mesh を構成します。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 アドレス範囲を追加します。プロキシが起動するまでアプリケーションがリクエストを送信しないようにする: 値が
true
のglobal.proxy.holdApplicationUntilProxyStarts
グローバル構成オプションを Istio 構成に追加します。
gke-metadata-server
Pod がクラッシュしている
gke-metadata-server
システム DaemonSet Pod により、ノードで GKE 用 Workload Identity 連携を利用できるようになります。Pod は、クラスタ内の Kubernetes サービス アカウントの数に比例してメモリリソースを使用します。
gke-metadata-server
Pod のリソース使用量が上限を超えると、次の問題が発生します。kubelet がメモリ不足エラーで Pod を強制排除します。クラスタに 3,000 を超える Kubernetes サービス アカウントがある場合、この問題が発生することがあります。
問題を特定する方法は次のとおりです。
kube-system
Namespace でクラッシュしている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 未満に減らします。
DeployPatch 失敗のエラー メッセージが表示され、GKE 用 Workload Identity 連携を有効にできない
GKE は、Google Cloud が管理する Kubernetes Engine サービス エージェントを使用して、クラスタ内の GKE 用 Workload Identity 連携が機能できるようにします。Google Kubernetes Engine API を有効にすると、Google Cloud がプロジェクトに対する Kubernetes Engine サービス エージェントのロール(roles/container.serviceAgent
)を、このサービス エージェントに自動的に付与します。
サービス エージェントに Kubernetes Engine サービス エージェントのロールがないプロジェクトのクラスタで GKE 用 Workload Identity 連携を有効にしようとすると、次のようなエラー メッセージが表示され、オペレーションが失敗します。
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
は、実際の Google Cloud プロジェクト ID に置き換えます。サービス エージェントが正しく構成されている場合、出力にはサービス エージェントの完全な ID が表示されます。
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 プロジェクトの番号に置き換えます。GKE 用 Workload Identity 連携をもう一度有効にしてみます。