AWS

AWS Vaultでアクセスキーをセキュアに管理して平文テキストファイル保存をやめる

ローカルPCからAWS CLIやTerraformを実行するときは、スイッチロールするにしろ最初のIAMユーザーの認証でアクセスキーが必要になります。

僕はしばらくこちらの記事のように、~/.aws/credencialsにそのまま平文保存していました。

しかし、せっかくAWSがセキュリティ周りを強固にしてくれているのにローカルPCへアクセスキーをテキストで平文保存していることが不安でした。


そこでアクセスキーを安全なキーストア用のアプリケーションに保存するためのツール AWS Vault を使ってみます。(vault = 金庫室、貴重品保管室)

99design という企業の方が、PCの盗難やマルウェアの脅威から守るため開発してくれたもので、記事執筆時点で、Star 5.2kと評価が高く、開発も継続されているため安心して使えそうです。

スポンサーリンク

AWS Vaultの使用方法

Macで進めます。Linux(EC2)での手順はこちらの記事にまとめました。

インストール

様々な環境に対応しています。各環境へのインストール方法は、公式ドキュメントのこちらに記載されています。

Mac では brew でインストールできます。

$ brew install --cask aws-vault
==> Downloading https://github.com/99designs/aws-vault/releases/download/v6.3.1/aws-vault-darwin-amd64.dmg
....

🍺  aws-vault was successfully installed!
$

基本構文・実行例

add – クレデンシャル追加

アクセスキーを保存します。

Macではキーの保存先として、デフォルトでキーチェーン(Keychain)が使用されるようです。

## aws-vault add プロファイル名
$ aws-vault add tester
Enter Access Key ID: ABCD1234
Enter Secret Access Key:
Added credentials to profile "tester" in vault
$

最初のコマンド実行時にはパスワードを2回求められると思います。パスワード入力を無効化したい場合は、こちらの手順を実施してください。

exec – AWSコマンド実行

aws-vaultコマンドに続いて、AWS CLIやTerraformコマンドなどを入力します。

途中にある “–” が aws-valutオプションの終了を意味しています。

## aws-vault exec プロファイル名 -- AWS CLIコマンド
$ aws-vault exec tester -- aws s3 ls
2021-06-04 14:42:19 bucket-a
2021-05-29 16:10:30 bucket-b
...
$


env コマンドを実行すると認証周りの環境変数が表示されます。

$ aws-vault exec dev -- env | grep AWS
AWS_VAULT=dev
AWS_DEFAULT_REGION=ap-northeast-1
AWS_REGION=ap-northeast-1
AWS_ACCESS_KEY_ID=ASIAXXX
AWS_SECRET_ACCESS_KEY=yyy
AWS_SESSION_TOKEN=zzz
AWS_SECURITY_TOKEN=zzz
AWS_SESSION_EXPIRATION=2021-08-12T14:00:01Z
$


また “–“をつけずに、そのまま起動したシェルの中でAWS CLIを操作できます。

$ aws-vault exec tester
$
$ aws s3 ls
2021-06-04 14:42:19 bucket-a
2021-05-29 16:10:30 bucket-b
...
$

ちなみにこの状態で ps をみると、子シェル(/bin/zsh とか)が立ち上がっていることがわかります。

list – プロファイル一覧

プロファイルを一覧表示します。

明示的に aws-vault で add したものだけではなく AWS CLI の config で定義されている内容が全部出力されます。

なお add したタイミングで、自動的に config へプロファイルが追加されます。

$ aws-vault list
Profile                  Credentials              Sessions
=======                  ===========              ========
hoge                     hoge                     -
tester                 tester                 sts.GetSessionToken:20m11s
...
$

remove – クレデンシャル削除

クレデンシャルをキーチェーンから削除します。

なおconfig からプロファイルは削除されないので、不要であれば手動で削除しましょう。

## aws-vault remove プロファイル名
$ aws-vault remove hoge
Delete credentials for profile "hoge"? (y|N) y
Deleted credentials.
$

