GKE上のアプリケーションがSecret ManagerやCloud Storageへアクセスするとき、サービスアカウントJSONキーをPodへ置く必要はありません。Workload Identity Federation for GKE を使い、短命な認証情報を取得します。
ここで混乱しやすいのがKSAと、Google CloudのIAM service accountです。
2種類のservice account
| 呼び方 | 正式な対象 | 管理場所 | 役割 |
|---|---|---|---|
| KSA | Kubernetes ServiceAccount | Kubernetes Namespace | PodがKubernetes内で名乗るID |
| IAM service account | Google Cloud IAM service account | Google Cloud IAM | Google Cloud APIで使うワークロードID |
Kubernetes関連資料では後者を GSA と呼ぶことがありますが、Google Cloudの正式名称ではなく、KSAと区別するための便宜的な略称です。本記事では「IAM service account」と表記します。
まずKSAをワークロードごとに分ける
apiVersion: v1
kind: ServiceAccount
metadata:
name: example-api
namespace: YOUR_NAMESPACE
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-api
namespace: YOUR_NAMESPACE
spec:
replicas: 2
selector:
matchLabels:
app: example-api
template:
metadata:
labels:
app: example-api
spec:
serviceAccountName: example-api
containers:
- name: api
image: registry.gitlab.com/GROUP/PROJECT/IMAGE:TAG
Namespaceの default KSAを全アプリで共有すると、権限境界が曖昧になります。API、バッチ、オペレーターなど役割ごとに専用KSAを作ります。
推奨:KSA主体をIAMへ直接認可する
現在のGKEでは、Workload Identity Pool内のKSA主体へIAMロールを直接付与できます。対応サービスではこの方式が経路が短く、IAM service accountを追加せずに済みます。
まずプロジェクト番号を確認します。
gcloud projects describe YOUR_PROJECT_ID \
--format='value(projectNumber)'
次に、対象リソースまたはプロジェクトへKSA主体を許可します。次はSecret Manager参照ロールをプロジェクト単位で付ける構文例です。実運用では可能なら個別Secret単位へ狭めます。
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--role=roles/secretmanager.secretAccessor \
--member="principal://iam.googleapis.com/projects/YOUR_PROJECT_NUMBER/locations/global/workloadIdentityPools/YOUR_PROJECT_ID.svc.id.goog/subject/ns/YOUR_NAMESPACE/sa/YOUR_KSA_NAME" \
--condition=None
Podの serviceAccountName に YOUR_KSA_NAME を指定します。Google CloudクライアントライブラリがApplication Default Credentialsを使うと、GKEのメタデータサービスを通じて短命トークンを取得できます。
GKE側の前提
- AutopilotクラスタではWorkload Identity Federation for GKEが常に有効
- StandardクラスタではクラスタとNode Poolの設定を確認する
- NodeのIAM service accountと、PodのKSA主体を混同しない
特にコンテナイメージのpullは、通常はNode側の資格情報または imagePullSecrets が関係し、アプリPodのWorkload Identityとは別経路です。
必要な場合:KSAからIAM service accountを借用する
一部のAPIや既存アプリがWorkload Identity Poolの主体を直接扱えない場合は、KSAがIAM service accountを借用する方式を使います。
gcloud iam service-accounts create YOUR_IAM_SA_NAME \
--project=YOUR_PROJECT_ID
gcloud iam service-accounts add-iam-policy-binding \
YOUR_IAM_SA_NAME@YOUR_PROJECT_ID.iam.gserviceaccount.com \
--role=roles/iam.workloadIdentityUser \
--member="serviceAccount:YOUR_PROJECT_ID.svc.id.goog[YOUR_NAMESPACE/YOUR_KSA_NAME]" \
--project=YOUR_PROJECT_ID
kubectl annotate serviceaccount YOUR_KSA_NAME \
-n YOUR_NAMESPACE \
iam.gke.io/gcp-service-account=YOUR_IAM_SA_NAME@YOUR_PROJECT_ID.iam.gserviceaccount.com
さらに、そのIAM service account自体へ必要最小限の業務ロールを付与します。roles/owner や広いEditor権限で済ませません。
どちらを選ぶか
KSA主体を対象Google Cloud APIが直接認可できるか
├─ はい → KSA主体へ対象リソースのIAMロールを直接付与
└─ いいえ/互換性要件あり
→ KSAが専用IAM service accountを借用
「KSAには必ずIAM service accountを1対1で紐付ける」という古い定型だけで設計せず、直接認可を先に検討します。
権限設計の要点
- KSAはワークロード単位、Namespace単位で分離する
- IAMロールはプロジェクト全体より個別リソースへ狭める
- JSONキーをKubernetes Secretやイメージへ置かない
- アプリの権限と、Nodeやデプロイ担当者の権限を分ける
kubectl auth can-iはKubernetes RBACの確認で、Google Cloud IAMとは別物
動作確認
Pod内へ gcloud を常設する必要はありません。アプリが利用する公式クライアントライブラリで対象APIへの最小操作を行い、Cloud Audit LogsとPodログを確認します。デバッグ用Podを使う場合も、本番KSAを無関係なイメージへ割り当てないよう注意します。
次回
このキーレス認証を使い、GKEでSecret Managerを安全に利用する方法を比較します。