aws-vault の tips

aws-vault のメモ。概ね USAGE.md を見れば十分ですが WSL で使用する場合の特有の問題などもあります。

pass バックエンド

ずっと昔は aws-vault で認証情報を保存するバックエンドとして Linux の CLI のみの環境だと aws-vault 独自の暗号化ファイルしか無く、その場合は環境変数 AWS_VAULT_FILE_PASSPHRASE にパスワードを持たせないことには使い勝手が悪く、実質のところ暗号化にあまり意味がありませんでした。

いつからかバックエンドとして pass というパスワードマネージャーが指定できるようになりました。

pass なら gpg 鍵で暗号化されるため gpg 鍵のパスフレーズがマスターパスワードとなり、より安全です(gpg-agent が一定時間記憶するので都度入力の必要はありません)。

.bash_profile で次のように環境変数を設定すれば pass をバックエンドにできます。AWS_VAULT_PASS_PREFIX は無くても良いですが pass のパスワードストア内でグループ化するために適当に指定した方が良いでしょう。

export AWS_VAULT_BACKEND=pass
export AWS_VAULT_PASS_PREFIX=aws-vault/

gpg や pass の初期設定も必要なら次のようにすればできると思います。

gpg --full-generate-key
# いろいろプロンプトが出てくるのでそれっぽく入力して進める
# 最後の方でパスフレーズの設定があります

# 鍵のIDを表示します。xxx のところにあるのが鍵のIDです
gpg -k
#=> /home/oreore/.gnupg/pubring.kbx
#=> -------------------------------
#=> pub   ed25519 2023-08-28 [SC]
#=>       xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
#=> uid           [ultimate] oreore
#=> sub   cv25519 2023-08-28 [E]

# gpg 鍵のIDを指定して pass のパスワードストアを初期化します
pass init xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# aws-vault でアクセスキー・シークレットキーが追加できます
aws-vault add my-profile

# 使用時は gpg 鍵のパスフレーズの入力が求められます
aws-vault exec my-profile

なお Linux なら keyctl なるバックエンドも利用可能なはずなのですが機能してないようです。

keyctl はデバイスが対応していれば TPM とかも使えるようです。

WSL では対応していませんが。

aws-vault login と wsl-open

aws-vault login を使えば一時クレデンシャルを使ってマネジメントコンソールにログインできます。ので IAM User のパスワードは必要ありません。 ただ、WSL 環境だと xdg-open でブラウザを開こうとするため普通には使えませんが wsl-open を入れておけば OK です。

既にブラウザでログイン済みだと次のようなページが表示されてしまうのが若干煩雑ですが、 (「ここ」を Ctrl+クリック とかで開いた後 F5 リロードで OK です)

Amazon Web Services サインインページ 別の AWS アカウントにログインするには、まずログアウトする必要があります。 ログアウトするには、 ここをクリックしてください。

これが表示されたページの URL をコピーして、シークレットモードやゲストモードで URL を張り付ければ複数プロファイルを同時に操作もできます。aws-vault login my-proile -s で URL が標準出力にでるの clip.exe などを使って直接クリップボードに張り付けとかでも良いと思います。

pass-otp と mfa_process

pass-otp は pass の拡張機能のようなもので、pass のパスワードストアに TOTP のシークレットを保存しておけば pass otp コマンドでワンタイムコードが得られるようになります。

もちろんシークレットは gpg 鍵で暗号化されます。

pass otp insert aws/otp/my-profile
# プロンプトが出るので otpauth:// の形式で入力する

pass otp aws/otp/my-profile
# ワンタイムコードが表示される

さらに ~/.aws/config で次のように記述しておくと aws-vault でワンタイムコードが必要なときに pass otp で生成されたワンタイムコードが使用されるため、都度ワンタイムコードを転記する必要がなくなります。

[profile my-profile]
mfa_serial=arn:aws:iam::999999999999:mfa/my-profile
mfa_process=pass otp aws/otp/my-profile

aws-vault exec --server