login – マネジメントコンソールログイン

自動的にブラウザが立ち上がり、AWSマネジメントコンソールが開きます。

$ aws-vault login tester
$


便利そうですが個人的にはあまり使ってません。ブラウザでのスイッチロールができず開発や本番などの各環境をいったりきたりできないので。。


loginはフェデレーションログインという機構を利用しているようです。その辺りの権限が足りない(以下はReadOnlyAccess ポリシーのみ付与していた場合)とエラーになります。

$ aws-vault login tester
aws-vault: error: login: Failed to get credentials for tester: AccessDenied: User: arn:aws:iam::111111111111:user/tester is not authorized to perform: sts:GetFederationToken on resource: arn:aws:sts::111111111111:federated-user/tester
	status code: 403, request id: xxx
$ 

rotate – クレデンシャルのローテーション

アクセスキーのローテーションを行います。今まで使用していたアクセスキーは削除されるので、その点ご注意ください。

## aws-vault rotate プロファイル名 -no-session
$ aws-vault rotate tester --no-session
Rotating credentials stored for profile 'tester' using master credentials (takes 10-20 seconds)
Creating a new access key
Created new access key ****************RGA3
Deleting old access key ****************24E6
Deleted old access key ****************24E6
Finished rotating access key
$


既にアクセスキーが最大数の2つあると作成できません。(新たに作成してから削除の流れなので)

$ aws-vault rotate tester --no-session
Rotating credentials stored for profile 'tester' using master credentials (takes 10-20 seconds)
Creating a new access key
aws-vault: error: rotate: LimitExceeded: Cannot exceed quota for AccessKeysPerUser: 2
	status code: 409, request id: xxx
$


特にドキュメントに記載が見当たらなかったのですが、–no-sessionでない、一時的なセッショントークンでは以下のエラーとなります。

$ aws-vault rotate tester
Rotating credentials stored for profile 'tester' using a session from profile 'tester' (takes 10-20 seconds)
Creating a new access key
aws-vault: error: rotate: InvalidClientTokenId: The security token included in the request is invalid
	status code: 403, request id: xxx
$


2段階認証(MFA)制限のスイッチロールで環境切替え

AWS CLI 2段階認証(MFA)制限のスイッチロールで環境切替え で、AWS CLIでスイッチロールをしていましたが、同じようにAWS Vaultでもスイッチロールが可能です。

AWS CLIの設定

~/.aws/config は こちらの内容と同じ設定をしてください。

設定後、aws-vault経由でのコマンドを実行すると以下のようにMFAコードの入力を求められます。

$ aws-vault exec dev -- aws s3 ls
Enter token for arn:aws:iam::111111111111:mfa/tester:      ->MFAコードを入力
2021-06-04 14:42:19 bucket-a
2021-05-29 16:10:30 bucket-b
...

mfa_serialをソースプロファイルにも記述してMFAコードの入力を省略

mfa_serial を踏み台のプロファイルにも記述します。

これにより、一度MFAコードを入力したら各環境でのコマンド実行時に、再度のMFAコードの入力が不要となります。
(踏み台に mfa_serial が設定されない場合は、各環境ごとにMFAコードを入力することになります)

MFAコードは、それほど頻繁に入力するものではないですが(セッションが切れない限り入力不要)、複数環境でコマンド打つときは地味に便利です。

$ vi ~/.aws/config
...

[profile jump]
region = ap-northeast-1
###########################
## jumpにもmfa_serial を記述 
###########################
mfa_serial=arn:aws:iam::111111111111:mfa/tester 

[profile dev]
region = ap-northeast-1
role_arn=arn:aws:iam::222222222222:role/AdminRoleFromJump
source_profile=jump
mfa_serial=arn:aws:iam::111111111111:mfa/tester
role_session_name=tester

[profile prod]
region = ap-northeast-1
role_arn=arn:aws:iam::333333333333:role/AdminRoleFromJump
source_profile=jump
mfa_serial=arn:aws:iam::111111111111:mfa/tester
role_session_name=tester

