【AWS】【GCP】AWSとGCP間のキーなし認証を試みる(1) GCP→AWS

# 1. はじめに
AWSとGCP、マルチクラウド間の接続に悩まされたことはありませんか？

もしこのような業務要件を聞かれたときに、最初はAWS側のIAM Userでアクセスキーを発行して、それをGCP側に渡して、GCP側がこのアクセスキーのを使ってAWSのサービスを接続するということを思い浮かびませんか？

もちろんこのやり方ではできるですが、アクセスキーの漏洩リスクがあり、それでセキュリティの低下や、運用上の煩雑に繋がりそうなので、極力アクセスキーを発行しないかわりに、ロールを使うことはクラウドのベストプラクティスになります。

そこで、なんとGCPとAWS間は非常によいお友達であることを発見し、AWSのIAMロールでGCPとキーなし認証できます！

# 2. 早速ネタバレ
AWS側IAMのウェブアイデンティティで、GCP側のサービスアカウントを指定することできます。それで、GCP→AWSでは、AWSのIAM Roleを使って、STSでGCPへ接続することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/fb56bee3-67d1-9f50-f86a-6cf5fb3c57ac.png)

# 3. 構成図
では早速下記の構成図のように、GCP→AWS間で、IAM Role経由でSTS接続を行います！
- IAM側にIAM Roleを発行作成し、GCP側のService Accountと連携します。
- GCP側のService Accountを、Compute Engineと連携します。
- Compute Engineから、AWS Cliコマンドを使って、AWS側のS3を作成します。
![3 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/164f386c-981f-1b79-7cf3-61420fbefbb0.png)

# 4.GCP側構築
上記構成図を元に構築していきます。
1. Service Account作成
`サービスアカウントを作成`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/ac6faf08-1147-2361-d33c-59b9db68f851.png)

2. `サービスアカウント名`と`サービスアカウントID`を入力の上、`完了`を押下します。
![gcp_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/7c47f24e-9d07-865a-7678-fa0e2505d55b.png)

3. Compute Engineを作成し、作成時に上記作成したサービスアカウントを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/eb61b9bd-b968-e999-259a-f84c74d49223.png)

4. Compute Engine作成後に、下記のミドルウェア等をCompute Engine内にインストールしておきます。
```shell
$ sudo yum install -y python3-pip
$ sudo yum install unzip -y
$ curl -L -o gcp-to-aws.zip https://github.com/cevoaustralia/gcp-sa-to-aws-iam-role/archive/master.zip
$ unzip gcp-to-aws.zip
$ cd gcp-sa-to-aws-iam-role-master/gcp
$ sudo pip3 install -r requirements.txt
```
上記インストール完了後に、`aws --version`コマンドを叩いて、AWS Cliがインストールされたことを確認します。
```text
[xxxxxxxx@instance-1 gcp]$ aws --version
aws-cli/1.24.10 Python/3.6.8 Linux/3.10.0-1160.71.1.el7.x86_64 botocore/1.26.10
```
上記確認できていればOK。
5. Service Account画面に戻り、上記の作成したService Accountの`一意のID`をメモっておきます。
![gcp_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/86366991-d70f-1235-86fa-3c938de81809.png)

# 5.AWS側構築
1. `IAM`の作成画面に遷移し、`ウェブアイデンティティ`を選択の上、`アイデンティティプロパイダー`に`Google`を選択します。`Audience`に上記手順のService Accountの`一意のID`を入力します。
![截屏2022-08-22 22.06.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/d62dce78-ff5a-870b-4fa7-b76847f744f7.png)

2. 今回はS3を作成することをターゲットにしているため、`AmazonS3FullAccess`権限を付与します。
![截屏2022-08-22 22.10.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/2d1c772f-e3fb-bd54-d1fe-b5a55f9282ed.png)

3. ロール名を入力の上、作成しておきます。
![截屏2022-08-22 22.12.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/b9650690-8d47-f96e-4d58-c7c178098e74.png)

4. 作成後に、当IAMロールの`ARN`をメモっておきます。
![截屏2022-08-22 22.26.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/e5bd961f-1492-de2d-3258-584edb5e90e4.png)


# 6.GCP上のCompute Engineでの操作