aws-vault で実行時間が超長いコマンドを実行するとき(例えば terraform で作成にものすごい時間のかかるリソースを作るときなど)、一時クレデンシャルの有効期限が途中が切れてしまうことがあります。そのような場合は aws-vault exec --server <profile> を使えば OK です。

--server オプションを付けて実行すると aws-vault がバックグラウンドで一時クレデンシャルを返すためのサーバを実行し、その URL や認証用トークンを環境変数 AWS_CONTAINER_CREDENTIALS_FULL_URIAWS_CONTAINER_AUTHORIZATION_TOKEN に設定します。

この環境変数は ECS でコンテナが一時クレデンシャルを得るためのもので、次のように認証情報が得られます。

aws-vault exec --server my-profile
curl -H "Authorization:$AWS_CONTAINER_AUTHORIZATION_TOKEN" "$AWS_CONTAINER_CREDENTIALS_FULL_URI"
#=> 一時クレデンシャル

AWS SDK がクレデンシャルを要求したとき、既に発行済の一時クレデンシャルの有効期限が切れていれば aws-vault によって一時クレデンシャルが再発行されるため、長時間のコマンドでも大丈夫です。

ただし、このオプションを使用するためには aws-vault の prompt で terminal 以外が使用可能な必要があります。

prompt とは aws-vault で何かしらのユーザー入力が必要になったときにどのような方法で入力を得るかの設定です。例えば MFA のワンタイムトークの入力などです。prompt には次のものが指定可能です。

  • kdialog
  • osascript
  • terminal
  • wincredui_windows
  • ykman
  • zenity

デフォルトは terminal で、これは標準入出力が用いられますが --server オプションを付けて何かのコマンドを実行中は標準入出力はそのコマンドに取られているので、仮に一時クレデンシャルの有効期限が切れて再発行が必要になったとしてもワンタイムコードが入力できません。そのため --server オプションの利用時は terminal 以外に何かの prompt が利用可能になっている必要があります。

ただ、前述の mfa_process を使っていればワンタイムコードを手入力することは無いし、gpg 鍵のパスフレーズの入力は環境変数 GPG_TTY を設定していれば標準入出力は使いません。ので、どうせ呼ばれないことが分かっているので適当にダミーのスクリプトを用意しておけば OK です。

touch ~/bin/kdialog
chmod +x ~/bin/kdialog

わたしは次のように tty から直接入出力するコマンドに置き換えています。

#!/bin/bash

title=
inputbox=

while [ $# -ne 0 ]; do
  case "$1" in
    --inputbox)
      shift
      inputbox=$1
      ;;
    --title)
      shift
      title=$1
      ;;
    *)
      echo "unknown kdialog options [$1]" 1>&2
      exit 1
  esac
  shift
done

exec </dev/tty 2>/dev/tty
read -p "[$title] $inputbox" -r input
echo -n "$input"

GPG_TTY

前後しましたが gpg 鍵のパスフレーズの入力が必要になったとき、デフォルトでは標準入出力が使用されますが、環境変数 GPG_TTY に tty デバイスファイルを指定しておけば標準入出力は使われずに tty から直接入出力されます。

export GPG_TTY="$(tty)"

前述の --server オプションもそうですが、ProxyCommand に aws ssm start-session を記述して ssm session manager で ssh している場合などでも標準入出力が使われると困るので GPG_TTY は指定しておくと良いでしょう。

さいごに

アクセスキー・シークレットキーと、MFA の TOTP シークレットが同じパスワードストアで同じ gpg 鍵で暗号化されていると MFA が台無しになりそうですが、アクセスキー・シークレットキーを暗記しているような人は存在しないわけで、アクセスキー・シークレットキーと TOTP は結局どちらもそれらが保存されているデバイスの所有物認証でしかなく、暗号化されたパスワードストア(所有物)と gpg 鍵のパスフレーズ(知識)の方がむしろ多要素ではないでしょうか。

もしくは MFA には YubiKey とかも使えるようなので(prompt の ykman が YubiKey です)使えるならそれでも良いかもしれませんが WSL だと簡単ではなさそうです。