Workload Identityを使用してAWS LambdaからBigQueryにキーレスで接続する

# はじめに
AWS LambdaからBigQueryに接続し、その結果を使って後続の処理を行いたい場合、Lambda上にGCPのサービスアカウントの認証キーを配置することで可能になりますが、認証キーの発行やLambda上への配置はできればしたくありません。

そういった時に便利なのが、GCPのWorkload Identityです。

https://cloud.google.com/blog/ja/products/identity-security/enable-keyless-access-to-gcp-with-workload-identity-federation

この方法では、GCPのサービスアカウントとAWS等のロールを紐付け、サービスアカウントの権限を借用して認証することができます。

今回はこの方法でLambdaからBigQueryに接続する方法を確認して行きます。


# 実行準備
以下は作成済みである前提で進めて行きます。

- GCP側
    - プロジェクト
    - BigQueryについて操作可能なGCPのサービスアカウント
    - BigQueryのテーブル
- AWS側
    - Lambda関数
    - Lambda関数の実行ロール

また、GCPのリソースについてCLIで操作を行なっていくので、gcloudが実行できる状態にしておいてください。

```sh
$ gcloud version
Google Cloud SDK 367.0.0
bq 2.0.72
core 2021.12.10
gsutil 5.5
```


#### BigQueryテーブル
テーブルについては以下の通り、`users`というテーブル名で`user_id`、`name`というカラムを持つシンプルなテーブルを用意しました。

![スクリーンショット 2022-01-16 18.50.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643279/d6623559-9eff-1844-69b1-ca90e89f4d66.png)

#### Lambda関数
Lambda関数は以下のように作成し、デプロイしておきます。
`users`のテーブルにクエリを投げて結果を取得するシンプルなものになっています。

```python
import os
from google.cloud import bigquery

def lambda_handler(event, context):
    client = bigquery.Client(project="<プロジェクト名>")

    query = """
        SELECT user_id, name FROM `<プロジェクトID>.<dataset名>.users`
    """
    query_job = client.query(query)
    print("The query data:")
    for row in query_job:
        print("user_id={}, name={}".format(row["user_id"], row["name"]))

    return event

```

※ `<プロジェクトID>`、`<dataset名>`は適宜書き換えてください
※ `from google.cloud import bigquery`するために`google-cloud-bigquery`をパッケージに含めてbuildする必要があることに注意してください

# やってみる
今回は、以下の手順で進めて行きます。

1. Workload Identity構築・アカウント紐付け
1. Lambda側で認証情報ファイルを配置・実行確認

### Workload Identity構築・アカウント紐付け
早速、構築して行きます。

※ コード中の`<hoge>`は適宜書き換えてください

1.GCP で以下 API が有効になっていることを確認します。

- Identity and Access Management (IAM) API
- Cloud Resource Manager API
- IAM Service Account Credentials API
- Security Token Service API

2.事前に作成しておいたlambda関数に紐付けた実行ロール名を確認しておきます

![スクリーンショット 2022-01-16 18.46.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643279/59607f4a-cfdc-9867-5615-cd3ed767395d.png)


3.Workload Identityプールを作成する
プール名は新規でセット

```sh
$ gcloud iam workload-identity-pools create "<Workload Identity プール名>" --location="global"
```

4.Workload IdentityプールにAWSアカウントIDをプロバイダとして追加する
プロパイダー名は新規でセット

```sh
$ gcloud iam workload-identity-pools providers create-aws "<プロバイダー名>" --location="global" --workload-identity-pool="<Workload Identity プール名>" --account-id="<AWSアカウントID>"
```

5.権限を借用するGCPサービスアカウントに、Lambda関数のロールを紐付け
まず、さきほど作成したプールのnameを確認しておきます。

```sh
$ gcloud iam workload-identity-pools list --location="global"
---
name: <POOL_NAME>
state: ACTIVE


Updates are available for some Cloud SDK components.  To install them,
please run:
  $ gcloud components update
```

確認した`<POOL_NAME>`とAWS Lambdaのロール名を使用して、両者を紐づけていきます。

```sh
$ gcloud iam service-accounts add-iam-policy-binding "<プロジェクト名>@<サービスアカウント名>.iam.gserviceaccount.com" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/<POOL_NAME>/attribute.aws_role/arn:aws:sts::<AWSアカウントID>:assumed-role/<Lambdaのロール名>"
```

6.サービスアカウントの認証情報ファイルをダウンロードする
ここまでで紐付けが完了したので、認証情報ファイルをダウンロードします。

```sh
$ gcloud iam workload-identity-pools create-cred-config \
"<POOL_NAME>/providers/<プロバイダー名>" \
--service-account="<プロジェクト名>@<サービスアカウント名>.iam.gserviceaccount.com" \
--output-file="<path/to/file.json>" \
--aws
```

ダウンロードしたファイルの中身を確認してみると分かりますが、キー情報が含まれていないファイルになっています。
これでこの認証情報ファイルとAWS側のロールを使って、BigQueryにアクセスする準備が整いました！


### Lambda側で認証情報ファイルを配置・実行確認
ここまでの手順で作成した認証情報ファイルをLambdaの実行環境に配置し、Lambda関数の環境変数に以下をセットしてください。

```sh
GOOGLE_APPLICATION_CREDENTIALS = "<path/to/file.json>"
```

![スクリーンショット 2022-01-16 19.13.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643279/e1a61992-fe31-0481-198d-89e84d1729e3.png)


Lambda側の設定はこれだけです。これでWorkload Identityによる連携が完了しました！

---

それでは実際に実行確認をしてみましょう。


Lambdaをテスト実行すると成功し、BigQueryのデータにアクセスできていることがわかります。![スクリーンショット 2022-01-16 19.16.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643279/fd6b3eac-8613-0679-58c6-6da341e6a0b3.png)


ちなみに、Lambdaにアタッチされているロールを剥がすとアクセスできなくなり、IAMロールでの連携がされていることが確認できます。![スクリーンショット 2022-01-16 19.21.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643279/e1f363e2-f724-bf18-8216-319346e8adaf.png)


# 最後に

Workload IdentityによってAWS側のIAMロールをGCPのサービスアカウントに紐づけてLambda->BigQueryのアクセスを確認できました。
キーレスで認証できるので、認証キーを作成・コピーする必要がなくなるのは嬉しいですね！

今回はCLIによって順番に操作を行なって行きましたが、次回はTerraformで構築も記事にしていこうかなと思います。


それでは今回はこれにて！