AWS CLIの認証情報の優先順位を実際に試して理解する

この記事は、[リンクバルアドベントカレンダー2022](https://qiita.com/advent-calendar/2022/linkbal)のシリーズ2の3日目の記事です。
昨日の記事は、[目に見えない文字を悪用してサイトを好き放題荒らされた話
](https://qiita.com/laineus/items/2d168a57fdbf7cd7c9c3)です。

## はじめに
AWS CLIでは、AWSが決めた優先順位に基づいて、認証情報を利用します。

普段は優先順位を意識しなくても問題が起きることはあまりないと思います。しかし、優先順位の存在を認識していないと、まれに想定していない挙動に混乱するかもしれません。

ありそうなケースとしては、環境変数にアクセスキーが設定済みのECSやEC2でIAMロールの認証情報を利用しようとするが、優先順位の関係で環境変数の認証情報が利用される、などでしょうか。
※IAMロールをアタッチしているのに、環境変数にアクセスキーを設定するなという話ですが

ということで、優先順位の理解のために、実際に挙動を試してみましょう！


## AWS CLIの認証情報の優先順位
まず、優先順位は、以下のとおりです。

1. コマンドラインオプション
    - オプションの一覧はドキュメントをご覧ください
    - https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-options.html
1. 環境変数( `AWS_ACCESS_KEY_ID` と `AWS_SECRET_ACCESS_KEY` )
1. 認証情報ファイル( `~/.aws/credentials` )
1. 設定ファイル( `~/.aws/config`)
1. コンテナ認証情報（ECSのタスク定義にアタッチされたIAMロール）
1. Amazon EC2 インスタンスプロファイル（EC2インスタンスにアタッチされたIAMロール）

詳しくは、公式ドキュメントをご覧ください。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-precedence


## 実際に挙動を試す
どの設定を使っているかがわかる `aws configure list` コマンドで、確認します。

なお、認証情報元のAccountやArnを知りたい場合は `aws sts get-caller-identity` コマンドをどうぞ。

### 環境
```
$ aws --version
aws-cli/1.22.34 Python/3.10.6 Linux/5.15.0-1022-aws botocore/1.23.34

$ uname -a
Linux ip-xx-xx-xx-xx 5.15.0-1022-aws #26-Ubuntu SMP Thu Oct 13 12:59:25 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
```

### 共通条件
- IAMロールがアタッチされているEC2インスタンス上で実行
- 環境変数 `AWS_ACCESS_KEY_ID` と `AWS_SECRET_ACCESS_KEY` が設定済み


### `~/.aws/credentials` に `default` の記載なしの場合
- `~/.aws/credentials` の `default` にアクセスキーの記載なし
    - もちろん `~/.aws/config` にもアクセスキーの記載なし
- `~/.aws/credentials` の `hoge` profileにはアクセスキーの記載あり

#### 実行内容
```sh
$ echo $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY
XXXXXXXXXXX YYYYYYYYYYYYYYYYYYYYYY

# 無指定
# 環境変数が優先される（Typeがenv）
$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************XXXX              env
secret_key     ****************YYYY              env
    region           ap-northeast-1      config-file    ~/.aws/config

# コマンドラインオプションで --profile hoge を指定
# コマンドラインオプションは優先順位が最高
# そのため hoge profile の参照元の shared-credentials-file(~/.aws/credentials)が利用される
$ aws configure list --profile hoge
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                     hoge             manual  --profile
access_key     ****************CCCC shared-credentials-file
secret_key     ****************DDDD shared-credentials-file
    region           ap-northeast-1      config-file    ~/.aws/config

# AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYを空にする
# IAMロールより優先順位が高い認証情報がないため、IAMロールが利用される（Typeがiam-role）
$ AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************AAAA         iam-role
secret_key     ****************BBBB         iam-role
    region           ap-northeast-1      config-file    ~/.aws/config

# AWS_ACCESS_KEY_IDだけ空にする
# IAMロールより優先順位が高い認証情報がないため、IAMロールが利用される（Typeがiam-role）
# AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYを空にするのと結果は同じ
$ AWS_ACCESS_KEY_ID= aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************AAAA         iam-role
secret_key     ****************BBBB         iam-role
    region           ap-northeast-1      config-file    ~/.aws/config

# AWS_SECRET_ACCESS_KEYだけ空にする
# エラーになる
$ AWS_SECRET_ACCESS_KEY= aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None

Partial credentials found in env, missing: AWS_SECRET_ACCESS_KEY
```

### `~/.aws/credentials` に `default` の記載ありの場合
- `~/.aws/credentials` の `default` にアクセスキーの記載あり
- `~/.aws/credentials` の `hoge` profileにアクセスキーの記載あり

#### 実行内容
```sh
$ echo $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY
XXXXXXXXXXX YYYYYYYYYYYYYYYYYYYYYY

# 無指定
# 環境変数が利用される（Typeがenv）
$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************XXXX              env
secret_key     ****************YYYY              env
    region           ap-northeast-1      config-file    ~/.aws/config

# コマンドラインオプションで --profile hoge を指定
# コマンドラインオプションは優先順位が最高
# そのため hoge profile の参照元の shared-credentials-file(~/.aws/credentials)が利用される
$ aws configure list --profile hoge
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                     hoge             manual  --profile
access_key     ****************CCCC shared-credentials-file
secret_key     ****************DDDD shared-credentials-file
    region           ap-northeast-1      config-file    ~/.aws/config

# AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYを空にする
# 環境変数の次に優先順位が高いshared-credentials-fileのdefaultが利用される
# （Typeがshared-credentials-file）
$ AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************EEEE shared-credentials-file
secret_key     ****************FFFF shared-credentials-file
    region           ap-northeast-1      config-file    ~/.aws/config

# AWS_ACCESS_KEY_IDだけ空にする
# 環境変数の次に優先順位が高いshared-credentials-fileのdefaultが利用される
# （Typeがshared-credentials-file）
# AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYを空にするのと結果は同じ
$ AWS_ACCESS_KEY_ID= aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************EEEE shared-credentials-file
secret_key     ****************FFFF shared-credentials-file
    region           ap-northeast-1      config-file    ~/.aws/config

# AWS_SECRET_ACCESS_KEYだけ空にする
# エラーになる
$ AWS_SECRET_ACCESS_KEY= aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None

Partial credentials found in env, missing: AWS_SECRET_ACCESS_KEY
```

## おわりに（自分語り）
最初は、「環境変数にアクセスキーが設定済みのECSとEC2のAWS CLIでIAMロールの認証情報利用する」というタイトルで記事を書いていました。
しかし、内容は環境変数を空にしてコマンドを実行しているだけで、タイトル負けしていたので、タイトルを変えて内容を増やしました！

誰かのお役に立てば幸いです！