aws-cli-oidcで一時的なAWSアクセスキーを使う

昨年のAdvent Calendarで書きました「[KeycloakのToken Exchangeを活用した一時的なAWSアクセスキーの発行](https://qiita.com/wadahiro/items/ff0f45b474001f515705) 」の続編ネタです。この中で紹介した **[aws-cli-oidc](https://github.com/openstandia/aws-cli-oidc)** というCLIツールの便利な使い方を紹介します。

# `aws-cli-oidc`とは

AWS管理コンソールへのログインを、Keycloakなどの外部IdPとSAMLまたはOIDCで連携させている場合に、`aws-cli` などのAWS向け各種CLIツールで利用可能な一時的なアクセスキーを取得してくれるちょっとしたCLIツールです。このツールの目的や説明は[昨年の記事](https://qiita.com/wadahiro/items/ff0f45b474001f515705)を読んでいただければと思いますが、この手の他のツールと異なり、利用者のクレデンシャルを本ツールに渡さずにアクセスキーを発行できるところがポイントです。AWSと外部IdP間のフェデレーションには、OIDCまたはSAML 2.0が利用できますがその両方に対応しています(ただし、SAMLの場合は外部IdPがToken Exchangeに対応している必要があります)。
下図は両パターンのフローを表したものです。AWS STSに対してOIDCのIDトークンまたはSAML Assertionを含むSAML Responseを送ると、一時的なアクセスキーを返してくれるためこれを利用しています。

## OIDCの場合
![aws-cli-oidcのフロー(OIDCの場合)](https://github.com/openstandia/aws-cli-oidc/blob/master/flow-with-oidc.png?raw=true "OIDCの場合")

## SAML 2.0の場合
![aws-cli-oidcのフロー(SAML 2.0の場合)](https://github.com/openstandia/aws-cli-oidc/blob/master/flow-with-saml2.png?raw=true "SAML 2.0の場合")


# 使い方

## 前提

* 外部IdP - AWS間のフェデレーションが設定されている必要があります。
* 外部IdP - `aws-cli-oidc` 間のフェデレーションが設定されている必要があります。

設定方法はお使いの外部IdPに依存するため本記事では割愛します。Keycloak用の設定については別途紹介したと思います。

## インストール

`aws-cli-oidc`の[リリースページ](https://github.com/openstandia/aws-cli-oidc/releases)よりプラットフォームに合ったバイナリをダウンロードし、解凍して実行ファイルを配置するだけです。

## セットアップ

`aws-cli-oidc setup`コマンドを実行すると、インタラクティブに設定が可能です。以下、セットアップ実行例です。

```bash
$ aws-cli-oidc setup
Using config file: /Users/wadahiro/.aws-cli-oidc/config.yaml
OIDC provider name:
Enter a value: IdP名
 
OIDC provider metadata URL (https://your-oidc-provider/.well-known/openid-configuration):
Enter a value: https://your-idp.example.com/auth/realms/example/.well-known/openid-configuration
 
Additional query for OIDC authentication request (Default: none):
Enter a value:
 
Successful redirect URL (Default: none):
Enter a value:
 
Failure redirect URL (Default: none):
Enter a value:
 
Client ID which is registered in the OIDC provider:
Enter a value: aws-cli
 
Client secret which is registered in the OIDC provider (Default: none):
Enter a value:
 
Choose type of AWS federation [oidc/saml2]:
Enter a value: saml2
 
The max session duration, in seconds, of the role session [900-43200] (Default: 3600):
Enter a value (Default is 3600): 43200
 
The default IAM Role ARN when you have multiple roles, as arn:aws:iam::<account-id>:role/<role-name> (Default: none):
Enter a value: arn:aws:iam::123456789012:role/developer
 
Select the subject token type to exchange for SAML2 assertion:
1. Access Token (urn:ietf:params:oauth:token-type:access_token)
2. ID Token (urn:ietf:params:oauth:token-type:id_token)
 
Enter a value: 1
 
Audience for token exchange:
Enter a value: urn:amazon:webservices
 
Saved /Users/wadahiro/.aws-cli-oidc/config.yaml
```

`$HOME/.aws-cli-oidc/config.yaml`として設定は保存されますので、今後何か変更する際はこのファイルを修正すればOKです。


## 使い方(Basic)

`aws-cli-oidc get-cred -p <IdP名>`コマンドを実行するとブラウザが起動し、指定したIdPの認証を経て(ここでクレデンシャルの入力となるので、ツールにはクレデンシャルが渡りません)、一時的なAWSアクセスキーが標準出力でコンソールに出力されます(Linux、Macなら`export`、Windowsなら`set`付きで)。後はこれをコピペして環境変数に設定すれば、`aws-cli`コマンドが使える、というものです。もちろん、世の中にある他のAWS用のCLIツールも使うことができます。

```bash
aws-cli-oidc get-cred -p myop
Using config file: /home/wadahiro/.aws-cli-oidc/config.yaml
Login successful!
Selected role: arn:aws:iam::123456789012:role/developer
PrincipalARN: arn:aws:iam::123456789012:saml-provider/myop
RoleARN: arn:aws:iam::123456789012:role/developer

export AWS_ACCESS_KEY_ID=ASIAT......
export AWS_SECRET_ACCESS_KEY=9bkS0whPelMYQ.......
export AWS_SESSION_TOKEN=FQoGZXIvYXdzENz.......
```

また、`pbcopy`のようなクリップボードコピーのCLIコマンドと組み合わせれば `aws-cli-oidc get-cred -p myop | pbcopy` のように実行することで一気にクリップボードにコピーすることも可能です(最後の環境変数設定用出力の部分だけが標準出力になっています)。


## 使い方(Advanced)

2ヶ月ほど前にリリースした [v0.6.0](https://github.com/openstandia/aws-cli-oidc/releases/tag/v0.6.0)では、[credential_process](https://docs.aws.amazon.com/sdkref/latest/guide/setting-global-credential_process.html)に対応しました :tada:

`credential_process`を使うと、`aws-cli`などのCLIツールが参照する`$HOME/.aws/config`ファイルの中に外部プログラム呼び出しを記述することで、`aws-cli-oidc`などの外部のCLIツールから直接一時アクセスキーを渡すことができます。**つまり、一々コピペして環境変数に設定する、という作業は不要になるわけです**。

### 設定例

`$HOME/.aws/config`ファイルに以下のようにプロファイルを設定しておきます。

```
[profile developer]
output=json
region=ap-northeast-1
credential_process=aws-cli-oidc get-cred -p myop -r arn:aws:iam::123456789012:role/developer -j -s -d 43200
```

各オプションの説明を補足しておきます。

* `-r`: `aws-cli-oidc`でどのIAMロールとして一時アクセスキーを取得するか、IAMロールを指定します。
* `-j`: `credential_process`に対応したJSONデータとして一時アクセスキーを標準出力に出力するようになります。
* `-s`: 一度得た一時アクセスキーをOSのシークレットストアに保存するモードになります。`-s`をつけないと、例えば`aws-cli`のコマンドを実行するたびに`credential_process`が評価される動きになるため、毎回認証が必要になりかえって使いづらくなります。そこで`-s`オプションで、一時アクセスキーが有効な間はOSの安全な領域にキャッシュするようにします。
* `-d`: 要求する一時アクセスキーの有効期限(秒)を指定します。ただし、IAMロール側で制限されている場合はその期限を超えて要求はできません。

これで、あとはプロファイルを切り替えて`aws-cli`などのCLIツールを実行するだけです！プロファイルの切り替えは色々方法がありますが、例えば`export AWS_PROFILE=developer`のように環境変数でプロファイル名を指定します。その後`aws sts get-caller-identity`を実行し、想定したIAMロールでアクセス可能か確認することができます(この時、ブラウザが起動してお使いのIdPに対して認証が要求されます)。

```
$ aws sts get-caller-identity
{
    "UserId": "AROA4P2G6HA6APGGSL2BG:foo@example.com",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/developer/foo@example.com"
}
```

### スイッチロールも簡単！

`credential_process`を使うと、スイッチロールも簡単にできるようになります。先程の設定例の`developer`プロファイルから、`admin`プロファイルにスイッチロールする場合、以下のように`$HOME/.aws/config`ファイルに書いておきます。スイッチロール先のプロファイルの定義に`source_profile=developer`と書くだけです。

```
[profile developer]
output=json
region=ap-northeast-1
credential_process=aws-cli-oidc get-cred -p myop -r arn:aws:iam::123456789012:role/developer -j -s -d 43200

[profile admin]
output=json
region=ap-northeast-1
role_arn=arn:aws:iam::123456789012:role/admin
source_profile=developer
```

後は`admin`プロファイルに切り替えるだけです。これで自動的にスイッチロールが行われて各種CLIツールが使えます。以下のように、`aws sts get-caller-identity`でスイッチロールがうまくできているか確認することができます。

```
$ export AWS_PROFILE=admin
$ aws sts get-caller-identity
{
    "UserId": "AROAIY7G3JPSAU5P2AI1E:botocore-session-1638348595",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/admin/botocore-session-1638348595"
}
```

# まとめ

というわけで [NRI OpenStandia Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nri-openstandia) の2日目の記事として、`aws-cli-oidc`について紹介しました。`credential_process`を利用した使い方にすると、たまにブラウザで認証が求められはしますが、一時的なアクセスキーの存在を忘れて各種CLIツールを利用することができるようになりオススメです。AWSとフェデレーション済みの外部IdPがある方は是非試してみてください。