aws-vaultを布教したい

[aws-vault](https://github.com/99designs/aws-vault) の印象ってどうですか？
クレデンシャルを平文で保管しなくても良くなるらしいけどめんどくさそう、あえて導入する必要もなさそう、そんなテキトーな理由で私は敬遠していました。

でも、ちゃんと使ってみたら最高に推せるツールでした。
これは布教したいと思ったので、3つのポイントで紹介します。

**業務で数年AWSに携わっていても、知らない便利機能だったので、ぜひ！**

# 推しポイント

## 1つ目 デメリットがない
私のローカル環境は[Oh My Zsh](https://ohmyz.sh/) や[awsp](https://github.com/johnnyopao/awsp) を用いて、AWSのプロファイルを設定していました。
この利便性が失われると想像していましたが、**aws-vaultとOh My Zshとawspは全然共存できます**。

一番シンプルな設定としては、**クレデンシャルの平文管理を辞めるだけ**です。

profile設定しているconfigで`credential_process`を記述します。

```.aws/config
[profile hoge-system]
region = ap-northeast-1
output = json
credential_process = aws-vault export --format=json hoge-system --no-session
```

その後、add実行でキーを保存します。

```
$ aws-vault add hoge-system
```

これで、ローカルの`.aws/credentials`は不要になります。
`aws-vault export --format=json hoge-system --no-session`によって、キーチェーンからアクセスキーとシークレットキーが出力されます。

**`--no-session`** がポイントです。
有りと無しでコマンド実行してみて下さい、一目瞭然です。

ただ、これではaws-vaultの一時的な認証情報を用いるっていうメリットも消えています。
キーチェーンで平文管理を回避出来ているだけです。

それで十分な気もしますが、基本的には、`--no-session`無しのが望ましいでしょうね。

ここで注意ですが、
`--no-session`では基本的に`GetSessionToken`が使われるはずで、そこに制限があります。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_mfa_configure-api-require.html

> GetSessionTokenリクエストによる一時的な認証情報で IAM および AWS STS API にアクセスできるのは、認証情報のリクエストに MFA 情報を含めた場合のみである点に注意してください。GetSessionToken によって返される一時的な認証情報には MFA 情報が含まれているので、認証情報によって実行される各 API オペレーションで MFA を確認できます。

つまり、**`--no-session`無しでは、MFAの登録が必須**と捉えても良いです。
IAMが実行できないと結構厳しいですからね。

```.aws/config
[profile hoge-system]
...
mfa_serial = arn:aws:iam::XX:mfa/XX
```

MFA有効化せずリソースを操作出来ている事自体、本来良くないと思うので、ギリギリデメリットと捉えないことにしましょう。

このように、`--no-session`で簡素化か、MFA登録した`--no-session`無しのどちらかの状況で、`awsp`を実行すれば、今まで通りです。

パスワード入力が一度必要とか、セッションとかキーチェーンのタイムアウトとかありそうですが、私はあまり気になっていません。

タイムアウト延ばせる方法もあるので、気になってから調べればOKだと思います。

また、**aws-vaultだけでawsp相当の使用感**も可能です。

そのためには、Oh My Zsh の[aws-vaultプラグイン](https://github.com/blimmer/zsh-aws-vault)も併せて用いると良いです。
設定は基本README通りで大丈夫です。

具体的な使用感について紹介します。

### 一度profileを設定すれば、余分なコマンド付与は要らない

awspでprofileを設定して、その後terraformコマンドを実行するケースも多いのではないでしょうか？
何回か実行するので、その都度余分なコマンドを付与するのはめんどくさいですよね。
これを普通にaws-vaultだけで出来ます。

```
# aws-vault exec hoge-system
Starting subshell /bin/zsh, use `exit` to exit the subshell
# 
# aws ...
# terraform ...
```

※先ほど同様、`--no-session`ｍを必要に応じて設定して下さい。

`exec`に対して引数を入力せずに実行するとサブシェルになって、profile(credential)が引き継がれます。
その後はawsコマンドでも、**terraformコマンドでもそのまま実行して問題なし**です。

### Oh My ZshでAWSプロファイル名を表示

複数のAWSプロファイルを用いる方でしたら、CLI上でどのプロファイルが設定されているか確認したいですよね。
これも出来ます。

先ほどのプラグイン機能でも、`prompt_aws_vault_segment`関数が用意されています。

[実際のコード](https://github.com/blimmer/zsh-aws-vault/blob/main/zsh-aws-vault.plugin.zsh)を確認すると、aws-vaultが使う環境変数を見やすいように処理しています。
関数使わなくても、$AWS_VAULT変数にプロファイル名が入るので、それを良い感じに表示させたらOKです。

![スクリーンショット 2025-06-18 0.36.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990358/6e2329d7-acd6-463b-bbac-b1b6925b04b9.png)

こんな感じで、私の環境ではプロファイル名を表示しています。

## 2つ目 マネージメントコンソールへのログインが簡単

これ超便利です。

```
# aws-vault login hoge-system
```

これだけです。デフォルトのブラウザでマネコンが立ち上がります。
**IAMユーザ名やパスワードの入力は必要ありません**。

この応用的な方法もあります。

### ブラウザの別プロファイルでマネコンにログイン

Oh My Zsh のaws-vaultプラグインの機能です。

```
# avli hoge-system
```

これだけで、好きなだけAWSにログインしたマネコンのブラウザが立ち上がります。
ブラウザにおいて別プロファイルなので影響し合うことが無く、**ログアウトする必要もありません**。

システム開発中で別システムの設定を参考したい時とかに、超超役立ちます。

使い心地の良い自作スクリプトを作るのは大変ですし、
もう、この2つ目だけで、十分aws-vaultのメリットがあると個人的に思います。

## 3つ目 スイッチロールが良い感じ

踏み台のAWSアカウントから、複数システムのアカウントへスイッチロールして操作する管理方法を採用していることもあると思います。

通常は困らないのですが、terraformコマンドをそのまま実行したい時とか、微妙に使い勝手が良くないんですよね。

それをaws-valutは良い感じにラップしてくれます。

```.aws/config
[profile bastion-system]
region = ap-northeast-1
output = json
mfa_serial = arn:aws:iam::XX:mfa/XX
[profile hoge-system]
region = ap-northeast-1
output = json
role_arn = arn:aws:iam::YY:role/YY-role
source_profile = bastion-system
```

```
# aws-vault exec hoge-system  // スイッチ先
Enter MFA code for arn:aws:iam::XX:mfa/XX:
Starting subshell /bin/zsh, use `exit` to exit the subshell
# 
# aws ...
# terraform ...
```

スイッチロール用の普通な`config`と`aws-vault exec`で完結します。
このサブシェルの中で、awsコマンドでも、terraformコマンドでもそのまま実行すればOKです。

また、次の方法も超便利です。

### aws-vault login でスイッチ先アカウントのマネコンにもログインできる

```
# avli hoge-system  // スイッチ先
```

これで良いんです。
マッハじゃないですか？

アカウントID、IAMロール名、表示名とか入力する、あの**ロールの切り替え画面を操作せず、マネコンにログインできる**んです。

<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3990358/b97ed3ad-d33f-464f-b271-370901b147b8.png">

**こいつが要らないんです**。

この快適さがあれば、踏み台AWSアカウント内だけでIAMユーザーやMFAを管理して、その他のシステムは全部スイッチロールで〜なんて運用ルールも余裕でいけると思います。

運用負荷的に爆アドです。

-----

以上、aws-vaultの推しポイント紹介でした。

`--no-session`やMFAのくだりをトラブルシュートするのが結構たいへんでしたが、良いツールだと思います。

少しでも参考になれば幸いです。

# オマケ

微妙にaws-vaultでうまく行かないケースについて整理してみました。

### aws-vault login出来ない場合
IAMポリシーやコマンド実行条件によってaws-vault login出来ない場合もありました。

サブシェルで実行した場合：

マネコンへのログインは一時的な認証情報(`GetFederationToken`)を用います。

これが一時的な認証情報である`GetSessionToken`状態だと失敗します。

```
# aws-vault exec hoge-system
Starting subshell /bin/zsh, use `exit` to exit the subshell
#
# avli 
aws-vault: error: login: operation error STS: GetFederationToken, https response error StatusCode: 403, RequestID: XX, api error AccessDenied: Cannot call GetFederationToken with session credentials
Could not login
```

公式ドキュメントにもそれっぽい記載があります。

https://docs.aws.amazon.com/ja_jp/STS/latest/APIReference/API_GetFederationToken.html

> You must call the GetFederationToken operation using the long-term security credentials of an IAM user.

`--no-session`で実行すれば、長期的な認証情報(アクセスキーやシークレットキー)になるので解決します。
ちょっと力技ですけどね。

```
# aws-vault exec hoge-system --no-session
Starting subshell /bin/zsh, use `exit` to exit the subshell
#
# avli
#
```

もしくは、親シェルで実行しても問題ないです。
`--no-session`無しなので一時認証情報な気がしますが、何故か問題なく成功します。
ここの仕様は判明できていません。

```
# aws-vault login hoge-system  // avlやavliでもOK
```

サブシェルで実行出来る場合：

逆にサブシェルで実行出来る場合もあります。

これは先程のスイッチロールした時に該当します。

```
# aws-vault exec hoge-system  // スイッチ先
Starting subshell /bin/zsh, use `exit` to exit the subshell
# avli  // OK
#
# aws-vault list
Profile                  Credentials              Sessions                    
=======                  ===========              ========     
bastion-system           bastion-system           sts.GetSessionToken:XXmYYs 
hoge-system              -                        sts.AssumeRole:XXmYYs   
```

スイッチロール先であるhoge-systemにおいては、`GetSessionToken`ではなく、`AssumeRole`で権限を持っているので、`GetFederationToken`も可能という仕様のはずです。

※なお、スイッチ元のcredentialをローカルに平文で持たない時(キーチェーンにある時)は、スイッチ先のSessions欄が`AssumeRole`でなく`-`表示になりました。`AssumeRole`しているはずですし、login操作は問題なさそうでしたが、仕様不明です。スミマセン。

IAMポリシーが原因の場合：

セキュリティ確保のために、IAMポリシーでMFA強制させている場合もあると思います。

この場合、login操作はエラーになります。

```
...
Token on resource: arn:aws:sts:: ... with an explicit deny
```

明示的な拒否エラー。

これは`GetFederationToken`のMFAサポートが不可なことに起因しているはずです。
MFA強制のポリシーを通らないので、拒否されます。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_sts-comparison.html

> MFA サポート 不可

抜け道的な対策かもしれませんが、これも`AssumeRole`で対応出来ます。

MFAはスイッチ元で確認(長期的な認証情報や`GetSessionToken`はMFAサポート可能)→スイッチ先ではMFA状態を確認する必要ないので、IAMポリシーでMFA強制させない→スイッチ先では`GetFederationToken`可能 といった感じです。

本質的な対策になっているかは、微妙かもです。