薄っぺらりん

厚くしていきたい

AWS CLIのcredentialsを簡単に更新できるツールを作ったよ!

AWSを使っていると、APIの呼び出しにMFA認証を必須とすることが多いかと思います。
コンソールではログイン時に認証コードを入力しますが、AWS CLIを使用する場合は get-session-tokenコマンドで一時的な認証情報を取得し、credentialsファイルを更新するか、 環境変数を設定する必要があります。
一時的な認証情報はAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_SESSION_TOKENの3つでワンセットです。
複数のアカウントを使用しなければならないときはその数だけコマンドを実行し、credentialsファイルのプロファイルを編集する必要があります。
私は最近毎日6アカウントくらい使うのでとても面倒でした。
そこでcredentialsファイルを簡単に更新できるツールaws-mfa-profileを作りました。

github.com

目次

前提条件

  • aws sts get-session-token --serial-number <value> --token-code <value>で一時的な認証情報を取得している
  • Rustのプロジェクトがビルドできる環境

使い方

aws-mfa-profileはオプション-p(あるいは--profile)で指定されたプロファイル名をもとに、mfa.jsonからエントリを探し、sts:GetSessionTokenAPIを叩いて一時的な認証情報を取得し、credentialsファイルを更新します。
mfa.jsonはあらかじめ作成しておく必要があります。

以下はヘルプオプションの実行結果です。

$ aws-mfa-profile -h

aws-mfa-profile 

USAGE:
    aws-mfa-profile [OPTIONS]

OPTIONS:
    -c, --credentials-file <CREDENTIALS_FILE>    aws credentials file name [default: 'credentials']
    -h, --help                                   Print help information
    -m, --mfa-file <MFA_FILE>                    mfa file name [default: 'mfa.json']
    -p, --profile <PROFILE>                      aws profile name [default: 'default']

例えば、devプロファイルでget-session-tokenを実行し、dev_mfaプロファイルの認証情報を更新する場合は次のようにします。
この時のトークンコードは123456です。

$ aws-mfa-profile -p dev
[input] token code: 123456
Success! "credentials" file has been updated.

credentialsファイルにdev_mfaプロファイルのエントリがない場合は[dev_mfa]として自動作成されます。

もしもmfa.jsonやcredentialsファイルがカレントディレクトリにない場合は-mオプションや-cオプションで指定します。

$ aws-mfa-profile -p dev -m .aws/mfa.json -c .aws/credentials
[input] token code: 123456
Success! "credentials" file has been updated.

mfa.jsonの作成

-mオプション(あるいは--mfa-file)で指定するmfa.jsonは次のようなフォーマットになっています。

[
  {
    "profile": "your profile name in .aws/credentials",
    "serial": "your mfa device id",
    "mfa_profile": "your profile name in .aws/credentials"
  }
]

次に示すのはmfa.jsonの例です。

[
  {
    "profile": "default",
    "serial": "default_mfa_device_id",
    "mfa_profile": "mfa"
  },
  {
    "profile": "dev",
    "serial": "dev_mfa_device_id",
    "mfa_profile": "dev_mfa"
  },
  {
    "profile": "prd",
    "serial": "prd_mfa_device_id",
    "mfa_profile": "prd_admin_role"
  }
]

この例の場合、ひとつ目のエントリはdefaultプロファイルを使用してget-session-tokenを実行し、--serial-numberにはdefault_mfa_device_idが使用されます。
取得した認証情報はcredentialsファイルのmfaプロファイルに設定されます。

aws-mfa-profileの実行例

.aws/config.aws/credentials.aws/mfa.jsonの内容を含めた完全な例を示します。

カレントディレクトリは~/.awsとします。

$ cd ~/.aws
$ ls
config credentials mfa.json

configファイルの内容は以下です。

[default]
region = us-east-1

[dev]
region = us-east-1

[dev_mfa]
region = us-east-1

credentialsファイルの内容は以下です。

[default]
aws_access_key_id = hoge_default
aws_secret_access_key = fuga_default

[dev]
aws_access_key_id = hoge_dev
aws_secret_access_key = fuga_dev

mfa.jsonファイルの内容は以下です。

[
  {
    "profile": "dev",
    "serial": "arn:aws:iam::000000000000:mfa/device_id",
    "mfa_profile": "dev_mfa"
  }
]

devプロファイルで一時的な認証情報を取得し、credentialsファイルのdev_mfaプロファイルを更新します。

$ aws-mfa-profile -p dev
[input] token code: 123456
Success! "credentials" file has been updated.

実行後のcredentialsファイルの内容は以下です。
[dev_mfa]のエントリが作成され、一時的な認証情報が設定されます。
もしエントリが既に存在する場合は認証情報に関する値の部分が更新されます。

[default]
aws_access_key_id = hoge_default
aws_secret_access_key = fuga_default

[dev]
aws_access_key_id = hoge_dev
aws_secret_access_key = fuga_dev

[dev_mfa]
aws_access_key_id = hoge_dev_mfa
aws_secret_access_key = fuga_dev_mfa
aws_session_token = token

実行前のcredentialsファイルはcredentials.bkpとしてバックアップされます。

$ ls
config credentials credentials.bkp mfa.json

まとめ

このツールは結構便利で毎日使っています。credentialsファイルの更新は結構面倒だけど頻繁に行う作業なので、同じようなツールを作って使っている人も多いと思います。
最近は仕事もすべてAWS関連のものになり、AWS SDKを使ってちょっとしたツールを作ることが多くなりました。 昨年12月にAWS SDK for Rustのデベロッパープレビューが発表され、Rustでツールを作れることが嬉しいです。 ただLambdaなどで動かすものになるとランタイムがないのでPythonで書いています。やっぱりちょっとしたことをするにはPythonがルーズに書けて便利だなって思ったりします。
そういえば最近そのちょっとしたことで感動したことがありました。 S3 BatchOperationのLambda関数の呼び出しオペレーションで、数万個のオブジェクトの書き換え処理を行ったとき、1~2時間かかるかと思っていたものが数分で完了しました。 メトリクスにはLambdaの同時実行数が900を超えたことが示されていて、スケーラブルとは斯くも素晴らしいことかと感動しました。