GKE cluster作成時にも指定できるアクセススコープはレガシー扱いになっている https://cloud.google.com/kubernetes-engine/docs/how-to/access-scopes#what_are_access_scopes

とはいえチュートリアルには--scopeを利用したものも見受けられる

アクセススコープは手軽だが細かい設定ができない。ServiceAccountを使うと必要最低限の権限のみ付与する事ができるので、セキュリティの品質が保たれるためGoogleとしてはServiceAccountを推している。という認識でいいのかな.

GKEの権限関係で迷わないよう、サービス アカウントを使用した Google Cloud への認証を題材にやり方を整理する

  1. アクセススコープを用いた認証
  2. ServiceAccountを用いた認証
  3. (おまけ) ServiceAccount認証にWorkload Identityを用いる

事前準備

題材に則りpubsub topicを作成し、publishとsubscribeができるか検証する

pubsub topicの作成

gcloud pubsub topics create echo
gcloud pubsub subscriptions create echo-read --topic=echo

ソースコード取得

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
cd kubernetes-engine-samples

cloud-pubsub/deployment以下のyamlファイルを実際に適応していく

1. アクセススコープを用いた認証

クラスタ作成

gcloud container clusters create pubsub-test --scopes=gke-default,https://www.googleapis.com/auth/pubsub --zone
asia-northeast1-a

scope オプションについて

--scopesオプションをつけることでクラスタに権限を付与できる gke-defaultは下記のscopeをまとめたエイリアスになる

Alias       URI
gke-default https://www.googleapis.com/auth/devstorage.read_only
            https://www.googleapis.com/auth/logging.write
            https://www.googleapis.com/auth/monitoring
            https://www.googleapis.com/auth/service.management.readonly
            https://www.googleapis.com/auth/servicecontrol
            https://www.googleapis.com/auth/trace.append

gcloud container clusters create --helpをすると他のエイリアスもあるのでみてみると良い (webのmanにも載っている)

また複数指定したいのでカンマ区切りで指定している scopeの一覧から選んで付与していく.

(権限を追加する)

後から権限を追加したくなるケースはどうするか? scopeを変えたいならば、node-poolsを作り変える事しかできない

# 新規作成
gcloud container node-pools create new-pools --cluster pubsub-test --scopes=gke-default,https://www.googleapis.com/auth/pubsub,https://www.googleapis.com/auth/something
# 古いnodeを削除
gcloud container node-pools delete old-pools --cluster pubsub-test

デプロイ

kubectl apply -f cloud-pubsub/deployment/pubsub.yaml
kubectl get po
NAME                     READY   STATUS    RESTARTS   AGE
pubsub-8cb8475c8-tvxwv   1/1     Running   0          95s

確認

Publish

gcloud pubsub topics publish echo --message="Hello, world\!"
messageIds:
- '3909513331830980'

Subscribe

kubectl logs -f pubsub-8cb8475c8-tvxwv
Pulling messages from Pub/Sub subscription...
[2022-03-21 06:37:27.265195] Received message: ID=3909513331830980 Data=b'Hello, world!'
[2022-03-21 06:37:27.265294] Processing: 3909513331830980
[2022-03-21 06:37:30.267957] Processed: 3909513331830980

2. ServiceAccountを用いた認証

Googleが推奨しているのはこちら サービス アカウントを使用した Google Cloud への認証と同じ事をしているだけなので説明は省く

クラスタ作成

gcloud container clusters create pubsub-test

Service Accountの作成

gcloud iam service-accounts create pubsub \
    --description="PUBSUB" \
    --display-name="pubsub"
gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member="serviceAccount:pubsub@$PROJECT_ID.iam.gserviceaccount.com" \
    --role="roles/pubsub.admin"

鍵の取得

ServiceAccountのページにアクセスする 作成したサービスアカウントの右にある3点リーダーから「鍵を管理」を選択 「鍵を追加」>「新しい鍵を作成」>「JSON」>「作成」を選択 json形式の鍵がDLされる

クラスタに登録

kubectl create secret generic dns-key --from-file=key.json=secret.json

登録後、secret.jsonはローカルから削除する

デプロイ

kubectl apply -f cloud-pubsub/deployment/pubsub-with-secret.yaml # scopeの例とは違うファイル
kubectl get po
NAME                     READY   STATUS    RESTARTS   AGE
pubsub-57ff86f846-6k455  1/1     Running   0          5s

疎通確認

Publish

$ gcloud pubsub topics publish echo --message="Hello, world\!"
messageIds:
- '3909437272511327'

Subscribe

