YubiKeyでCLI環境でのAWS MFA認証を楽にする
Quick start
YubiKeyの設定ツールをインストール
> brew install ykman
YubiKeyにMFAを登録
> ykman oath accounts add -t arn:aws:iam::${ACCOUNT_ID}:mfa/${MFA_DEVICE_NAME}
YubiKeyタッチでMFAコードを生成
> ykman oath accounts code arn:aws:iam::${ACCOUNT_ID}:mfa/${MFA_DEVICE_NAME}
AWS Vaultをインストール
> brew install --cask aws-vault
AWS VaultにIAMユーザのクレデンシャルを登録
> aws-vault add ${IAM_USERNAME}
~/.aws/config
でMFAとプロファイルの紐付け、Role専用のプロファイルを追加する。
[profile ${IAM_USERNAME}]
region=ap-northeast-1
mfa_serial=arn:aws:iam::${ACCOUNT_ID}:mfa/${MFA_DEVICE_NAME}
source_profile=${IAM_USERNAME}
[profile ${ROLE_PROFILE_NAME}]
include_profile=${IAM_USERNAME}
role_arn=arn:aws:iam::${ACCOUNT_ID}:role/${IAM_ROLE_NAME}
指定したRoleを引き受ける
> aws-vault exec --prompt ykman ${ROLE_PROFILE_NAME}
指定したRoleでAWSコンソールにログイン
> aws-vault login --prompt ykman ${ROLE_PROFILE_NAME}
はじめに
エビリーでは、セキュリティ向上のためにAWS IAM アカウントのMFAを必須にしています。
ただ、ローカル環境からAssumeRoleするたびにMFAの入力を求められるため、1日に数回しか入力しないとしても、毎日続くと、MFAの入力はなかなかの手間です。
そこで、YubiKeyを使った、タッチだけで完了するMFA認証をCLIにも導入する方法を紹介します。
AssumeRole (スイッチロール) について
IAMに細かく権限を設定することで、AWSリソースへのアクセスを制限することができますが、作業する内容ごとにIAMユーザを作成していたのでは、IAMユーザの数が増えて管理が大変です。
そこで、IAMユーザを作業内容ごとに作成せずに、IAM Roleを作業内容ごとに作成し、そのRoleをIAMユーザが作業内容に合わせて引き受けるようにすることで、IAMユーザの管理コストを低減できます。 これを実現するのがAssumeRoleです。
AssumeRoleを細かく説明すると長くなるため、AssumeRoleの説明はここまでとして、
AssumeRoleで引き受けるRoleと、Roleを引き受けるためのPolicyの作成例を紹介します。
AWSコンソールから、IAMロールを作成します。このとき、IAMユーザに対してRoleを引き受けさせる場合は、Fig.1のようにTrusted entity type
にAWS account
を指定します。
他のAWSアカウント内のIAMに対してRoleの引き受けを許可する場合は、An AWS account
の項目でAnother AWS account
を指定することができます。この例では、同じAWSアカウント内のIAMユーザにRoleの引き受けを許可するため、This account
を選択します。
MFA認証を通過したIAMユーザのみに引き受けを許可するため、Require MFA
チェックボックスをONにします。
Fig. 1 Roleの引受先の設定
今回は、Fig.2のように、読み取りのみの権限である、ReadOnlyAccessポリシーをアタッチします。
Fig. 2 Roleへのポリシー割当
最後に、Fig.3のとおりRoleの名前と説明を入力して完了です。
Fig. 3 Role名設定
Policyでは、下記のように作成したRoleのARNに対してAssumeRoleを許可します。${ACCOUNT_ID}
は環境に合わせて設定してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::${ACCOUNT_ID}:role/read-only-access"
}
]
}
このポリシーをIAMグループにアタッチすることで、グループに所属するIAMユーザは、作成した読み取り専用Role(role/read-only-access
)を引き受けることができます。
YubiKey について
YubiKeyは、USBに接続してタッチするだけで認証が完了するデバイスになります。
GoogleやGithub等のログイン時にも使用できるため、既に利用されている方も多いと思います。
今回は、パスワードレス認証(FIDO認証)ではなく、ワンタイムパスワード認証(OATH-TOTP認証)を使用するため、YubiKeyでも比較的安価なSecurity Keyシリーズは利用することができません。5シリーズ等のOATH-TOTP認証が利用可能なYubiKeyを使用する必要があります。
YubiKeyにMFAを登録する
AWSコンソールへのログインにYubiKeyを利用されている方も多いのではないでしょうか。
そのため、IAMユーザへのMFAデバイスの登録時にSecurity Keyを選択したくなりますが、2022年11月現在では、CLI環境下でのMFA認証でSecurity Keyを使用することはできません。
Fig.4のとおり、CLI環境下でもMFA認証可能な、Virtual MFA デバイスとして登録する必要があります。
Fig. 4 MFAデバイスの指定 (Virtual MFA deviceを指定する)
Virtual MFA デバイスを登録する際に、QRコードを読み取るのではなく、Fig.5のようにシークレットキーを表示してYubiKeyに登録します。
Fig. 5 MFAシークレットキーの取得
YubiKeyの設定ツールであるykmanをインストールします。
> brew install ykman
発行したシークレットキーを登録します。${ACCOUNT_ID}
と${MFA_DEVICE_NAME}
は、ご利用の環境に合わせて変更してください。
> ykman oath accounts add -t arn:aws:iam::${ACCOUNT_ID}:mfa/${MFA_DEVICE_NAME}
Enter a secret key (base32):
YubiKeyへの登録に成功すると下記のコマンドでMAFコードを生成できるようになりますので2つMFAコードを生成して、AWS側の登録を完了させます。
> ykman oath accounts code arn:aws:iam::${ACCOUNT_ID}:mfa/${MFA_DEVICE_NAME}
Touch your YubiKey...
arn:aws:iam::${ACCOUNT_ID}:mfa/${MFA_DEVICE_NAME} 289460
AWS Vault について
AWS Vaultは、AWSクレデンシャルを安全に保存するツールです。
AWSクレデンシャルは、~/.aws/credentials
に平文で保存されるため、MAF認証が必要だとしても、安心できないため利用されている方も多いのではないでしょうか。
上述の手順で、MAFコードを生成できるようにはなりましたが、まだ、YubiKeyのタッチだけでAssumeRoleが完了するようにはなっていません。
AWS Vaultとykmanを組み合わせることで、タッチだけでのAssumeRoleが可能となります。
まず、AWS Vaultをインストールします。
> brew install --cask aws-vault
次に、Fig.5のようにMFAを設定したIAMユーザのクレデンシャルを取得して、aws-vaultに登録します。
Fig. 5 IAMクレデンシャルの取得
> aws-vault add ${IAM_USERNAME}
Enter Access Key ID:
Enter Secret Access Key:
Added credentials to profile "${IAM_USERNAME}" in vault
AWS VaultへのIAMユーザの登録に成功すると、~/.aws/config
に[profile ${IAM_USERNAME}]
が追加されます。
ここに、mfa_serial
とsource_profile
追記します。mfa_serial
はvirtual MFAとプロファイルの紐付けを設定し、source_profile
は、このプロファイルがRoleの引き受け元プロファイルであることを設定しています。
[profile ${IAM_USERNAME}]
mfa_serial=arn:aws:iam::${ACCOUNT_ID}:mfa/${MFA_DEVICE_NAME}
source_profile=${IAM_USERNAME}
さらに、AssumeRoleで引き受けるRoleのプロファイル設定を追記します。ここでは、AssumeRoleのセクションで作成したarn:aws:iam::${ACCOUNT_ID}:role/read-only-access
を引き受けるプロファイルを追加します。ここで、include_profile
は、引き受けるRoleの元プロファイルを指定しています。
[profile read-only-role]
include_profile=${IAM_USERNAME}
role_arn=arn:aws:iam::${ACCOUNT_ID}:role/read-only-access
これで、設定完了です。試しに、作成した読み取り専用のRoleに切り替えてみましょう。
> aws-vault exec --prompt ykman read-only-role
Touch your YubiKey..
YubiKeyをタッチするだけで、Roleを引き受けることができました。あとは、通常通りaws cliを実行するだけで、読み取り専用のRoleでaws cliが実行されます。
> aws s3 ls
その他にも、aws-vaultのloginコマンドを使用することで、YubiKeyをタッチするだけで、指定したRoleでAWSコンソールにログインすることができます。
> aws-vault login --prompt ykman read-only-role
AWS Vaultはクレデンシャルのローテーション等、AWSクレデンシャルを取り扱う上で、便利な機能がたくさんあるため、使い方を時間があるときに読むことをおすすめします。
終わりに
YubiKeyをタッチするだけでセキュアなAssumeRoleができるようになりました。
これで、日々のフラストレーションが軽減できたのではないかと思います。
ただ、1回だけと言っても、上述の設定をするのが面倒なため、
はやくCLI環境でも、Virtual MFAデバイスを経由するのではなく、YubiKey、パスキーを直接使用したMFA認証に対応してほしいですね。
追記 - プロファイルオプションについて
コメントいただきましたので追記します。
aws関連のコマンドで--profile
オプションでRoleを指定することで、Roleの切り替えとCLIによる操作を同時に行えます。
このときは、コメント頂きましたように、Roleの引き受け元プロファイルにcredential_process
を記述します。
また、Roleの引き受け元プロファイルにcredential_process
が存在する場合は、source_profile
は引き受けるRole側のプロファイルに記述する必要がありますので、~/.aws/config
でのプロファイル設定は下記のようになります。
[profile ${IAM_USERNAME}]
mfa_serial=arn:aws:iam::${ACCOUNT_ID}:mfa/${MFA_DEVICE_NAME}
credential_process=aws-vault exec ${IAM_USERNAME} --json --prompt ykman --
[profile ${ROLE_PROFILE_NAME}]
include_profile=${IAM_USERNAME}
source_profile=${IAM_USERNAME}
role_arn=arn:aws:iam::${ACCOUNT_ID}:role/${IAM_ROLE_NAME}
以上の設定で、下記のようにRoleの切り替えとCLIによる操作を同時に行うことができます。ただし、セッションが切れると、MFAの再認証のためYubiKeyのタッチが必要になりますが、タッチを促すメッセージは2022年11月現在では表示されない模様です。
セッションが切れていると思われる状況で、YubiKeyが点滅している場合は、YubiKeyをタッチしてください。ただし、YubiKeyのタッチは不用意に実行すると不正にMFA認証を通過させてしてしまう可能性があるため慎重にタッチしましょう。
> aws s3 ls --profile ${ROLE_PROFILE_NAME}
Discussion
.aws/config
に以下の設定をすると、セッションがない場合に自動で認証してくれます。コメントありがとうございます。コメントいただきました内容に関して追記させていただきました。
MFAを有効にしたIAMユーザーでAWS CLIを使う際に作業負荷を下げる方法を探していたので、非常に助かりました。
ありがとうございます。
ところで、
${IAM_USERNAME}
というプレースホルダーの部分、ここは少々混乱しました。実際に指定するのは任意の文字列であり、IAMユーザー名とは無関係ですよね。
なので、プロジェクト名
project-1
で使っているアカウントID123456789012
のIAMユーザーlongman
について、わかりやすいようにプロジェクト名
+IAMユーザー名
でプロファイルを作りました。というコマンドを実行し、configに
[profile project1-longman]
というエントリが生成されます。あともう1つ、私の環境ではデフォルトリージョンをセットしていないので、プロファイルにリージョンがない場合は
aws-vault exec --prompt ykman project1-longman-s3-io
で以下のエラーが返りました。そんなこんなで、最終的なconfigがこんな感じになりました(
s3-io
は検証用にS3フルアクセスを持つロールです)。