13
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【本気で学ぶKubernetes】Workload Identity入門 - PodからGoogle Cloudリソースに安全にアクセスする

Last updated at Posted at 2025-12-23

はじめに

こんにちは!

本記事は「本気で学ぶKubernetes」シリーズの第22回です。このシリーズでは、Kubernetesの基礎から実践まで、段階的に学んでいきます。

このシリーズは、第1回から順に読むことで体系的に学べる構成にしています。
まだご覧になっていない方は、ぜひ最初からご覧ください!

Kubernetesとは?クラスタ構成の全体像をつかむ

今回はGoogle Cloud環境におけるGKEのIAMロールベースのアクセス管理について焦点を当てていきたいと思います。

この記事は人間がKubernetesの公式ドキュメントを読み漁りながら書いていますのでご安心ください!

TL;DR

忙しい方のために要点だけ図示しておきます!

gke-day22-tldr.png

GKEからGoogle Cloudリソースへのアクセス管理

GKEでアプリケーションを動かしていると、PodからCloud StorageやCloud SQL、BigQueryなどのGoogle Cloudリソースにアクセスしたい場面がよくあります。

例えば以下のような処理をイメージしてみてください。

  • 画像処理アプリがCloud Storageに画像をアップロードする
  • バッチ処理でGigQueryにデータを投入する
  • WebアプリがCloud SQLに接続してデータを読み書きする

こうした場合に重要になってくるのが、どのように認証情報を管理するかという点になります。

特にGoogle CloudではIAMでアクセス可能なリソースを制限しています。
GKEにおけるアクセス管理の方法は、大きく分けて4つあります。

  • ノードのサービスアカウントを使う
  • JSONサービスアカウントキーを使う
  • Workload Identityを使う
  • Workload Identity Federationを使う

ノードのサービスアカウントを使う

gke-day22-1.png

GKEクラスタを作成すると、各ノードにサービスアカウントを割り当てられます。
Pod内のアプリケーションはこのノードに割り当てられたサービスアカウントを使ってGoogle Cloud APIを利用することができます。

クラスタ作成時に--service-accountオプションでカスタムのサービスアカウントを作成して、必要最小限の権限だけ付与するのが一般的な運用です。

ただし、ノード単位でしか権限を分けられないという制約があるため、先ほど処理イメージであげましたが、同じノード上で「Cloud Storageにアクセスするアプリ」と「BigQueryにアクセスするアプリ」を動作させる場合は同じサービスアカウントを使うことになります。
そのため両方のアプリがCloud StorageとBigQueryの両方にアクセスできてしまうという状態が発生してしまいます。

Pod単位で細かく権限を制御したいといった場合では不向きだということがわかります。

JSONサービスアカウントキーを使う

gke-day22-2.png

次に考えられるのが、Google Service AccountのJSONキーファイルを使う方法です。

# Google Service Accountのキーを作成
gcloud iam service-accounts keys create key.json \
  --iam-account=my-service-account@PROJECT_ID.iam.gserviceaccount.com

# SecretとしてKubernetesに登録
kubectl create secret generic gcs-key --from-file=key.json=key.json

この方法であれば、Pod毎に異なるサービスアカウントを使い分けることができるため、ノードでサービスアカウントを割り当てるよりも細かくアクセス制御を行えます。

ただしJSONキーファイルでの運用は、間違ってコミットして認証情報の漏洩に繋がったり、キーローテーションなど運用が面倒になりがちなので基本的には推奨されまれん

Workload Identity

gke-day22-3.png

3つ目のアプローチとして紹介するのがWorkload Identityです。

Workload Identityは、Kubernetes Service Account(KSA)とGoogle Service Account(GSA)を紐付けることで、キーファイル不要でPodからGoogle Cloud APIに安全にアクセスできるようになる仕組みです。

Pod内のアプリケーションからGoogle Cloud APIを呼び出すと、GKE Metadata Serverが認証を行います。

権限もPod単位で細かく制御できますし、Cloud Audit LogsなどでPodレベルでのログ追跡も可能になります。

ただしGSAを作成してKSAと紐付ける必要がありますので、設定がやや複雑になりがちかと思います。

Workload Identity Federation(推奨)

gke-day22-4.png

最後にWorkload Identity Federationです。

この方式はKSAをIAMのプリンシパルとして直接扱って直接IAMロールを付与するというものです。

先ほどあげた3つ目のWorkload Identityと比べると、Google Service Accountを作成・管理する必要がなかったり、 SAに直接IAMロールを付与するだけでアクセス管理が可能といったメリットがあります。

本番環境ではセキュリティと運用の両面からこのWorkload Identity Federationの方式を使うことが強く推奨されます。

GKE AutopilotクラスタでWorkload Identityを使う

ここからは実際にWorkload Identity対応のGKEクラスタを作成していきます。
なおAutopilotではWorkload Identityがデフォルトで有効化されているため、クラスタ作成後すぐに使い始められます。

クラスタの作成

GKE APIを有効化されていない方は以下のコマンドで有効化してください。

gcloud services enable container.googleapis.com

# Operation "operations/..." finished successfully.