１．ディレクトリ`~gcp-sa-to-aws-iam-role-master/gcp`に遷移していることを確認します。
```text
[xxxxxxxxx@instance-1 gcp]$ pwd
/home/xxxxxxxxxx/gcp-sa-to-aws-iam-role-master/gcp
```
もしほかのディレクトリ配下にいれば、`gcp-sa-to-aws-iam-role-master/gcp`に遷移してください。

２．`ll`コマンドを叩いて、`get_aws_creds.py`ファイルが存在していることを確認します。
```text
[xxxxxxxxx@instance-1 gcp]$ ll
total 8
-rwxr-xr-x. 1 xxxxxxx xxxxxxx  1400 Mar 30  2021 get_aws_creds.py
-rw-rw-r--. 1 xxxxxxx xxxxxxx    22 Mar 30  2021 requirements.txt
```
こちらの`get_aws_creds.py`ファイル中身を見てみると、AWS側のSTSトークンを取得してきて、それを最終的に`~/.aws/credentials`に格納しにいきます。AWS Cliは`~/.aws/credentials`に認証情報を取得してアクセスする動作になります。
```python
[xxxxxxxx@instance-1 gcp]$ cat get_aws_creds.py 
#!/usr/bin/env python3
#
# This code must run on a VM instance with a service account associated with it.
# The service account must be granted the 'Service Account Token Creator' IAM Role

import os
import sys
from os import path
import requests
import boto3

role = sys.argv[1]

# Set up the URL to request
SERVICE_ACCOUNT = os.getenv("SERVICE_ACCOUNT", "default")
BASE_URL = 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/'
AUDIENCE = 'potato'
FORMAT = 'full'
METADATA_HEADERS = { 'Metadata-Flavor': 'Google' }

# Construct a URL with the audience and format
url = BASE_URL + SERVICE_ACCOUNT + "/identity?audience=" + AUDIENCE + "&format=" + FORMAT

# Get the service token
r = requests.get(url, headers=METADATA_HEADERS)
token = r.text

# Turn the token into AWS credentials
sts = boto3.client('sts')
res = sts.assume_role_with_web_identity(
        RoleArn=role,
        WebIdentityToken=token,
        RoleSessionName='example')

creds = res['Credentials']

key = str(creds['AccessKeyId'])
secret = str(creds['SecretAccessKey'])
token = str(creds['SessionToken'])

output = "[default]\naws_access_key_id=%s\naws_secret_access_key=%s\naws_session_token=%s\n" % (key, secret, token)

try:
    os.mkdir(path.join(os.getenv('HOME'), '.aws'))
except:
    pass

with open(path.join(os.getenv('HOME'), '.aws', 'credentials'), 'w') as fp:
        print(output, file=fp)

```
出典：https://github.com/cevoaustralia/gcp-sa-to-aws-iam-role
※最初は自分でスクリプトを書こうと思ったら、すでにGithub上で私が書いたスクリプトより良さそうなものがあったので、それで今回そちらを使うことになりました。
なお、当スクリプトは一点不足しており、AWSリージョン情報を定義しておらず、興味のある方は`~/.aws/config`にリージョンを定義してください。

