Workload Identity (AWS連携) で gcloud auth からコマンド実行までの流れをスクリプト化した話


## これは何?
gcloud authなどの認証から実行までの流れをスクリプトで実現するにはどのように実施するのかについて、特にgoogle-auth-libraryのAwsClientの使い方であまり参考となる資料が無かったため、自分なりに調べてスクリプト化までをした話になります。

## 環境構築
下準備として、AWS -> GCP リソースへのアクセスを許可する環境を構築します。
構築には、G-genさんのサイトで掲載されているサイトを参考に、環境を構築しました。
https://blog.g-gen.co.jp/entry/using-workload-identity-federation-with-aws


上記の方法で環境を構築することで

- Workload Identity 連携環境を使用して、Amazon EC2 から Service Accountの権限を借用(impersonate)してGCP上のリソースを操作できる
- Service Accountキーを発行せずに一時認証用トークンを使用してAWS連携できる

ようになりました。

上記のサイトではgcloud を使って、gcloud auth を実行してから、サービスアカウントで許可されたコマンドを実行しますが、勿論これはsh上で実行するものであります。
上記のgcloudのような作業を、Node.jsやPython上で実施する際、どのような手順で認証をして実行するのかを解説します。

また、今回の実行言語はNode.jsになります。

## 本題
gcloud auth は [AwsClient](https://cloud.google.com/nodejs/docs/reference/google-auth-library/latest/google-auth-library/awsclient)として実行することができます。

しかし、AwsClient を使用した記事がほとんど見られなかったため、今回記載しようと思った次第です。

アルゴリズムとしては、

1. AwsClientによって認証情報の取得
1. Service Account で許可したサービスクライアントを呼び出し
1. 参照や書き込みなどService Account で許可されたポリシーを実行

となります。

まず手始めに以下のようなスクリプト(綺麗ではないですが、、)を作成します。

```js:test.js
const { AwsClient } = require('google-auth-library');
const {Storage} = require('@google-cloud/storage');

const clientOptions = {
    /* 
        以下リンクでダウンロードしたJSONファイルを指定
        https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds?hl=ja
    */
  }

(async function () {

    const client = new AwsClient(clientOptions);

    const projectId = await client.getProjectId();

    const storageOptions = {
        projectId: projectId,
        authClient: client,
      };
    const storage = new Storage(storageOptions);

    console.log("----- get Buckets -----");
    const buckets = await storage.getBuckets()
    console.log(buckets);
})();
```

スクリプトを作成したら、以下のコマンドを実行します。
```bash
node test.js
```

上記のコマンドを実行することで以下のような結果になります。
一応作成したCloudStorageバケット「poc-test-aws-apps」を確認することができます。

```bash
----- get Buckets -----
[
  [
    Bucket {
      _events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: undefined,
      metadata: [Object],
      baseUrl: '/b',
      parent: [Storage],
      id: 'poc-test-aws-apps',
      createMethod: [Function: bound wrapper],
      methods: [Object],
      interceptors: [],
      projectId: undefined,
      name: 'poc-test-aws-apps',
      storage: [Storage],
      userProject: undefined,
      acl: [Acl],
      crc32cGenerator: [Function: CRC32C_DEFAULT_VALIDATOR_GENERATOR],
      iam: [Iam],
      getFilesStream: [Function (anonymous)],
      instanceRetryValue: true,
      instancePreconditionOpts: undefined,
      [Symbol(kCapture)]: false
    }
  ],
  { project: 'プロジェクト名' },
  { kind: 'storage#buckets', items: [ [Object] ] }
]
```


上記で gcloud auth のような認証から、コマンド実行までをスクリプト化することができました。


## 補足
ハマったこととしては、以下のキャプチャは [AwsClient](https://cloud.google.com/nodejs/docs/reference/google-auth-library/latest/google-auth-library/awsclient)の資料なのですが、最初は「使用できるMethodがretrieveSubjectTokenしかないのか！　getProjectIdとかないのか!」と焦ったのですが
AwsClient自体が[BaseExternalAccountClient](https://cloud.google.com/nodejs/docs/reference/google-auth-library/latest/google-auth-library/baseexternalaccountclient)を継承したクラスになるため、BaseExternalAccountClientの資料を見るときちんとgetProjectIdもあり、スクリプトにもあるように、呼び出すことができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/32c7676b-a9f5-4f89-00de-2ee57d62313c.png)

getProjectIdなどのメソッドやオプションの指定などは、継承元のBaseExternalAccountClientを参照するような資料の見方を実施した方が、より円滑に開発することができるかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/872532/c11a9c68-5afc-7564-5e3d-4fabae21c2d4.png)