$ kubectl logs -f pubsub-57ff86f846-6k455
Pulling messages from Pub/Sub subscription...
[2022-03-21 06:21:01.512711] Received message: ID=3909437272511327 Data=b'Hello, world!'
[2022-03-21 06:21:01.512785] Processing: 3909437272511327
[2022-03-21 06:21:04.515914] Processed: 3909437272511327

3. (おまけ) ServiceAccount認証にWorkload Identityを用いる

ServiceAccount認証では鍵の管理で難易度が上がる予想ができる、そこでWorkload Identityを試してみる

Workload Identityとはなにか

Google Cloudによると下記のようなことができるらしい

GKE クラスタ内のワークロードが Identity and Access Management(IAM)サービス アカウントに代わって Google Cloud サービスにアクセスできます

こちらの解説にある下記の説明がストレートでわかりやすかった

Kubernetes の Service account と GCP の Service account を紐づけられるようにする機能

とはいえ、試してしてわかったこともあるので実際に流れを記載しておく この章ではGCPとk8sのServiceAccountを見分けられるようにGSA, KSAと用語統一する

クラスター作成

$ gcloud container clusters create pubsub-wi \
    --zone=asia-northeast1-a \
    --workload-pool=$PROJECT_ID.svc.id.goog

クラスター認証情報を取得

$ gcloud container clusters get-credentials pubsub-wi --zone asia-northeast1-a
Fetching cluster endpoint and auth data.
kubeconfig entry generated for pubsub-wi.

KSAの作成

$ kubectl create namespace workloadidentity
apiVersion: v1
kind: ServiceAccount
metadata:
  name: k8s-pubsub-sa
  namespace: workloadidentity

pubsubの権限を持つGSAを作成

gcloud iam service-accounts create gcp-pubsub-sa --project=$PROJECT_ID
gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member="serviceAccount:gcp-pubsub-sa@$PROJECT_ID.iam.gserviceaccount.com" \
    --role="roles/pubsub.admin"

KSA(k8s-pubsub-sa)GSA(gcp-pubsub-sa)を連携する. その結果、KSAGSAの権限を借用できるようになる これが当初述べていた「Kubernetes の Service account と GCP の Service account を紐づけられるようにする機能」のコア作業になる(と思う)

gcloud iam service-accounts add-iam-policy-binding gcp-pubsub-sa@$PROJECT_ID.iam.gserviceaccount.com \
    --role roles/iam.workloadIdentityUser \
    --member "serviceAccount:$PROJECT_ID.svc.id.goog[workloadidentity/k8s-pubsub-sa]"

デプロイ

KSAの設定にGSAの情報を付与

上のyamlからannotation部を追加した

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    iam.gke.io/gcp-service-account: gcp-pubsub-sa@$PROJECT_ID.iam.gserviceaccount.com
  name: k8s-pubsub-sa
  namespace: workloadidentity

Podにnodeを指定

WorkloadIdentityが有効なnodeでKSAを利用するようにPodの設定を更新する

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pubsub
  namespace: workloadidentity
spec:
  selector:
    matchLabels:
      app: pubsub
  template:
    metadata:
      labels:
        app: pubsub
    spec:
      containers:
      - name: subscriber
        image: us-docker.pkg.dev/google-samples/containers/gke/pubsub-sample:v1
      serviceAccountName: k8s-pubsub-sa
      nodeSelector:
        iam.gke.io/gke-metadata-server-enabled: "true"

疎通確認

Publish

$ gcloud pubsub topics publish echo --message="Hello, world\!"
messageIds:
- '3910950575108654'

Subscribe

$ kubectl logs -f pubsub-6f88675785-bfp2x -n workloadidentity
Pulling messages from Pub/Sub subscription...
[2022-03-21 10:47:58.059249] Received message: ID=3910950575108654 Data=b'Hello, world!'
[2022-03-21 10:47:58.059274] Processing: 3910950575108654
[2022-03-21 10:48:01.060928] Processed: 3910950575108654

まとめ

GKEにおける権限付与のやり方をscopeとServiceAccount(gcloudコマンド利用、workload identity)の3つを整理した 検証用にクラスタを一時的に建てるならばscopeでもいいかもしれないが、セキュリティや後からの追加のしやすさから運用し続けるクラスタにはServiceAccountを用いた方が楽だろう. gcloudの場合は鍵の管理でセキュリティ面や運用面で難易度が上がる恐れがあるが、workload identityを利用する事でその不安点も回避できる。

こちらの記事ではterraformでのworkload identityのやり方も記載されているので、別PJへの展開もスムーズに行えそうだ. また、今回は検証していないがConfig Connectorを利用するとServiceAccountの発行もYAMLで記載できそうなので、terraform以外の選択肢になるかもしれない