本記事は生成AIと共同で執筆しています。事実関係は可能な範囲で公式ドキュメント等と照合していますが、誤りが含まれている可能性があります。重要な判断を行う前にご自身でも一次情報をご確認ください。
本記事は筆者個人の環境での作業記録であり、特定のツールや手順を推奨するものではありません。内容の正確性・安全性を保証するものでもありません。記載のコマンドや設定の適用は各自の責任で、検証環境などで十分に確認のうえ行ってください。本記事を参照した結果生じたいかなる損害についても、筆者は責任を負いかねます。
背景
AWS CLI / SDK を使うとき、IAM (Identity and Access Management) ユーザーのアクセスキーを ~/.aws/credentials に平文で書く方法が長く使われてきました。
[myprofile]
aws_access_key_id = AKIA...
aws_secret_access_key = ...
このファイル形式は AWS の標準で機能的には今でも有効ですが、平文である以上は次のような経路で露出する余地があります。
- バックアップに紛れ込む (Time Machine、iCloud Drive、外部ディスクへのコピー)
- エディタや IDE のワークスペースインデックス・キャッシュ
- ターミナル履歴 (
~/.zsh_history) にcat ~/.aws/credentialsが残る - うっかり git に commit してしまう
- 同一マシン上の他プロセスからの読み取り (権限設定ミス)
AWS 自身も近年は IAM Identity Center (旧 AWS Single Sign-On) と aws sso login を推奨しており、短期セッショントークン (ASIA...) で運用することで長期キー (AKIA...) をローカルに置かない方針が標準になりつつあります。
ただし、Identity Center を採用しない / できないケースもあります。
IAM Identity Center が選びにくいケース
調査した限り、以下のような状況では Identity Center の導入コストが見合わないか、構成上選択できないことがあるようです。
- 個人で 1 アカウントだけ使っている。Identity Center 有効化と permission set 整備の運用負荷が、得られる利点に見合わないと判断するケースがある
- 共有 IAM ユーザーを複数人で使っている運用 (各メンバーが個別の Identity Center ユーザーを持っていない)
- AWS Organizations 配下にない単独アカウント
- レガシー連携や外部サービスで IAM ユーザーキーが前提になっているもの
本記事では、こうした環境で平文 ~/.aws/credentials を維持するのではなく、macOS Keychain にキー本体を格納し、必要なときだけ一時セッションとして取り出す構成を扱います。
aws-vault の概要
aws-vault は IAM ユーザーキーを OS のキーストア (macOS Keychain、Windows Credential Manager、Linux Secret Service 等) に格納し、AWS CLI / SDK には credential_process 経由で一時セッショントークンを渡すツールです。
もともとは 99designs/aws-vault として公開されていました。このリポジトリの最終リリースは v7.2.0 (2023年3月) で、その後 2025年6月に README で「This project has been abandoned and it's not receiving any more updates」とアナウンスされました。現在はコミュニティの active fork である ByteNess/aws-vault が継続的に更新されており、Homebrew の formula (brew install aws-vault) も 2025年6月以降こちらに切り替わっています。本記事のコマンド例も ByteNess fork (執筆時点 v7.10.7) を前提とします。
macOS では Homebrew でインストールできます。
brew install aws-vault # Homebrew formula (ByteNess fork、現在のアクティブ版)
# brew install --cask aws-vault-binary # 99designs の最終バイナリ (v7.2.0、メンテ停止)
両者の CLI は実質的に互換で、ByteNess fork のほうがバージョンが新しく更新も継続しています。配布バイナリのコード署名については、99designs の最終版 (v7.2.0) が DMG 内バイナリに Apple Developer ID 署名と hardened runtime を持つのに対し、ByteNess のリリースは生バイナリで ad-hoc 署名にとどまります。ただし Homebrew formula (brew install aws-vault) はソースからビルドされるため、この署名差は実質的に関係しません。古い 99designs バイナリを使い続けると今後のセキュリティパッチや依存ライブラリの更新が受けられないため、新規導入なら formula 経由が現実的です。
仕組みのイメージは次のとおりです。
[AWS CLI / SDK]
↓ credential_process を呼ぶ
[aws-vault export --duration=12h myprofile]
↓ Keychain から長期キー (AKIA...) を取得
↓ STS GetSessionToken (または AssumeRole) を呼ぶ
[一時セッショントークン (ASIA...) を返す]
↓
[AWS CLI / SDK が AWS API を呼び出す]
長期キーそのものはファイルとして書き出されず Keychain 内に留まり、アプリケーション側に渡るのは STS (Security Token Service) が発行した一時セッションです。これは --duration で指定した期間で失効します (本記事の例では 12 時間。GetSessionToken の場合、IAM ユーザーなら 15 分〜36 時間の範囲で指定でき、未指定時のデフォルトは 12 時間です)。
~/.aws/config の構成
aws-vault に切り替えると、~/.aws/credentials は空ファイルで運用できます。各プロファイルの設定は ~/.aws/config 側に credential_process として記述します。
MFA を使わない場合:
[profile myprofile]
region = ap-northeast-1
credential_process = sh -c "AWS_VAULT_KEYCHAIN_NAME=login AWS_VAULT_PROMPT=osascript aws-vault export --format=json --duration=12h myprofile"
ポイントは 2 つです。
AWS_VAULT_KEYCHAIN_NAME=login で macOS 標準の login keychain を使うように指定しています。aws-vault のデフォルトは専用 keychain (aws-vault.keychain) を作る挙動ですが、login keychain に揃えると Touch ID やパスワード管理を他のアプリと統合しやすくなります。
AWS_VAULT_PROMPT=osascript は MFA (多要素認証) コード入力ダイアログを macOS のネイティブダイアログにする指定です。ターミナルではなく IDE や CI ラッパなど外部プロセスから呼ばれた場合にも入力プロンプトを出せます。
MFA を使う場合:
[profile myprofile]
region = ap-northeast-1
mfa_serial = arn:aws:iam::123456789012:mfa/myuser-totp
credential_process = sh -c "AWS_VAULT_KEYCHAIN_NAME=login AWS_VAULT_PROMPT=osascript aws-vault export --format=json --duration=12h myprofile"
mfa_serial を設定すると、aws-vault はセッション発行時に 6 桁の TOTP (Time-based One-Time Password) コードを要求します。一度入力すれば指定期間 (上記の例では 12 時間) 有効なセッションがキャッシュされるため、頻繁な入力にはなりません。
なお、aws-vault は U2F (Universal 2nd Factor。FIDO 準拠のセキュリティキー) には対応していないようです。MFA を活用するなら TOTP デバイス (Google Authenticator、1Password の TOTP 機能など) を IAM に追加登録する必要があります。
既存の平文プロファイルを移行する
既存のキーを Keychain に登録するには、環境変数経由でキー値を渡すのが簡単です。
AWS_VAULT_KEYCHAIN_NAME=login \
AWS_ACCESS_KEY_ID=AKIA... \
AWS_SECRET_ACCESS_KEY=... \
aws-vault add --backend=keychain --env --no-add-config myprofile
--envで標準入力ではなく環境変数からキー値を読み込む--no-add-configで~/.aws/configへの自動追記を抑止 (設定を自分で管理したいため)
登録に成功すると Added credentials to profile "myprofile" in vault と出ます。その後 ~/.aws/credentials から該当プロファイルセクションを削除します。
動作確認:
aws --profile myprofile sts get-caller-identity
mfa_serial を設定している場合は最初に macOS のダイアログが出ます。コードを入力すれば次のような結果が返ります。
{
"UserId": "AID...",
"Account": "123456789012",
"Arn": "arn:aws:iam::123456789012:user/myuser"
}
セッションのキャッシュ状況は aws-vault list で確認できます。
Profile Credentials Sessions
======= =========== ========
myprofile myprofile sts.GetSessionToken:11h59m51s
キーローテーション
aws-vault には rotate サブコマンドがあり、「新キー発行 → Keychain 更新 → 旧キー削除」をひとつのコマンドで実行できます。
rotateは旧アクセスキーを AWS 側から削除します。CI、別の端末、デプロイスクリプト、Terraform などが同じ IAM ユーザーのアクセスキーを参照していないか確認してから実行してください。共有 IAM ユーザーの場合は、他の利用者が同じキーを使っていないかの確認も必要です。実行前に検証環境で挙動を確かめておくと安全です。
AWS_VAULT_KEYCHAIN_NAME=login AWS_VAULT_PROMPT=osascript \
aws-vault rotate myprofile
実行ログの例 (キー ID は伏字):
Rotating credentials stored for profile 'myprofile' using a session from profile 'myprofile' (takes 10-20 seconds)
Creating a new access key
Created new access key ****************BCIU
Deleted 1 sessions for myprofile
Deleting old access key ****************QYXF
Deleted old access key ****************QYXF
Finished rotating access key
iam:CreateAccessKey に MFA 必須条件 (aws:MultiFactorAuthPresent) が課された共有アカウントでも、ポリシーの条件設計にもよりますが、aws-vault 経由の MFA セッションから呼ぶことで通過する場合があります。
実運用でつまずいた点
実際に移行を進めていくつか細かい落とし穴があったので記録しておきます。
MFA コードは半角数字でしか受け付けない
osascript ダイアログは macOS の IME を経由するため、入力モードによっては全角数字が入ります。AWS の API は半角数字のみを受け付けるため、次のように弾かれます。
ValidationError: Value '831405' at 'tokenCode' failed to satisfy
constraint: Member must satisfy regular expression pattern: [\d]*
入力前に英数モードに切り替える習慣をつけておくと安全です。
TOTP コードは続けて使えない
経験した範囲では、同じ 30 秒枠で生成された TOTP コードを 2 回続けて送信すると拒否されるようです。AWS の API リファレンスに明示の記述は見当たりませんでしたが、1 度目に失敗 (例: タイプミス) して即座にリトライしたケースで、同じコードでは通らず、アプリが次のコードを表示するまで待つ必要がありました。
AccessDenied: MultiFactorAuthentication failed with invalid MFA one time pass code.
U2F セキュリティキーは aws-vault からは利用できない
IAM 側に U2F (Yubikey 等の FIDO デバイス) を登録していても、aws-vault は U2F に対応していないため mfa_serial には設定できません。TOTP デバイスを別途追加します。たとえばコンソールで「Authenticator app」を選び、QR コードを TOTP アプリ (1Password、Google Authenticator など) で読み取って 2 回連続のコードを入力する流れになります。
CreateAccessKey が deny されているケース
共有アカウントで IAM 操作に explicit deny がかかっていると、平文キー直叩きで aws iam create-access-key を呼んでも拒否されます。
AccessDenied: User ... is not authorized to perform: iam:CreateAccessKey
... with an explicit deny in an identity-based policy
この場合は、既存キーをまず aws-vault に登録し、MFA セッションを発行した状態で改めて aws-vault rotate を試すと、aws:MultiFactorAuthPresent 条件を満たして通過することがあります。
バックアップファイルや CSV の後始末
移行作業中に ~/.aws/credentials.bak.YYYYMMDD-HHMMSS のような形でバックアップを作ると、そこに平文キーが残ったままになります。AWS コンソールでキー作成時にダウンロードされる accessKeys.csv も同様で、開いた瞬間に Secret access key が画面に表示されます。aws-vault に取り込んだあとは、これらを速やかに削除します。
default プロファイルを残すかどうか
[default] セクションは --profile を省略したとき暗黙に使われるため、複数アカウントを行き来する運用ではうっかり別アカウントを操作してしまう事故が起きやすい場所です。[default] を廃止し、用途を反映した別名 (たとえば s3-admin や <アカウント名>-<役割> のような命名) に置き換える方針もあります。常に --profile を明示する習慣にすると、コマンドの意図が読みやすくなります。
aws-vault そのものをどこまで信頼するか
「IAM ユーザーキーという機密情報を、サードパーティの OSS (オープンソースソフトウェア) ツールに任せて大丈夫か」というのは当然出てくる疑問なので、整理しておきます。
- メンテナーが交代している: 前述のとおり、99designs 版は abandoned とアナウンスされていて、現在の active fork は ByteNess。Homebrew formula は ByteNess に追従しているため、
brew install aws-vault経由で入れていれば自動的にメンテ継続版になります。古いバイナリを直接ダウンロードして使い続けると、依存ライブラリの脆弱性などへの対応が受けられないため、formula 経由かソースビルドで最新を取り込む運用が望ましいと言えます。 - 入手経路の信頼性: Homebrew core formula は SHA256 チェックサム検証が走るため、ミラー改ざんへの耐性があります。GitHub Releases から直接バイナリをダウンロードする場合は、署名・ハッシュを各自で確認します。
- 既知の脆弱性: 過去には 99designs 版に DNS Rebinding の脆弱性が報告され、v5.4.4 / v4.7.2 で修正されています。これは
aws-vault exec --serverで起動する EC2 メタデータサーバ周りの問題で、本記事のようなcredential_process経由の利用では--serverを使わないため影響を受けにくい構成です。とはいえ「自分の使い方では関係ない」と決めつけず、依存ライブラリを含めて随時アップデートする運用を維持するのが安全です。 - ローカル侵害との関係: aws-vault プロセスは macOS のユーザー権限で動作し、login keychain にアクセスする際は macOS のアクセス制御が働きます。「常に許可」を選んだ後は再認証なしでキーを取れるため、aws-vault バイナリ自体やそれを呼び出すシェルが侵害された場合には、Keychain からキーを取り出されるリスクが残ります。これは aws-vault 固有の話ではなく、ローカルファイル管理・OS キーチェーン管理に共通する制約として整理できます (このレイヤーの対策は EDR (Endpoint Detection and Response)、FileVault、開発ツールの審査など別の領域)。
要するに、平文ファイルよりは段階的にリスクを下げられるものの、絶対的な防御ではない、という位置づけになります。
実用性についての評価
複数のプロファイルで運用してみた範囲での印象です。
メリット:
~/.aws/credentialsを空ファイルにでき、ローカルファイルベースの露出経路がなくなる- 12 時間の一時セッションキャッシュにより、MFA 入力頻度は許容範囲に収まる
aws-vault rotateによりローテーション運用のハードルが下がる- 既存の AWS CLI / SDK が
credential_process経由で透過的に動作するため、アプリ側コードの変更は不要
トレードオフ:
- macOS Keychain への依存。login keychain がアンロックされた状態であることが前提となる
- MFA を併設しないプロファイルでは、流出経路は減らせるものの、いったんキーが流出してしまえば攻撃者ができること自体は平文時代と変わらない (経路の遮断と、流出後の権限の大きさは別の話)
- セットアップが macOS 固有なので、Windows・Linux への移植やチーム全員に同じ構成を組ませる場合は別途設計が必要
マルウェア対策とは別レイヤー
「マシン自体がマルウェアに感染した場合、Keychain からキーが抜かれるのでは」という懸念は、aws-vault 固有の話というよりは OS レベルのセキュリティ全般 (EDR、FileVault、ファームウェアアップデート、開発ツールの審査など) の領域です。aws-vault による平文回避は、あくまで「ローカルファイルからの偶発的な露出」(バックアップ、エディタキャッシュ、scp での持ち出し、git への混入など) を遮断するのが主目的で、それ自体が高度な攻撃者からの防御策ではない、と整理しておくと役割が明確になります。
推奨する組み合わせ
IAM Identity Center を採用しない環境では、aws-vault と Keychain と TOTP MFA、そして定期ローテーションを組み合わせることで、平文ファイル運用よりも段階的にリスクを下げることができます。Identity Center に移行できる規模と運用体制があればそちらが本筋ですが、そうでない場合の現実的な選択肢として実用に耐える構成だと感じます。
併用すると効果的なものは以下のとおりです。
gitleaksなどのシークレットスキャナーで過去コミットへの漏洩を検査する- TOTP を 1Password 等のパスワードマネージャに集約して、MFA 管理を一元化する
- 定期的に
aws-vault rotateを実行し、長期キーが「古いまま」になる状態を避ける
参考
- ByteNess/aws-vault — GitHub (現在の active fork)
- 99designs/aws-vault — GitHub (元リポジトリ、メンテ停止)
- AWS IAM Identity Center ユーザーガイド
- AWS CLI の
credential_process
コメント
…