ツールが未対応でもMFA & AssumeRoleしたい! aws-mfaを使って簡単に一時的な資格情報を生成してみた

aws-mfaって?

aws-mfaはOSS(MITライセンス)で公開されている、MFAが適用されている、AssumeRoleが必要なアカウントに対して使用するツールです。
AWS STSから一時的な資格情報を取得して、AWS資格情報ファイル(~/.aws/credentials)へ書き出しするプロセスを自動で行ってくれます。
broamski/aws-mfa: Manage AWS MFA Security Credentials

インストール

インストール方法は2通りあります。お好みの方法でインストールしてください。

pipを使ってインストール

pip install aws-mfa

リポジトリをクローンしてインストール

git clone https://github.com/broamski/aws-mfa
cd ./aws-mfa
python setup.py install

使い方

~/.aws/credentialsの設定

~/.aws/credentials に以下の様に設定します。
profile_nameは任意のプロファイル名を設定し、AWS_ACCESS_KEY,AWS_SECRET_ACCESS_KEYには自分のアカウントの資格情報を取得して設定してください。
対象のアカウントが、MFA適用でないならaws_mfa_deviceは指定する必要がありません。

[profile_name-long-term]
aws_access_key_id = {AWS_ACCESS_KEY}
aws_secret_access_key = {AWS_SECRET_ACCESS_KEY}
aws_mfa_device = {AWS_MFA_DEVICE}
assume_role = {ASSUME_ROLE}
arn:aws:iam::123456789012:mfa/tanaka.taro
AWSアカウント番号は自分のアカウント番号です。(AssumeRole元)
arn:aws:iam::210987654321:role/tanaka.taro
AWSアカウント番号は対象のアカウント番号です。(AssumeRole先)

資格情報の取得

資格情報を取得します。

aws-mfa --profile profile_name

ワンタイムパスワードの入力を求められるので入力します。

INFO - Validating credentials for profile: profile_name
INFO - Short term credentials section profile_name is missing, obtaining new credentials.
Enter AWS MFA code for device [arn:aws:iam::123456789012:mfa/tanaka.taro] (renewing for 3600 seconds):{OTP}
INFO - Assuming Role - Profile: profile_name, Role: arn:aws:iam::210987654321:role/tanaka.taro, Duration: 3600
INFO - Success! Your credentials will expire in 3600 seconds at: 2018-05-16 12:37:48+00:00

~/.aws/credentials を確認すると資格情報が登録されています。

[profile_name]
assumed_role = True
assumed_role_arn = arn:aws:iam::210987654321:role/tanaka.taro
aws_access_key_id = {AWS_ACCESS_KEY}
aws_secret_access_key = {AWS_SECRET_ACCESS_KEY}
aws_session_token = {AWS_SESSION_TOKEN}
aws_security_token = {AWS_SECURITY_TOKEN}
expiration = 2018-05-16 12:37:48

再度コマンドを実行すると、どうなるのでしょうか?試してみました。

aws-mfa --profile profile_name

取得中の認証情報がまだ有効であると表示されました。

INFO - Validating credentials for profile: profile_name with assumed role: arn:aws:iam::210987654321:role/tanaka.taro
INFO - Your credentials are still valid for 3295.108415 seconds they will expire at 2018-05-16 12:37:48

さらに、意図的にexpiration を過去の日付に書き換えて実行してみました。

aws-mfa --profile profile_name

期限切れの場合は初回と同じように動作しました。

INFO - Validating credentials for profile: profile_name
INFO - Short term credentials section profile_name is missing, obtaining new credentials.
Enter AWS MFA code for device [arn:aws:iam::123456789012:mfa/tanaka.taro] (renewing for 3600 seconds):{OTP}
INFO - Assuming Role - Profile: profile_name, Role: arn:aws:iam::210987654321:role/tanaka.taro, Duration: 3600
INFO - Success! Your credentials will expire in 3600 seconds at: 2018-05-16 12:44:39+00:00

~/.aws/credentials を確認すると資格情報が更新されていました!

オプションの紹介

aws-mfaには --profile 以外の複数のオプションがあります。
それぞれの使い方を紹介していきます。

--device

--device arn:aws:iam::123456788990:mfa/dudeman
                        The MFA Device ARN. This value can also be provided
                        via the environment variable 'MFA_DEVICE' or the
                        ~/.aws/credentials variable 'aws_mfa_device'.

