saml2aws代替案(GoogleアカウントでOIDC federation)

## はじめに
株式会社インティメート・マージャーのy_kannoです。

弊社ではメインクラウドとしてGCPを利用していますが、
一部のシステムにてAWSを利用しています。

AWSの運用にあたってCLIでのアクセスが必要な際は

- Google workspaceで管理しているGoogleアカウントから
- [saml2aws](https://github.com/Versent/saml2aws)を利用してassume role

を行っているのですが、以下の問題がありました。

- 2段階認証に関する不安定性
    - 筆者のローカル端末では、TOTPやプッシュ通知による認証が成功する日もあれば失敗する日もある
    - Google側の変更に対し、saml2awsが追随できていない[可能性が考えられる](https://github.com/Versent/saml2aws/issues/1259)
- 運用手順の煩雑さ
    - 問題を回避するために[ブラウザモード]((https://github.com/Versent/saml2aws/issues/1259#issuecomment-2092996653))で運用しているが、ログイン手順がCLIで完結せず手間がかかる

これらの課題を踏まえ、代替ソリューションに何かないかと考えている状態でした。

## 代替案

色々調べてみたところ
- Google Compute EngineのVMに紐付いたサービスアカウント

をベースにAWS CLIからAWS STSを叩いて一時的なcredentialsを取得する方法がありました。

https://aws.amazon.com/jp/blogs/security/access-aws-using-a-google-cloud-platform-native-workload-identity/

リンク先の方法はGCE VMとサービスアカウントを前提としていますが、
弊社ではGoogleアカウントによるAWS CLI操作を必要としていました。
この記事では、Googleアカウントベースの方法を共有します。

※ 動作のおおまかな仕組み自体はリンク先に記載されている通りです。
この記事で実行する内容としては下記の図（いずれもリンク先より引用）において
![スクリーンショット 2024-12-06 17.02.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158500/b8675ff8-91b8-dc5f-3817-ae27666f7466.png)
`1: Get Instance's identity token -> 1: Google account's identity token`

![スクリーンショット 2024-12-06 17.05.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158500/f57b6f7b-8b51-3985-e0c3-699dd18328b0.png)
`Google Cloud IAM(ServiceAccount) -> Google Account`
へ置き換えるイメージになります。

## 権限設定の手順

### 初期設定 - CLI実行マシン側

- assume roleしたいAWS IAMロールが存在する前提です
- gcloud CLIをインストールしておき
hoge.fuga@example.com (対象のgoogleアカウント)で実行できるように設定します
- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html), jq, curlをインストールしておきます

- 以下のscriptを適当なディレクトリ(ここでは`/opt/credentials.sh`)に追加します
※ `<YOUR_AWS_ACCOUNT_ID>`をassume roleしたい対象のAWSアカウント
`<YOUR_TARGET_IAM_ROLE>`をassume roleしたい対象のAWS IAMロール名 に置き換えておきます
```bash
#!/bin/bash

ROLE_ARN="arn:aws:iam::<YOUR_AWS_ACCOUNT_ID>:role/<YOUR_TARGET_IAM_ROLE>"

jwt_token=$(gcloud auth print-identity-token)
jwt_sub=$(jq -R 'split(".") | .[1] | @base64d | fromjson' <<< "$jwt_token" | jq -r '.sub')

credentials=$(aws sts assume-role-with-web-identity --role-arn $ROLE_ARN --role-session-name $jwt_sub --web-identity-token $jwt_token | jq '.Credentials' )

export AWS_ACCESS_KEY_ID=$(echo "$credentials" | jq -r '.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo "$credentials" | jq -r '.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo "$credentials" | jq -r '.SessionToken')
```


### 初期設定 - AWS側

- 以下コマンドを実行して
```bash
gcloud auth print-identity-token
```
出力されたJWTトークンを https://jwt.io/ でdecodeします。
- decodeされた`PAYLOAD: DATA`から `azp, aud, sub` の値をコピーしておきます

コピーした値を元にassumeする対象のAWS IAMロールの信頼関係ポリシーに、
以下の通り記載します。
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "accounts.google.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "accounts.google.com:oaud": "<aud-value>",
                    "accounts.google.com:sub": [
                        "<sub-value>"
                    ],
                    "accounts.google.com:aud": "<azp-value>",
                }
            }
        }
    ]
}
```

※ 同一ドメインで信頼するGoogleアカウントを追加する際は
`accounts.google.com:sub` に値を追加することで対応可能です


ここまで実施すれば初期設定は完了です!

### 運用時の権限設定
CLIにて対象のGoogleアカウントに切り替えてから

- `source /opt/credentials.sh` を実行します
`aws sts get-caller-identity` を実行して以下のように出力されればassume role成功です

```json
{
   "UserId":"AIDACKCEVSQ6C2EXAMPLE:[Identity subject claim]",
   "Account":"<YOUR_AWS_ACCOUNT_ID>",
   "Arn":"arn:aws:iam::<YOUR_AWS_ACCOUNT_ID>:role/YOUR_TARGET_IAM_ROLE:[Identity subject claim]"
}

```

## まとめ
Googleアカウントベースによるsaml2awsの運用に困っていたので、
代替案として
- GoogleアカウントのJWTトークンによる
- AWS CLIでのassume role実行

について手順をまとめてみました。

saml2awsはサードパーティ製の非常に便利なツールですが、
- プラットフォーム側の都合に伴って一時的に使えなくなる可能性
- 運用にあたっての代替案

を考えておくのが重要だな、と記事を書いて改めて感じた次第です。

不明な点がありましたら、随時コメントなど頂けますと幸いです。

## おわりに

まだまだアドベントカレンダーは続きますのでお楽しみに！

https://qiita.com/advent-calendar/2024/intimatemerger

また、インティメート・マージャーでは、新卒から中途採用まで幅広く採用募集中です！
記事を読んで弊社に興味をお持ちいただけた方は、採用情報もあわせてご確認ください！

https://recruit.intimatemerger.com/