.env の代わりに aws-vault で安全に環境変数を与える — Claude Code 時代の AWS 認証情報管理

AI エージェントがローカルファイルを直接読み書きする時代、.env に平文で認証情報を置くリスクが顕在化しています。前回の記事では、この問題の背景と複数のシークレット管理ツールを紹介しました。

本記事では、AWS を利用しているチームに向けて、aws-vault を使って .env~/.aws/credentials を完全に排除する具体的な手順を解説します。

aws-vault が解決する問題

~/.aws/credentials の平文問題

AWS CLI を使う開発者の多くは、~/.aws/credentials にアクセスキーを平文で保存しています。

1
2
3
4
# ~/.aws/credentials(平文で保存されている)
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

このファイルには2つのリスクがあります。

  1. Claude Code が読み取れる: AI エージェントがファイルシステムを探索する際、~/.aws/credentials のアクセスキーが LLM のコンテキストに載る可能性がある
  2. 長期的な認証情報が漏洩する: アクセスキーには有効期限がなく、漏洩した場合は手動でローテーションするまで悪用され続ける

aws-vault のアプローチ

aws-vault は以下の2段階で問題を解決します。

  1. 暗号化保存: アクセスキーを ~/.aws/credentials ではなく、OS のキーストア(macOS Keychain 等)に暗号化して保存する
  2. 一時認証の生成: AWS STS(Security Token Service)を使って、1時間で失効する一時認証情報を生成し、子プロセスに注入する
[従来]
~/.aws/credentials(平文) → AWS CLI / boto3 が直接読み取り
                              → 長期キーがメモリに残る

[aws-vault]
macOS Keychain(暗号化) → aws-vault が STS で一時認証を生成
                          → 子プロセスに環境変数として注入
                          → 1時間で失効

セットアップ

インストール

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# macOS(推奨)
brew install --cask aws-vault

# macOS(Homebrew formula 版)
brew install aws-vault

# Linux
brew install aws-vault

# Windows
choco install aws-vault
# または
scoop install aws-vault

macOS では --cask 版が推奨されています。コード署名されているため、Keychain アクセス時の追加のパスワードプロンプトが少なくなります。

認証情報の登録

1
2
3
4
5
# プロファイルを追加(対話的にアクセスキーを入力)
$ aws-vault add my-profile
Enter Access Key ID: AKIAIOSFODNN7EXAMPLE
Enter Secret Access Key: ****
Added credentials to profile "my-profile" in vault

この時点で ~/.aws/credentials にはキーが書き込まれません。Keychain に暗号化保存されます。

登録できたことの確認

1
2
3
4
$ aws-vault list
Profile                  Credentials              Sessions
=======                  ===========              ========
my-profile               my-profile               -

~/.aws/credentials を削除

既に ~/.aws/credentials に平文キーがある場合は、aws-vault に移行後に削除します。

1
2
3
4
5
6
7
8
# まず aws-vault に登録
$ aws-vault add my-profile

# 動作確認
$ aws-vault exec my-profile -- aws sts get-caller-identity

# 確認できたら平文ファイルを削除
$ rm ~/.aws/credentials

基本的な使い方

コマンド実行

1
2
3
4
5
6
7
8
# AWS CLI コマンドを一時認証で実行
$ aws-vault exec my-profile -- aws s3 ls

# Django の開発サーバーを起動(boto3 が AWS にアクセスする場合)
$ aws-vault exec my-profile -- python manage.py runserver

# Terraform を実行
$ aws-vault exec my-profile -- terraform plan

aws-vault exec は内部で以下を行います。

  1. Keychain からアクセスキーを取得
  2. STS の GetSessionToken API を呼び出し、一時認証情報を生成
  3. AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_SESSION_TOKEN を環境変数として設定
  4. 指定したコマンドを子プロセスとして実行

子プロセスが終了すれば、一時認証情報は環境変数とともに消えます。

サブシェルで作業

コマンドを指定せずに実行すると、認証情報が設定されたサブシェルが起動します。

1
2
3
4
5
6
7
8
9
$ aws-vault exec my-profile

# サブシェル内で自由に作業
$ aws s3 ls
$ aws ec2 describe-instances
$ python manage.py shell

# 作業が終わったらサブシェルを終了
$ exit

複数の AWS コマンドを連続して実行する場合に便利です。

AWS コンソールにブラウザでログイン

1
$ aws-vault login my-profile

ブラウザが開き、一時認証情報で AWS マネジメントコンソールにログインできます。IAM ユーザーのパスワードを入力する必要がありません。

~/.aws/config の設定

aws-vault は ~/.aws/config(設定ファイル)を読み取ります。認証情報(credentials)ではなく設定(config)であるため、平文のキーは含まれません。