MFAデバイスを指定するオプションです。
環境変数 'MFA_DEVICE' または ~/.aws/credentials の aws_mfa_device を使用して指定することもできます。
MFA非適用のアカウントの場合は意識する必要がありません。

--duration

--duration DURATION     The duration, in seconds, that the temporary
                        credentials should remain valid. Minimum value: 900
                        (15 minutes). Maximum: 129600 (36 hours). Defaults to
                        43200 (12 hours), or 3600 (one hour) when using
                        '--assume-role'. This value can also be provided via
                        the environment variable 'MFA_STS_DURATION'.

取得する一時的な資格情報の有効期間を秒で指定するオプションです。
デフォルト値は43200(12時間)で、最小は900(15分) 最大は129600(36時間)です。
'--assume-role'を使用している場合、デフォルトが3600(1時間)になります。
環境変数 'MFA_STS_DURATION'を使用して指定することもできます。

--profile

--profile PROFILE       If using profiles, specify the name here. The default
                        profile name is 'default'. The value can also be
                        provided via the environment variable 'AWS_PROFILE'.

~/.aws/credentials から読み込むプロファイル名を指定します。
デフォルトでは default がプロファイル名です。
環境変数 'AWS_PROFILE'を使用して指定することもできます。

--long-term-suffix

--long-term-suffix LONG_TERM_SUFFIX
                        To identify the long term credential section by
                        [<profile_name>-LONG_TERM_SUFFIX]. Use 'none' to
                        identify the long term credential section by
                        [<profile_name>]. Omit to identify the long term 
                        credential section by [<profile_name>-long-term].

~/.aws/credentials から読み込むプロファイル名のサフィックスを指定します。
指定しなければ、 {profile_name}-long-term が読み込まれます。
サフィックスなしにしたい場合は、 none で指定してください。

--short-term-suffix

--short-term-suffix SHORT_TERM_SUFFIX
                        To identify the short term credential section by
                        [<profile_name>-SHORT_TERM_SUFFIX]. Omit or use 'none'
                        to identify the short term credential section by
                        [<profile_name>].

~/.aws/credentials へ生成するプロファイル名のサフィックスを指定します。
指定しなければ、 {profile_name} で生成されます。
明示的にサフィックスなしにしたい場合は、 none で指定してください。

--assume-role

--assume-role arn:aws:iam::123456788990:role/RoleName
                        The ARN of the AWS IAM Role you would like to assume,
                        if specified. This value can also be provided via the
                        environment variable 'MFA_ASSUME_ROLE'

AssumeRoleを指定するオプションです。
環境変数 'MFA_ASSUME_ROLE' または ~/.aws/credentials の assume_role を使用して指定することもできます。
AssumeRoleしないアカウントの場合は意識する必要がありません。

--role-session-name

--role-session-name ROLE_SESSION_NAME
                        Friendly session name required when using --assume-
                        role. By default, this is your local username.

AssumeRoleする際のロールセッション名を指定するオプションです。
指定しない場合は、ローカルユーザー名が使用されます。
AssumeRoleしないアカウントの場合は意識する必要がありません。

運用方法

direnvと組み合わせて使用しています。

direnv で特定のディレクトリ下の環境変数を定義する

aws-mfa --profile myproject --short-term-suffix dev
aws-mfa --profile myproject --short-term-suffix stg
aws-mfa --profile myproject --short-term-suffix prd

後は、ツール側でdevの時は myproject-devをstgの時はmyproject-stgを読み込むように設定します。
環境分けが不要な時は--short-term-suffixを外して、myprojectを読み込むように設定しています。

あとがき

このツールを知ったきっかけは、TerraformがAssumeRoleやMFA適用されたアカウント'単独'には対応しているが、AssumeRoleかつ元アカウトがMFA適用されている場合は動作しなかったからです。
TerraformのWorkspace機能を使って環境分けを行っており、なんとかしたいなとひたすらググり続けてたどり着きました。
AssumeRole、MFAの利用を肩代わりしてくれるイカしたツールです!(~/.aws/credentials から aws_session_token,aws_security_token を読み込むのに対応している必要はありますが)
このブログを書いている今 TerraformでMFA & AssumeRoleできるぞ!ってマサカリ飛んできそうで怖いですwでも、できるならぜひ知りたいです!