これまで
- GKE で Pod から GCP の API をリクエストする場合には Secrets リソースに Google Service Account の Credential を作ってマウントしていた
- そのため Credential を発行してダウンロードするという作業が必要となる
- Google Service Account にはそのアプリケーションで必要となる API の各種権限を割り当てているのでセンシティブな情報と言える
- それにも関わらず一度は作業者のローカルや作業環境などに保存する必要があるため管理が甘い (使用後即座に消さないとか) と作業者本人も含めてアプリケーション以外で使用されてしまう
- Credential なんてダウンロードしないで Pod に Service Account を指定したい...
今
- Workload Identity 登場
- fin.
使ってみた (CronJob)
前提
- 作業者に各種権限が付与されていること
- 以下の権限が含まれていればいけそう (要らないのも混ざってるかも)
resourcemanager.projects.get
iam.serviceAccounts.get
iam.serviceAccounts.list
iam.serviceAccounts.create
iam.serviceAccounts.actAs
iam.serviceAccounts.setIamPolicy
iam.serviceAccounts.getIamPolicy
compute.projects.get
compute.regions.get
compute.regions.list
compute.zones.get
compute.zones.list
compute.networks.get
compute.networks.list
compute.networks.create
compute.networks.updatePolicy
compute.subnetworks.get
compute.subnetworks.list
compute.subnetworks.create
container.operations.get
container.clusters.get
container.clusters.create
- 各種リソースの名前は以下で統一
Name | Description |
---|---|
${my_pj} | クラスタを作成する GCP のプロジェクト |
${my_gsa} | CronJob で使用したい Google Service Account 名 |
${k8s_ns} | Kubernetes の Namespace 名 |
${k8s_ksa} | Kubernetes の Namespace 内の Service Account 名 |
${my_clstr} | クラスタ名 |
${my_nw} | GCP の VPC ネットワーク名 |
${my_subnw} | クラスタ用のサブネットワーク名 |
${my_region} | サブネットワークのリージョン |
${my_zone} | クラスタのゾーン (リージョンで作るとノード数多いので) |
- https://console.cloud.google.com/apis/api/iamcredentials.googleapis.com/overview にアクセスして API の許可がされていること
作業
$ docker run --rm -it --name gcp-cli -w /opt google/cloud-sdk:latest
% gcloud auth login
% gcloud config set project ${my_pj}
% : Step01. ${my_gsa} の作成
% gcloud beta iam service-accounts create\
${my_gsa}\
--project ${my_pj}\
--display-name "My Google Service Account"\
--description "Qiita Example"
% : Step02. ${my_gsa} への権限設定
% gcloud projects add-iam-policy-binding\
${my_pj}\
--member ${my_gsa}@${my_pj}.iam.gserviceaccount.com\
--role resourcemanager.projects.get
% : Step03. クラスタ用のネットワーク作成
% gcloud compute networks create\
${my_nw}\
--project ${my_pj}\
--bgp-routing-mode regional\
--subnet-mode custom
% gcloud compute networks subnets create\
${my_subnw}\
--project ${my_pj}\
--network ${my_nw}\
--region ${my_region}\
--range xxx.xxx.xxx.xxx/xx\
--enable-private-ip-google-access
% : Step04. クラスタ作成
% gcloud beta container clusters create\
${my_clstr}\
--project ${my_pj}\
--zone ${my_zone}\
--identity-namespace ${my_pj}.svc.id.goog\
--network ${my_nw}\
--subnetwork ${my_subnw}\
--machine-type n1-standard-1\
--preemptible\
--disk-size 100\
--disk-type pd-standard\
--image-type cos\
--enable-ip-alias\
--enable-private-nodes\
--master-ipv4-cidr yyy.yyy.yyy.yyy/yy\
--enable-master-authorized-networks\
--master-authorized-networks zzz.zzz.zzz.zzz/zz\
--num-nodes 1\
--no-enable-legacy-authorization\
--no-enable-basic-auth\
--no-issue-client-certificate\
--metadata 'disable-legacy-endpoints=true'
% : Step05. Workload Identity からの ${my_gsa} へのアクセスを許可
% gcloud iam service-accounts add-iam-policy-binding\
${my_gsa}@${my_pj}.iam.gserviceaccount.com\
--role "roles/iam.workloadIdentityUser"\
--member "serviceAccount:${my_pj}.svc.id.goog[${k8s_ns}/${k8s_ksa}]"
% : Step06. クラスタに Namespace と Service Account を作成
% cat <<EOS | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: ${k8s_ns}
---
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: ${k8s_ns}
name: ${k8s_ksa}
annotations:
iam.gke.io/gcp-service-account: ${my_gsa}@${my_pj}.iam.gserviceaccount.com
EOS
% : Step07. Pod 作ってテスト
% kubectl run\
-it\
--rm\
--generator=run-pod/v1\
--image google/cloud-sdk\
--namespace ${k8s_ns}\
--serviceaccount ${k8s_ksa}\
workload-identity-test\
-- gcloud auth list
% kubectl run\
-it\
--rm\
--generator=run-pod/v1\
--image google/cloud-sdk\
--namespace ${k8s_ns}\
--serviceaccount ${k8s_ksa}\
workload-identity-test\
-- gcloud projects describe ${my_pj}
% : Step08. CronJob を作成
% cat <<EOS | kubectl apply -f -
apiVersion: batch/v1beta1
kind: CronJob
metadata:
namespace: ${k8s_ns}
name: workload-identity-test
spec:
schedule: "*/1 * * * *"
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: Never
serviceAccountName: ${k8s_ksa}
containers:
- name: batch
image: google/cloud-sdk
imagePullPolicy: Always
command: ["gcloud", "projects", "describe", "${my_pj}"]
EOS
% kubectl get cronjob --namespace ${k8s_ns}
% kubectl pod cronjob --namespace ${k8s_ns}
% kubectl get pod --namespace ${k8s_ns} --field-selector status.phase==Succeeded -o name\
| kubectl logs $(cat) --namespace ${k8s_ns}
調査
Pod 内で gcloud auth list
がエラー
こんなの
ERROR: gcloud crashed (MetadataServerException): HTTP Error 403: Forbidden
- Stack Driver で以下のようなフィルターでログ調査
resource.type="container"
resource.labels.cluster_name="${my_clstr}"
resource.labels.namespace_id="kube-system"
resource.labels.project_id="${my_pj}"
resource.labels.zone:"${my_zone}"
resource.labels.container_name="gke-metadata-server"
resource.labels.pod_id:"gke-metadata-server-"
- IAM とかの API を enable にしてなかったり権限が足りてなかったり