...

include_profile でスマートに記述する

include_profile を使用して、冗長な記述を省略できます。直感的にも設定内容がわかりやすくなると思います。

例えば前述の設定では、include_profile を使用して以下のように置き換えられます。

$ vi ~/.aws/config
...

[profile jump]
region=ap-northeast-1
source_profile=jump
mfa_serial=arn:aws:iam::111111111111:mfa/tester
role_session_name=tester

[profile dev]
role_arn=arn:aws:iam::222222222222:role/AdminRoleFromJump
include_profile=jump

[profile prod]
role_arn=arn:aws:iam::333333333333:role/AdminRoleFromJump
include_profile=jump

...


ただ、この include_profileはaws-vault独自の実装であるため、素の AWS CLI でのスイッチロールが動かなくなるのでご注意ください。

$ aws s3 ls --profile dev

Partial credentials found in assume-role, missing: source_profile or credential_source
$

メタデータサーバ

exec での環境変数から資格情報を取得するのとは別の、もう一つのやり方がメタデータサーバを使用した方法になります。

が、個人的に使用しておらず、かつ exec のサブシェルの中で実行するの比較して何がメリットなのかイマイチ把握できてないので、どなたか教えてくださいmm
(クレデンシャル知らない人もURIから取得できるから便利とか?)

ECSサーバ – ecs-server

ecs-serverオプションで起動すると環境変数が以下のように設定されます。

## aws-vault exec プロファイル名 --ecs-server
$ aws-vault exec dev --ecs-server
$
$ env | grep AWS
AWS_VAULT=dev
AWS_DEFAULT_REGION=ap-northeast-1
AWS_REGION=ap-northeast-1
AWS_CONTAINER_CREDENTIALS_FULL_URI=http://127.0.0.1:57914
AWS_CONTAINER_AUTHORIZATION_TOKEN=3aovxxx
$


exec のときと同様、そのままサブシェルの中でコマンドが打てます。Terraformもできます。

$ aws s3 ls
2021-06-04 14:42:19 bucket-a
2021-05-29 16:10:30 bucket-b
...
$


また AWS_CONTAINER_AUTHORIZATION_TOKEN を Authorization ヘッダにセットし、AWS_CONTAINER_CREDENTIALS_FULL_URI へアクセスすれば、サブシェルではない別なプロセスからもクレデンシャルを取得できます。

それらを環境変数へセットすればAWS CLIを実行できます。

$ curl -s http://127.0.0.1:57914  -H "Authorization: 3aovxxx" | jq .
{
  "AccessKeyId": "ASIAXXX",
  "Expiration": "2021-08-12T13:37:29Z",
  "SecretAccessKey": "yyy",
  "Token": "zzz"
}
$
$
## 取得したクレデンシャルを環境変数へセット
$ export AWS_ACCESS_KEY_ID=ASIAXXX
$ export AWS_SECRET_ACCESS_KEY=yyy
$ export AWS_SESSION_TOKEN=zzz
$
$ aws sts get-caller-identity
{
    "UserId": "AROAXXX:tester",
    "Account": "111111111111",
    "Arn": "arn:aws:sts::111111111111:assumed-role/AdminRoleFromJump/tester"
}
$

EC2サーバ – server

serverオプションで起動すると、環境変数が以下のように設定されます。コマンド実行時、特権ポートにバインドするためにrootのパスワードを求められます。

## aws-vault exec プロファイル名 --server
$ aws-vault exec dev --server
Password:
$
$ env | grep AWS
AWS_VAULT=dev
AWS_DEFAULT_REGION=ap-northeast-1
AWS_REGION=ap-northeast-1
$


ECSのときと同様、メタデータ取得URLにアクセスしクレデンシャルを取得できます。

ただ、EC2の場合はURLが固定されており、Authorizationなどが不要です。
URLを知っていれば、誰でもアクセスできるためセキュリティ面ではECSより劣ります。

$ curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/local-credentials | jq .
{
  "AccessKeyId": "ASIAXXX",
  "Code": "Success",
  "Expiration": "2021-08-12T14:03:38Z",
  "LastUpdated": "2021-08-12T13:10:43Z",
  "SecretAccessKey": "yyy",
  "Token": "zzz",
  "Type": "AWS-HMAC"
}
$

ちなみにURLパスは、ソースコードのここら辺に書いてあります。



Tips

Mac キーチェーンのパスワード入力の無効化

AWS Vault実行時、ロック解除やKeychainの使用許可のため連続で最大2回パスワード入力を求められると思います。これはキーチェーンの設定画面から変更、確認できます。

コマンドプロンプトで以下のコマンドを実行してキーチェーンを起動してください。

$  open ~/Library/Keychains/aws-vault.keychain-db

なお上記コマンドでキーチェーンを一度起動したあとは、Launchpad の [ その他 ] → [ キーチェーン アクセス ] をクリックでもいけます。(上記コマンド実行前にLaunchpadからキーチェーンを起動しても後述のカスタムキーチェーンに”aws-vault” が表示されません

1回目のパスワード入力の無効化

これは、キーチェーン設定画面の左ペイン [ カスタムキーチェーン ] → [ aws-vault ] を右クリック → [ キーチェーン”aws-vault”の設定を変更 ] → [ 操作しない状態がx分間続いたらロック ] のチェックを外すことで無効化できます。

なお時間を延長することで入力頻度を減らすことも可能です。

2回目のパスワード入力の無効化

これは、左側にある [ 常に許可 ] をクリックすれば無効になります。

キーチェーン設定画面の左ペイン [ カスタムキーチェーン ] → [ aws-vault ] → 当該行のアプリケーションパスワードをダブルクリック → [ アクセス制御 ] タブを選択すると、以下のようにaws-vaultへの許可設定が追加されていることが確認できます。

Mac キーチェーンの中身

アプリケーションパスワード と aws-vault session の2種類が作成されています。


当該行をダブルクリックして、[ パスワードの表示 ] をするとアプリケーションパスワードには、add した際に入力したアクセスキーが保存されています。

{"AccessKeyID":"AKIAXXX","SecretAccessKey":"yyy","SessionToken":"","ProviderName":""}


aws-vault session には、exec コマンド実行時に発行された一時的なセッション用のクレデンシャルが保存されています。

{"AccessKeyId":"ASIAXXX","Expiration":"2021-08-12T16:36:23Z","SecretAccessKey":"yyy","SessionToken":"zzz"}

実行エラー sessions should be nested with care

aws-vault実行時に aws-vault: error: exec: aws-vault sessions should be nested with care, unset $AWS_VAULT to force とエラーメッセージが表示されることがあります。

aws-vaultで起動したシェルに入った状態になっているので、exitでカレントシェルを抜けましょう。

$ aws-vault exec dev -- aws s3 ls
aws-vault: error: exec: aws-vault sessions should be nested with care, unset $AWS_VAULT to force
$
## aws-vaultの環境変数が設定されている
$ env | grep AWS
AWS_VAULT=dev
AWS_DEFAULT_REGION=ap-northeast-1
...
$
$ exit
$
$ aws-vault exec dev -- aws s3 ls
2021-06-04 14:42:19 bucket-a
2021-05-29 16:10:30 bucket-b
...
$

アクセスキーの AKIA とか ASIA の意味

今までなんとなく違うなーくらいで、特に調べてなかったのですが、公式ドキュメント 一意の識別子 に記載がありました。

とりあえず僕がちょこちょこ見るのを記載しておきます。

プレフィックス意味
AKIAアクセスキー
ASIA一時 (AWS STS) アクセスキー ID
AROAロール



今回は以上です〜ノシ

参考

アリガト━━━ヾ(´∀`)ノ━━━━♪

GitHub aws-vault
99designsのエンジニアブログ Securing AWS Credentials on Engineer’s Machines
aws-vaultのmacOSのキーチェーンのタイムアウトを伸ばす