~/.aws/(config|credentials)の設定情報を元にMFAを行い、一時的なセキュリティ認証情報を取得してコマンドを実行するawsdoを作った

久しぶりに使うAWSのprofileがありまして、そのprofileについての記憶が失われていた結果、コマンド実行成功までに時間を溶かしてしまいました。

というのも、私は普段使うprofileではaswrapでAssumeRole(と多要素認証)を透過的に便利に実行していた結果、IAMの認証設定については何も考えなくなっていて「とりあえず aswrap 」を実行していました。

そして、

$ AWS_PROFILE=myaws aswrap aws s3 ls

An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied

「あれ?認証情報無効にしたっけな 🤔」とか、トンチンカンな推測をしていました。

よくよく確認してみたらそのprofileは「MFAは必須だがAssumeRole用ではない」profileで、aws sts assume-role ではなく、 aws sts get-session-token でMFAを通す(多要素認証をする)べきものでした。

「じゃあ aswrap と同じ使い勝手で aws sts get-session-token を実行するラッパーコマンドを作ればいい」と思い立ち、書いているうちに最終的には~/.aws/(config|credentials)の設定情報を元に aws sts assume-roleaws sts get-session-token を使い分けて一時的なセキュリティ認証情報を取得してコマンドを実行するラッパーコマンドになりました。

github.com

インストール

macOSであればHomebrewでインストール可能です。

$  brew install k1LoW/tap/awsdo

その他のインストール方法はREADMEに記載しています。

使い方

使い方はaswrapとほぼ同じで、一時的なセキュリティ認証情報を使って実行したいコマンドを awsdo の引数に指定するだけです。

AWS_PROFILE=myaws awsdo -- terraform apply
Enter MFA code for arn:aws:iam::111111111111:mfa/k1low: 123456
[...]

引数に何も渡さなければ環境変数を出力します。

$ AWS_PROFILE=myaws awsdo
Enter MFA code for arn:aws:iam::111111111111:mfa/k1low: 123456
export AWS_REGION=ap-northeast-1
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=vl/Zv5hGxdy1DPh7IfpYwP/YKU8J6645...
export AWS_SESSION_TOKEN=FwoGZXIYXdGUaFij9VStcW9fcbuKCKGAWjLxF/3hXgGSoemniFV...

awsdoの動き

awsdoは以下のように動きます。

  • まず、~/.aws/credentials~/.aws/config を読み込みます。
  • 環境変数 AWS_PROFILE--profile オプションから対象のprofileのセクションを探します。
  • 一時的なセキュリティ認証情報を取得します。対象セクションの設定によって以下のように挙動を変えます。
    1. もし対象セクションが role_arn を持っていれば、 awsdo は assume role を試みます ( sts:AssumeRole ).
      • 対象セクションに mfa_serial の記載がない場合でも、 awsdo は一度有効なMFAデバイスの有無を問い合わせます。 ( iam:ListMFADevices ).
      • 前段でMFAデバイス ( mfa_serial )を取得出来ている場合、MFAを実施します(トークンコードを要求します)
      • 一時的なセキュリティ認証情報を取得します
    2. もし対象セクションが role_arn を持っていなければ、awsdo は session token の取得を試みます ( sts:getSessionToken ).
      • 対象セクションに mfa_serial の記載がない場合でも、 awsdo は一度有効なMFAデバイスの有無を問い合わせます。 ( iam:ListMFADevices ).
      • 前段でMFAデバイス ( mfa_serial )を取得出来ている場合、MFAを実施します(トークンコードを要求します)
      • 一時的なセキュリティ認証情報を取得します
  • 一時的なセキュリティ認証情報を環境変数にセットして引数に渡されたコマンドを実行するか、環境変数をexportコマンドの形で出力します。
    • AWS_ACCESS_KEY_ID
    • AWS_SECRET_ACCESS_KEY
    • AWS_SESSION_TOKEN
    • AWS_REGION

挙動として特徴的なのは

  1. ~/.aws/credentials~/.aws/config の設定によってaws sts assume-roleaws sts get-session-token と挙動を変える
  2. 設定情報に mfa_serial がなくてもMFAデバイスを問い合わせてMFAをしようと試みる
  3. 必ず一時的なセキュリティ認証情報を取得して利用する

というところでしょうか。

1と2を実現したことで、~/.aws/(config|credentials)の設定について考えることができるだけなくなることを期待しています。

まとめ

AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY は手元にあるけどCLIでMFAを通すための設定よくわからん」「STS好き」という方は是非「とりあえず awsdo 」も試してみてください。

また、本文からもお分かりのとおり、 awsdo は aswrap の仕組みに大きな影響を受けています。aswrapの便利さを知っていたからこそawsdoの実装をしたのは間違いありません。

aswrap に限らず数々の便利OSSツール/ライブラリの発明していただいているfujiwara さんには本当に感謝しております!!

以上、久しぶりのAWS関連エントリでした。