概要 #
GKE PodからGoogle Cloud APIを呼ぶとき、JSON Keyを使う方法は管理の手間が増えます。Secretとしての漏洩経路にもなります。PodにKeyファイルを配りたくないところです。
Workload Identity Federation for GKEを使えば、鍵なしで権限を借用できます。Kubernetes Service Account(KSA)をGoogle Cloud Service Account(GSA)に紐づける仕組みです。ここでは実際にPodからCloud Storageへ書き込みます。
Terraformの基本操作とkubectlの基本操作は前提としています。GKEのWorkload Identityが初めての方向けです。
Private Cluster化、Network Policy、複数Namespaceでの権限分離は扱いません。
検証すること #
- Workload Identity Federationを有効にしたGKE Clusterを作成できること
- Kubernetes Service AccountとGoogle Cloud Service Accountを関連付けられること
- Service Account KeyなしでPodからCloud Storageへ書き込めること
前提環境 #
- Google Cloud CLI、Terraform、kubectl
- Billingが有効な検証用Google Cloud Project
- GKE、IAM、Cloud Storageを操作できるGoogleアカウント
- 検証時のバージョン:Terraform 1.14.3、google 7.43.0、kubernetes 2.38.0
今回の構成 #
KubernetesのService AccountとGoogle CloudのService Accountは別物です。Workload Identityは、その2つを結びつけます。
flowchart TB
subgraph GCP["Google Cloud"]
subgraph Project["Project"]
GSA["Google Cloud
Service Account"]
Bucket["Cloud Storage Bucket"]
subgraph Region["asia-northeast1"]
subgraph Cluster["GKE Cluster"]
subgraph NS["Namespace"]
Pod["Job / Pod"]
KSA["Kubernetes
Service Account"]
Pod --- KSA
end
end
end
end
end
KSA -.->|"Workload Identity で紐付け"| GSA
GSA -.->|"objectCreator"| Bucket
Pod -->|"オブジェクトを書き込み"| Bucket
点線が権限の関係、実線が実際の通信です。鍵ファイルをPodへ配らずに済みます。
Podが書き込むまでの流れです。
sequenceDiagram
participant Pod as Job / Pod
participant KSA as Kubernetes SA
participant Meta as GKE Metadata Server
participant GSA as Google Cloud SA
participant GCS as Cloud Storage
Pod->>Meta: 認証情報を要求
Meta->>KSA: 紐付けを確認
KSA-->>Meta: Workload Identity の対応あり
Meta->>GSA: 権限を借用
GSA-->>Pod: 一時的なアクセストークン
Pod->>GCS: オブジェクトを書き込み
Service Account Keyを作らないため、Secretとして鍵を管理する必要がありません。
使用するTerraformコード #
KSAとGSAを関連付ける #
resource "google_service_account_iam_member" "workload_identity_user" {
service_account_id = google_service_account.gcs.name
role = "roles/iam.workloadIdentityUser"
member = "serviceAccount:${var.project_id}.svc.id.goog[${var.k8s_namespace}/${var.k8s_service_account}]"
}
resource "kubernetes_service_account_v1" "gcs" {
metadata {
name = var.k8s_service_account
namespace = kubernetes_namespace_v1.demo.metadata[0].name
annotations = {
"iam.gke.io/gcp-service-account" = google_service_account.gcs.email
}
}
}
IAM MemberのNamespaceとKSA名、KSA AnnotationのGSA Emailが対応します。GSAにはBucket単位でObject書込権限を付与し、Project全体へ広げません。
GKEと検証Job #
ClusterではWorkload Poolを有効化します。
workload_identity_config {
workload_pool = "${var.project_id}.svc.id.goog"
}
サンプルのKubernetes Jobは対象KSAで起動し、gcloud storage cpでObjectを作成します。TerraformのKubernetes Providerは作成したClusterのEndpointとToken、CA Certificateを使います。
実行と確認 #
cd Advanced-Examples/03-gke-workload-identity-gcs
cp terraform.tfvars.example terraform.tfvars
terraform init
terraform fmt -check
terraform validate
terraform apply
VPC、GKE Cluster、Spot Node Pool、Bucket、Namespace、Jobが作成されます。合わせて15リソースです。GKE作成に十数分、Job完了待ちでさらに1分ほどかかりました。
Apply complete! Resources: 15 added, 0 changed, 0 destroyed.
Outputs:
bucket_name = "tf-adv-gke-wi-YOUR_PROJECT_ID"
cluster_name = "tf-adv-gke-wi"
gcp_service_account_email = "tf-adv-gke-wi-gcs@YOUR_PROJECT_ID.iam.gserviceaccount.com"
k8s_namespace = "wi-demo"
object_name = "workload-identity/hello.txt"
ClusterがRUNNING、Jobが実際にオブジェクトを書き込めたかを確認します。
gcloud container clusters describe "$(terraform output -raw cluster_name)" \
--zone="$(terraform output -raw cluster_location)" \
--format='value(status)'
gcloud storage cat "gs://$(terraform output -raw bucket_name)/$(terraform output -raw object_name)"
RUNNING
hello-from-workload-identity
Job Logも確認します。
eval "$(terraform output -raw get_credentials_example)"
kubectl -n "$(terraform output -raw k8s_namespace)" logs job/wi-gcs-write
Copying from <STDIN>...
Operation completed over 1 objects.
hello-from-workload-identity
ObjectとJob Logの両方にhello-from-workload-identityが表示されました。KSAからGSAを経由した書き込みが成功しています。
後片付けと注意点 #
terraform destroy
Destroy complete! Resources: 15 destroyed.
GKE Clusterは課金が発生します。サンプルは費用を抑えるためSpot Nodeを使いますが、中断を許容できる検証用です。Kubernetes ResourceをTerraformで扱う場合は、Cluster削除より先にProviderが到達不能にならないDependencyにも注意します。
まとめ #
- PodへService Account Keyを保存せずGoogle Cloud APIを利用できる
- KSAとGSAの対応をIAMとAnnotationで宣言できる
- GCS権限をBucket単位へ限定できる
- Jobによって実際のObject書込みまで検証できる
参考資料 #
次回 #
次回はTerraform StateをCloud Storage Backendへ移行します。