🔥

YubiKeyでCLI環境でのAWS MFA認証を楽にする

2022/11/25に公開
3

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専用のプロファイルを追加する。

~/.aws/config
[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 typeAWS accountを指定します。
他のAWSアカウント内のIAMに対してRoleの引き受けを許可する場合は、An AWS accountの項目でAnother AWS accountを指定することができます。この例では、同じAWSアカウント内のIAMユーザにRoleの引き受けを許可するため、This accountを選択します。
MFA認証を通過したIAMユーザのみに引き受けを許可するため、Require MFAチェックボックスをONにします。

role-entity.png
Fig. 1 Roleの引受先の設定

今回は、Fig.2のように、読み取りのみの権限である、ReadOnlyAccessポリシーをアタッチします。
role-policy.png
Fig. 2 Roleへのポリシー割当

最後に、Fig.3のとおりRoleの名前と説明を入力して完了です。
role-name.png
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 デバイスとして登録する必要があります。

mfa-virtual.png
Fig. 4 MFAデバイスの指定 (Virtual MFA deviceを指定する)

Virtual MFA デバイスを登録する際に、QRコードを読み取るのではなく、Fig.5のようにシークレットキーを表示してYubiKeyに登録します。
mfa-secret.png
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に登録します。
access_key.png
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_serialsource_profile追記します。mfa_serialはvirtual MFAとプロファイルの紐付けを設定し、source_profileは、このプロファイルがRoleの引き受け元プロファイルであることを設定しています。

~/.aws/config
[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の元プロファイルを指定しています。

~/.aws/config
[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でのプロファイル設定は下記のようになります。

~/.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

Tomoya AmachiTomoya Amachi

.aws/config に以下の設定をすると、セッションがない場合に自動で認証してくれます。

[profile ${IAM_USERNAME}]
mfa_serial=arn:aws:iam::${ACCOUNT_ID}:mfa/${MFA_DEVICE_NAME}
credential_process=aws-vault exec  <aws-vault profile名> --json --prompt ykman --
Eviry Tech BlogEviry Tech Blog

コメントありがとうございます。コメントいただきました内容に関して追記させていただきました。

longman_584longman_584

MFAを有効にしたIAMユーザーでAWS CLIを使う際に作業負荷を下げる方法を探していたので、非常に助かりました。
ありがとうございます。

ところで、${IAM_USERNAME}というプレースホルダーの部分、ここは少々混乱しました。
実際に指定するのは任意の文字列であり、IAMユーザー名とは無関係ですよね。

なので、プロジェクト名project-1で使っているアカウントID123456789012のIAMユーザーlongmanについて、わかりやすいようにプロジェクト名+IAMユーザー名でプロファイルを作りました。

aws-vault add project1-longman

というコマンドを実行し、configに[profile project1-longman]というエントリが生成されます。

あともう1つ、私の環境ではデフォルトリージョンをセットしていないので、プロファイルにリージョンがない場合はaws-vault exec --prompt ykman project1-longman-s3-ioで以下のエラーが返りました。

operation error STS: AssumeRole, failed to resolve service endpoint, an AWS region is required, but was not found

そんなこんなで、最終的なconfigがこんな感じになりました(s3-ioは検証用にS3フルアクセスを持つロールです)。

[profile project1-longman]
region=ap-northeast-1
mfa_serial=arn:aws:iam::123456789012:mfa/yubi-for-switch
source_profile=project1-longman

[profile project1-longman-s3-io]
include_profile=project1-longman
role_arn=arn:aws:iam::123456789012:role/s3-io