基本設定

1
2
3
4
5
# ~/.aws/config

[profile my-profile]
region = ap-northeast-1
output = json

MFA(多要素認証)の設定

IAM ユーザーに MFA を設定している場合、mfa_serial を追加します。

1
2
3
[profile my-profile]
region = ap-northeast-1
mfa_serial = arn:aws:iam::123456789012:mfa/my-user
1
2
$ aws-vault exec my-profile -- aws s3 ls
Enter MFA code for arn:aws:iam::123456789012:mfa/my-user: 123456

MFA コードを入力すると、セッションがキャッシュされます。セッションが有効な間(デフォルト1時間)は再入力不要です。

AssumeRole(ロール切り替え)の設定

開発環境と本番環境で異なる IAM ロールを使い分ける場合の設定です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# ~/.aws/config

# ベースプロファイル
[profile base]
region = ap-northeast-1
mfa_serial = arn:aws:iam::123456789012:mfa/my-user

# 開発環境(base の認証情報で AssumeRole)
[profile dev]
source_profile = base
role_arn = arn:aws:iam::123456789012:role/dev-role
region = ap-northeast-1

# 本番環境(MFA 必須の AssumeRole)
[profile prod]
source_profile = base
role_arn = arn:aws:iam::123456789012:role/prod-role
region = ap-northeast-1
1
2
3
4
5
# 開発環境ロールで Terraform を実行
$ aws-vault exec dev -- terraform apply

# 本番環境ロールでデプロイ(MFA が求められる)
$ aws-vault exec prod -- ./deploy.sh

aws-vault が自動的に AssumeRole API を呼び出し、ロール切り替えを行います。

credential_process による AWS CLI との統合

aws-vault exec のラッパーなしで、通常の aws コマンドをそのまま使いたい場合は、credential_process を設定します。

1
2
3
4
# ~/.aws/config
[profile my-profile]
region = ap-northeast-1
credential_process = aws-vault export --format=json my-profile
1
2
3
4
5
# aws-vault exec なしで直接実行できる
$ aws s3 ls --profile my-profile

# boto3 を使うスクリプトもそのまま動く
$ AWS_PROFILE=my-profile python manage.py runserver

この設定により、AWS SDK(boto3 等)が認証情報を必要とする際に aws-vault が自動的に呼び出されます。

macOS では --prompt osascript オプションを追加すると、Keychain のパスワード入力がネイティブダイアログで表示されます。

1
credential_process = aws-vault export --format=json --prompt=osascript my-profile

Docker コンテナへの認証情報の受け渡し

ローカル開発で Docker コンテナ内のアプリケーションに AWS 認証情報を渡す方法です。

環境変数で渡す

1
2
3
4
# aws-vault が生成した一時認証情報をコンテナに渡す
$ aws-vault exec my-profile -- env | grep AWS > /tmp/aws-env
$ docker run --env-file /tmp/aws-env my-app
$ rm /tmp/aws-env

ただし、一時ファイルに認証情報が残るため、よりセキュアな方法を推奨します。

ECS ローカルエンドポイントで渡す(推奨)

aws-vault には、ECS コンテナが使う認証エンドポイントをローカルで再現する機能があります。

1
2
3
4
5
6
7
# ローカルに ECS 互換のメタデータサーバーを起動
$ aws-vault exec my-profile --ecs-server

# 別のターミナルで Docker コンテナを起動
$ docker run \
  -e AWS_CONTAINER_CREDENTIALS_FULL_URI=http://host.docker.internal:9099/ecs \
  my-app

この方法では、認証情報がファイルにも環境変数にも直接渡されません。コンテナ内の AWS SDK が HTTP 経由で一時認証情報を取得します。

キーローテーション

IAM のベストプラクティスでは、アクセスキーを90日ごとにローテーションすることが推奨されています。aws-vault ならコマンド一つで完了します。

1
2
3
4
$ aws-vault rotate my-profile
Rotating credentials stored for profile 'my-profile'
Created new access key ****NEWKEY
Deleted old access key ****OLDKEY

内部的には以下が行われます。

  1. 新しいアクセスキーを IAM に作成
  2. Keychain のキーを新しいものに更新
  3. 古いアクセスキーを IAM から削除

アプリケーションのシークレットとの組み合わせ

aws-vault は AWS 認証情報を守るツールです。アプリケーション固有のシークレット(データベースパスワード、API キー等)は、別途 AWS Secrets Manager から取得する構成が推奨されます。

一括注入スクリプト

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/bin/bash
# scripts/dev-server.sh
# aws-vault + AWS Secrets Manager でシークレットを一括注入

set -euo pipefail