Autopilotモードでクラスタを作成します。

# Autopilotクラスタを作成
gcloud container clusters create-auto wi-cluster \
  --region=asia-northeast1

# Creating cluster wi-cluster in asia-northeast1... Cluster is being health-checked (Kubernetes Control Plane is healthy)...done.
# Created [https://container.googleapis.com/v1/projects/<project>/zones/asia-northeast1/clusters/wi-cluster].
# To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/asia-northeast1/wi-cluster?project=<project>

kubeconfigの認証情報を取得します。

# kubeconfigを取得
gcloud container clusters get-credentials wi-cluster \
  --region=asia-northeast1

# Fetching cluster endpoint and auth data.
# kubeconfig entry generated for wi-cluster.

クラスタが作成されていることを確認します。

kubectl cluster-info

# Kubernetes control plane is running at https://xxx.xxx.xxx.xxx
# GLBCDefaultBackend is running at https://xxx.xxx.xxx.xxx/api/v1/namespaces/kube-system/services/default-http-backend:http/proxy
# KubeDNS is running at https://xxx.xxx.xxx.xxx/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
# Metrics-server is running at https://xxx.xxx.xxx.xxx/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy

Autopilotクラスタの作成には数分かかります。
完了するとWorkload Identityが自動的に有効化された状態でクラスタが利用可能になります。

AutopilotのクラスタではWorkload Identityがデフォルトで有効化されています。
Standardクラスタの場合はクラスタ作成時に--workload-pool=PROJECT_ID.svc.id.googフラグを指定して明示的に有効化する必要があります。

Cloud Storageバケットの作成

テスト用のCloud Storageバケットを作成します。この時点ではまだ権限は付与しません。

プロジェクトIDとプロジェクト番号の設定

以降のコマンドで使用するプロジェクトIDとプロジェクト番号を環境変数に設定します。

# プロジェクトIDを環境変数に設定
export PROJECT_ID=$(gcloud config get-value project)
echo "プロジェクトID: $PROJECT_ID"

# プロジェクトID: my-project

# プロジェクト番号を取得
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
echo "プロジェクト番号: $PROJECT_NUMBER"

# プロジェクト番号: 123456789012

これで、以降のコマンドで$PROJECT_ID$PROJECT_NUMBERを使えるようになります。

バケットの作成

# バケットを作成
gsutil mb gs://$PROJECT_ID-workload-identity-demo

# Creating gs://my-project-workload-identity-demo/...

# Uniform Bucket Level Accessを有効化(Workload Identity Federationで必須)
gsutil uniformbucketlevelaccess set on gs://$PROJECT_ID-workload-identity-demo

# Enabling uniform bucket-level access for gs://my-project-workload-identity-demo/...

Workload Identity Federationのプリンシパルを使ってバケットにアクセスする場合、Uniform Bucket Level Access(均一なバケットレベルアクセス)を有効にする必要があるようです。

権限なしでアクセスを試してみる

Workload Identityの効果を実感するために、まずは権限設定なしでCloud Storageにアクセスしてみます。

namespaceとKSAの作成

Kubernetes側のリソース作成を行なっていきます。

# namespaceを作成
kubectl create namespace wi-demo

# namespace/wi-demo created
# KSAを作成
kubectl create serviceaccount gcs-access-ksa -n wi-demo

# serviceaccount/gcs-access-ksa created

Podマニフェストの作成

公式のgoogle/cloud-sdk:slimイメージを使って、Cloud Storageへのアクセスを試してみます。

gcs-test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: gcs-test
  namespace: wi-demo
spec:
  serviceAccountName: gcs-access-ksa  # KSAを指定(まだIAMロールは付与されていない)
  containers:
  - name: cloud-sdk
    image: google/cloud-sdk:slim
    command:
    - /bin/bash
    - -c
    - |
      echo "=== Workload Identity Test ==="
      echo "Uploading file to GCS..."
      echo "Hello from Workload Identity!" > /tmp/test.txt
      gsutil cp /tmp/test.txt gs://$PROJECT_ID-workload-identity-demo/test.txt
      echo ""
      echo "File uploaded successfully!"
      echo ""
      echo "Downloading file from GCS..."
      gsutil cat gs://$PROJECT_ID-workload-identity-demo/test.txt
      echo ""
      echo ""
      echo "Listing files in bucket..."
      gsutil ls gs://$PROJECT_ID-workload-identity-demo/
      echo ""
      echo "=== Test completed successfully! ==="
    env:
    - name: CLOUDSDK_CORE_PROJECT
      value: "$PROJECT_ID"
  restartPolicy: Never

デプロイと失敗の確認

それでは、このPodをデプロイしてみます。

# Podをデプロイ
kubectl apply -f gcs-test.yaml

# pod/gcs-test created

数十秒ほど待ってからログを確認してみます。

# ログを確認
kubectl logs gcs-test -n wi-demo

# === Workload Identity Test ===
# Uploading file to GCS...
# AccessDeniedException: 403 Caller does not have storage.objects.list access to the Google Cloud Storage bucket. Permission 'storage.objects.list' denied on resource (or it may not exist).

# File uploaded successfully!