３．pythonシェルを実行
下記のように実行します。上記手順内でメモっていた`ARN`を後ろに代入してください。
```text
[xxxxxxxxx@instance-1 gcp]$ ./get_aws_creds.py arn:aws:iam::xxxxxxxxxxxx:role/aws-allow-gcp-access
```
上記実行後、`aws sts get-caller-identity`コマンドを叩くと、Assumeロールベース認証が確認できています。
```text
[xxxxxxxxxx@instance-1 gcp]$ aws sts get-caller-identity
{
    "UserId": "xxxxxxxxxxxxxx:example",
    "Account": "xxxxxxxxxx",
    "Arn": "arn:aws:sts::xxxxxxxxxx:assumed-role/aws-allow-gcp-access/example"
}
```
さらに、`~/.aws/credentials`認証情報をみると、STSトークンが発行されていることを確認できます。
```text
[xxxxxxxxxxx@instance-1 gcp]$ cat ~/.aws/credentials 
[default]
aws_access_key_id=ASIAXXXXXXXXXX6LNI6UI
aws_secret_access_key=nVW2D1J11+XXXXXXXXXXXXxeDIfSk2LTUgvbJ8U
aws_session_token=FwoGZXIvYXdzEA8aDCE1V5NUr2Ee6xDvJiLQAVeNoH8gU2vUxmRL7UNM8xvYvYsfuCg5bPgYQal1E/AM/7wNr9rzrzqV2j7lJ5BVY4mhqn0IuZ5jg5+ST208xyzHc/GK2yo+ZiismMYalF47tfCfERgC/7kh61+u0LaEhohfSLciwF0R59VZHZiQyy00saNPY9zQa8JLjdg4shpxL+xSY12dysEmXDJMKMAZYcIMLvZIf0pJ5JoKPnvc6BPgNU+nTB6MLHOU+g+a3A8f2TxmLP7CP4R4KiWoyWFJc7I0wSLNKiQrOKwogr+xikgol4eOmAYyWK6QH+VxXXXXXXXXXXXXXXXXXXXx4x6cLuOecFFBgnEY1e2H0Jqq5uWaJjjoKuwH8VRhIaw5yuAqnra+2flOwwMYwyugHc1w9ama+qJgP97EJC2MwmgK5I=
```
STSトークンであるため、下記のコマンドをもう一回叩くと、STSトークンが新しく発行されることを確認できますよ〜
```text
[xxxxxxxxx@instance-1 gcp]$ ./get_aws_creds.py arn:aws:iam::xxxxxxxxxxxx:role/aws-allow-gcp-access
[xxxxxxxxx@instance-1 gcp]$ cat ~/.aws/credentials 
[default]
aws_access_key_id=ASIAXXXXXXXXXXXXUTGNA
aws_secret_access_key=iOPfLGkRQrzFM4BXXXXXXXXXXXXxO2piRHHwpCwUX
aws_session_token=FwoGZXIvYXdzEA8aDP4YPD/LaisLZnoufiLQARoaMPZx7u4I46VtKIW0zk67iVteo61FAmSwMhSR53wtuMB3wNwev6PL4sz7bpMotuXv0ZlLx49OSX5TV3xApcIr+JbJim8KyA7sM+zx16lehlTi1bBlTIFYnYh46a4PqcOyCBBtYD/qNRoydTJOR/cHBb5Lv3pGbu6TUNVJoqEdtRx/ERVtcddLS3O6F3ejiVmRt3QNreog2hJSDOZTdmJq53kO5IbxjW8gH2aNsK/JxNbsXD/yregYnspCTNHi7EyBHkpOLiFPWEMW9ib1SIEo+I+OmAYyWAfKVxXXXXXXXXXXXXXXXXXXXx4rYGYshuellrsC4puSmw3VFonPc06E3Oz0VvtaB+Bnk9rejj7cFmt6dRyXXd6sLbW485EPzGHrTibHUek9+6mjAFYk=
```

# 7. S3を作成してみます
AWSのIAM RoleにS3FullAccessの権限を付与したため、S3を作成することができると予想されます。
```text
[xxxxxxxxx@instance-1 gcp]$ aws s3 mb s3://sdfhskgshkdfhkw48XXXX
make_bucket: sdfhskgshkdfhkw48XXXX
[xxxxxxxxx@instance-1 gcp]$ aws s3 ls
2022-08-22 13:45:56 sdfhskgshkdfhkw48XXXX
```
上記のように、S3が作られたことを確認できました。

# 8. STSトークンのセッション時間について
デフォルトは一時間になっていますが、AWS側のIAMロールのところで、セッション時間を最大12時間まで指定することができます。
![截屏2022-08-22 22.49.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/636f8432-589b-66db-4a06-6525302931e7.png)

# 9. AWSとGCP間の通信
もしAWSとGCP間のパブリック通信を懸念している方がいたら、GCPとAWS間に専用線とかのルーティングを設定して、AWSのSTS用VPC Endpointsにルーティングできれば良いです。

https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_sts_vpce.html

# 10. 参考資料
１．キーなしの API 認証 - サービス アカウント キーを必要としない Workload Identity 連携によるクラウド セキュリティの向上

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

２．AWS IAM Role を GCP から STS 認証で利用する設定例

https://www.qoosky.io/techs/30f7c61cfa

３．GCP Service Account を AWS から STS 認証で利用する設定例

https://www.qoosky.io/techs/fb1efc43bf

４．gcp-sa-to-aws-iam-role

https://github.com/cevoaustralia/gcp-sa-to-aws-iam-role/archive/master.zip