# AWS Secrets Manager からアプリケーションのシークレットを取得
SECRET_JSON=$(aws secretsmanager get-secret-value \
  --secret-id "my-app/${ENV:-dev}/config" \
  --query SecretString --output text)

# JSON の各キーを環境変数にエクスポート
eval $(echo "$SECRET_JSON" | jq -r 'to_entries[] | "export \(.key)=\(.value)"')

echo "Loaded secrets for environment: ${ENV:-dev}"

# 引数のコマンドを実行
exec "$@"
1
2
# 使い方:aws-vault でラップして実行
$ aws-vault exec dev -- ./scripts/dev-server.sh python manage.py runserver

この構成では以下の全てが平文ファイルから排除されます。

認証情報保存場所平文ファイル
AWS アクセスキーmacOS Keychainなし
AWS 一時認証情報メモリ上のみ(1時間で失効)なし
DB パスワードAWS Secrets Managerなし
外部 API キーAWS Secrets Managerなし

Makefile での統合

チーム全体で同じ方法を使えるよう、Makefile に定義しておくと便利です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Makefile
ENV ?= dev
PROFILE ?= $(ENV)

.PHONY: server migrate shell

server:
	aws-vault exec $(PROFILE) -- ./scripts/dev-server.sh python manage.py runserver

migrate:
	aws-vault exec $(PROFILE) -- ./scripts/dev-server.sh python manage.py migrate

shell:
	aws-vault exec $(PROFILE) -- ./scripts/dev-server.sh python manage.py shell

deploy:
	aws-vault exec prod -- ./scripts/deploy.sh
1
2
3
4
# チームメンバーは以下を実行するだけ
$ make server
$ make server ENV=stg
$ make deploy

Claude Code との共存

deny 設定

Claude Code が AWS 関連の認証ファイルを読み取らないよう、プロジェクトの .claude/settings.json に deny ルールを追加します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(**/.aws/credentials)",
      "Read(**/.aws/sso/cache/**)"
    ]
  }
}

aws-vault 環境で Claude Code を使う

Claude Code 自体も aws-vault の子プロセスとして起動できます。Claude Code が AWS リソースにアクセスする必要がある場合(例: S3 バケットの内容を確認する等)に有効です。

1
2
# Claude Code に一時認証情報を渡して起動
$ aws-vault exec dev -- claude

ただし、Claude Code に AWS 認証情報を渡すこと自体がリスクになり得ます。必要な場合のみ使用し、通常は認証情報なしで起動することを推奨します。

トラブルシューティング

Keychain のパスワード入力が頻繁に求められる

macOS Keychain の「aws-vault」キーチェーンのロック時間を調整します。

  1. 「キーチェーンアクセス.app」を開く
  2. 左ペインで「aws-vault」キーチェーンを右クリック
  3. 「“aws-vault” の設定を変更」を選択
  4. 「操作がない状態が XX 分続いたらロック」の時間を調整

セッション期限切れ

デフォルトのセッション期限は1時間です。長時間の作業では、環境変数でカスタマイズできます。

1
2
3
4
5
# セッション時間を8時間に延長
$ AWS_SESSION_TOKEN_TTL=8h aws-vault exec my-profile -- python manage.py runserver

# ~/.zshrc に設定しておくことも可能
export AWS_SESSION_TOKEN_TTL=4h

ただし、セッション時間を長くするほどセキュリティリスクは増加します。

–no-session オプション

一部の IAM 操作(アクセスキーのローテーション等)は一時認証情報では実行できません。その場合は --no-session を使いますが、長期キーがそのまま使われるためセキュリティリスクが高くなります。通常の開発では使用を避けてください。

1
2
# 特別な場合のみ使用(長期キーが直接使われる)
$ aws-vault exec my-profile --no-session -- aws iam list-access-keys

まとめ

  • ~/.aws/credentials を廃止: aws-vault でアクセスキーを OS Keychain に暗号化保存し、平文ファイルを排除する
  • 一時認証情報で作業: STS が生成する1時間で失効する認証情報のみを使い、漏洩リスクを限定する
  • credential_process で透過的に統合: aws-vault exec のラッパーなしで、通常の AWS CLI や boto3 をそのまま使える
  • AssumeRole で環境分離: dev / stg / prod を IAM ロールで切り替え、本番アクセスには MFA を必須にする
  • AWS Secrets Manager と組み合わせる: アプリケーションのシークレットは Secrets Manager に集約し、一括注入スクリプトで管理する
  • Makefile でチーム標準化: make server 一つで安全にローカル開発サーバーを起動できる環境を整備する
  • Claude Code の deny 設定: ~/.aws/credentials.env へのアクセスを拒否し、多層防御を実現する

参考