# Downloading file from GCS...
# AccessDeniedException: 403 Caller does not have storage.objects.list access to the Google Cloud Storage bucket. Permission 'storage.objects.list' denied on resource (or it may not exist).


# Listing files in bucket...
# AccessDeniedException: 403 Caller does not have storage.objects.list access to the Google Cloud Storage bucket. Permission 'storage.objects.list' denied on resource (or it may not exist).

# === Test completed successfully! ===

権限がないためCloud Storageへのアクセスが拒否され、403 AccessDeniedExceptionというエラーが表示されています。

次はWorkload Identity Federationを設定して、このPodが正常にアクセスできるようにしていきます。

一旦失敗しているPodを削除しておきます。

# Podを削除
kubectl delete pod gcs-test -n wi-demo

# pod "gcs-test" deleted

KSAに直接IAMロールを付与

ここが重要な部分です。Workload Identity Federationでは、KSAに直接IAMロールを付与できます。
この際Google Service Accountを作成する必要はなく、Kubernetes Service Accountに直接ロールを付与できます。
※IAMロールに関する説明はここでは行いません

# KSAに直接バケットへのアクセス権限を付与
gcloud storage buckets add-iam-policy-binding \
  gs://$PROJECT_ID-workload-identity-demo \
  --member="principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT_ID.svc.id.goog/subject/ns/wi-demo/sa/gcs-access-ksa" \
  --role="roles/storage.objectAdmin"

# bindings:
# - members:
#   - projectEditor:my-project
#   - projectOwner:my-project
#   role: roles/storage.legacyBucketOwner
# - members:
#   - projectViewer:my-project
#   role: roles/storage.legacyBucketReader
# - members:
#   - principal://iam.googleapis.com/projects/123456789012/locations/global/workloadIdentityPools/my-project.svc.id.goog/subject/ns/wi-demo/sa/gcs-access-ksa
#   role: roles/storage.objectAdmin
# etag: CAM=
# kind: storage#policy
# resourceId: projects/_/buckets/my-project-workload-identity-demo
# version: 1

これでwi-demoというnamespace内のgcs-access-ksaというKSAを使うPodは、Cloud Storageバケットにアクセスできるようになりました。

Workload Identity Federationの動作確認

KSAに権限を付与したので、先ほど失敗したPodを再度デプロイしてアップロードできるようになっていることを確認します。
serviceAccountName: gcs-access-ksaとしていますが、これによりPodが権限を付与されたKSAを使ってCloud Storageにアクセスできるようになります。

# Podをデプロイ
kubectl apply -f gcs-test.yaml

# pod/gcs-test created

数十秒ほど待ってから以下のコマンドを実行します。

# ログを確認
kubectl logs gcs-test -n wi-demo

# === Workload Identity Test ===
# Uploading file to GCS...
# Copying file:///tmp/test.txt [Content-Type=text/plain]...
# / [1 files][   30.0 B/   30.0 B]
# Operation completed over 1 objects/30.0 B.

# File uploaded successfully!

# Downloading file from GCS...
# Hello from Workload Identity!


# Listing files in bucket...
# gs://my-project-workload-identity-demo/test.txt

# === Test completed successfully! ===

成功しました!Workload Identityが正しく機能して、PodからCloud Storageにアクセスできています。

Cloud Storageで確認

念のため、Cloud Storage側でもファイルが作成されていることを確認してみます。

gsutil catなどを実行してファイルの内容を確認する場合、自身のユーザーアカウントにもバケットへの権限を付与する必要がありますのでご注意ください。

# バケット内のファイルを確認
gsutil ls gs://$PROJECT_ID-workload-identity-demo/

# gs://my-project-workload-identity-demo/test.txt

ファイルが作成されていることが確認できました!

クリーンアップ

# Podを削除
kubectl delete pod gcs-test -n wi-demo

# pod "gcs-test" deleted
# namespaceごと削除
kubectl delete namespace wi-demo

# namespace "wi-demo" deleted
# Cloud Storageバケットを削除
gsutil rm -r gs://$PROJECT_ID-workload-identity-demo

# Removing gs://my-project-workload-identity-demo/test.txt#...
# Removing gs://my-project-workload-identity-demo/...
# GKEクラスタを削除
gcloud container clusters delete wi-cluster \
  --region=asia-northeast1

# The following clusters will be deleted.
#  - [wi-cluster] in [asia-northeast1]
#
# Do you want to continue (Y/n)?  Y
#
# Deleting cluster wi-cluster...done.
# Deleted [https://container.googleapis.com/v1/projects/my-project/locations/asia-northeast1/clusters/wi-cluster].

まとめと次回予告

Workload Identity Federationの機能を活用して、KSAに直接IAMロールを付与することでセキュアにGoogle Cloudのリソースにアクセス可能なことを確認しました。

クラウドネイティブでGKEを利用していく上で、IAMロール管理は避けては通れない内容になりますので、必ず要点をおさえて設計開発に取り込んでいきたいですね!

次回は Kubernetesを活用していく上でのベスプラや実務レベルで利用できるツールなどについて触れていきたいと思います。

それでは、また次回!

13
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?