aws-vaultでcliとterraformをいい感じにしてみる

2023.07.25

はじめに

データアナリティクス事業本部のkobayashiです。

最近入社以来使用していた愛機のMacBookProの入れ替えを行いました。開発環境の引っ越しは中々面倒ですがいい機会なので冗長になっていた設定だったりセキュアでない設定を見直すことにしました。その中でawsへの認証情報を管理してくれているツールでaws-vaultがありますが、この度aws-vaultの設定を見直したところ非常に使い勝手が良くなったのでまとめます。

GitHub - 99designs/aws-vault: A vault for securely storing and accessing AWS credentials in development environments

aws-vaultとは

aws cliやプログラムからAWSの認証情報を使う際にはaws configureを実行し、アクセスキーとシークレットキーを入力して~/.aws/credentialsにそれらの値を平文で保存して使うことになります。平文で保存されているので、~/.aws/credentialsを見れば簡単にアクセスキーとシークレットキーを見ることができてしまいます。そこでaws-vaultを使うことでアクセスキーとシークレットキーをOSのキーストアに保存し、認証情報が必要な場面において一時的な認証情報を取得してaws cliやプログラムから使うことができます。

詳しくは当ブログに導入から丁寧に説明してある記事がありますのでそちらをご一読ください。

AWS CLIをaws-vaultの認証情報で実行する

AWS CLIでサポートされているcredential_processでは外部プロセスから資格情報を取得しAWS CLIの実行時に使うことができます。 今回行ってみるのはこのcredential_processを使用して外部プロセスとしてaws-vaultから直接認証情報を取得することにより

aws-vault exec myrole1 -- aws sts get-caller-identity

のようにaws-vault execの引数でawsコマンドを指定するのではなく

aws sts get-caller-identity --profile myrole1

のような形でAWS CLIのコマンドをそのまま使った形で実行することができるように設定します。

またMFAが設定されたスイッチ元のアカウントから複数のAWSアカウントへのスイッチロールを行う場合、通常それぞれのAWSアカウントごとにMFAコードの入力が必要になります。しかし、aws-vaultのセッションキャッシュ機能を利用することで、stsのセッションが切れるまでMFAコードを一度だけ入力すればよくなります。

まとめると以下を行うことが目的です。

  • credential_processを使ってaws-vault exec myrole1 -- aws sts get-caller-identityではなくaws sts --profile myrole1 get-caller-identityで実行できるようにする
  • stsのセッションが切れるまではスイッチロールしても初回だけしかMFAコードを聞かれないようにする

環境

  • aws-vault: v7.2.0
  • aws-cli: 2.12.3

設定

では早速設定を行っていきますが、当ブログエントリのAWS Vaultで端末内のAWSアクセスキー平文保存をやめてみた | DevelopersIO の下記設定をもとにして設定を変更していきます。

$ cat ~/.aws/config
[profile classmethod]

[profile common]
source_profile = classmethod
region=ap-northeast-1
output=json
mfa_serial=arn:aws:iam::123456789012:mfa/<IAMユーザ名>
role_session_name=<IAMユーザ名>

[profile myrole1]
include_profile=common
role_arn=arn:aws:iam::999999999999:role/<ロール名>

[profile myrole2]
include_profile=common
role_arn=arn:aws:iam::888888888888:role/<ロール名>

この設定はaws-vaultclassmethodというプロファイル名でアクセスキーとシークレットキーを登録し、スイッチ元の設定をcommonプロファイルに設定した上でスイッチ先をmyrole1myrole2として呼び出す設定でした。

この設定を以下のように変更します。

  • スイッチ元のプロファイル設定をアクセスキーとシークレットキーを登録してあるclassmethodに設定する
  • commonプロファイルにcredential_processを追加してaws-vaultの認証情報を受け取る
    • --duration 12hでセッションの継続時間を最大の12時間に設定
  • スイッチ元のプロファイルのinclude_profilesource_profileに変更する
    • include_profileaws-vault独自の値なのでrole_session_name,region,outputをそれぞれのプロファイルに設定する

設定変更後は下記の内容になります。

[profile classmethod]
mfa_serial=arn:aws:iam::123456789012:mfa/<IAMユーザ名>
region=ap-northeast-1
output=json

[profile common]
credential_process=aws-vault --prompt terminal export classmethod --duration 12h --format=json

[profile myrole1]
source_profile=common
role_arn=arn:aws:iam::999999999999:role/<ロール名>
role_session_name=<ロールセッション名>
region=ap-northeast-1
output=json

[profile myrole2]
source_profile=common
role_arn=arn:aws:iam::888888888888:role/<ロール名>
role_session_name=<ロールセッション名>
region=ap-northeast-1
output=json

これで設定は終わりなので実際のコマンドを使って試してみます。

直接AWSコマンドを実行してみる

はじめにmyrole1にAWSコマンドを実行してみますが念のためaws-vault clearでセッションをクリアしておきます。

$aws-vault clear

myrole1にAWSコマンドを実行してみるとMFAコードを聞かれ、入力すると以下のようにロールの一時的な認証情報を利用してコマンドを実行することができます。

$aws --profile myrole1 sts get-caller-identity
Enter MFA code for arn:aws:iam::123456789012:mfa/<IAMユーザ名>: 123456
{
    "UserId": "AROA2YA6CJSXXXXXXXXXX:<ロールセッション名>",
    "Account": "999999999999",
    "Arn": "arn:aws:sts::999999999999:assumed-role/<ロール名>/<ロールセッション名>"
}

次にmyrole2にAWSコマンドを実行してみると今度はMFAコードを聞かれずロールの一時的な認証情報を利用してコマンドを実行することができます。

$aws --profile myrole2 sts get-caller-identity
{
    "UserId": "AROATCX6VEHXXXXXXXXXX:<ロールセッション名>",
    "Account": "888888888888",
    "Arn": "arn:aws:sts::888888888888:assumed-role/<ロール名>/<ロールセッション名>"
}

このようにAWSコマンドを直接利用できるのとMFA資格情報をキャッシュできるようになったことがわかります。

またaws-vaultコマンドを使ってAWSコマンドを実行することもできます。

$aws-vault exec myrole1 -- aws sts get-caller-identity
{
    "UserId": "AROA2YA6CJSXXXXXXXXXX:<ロールセッション名>",
    "Account": "999999999999",
    "Arn": "arn:aws:sts::999999999999:assumed-role/<ロール名>/<ロールセッション名>"
}
$aws-vault exec myrole2 -- aws sts get-caller-identity
{
    "UserId": "AROATCX6VEHXXXXXXXXXX:<ロールセッション名>",
    "Account": "888888888888",
    "Arn": "arn:aws:sts::888888888888:assumed-role/<ロール名>/<ロールセッション名>"
}

そのため引き続きaws-vaultをTerraformで使うこともできます。

$aws-vault exec myrole1 -- terraform init

まとめ

aws-vaultの設定を見直して、AWSコマンドを直接使えるようにしつつMFAのセッション情報を共通のプロファイルでキャッシュできるようにしてみました。これによりaws-vault exex プロファイル名 -- awsのような形ではなくaws --profile プロファイル名の形でAWSコマンドを使用できるようになり、また一度MFAコードを入力すればセッションが切れるまでは別のプロファイルでもMFAコードを入力する必要がなくなりました。

最後まで読んで頂いてありがとうございました。