AWS の IAM ロールと GCP のサービスアカウントを紐付けて鍵なしでアクセスする方法
GCP には Workload Identity 連携 と呼ばれる機能があります。現時点ではβ版です。 ブログを書いている間に GA してました。
この機能を活用することで、GCP 上のサービスアカウントを AWS IAM と紐付けることができ、サービスアカウントの鍵を使うことなく GCP へアクセス可能になります。
AWS から BigQuery へデータを送るためにサービスアカウントの鍵を渡すケースは多いと思いますが、今後はその必要がなくなるかもしれません。
登場する概念
Workload Identity プールと、Workload Identity プロバイダという2つの概念を最初に抑えておくと理解しやすくなります。(なりました)
- Workload Identity プール
- 外部 ID と連携するときに使う
- 好きな名前をつけて作れる
- この中に ID プロバイダを登録する
- Workload Identity プロバイダ
- ID を管理する外部のプロバイダ
- 好きな名前をつけて作れる
- OpenID Connect をサポートするプロバイダが登録できる
- 今回は AWS をプロバイダとして登録する
「プールを作ってその中に AWS という ID プロバイダを登録する」のが今回やることです。
GCP サービスアカウントと AWS IAM ロールを紐付ける手順
前提条件
- 組織に属する GCP アカウントであること
- 個人で試す場合は Google Cloud Identity Free edition がおすすめ
- Workload Identity プール管理者権限を持っていること(オーナーなら問題なし)
公式ドキュメントの手順に沿って検証しました。
https://cloud.google.com/iam/docs/access-resources-aws?hl=ja
API を有効化
今回使用する以下4つの API を有効化します。
Workload Identity プールを作る
管理権限のあるアカウントで Google Cloud Shell から操作するのが楽です。
プール名とプロバイダ名は任意で指定しましょう。
# GCP project 情報をセット
$ gcloud config set project "<project-id>"
# Workload Identity プールを作る
$ gcloud iam workload-identity-pools create "<pool-name>" --location="global"
# AWS をプロバイダとして追加する
$ gcloud iam workload-identity-pools providers create-aws "<provider-name>" --location="global" --workload-identity-pool="<pool-name>" --account-id="<aws-account-id>"
サービスアカウントと紐付ける
今回は事前に作ってあるサービスアカウントを使います。
コマンドの引数がかなり長いので、先に組み立てておくことを推奨。
# Identity プールの name を確認しておく
$ gcloud iam workload-identity-pools list --location="global"
---
name: projects/123456789012/locations/global/workloadIdentityPools/mypool01
state: ACTIVE
# サービスアカウントと紐付ける
$ gcloud iam service-accounts add-iam-policy-binding "<service-account-email>" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/<先ほど確認した name>/attribute.aws_role/arn:aws:sts::<aws-account-id>:assumed-role/<aws-iam-role-name>"
認証情報ファイルを作る
クライアントで利用する認証情報を作ります。サービスアカウントの鍵代わりとなるものです。
$ gcloud iam workload-identity-pools create-cred-config \
"<先ほど確認した name>/providers/<provider-name>" \
--service-account="<service-account-email>" \
--output-file="<file-path>" \
--aws
指定したファイルパスに JSON が出てくるので、AWS の実行環境に配置しましょう。
中身を覗いてみると、メタデータしか入っていないことが分かります。
{
"type": "external_account",
"audience": "//iam.googleapis.com/projects/123456789012/locations/global/workloadIdentityPools/mypool01/providers/myprovider01",
"subject_token_type": "urn:ietf:params:aws:token-type:aws4_request",
"token_url": "https://sts.googleapis.com/v1/token",
"credential_source": {
"environment_id": "aws1",
"region_url": "http://169.254.169.254/latest/meta-data/placement/availability-zone",
"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials",
"regional_cred_verification_url": "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15"
},
"service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa01@xxxxxxxxx.iam.gserviceaccount.com:generateAccessToken"
}
AWS からアクセスしてみる
Node.js SDK の最新版を使い、BigQuery からデータを取得するだけの簡単なスクリプトです。
キーファイルの欄には先ほど作成した JSON を指定します。
const { BigQuery } = require('@google-cloud/bigquery');
const bigquery = new BigQuery({
projectId: 'xxxxxxxxx',
keyFilename: 'credential.json'
});
bigquery.query('SELECT * FROM mydataset.users ORDER BY id')
.then(data => {
const rows = data[0];
rows.forEach(row => {
console.log(JSON.stringify(row));
});
})
.catch(error => {
console.log(error);
});
GCP と紐付けた IAM ロールを持つ EC2 から実行すると、無事にデータを取得できました。
$ node ./bq.js
{"id":1,"name":"aaaaa","email":"aaaaa@example.com","created":{"value":"2021-04-01T03:00:00"}}
{"id":2,"name":"bbbbb","email":"bbbbb@example.com","created":{"value":"2021-04-01T06:00:00"}}
{"id":3,"name":"ccccc","email":"ccccc@example.com","created":{"value":"2021-04-01T09:00:00"}}
{"id":4,"name":"ddddd","email":"ddddd@example.com","created":{"value":"2021-04-01T12:00:00"}}
{"id":5,"name":"eeeee","email":"eeeee@example.com","created":{"value":"2021-04-01T15:00:00"}}
試しにインスタンスから IAM ロールを剥がして実行すると権限エラーとなり、実際に AWS の IAM ロールと紐付いて認証されていることが確認できます。
$ node ./bq.js
GaxiosError: The caller does not have permission
at Gaxios._request (/home/ec2-user/bqtest/node_modules/gaxios/build/src/gaxios.js:127:23)
at processTicksAndRejections (node:internal/process/task_queues:94:5)
at async AwsClient.getImpersonatedAccessToken (/home/ec2-user/bqtest/node_modules/google-auth-library/build/src/auth/baseexternalclient.js:322:26)
at async AwsClient.refreshAccessTokenAsync (/home/ec2-user/bqtest/node_modules/google-auth-library/build/src/auth/baseexternalclient.js:258:38)
at async AwsClient.getAccessToken (/home/ec2-user/bqtest/node_modules/google-auth-library/build/src/auth/baseexternalclient.js:116:13)
at async AwsClient.getRequestHeaders (/home/ec2-user/bqtest/node_modules/google-auth-library/build/src/auth/baseexternalclient.js:133:37)
at async GoogleAuth.authorizeRequest (/home/ec2-user/bqtest/node_modules/google-auth-library/build/src/auth/googleauth.js:593:25)
まとめ
- AWS IAM と GCP サービスアカウントを紐付けできる
- サービスアカウントの鍵を管理する必要がない
まだベータ版なので注意が必要
AWS からサービスアカウントを使う箇所は、この連携機能に乗り換えても良さそうですね。
誤りなどを発見した場合はぜひコメントください。
ディスカッション
コメント一覧
まだ、コメントがありません
フォローする
カテゴリー
最近の投稿
ブログについて