特定の接続元IPアドレス以外からの「AWSコマンドラインインターフェイス(AWS CLI v2)」実行時のみMFA(Multi-Factor Authentication)が必要になるようにIAMの設定をしたので、その際の手順を自分用のメモとしてまとめました。
MFA(Multi-Factor Authentication:多要素認証)とは
参考: Wikipedia - 多要素認証
https://ja.wikipedia.org/wiki/多要素認証
簡単に説明すると次の4つの要素のうち2要素以上を使用して認証を行うことです
1.知る要素
2.持つ要素
3.備える要素
4.場所の要素
認証を多段階で実施しても(多段階認証をしても)、同じ要素での認証ではセキュアではないとされています(例: ”印鑑”と”通帳”など)
ちなみに、
天空の城ラピュタにおける崩壊の呪文は、
- ”バルス” という呪文を【←知る要素】
- 飛行石の結晶 を持った状態で【←持つ要素】
- 王族の人間 が【←備える要素】
- ラピュタ内の聖域と呼ばれる場所 で【←場所の要素】
唱えた場合のみ発動するので四要素認証になっています∑d(゚∀゚d)イカス!!
MFA(Multi-Factor Authentication)を設定しないとどうなるのか?
「AWS CLI」を使用するためにはアクセスキー(アクセスキーIDとシークレットキーのキーペア)が必要になるのですが、このアクセスキーが漏洩すると怖いことが起こります。
参考: 初心者がAWSでミスって不正利用されて$6,000請求、泣きそうになったお話。
https://qiita.com/mochizukikotaro/items/a0e98ff0063a77e7b694
参考: GitHub に AWS キーペアを上げると抜かれるってほんと???試してみよー!
https://qiita.com/saitotak/items/813ac6c2057ac64d5fef
AWSではどういった対策ができるのか?
[AWSマネージメントコンソールへのアクセス]時に ”スマーフォンデバイス(TOTP:Time-based One-Time Password)” での認証を有効にする↓というのは比較的知られていますが、「AWS CLI」でも同様に設定することが可能です。
少し違う点は、「AWS CLI」の場合、1コマンド実行するごとにワンタイムパスワード認証を求められるのはツライので、
「AWS Security Token Service (AWS STS)」より払い出された有効期限付き(デフォルト1時間)のセッショントークンを使用するという点です。
まず、前半の部分で「AWS STS」のセッショントークンを払い出す際はMFAを必要とする設定を行います。
加えて、後半の部分で、特定の接続IPアドレスからのアクセス時のみは、ワンタイムパスワードの入力なしでアクセスキー(アクセスキーIDとシークレットキーのキーペア)だけで実行できるようにする設定を行います。
1. IAMグループとIAMユーザーの作成 (「管理者」側手順)
まず、AWS CLI を実行する際に使用するIAMユーザーを作成します。
設定はIAMポリシーで制御するのですが、AWSのベストプラクティスに従って、IAMユーザーに直接ポリシーをアタッチするのではなく、IAMグループを作成して、作成したIAMグループに対してMFAを有効化するためのポリシーをアタッチしていきます
□手順 1-1: [Identity and Access Management(IAM)]サービスの[グループ]メニュー画面で[新しいグループの作成]をクリックします
□手順 1-2: [グループ名]に任意の名前(ここではMyUsers
)を入力し[次のステップ]をクリックします
□手順 1-3: [ポリシーのアタッチ]画面で、任意のAWS管理ポリシー(ここではPowerUserAccess
ポリシー)を選択し[次のステップ]をクリックします
□手順 1-4: 内容を確認し[グループの作成]をクリックします
□手順 1-5: IAMグループ(MyUsers
)が作成されたことを確認します
□手順 1-6: 続いて[Identity and Access Management(IAM)]サービスの[ユーザー]メニュー画面に移り[ユーザーを追加]をクリックします
□手順 1-7: [ユーザー名]に任意の名前(ここではcli-user
)を入力し[プログラムによるアクセス]にチェックを入れて[次のステップ:アクセス権限]をクリックします
※必要ではないのでチェックを入れていませんが[AWSマネージメントコンソールへのアクセス]にチェックを入れても問題はないと思います
□手順 1-8: [ユーザーをグループに追加]で先ほど作成したIAMグループを選択し[次のステップ:タグ]をクリックします
□手順 1-9: 必要に応じてタグを設定し(ここでは何も設定せずに)[次のステップ:確認]をクリックします
□手順 1-10: 内容を確認し[ユーザーの作成]をクリックします
□手順 1-11: "成功"のメッセージを確認し[.csvのダウンロード]をクリックして完了です
※ダウンロードした CSVファイル は後ほど使用します
2. 「スマートフォンデバイス」(←持つ要素)によるMFA(多要素認証)の有効化 (「管理者」側手順)
AWSでは「仮想MFAデバイス」と「AWS Security Token Service (AWS STS)」の仕組みを使う事で「AWS CLI」でも「スマートフォンデバイス」(←持つ要素)でのMFA(多要素認証)を実現することができます
□手順 2-1: 作成したIAMグループ(MyUsers
)をクリックします
□手順 2-2: [アクセス許可]タブをクリックします
□手順 2-3: [インラインポリシー]の”ここをクリックしてください”部分をクリックします
□手順 2-4: [カスタムポリシー]にチェックを入れます
□手順 2-5: [ポリシー名]に任意の名前(ここではMyUsersPolicy
)、[ポリシードキュメント]に次の「AWSユーザーガイド」記載の内容を入力して[ポリシー]の適用をクリックします
AWSユーザーガイド - IAM: IAM ユーザーに MFA デバイスの自己管理を許可する
https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_examples_iam_mfa-selfmanage.html
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListActions",
"Effect": "Allow",
"Action": [
"iam:ListUsers",
"iam:ListVirtualMFADevices"
],
"Resource": "*"
},
{
"Sid": "AllowIndividualUserToListOnlyTheirOwnMFA",
"Effect": "Allow",
"Action": [
"iam:ListMFADevices"
],
"Resource": [
"arn:aws:iam::*:mfa/*",
"arn:aws:iam::*:user/${aws:username}"
]
},
{
"Sid": "AllowIndividualUserToManageTheirOwnMFA",
"Effect": "Allow",
"Action": [
"iam:CreateVirtualMFADevice",
"iam:DeleteVirtualMFADevice",
"iam:EnableMFADevice",
"iam:ResyncMFADevice"
],
"Resource": [
"arn:aws:iam::*:mfa/${aws:username}",
"arn:aws:iam::*:user/${aws:username}"
]
},
{
"Sid": "AllowIndividualUserToDeactivateOnlyTheirOwnMFAOnlyWhenUsingMFA",
"Effect": "Allow",
"Action": [
"iam:DeactivateMFADevice"
],
"Resource": [
"arn:aws:iam::*:mfa/${aws:username}",
"arn:aws:iam::*:user/${aws:username}"
],
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
},
{
"Sid": "BlockMostAccessUnlessSignedInWithMFA",
"Effect": "Deny",
"NotAction": [
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:ListMFADevices",
"iam:ListUsers",
"iam:ListVirtualMFADevices",
"iam:ResyncMFADevice"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}
このインラインポリシーを適用することによりユーザーは後述するMFAデバイスの登録作業などを以外のオペレーションはMFAなしでは実行できないようになります
□手順 2-6: 「管理者」側手順はこれで終了です
4. 仮想MFAデバイスの作成 (「ユーザー」側手順)
ここから「AWS CLI v2」を使用する「ユーザー」側の手順です
□手順 4-1: 「AWS CLI v2」の新機能であるaws configure import
コマンドを使ってIAMユーザー作成時にダウンロードしたCSVファイルからクレデンシャル情報(アクセスキーの情報)を読み取ります
aws configure import --csv file://<CSVファイル名>
[user@workstaion ~]$ aws configure import --csv file://credentials.csv
Successfully imported 1 profile(s)
□手順 4-2: この状態でコマンドを実行するとAccess Denied
となってしまうことを確認します
[user@workstaion ~]$ aws s3 ls --proflie "cli-user"
An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
□手順 4-3: aws iam create-virtual-mfa-device
コマンドを実行して仮想MFAデバイスと共有鍵情報が保存されたQRコードを生成します
--virtual-mfa-device-name
パラメーターに設定する名前はIAMユーザーと同じにしてください
aws iam create-virtual-mfa-device --virtual-mfa-device-name "<IAMユーザー名>" --outfile <QRコードを出力する任意のパス> --bootstrap-method "QRCodePNG" --profile "<IAMユーザープロファイル名>"
[user@workstaion ~]$ aws iam create-virtual-mfa-device --virtual-mfa-device-name "cli-user" --outfile .\QRCode.png --bootstrap-method "QRCodePNG" --profile "cli-user"
{
"VirtualMFADevice": {
"SerialNumber": "<作成された仮想MFAデバイスのリソースネーム(ARN)>"
}
}
ここで出力される”仮想MFAデバイスのリソースネーム(ARN)"の値は後ほど使用するのでメモしておきます
AWS管理コンソールからも確認可能です(該当IAMユーザーの[認証情報]タブ)↓
□手順 4-4: 「Google 認証システム(Google Authenticator)」などをスマートフォンにインストールして先ほど生成した共有鍵情報が保存されたQRコードを読み取ります
App Store - Google Authenticator
https://apps.apple.com/jp/app/google-authenticator/id388497605
Google Play - Google 認証システム
https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2
□手順 4-5: aws iam enable-mfa-device
コマンドを実行して作成した仮想MFAデバイスの有効化(スマートフォンデバイスとの同期)を行います
aws iam enable-mfa-device --user-name "<IAMユーザー名>" --serial-number "<仮想MFAデバイスのリソースネーム(ARN)>" --authentication-code1 "<MFAデバイスに表示されている6桁の数字>" --authentication-code2 "<`--authentication-code1`に設定した値の次に表示される6桁の数字>" --profile "<IAMユーザープロファイル名>"
[user@workstaion ~]$ aws iam enable-mfa-device --user-name "cli-user" --serial-number "<仮想MFAデバイスのリソースネーム(ARN)>" --authentication-code1 "123456" --authentication-code2 "234567" --profile "cli-user"
□手順 4-6: aws sts get-session-token
コマンドを実行することで有効期限付き(デフォルト1時間)のセッショントークンを取得することができます
aws sts get-session-token --serial-number "<仮想MFAデバイスのリソースネーム(ARN)>" --token-code <MFAデバイスに表示されている6桁の数字> --profile "<IAMユーザープロファイル名>"
[user@workstaion ~]$ aws sts get-session-token --serial-number "<仮想MFAデバイスのリソースネーム(ARN)>" --token-code <MFAデバイスに表示されている6桁の数字> --profile "cli-user"
{
"Credentials": {
"AccessKeyId": "<アクセスキーID>",
"SecretAccessKey": "<シークレットアクセスキー>",
"SessionToken": "<セッショントークン>",
"Expiration": "<セッショントークンの有効期限(yyyy-MM-ddTHH:mm:ss+00:00)>"
}
}
□手順 4-7: aws sts get-session-token
コマンドで得られた値を次の環境変数に設定します
環境変数名 | 設定する値 | 説明 |
---|---|---|
AWS_ACCESS_KEY_ID | Credentials.AccessKeyIdの値 | アクセスキーID |
AWS_SECRET_ACCESS_KEY | Credentials.SecretAccessKeyの値 | シークレットアクセスキー |
AWS_SESSION_TOKEN | Credentials.SessionTokenの値 | セッショントークン |
[MacOSやLinux環境での実行例]jq
コマンドが使える環境であれば次のようなスクリプトを作成して実行します
virtualMFADevice = "<仮想MFAデバイスのリソースネーム(ARN)>"
profileName = "cli-user"
echo "MFAデバイスに表示されている6桁の数字を入力してください"
read tokenCode
sessionToken=$(aws sts get-session-token --serial-number "$virtualMFADevice" --token-code "$tokenCode" --profile "$profileName")
export AWS_ACCESS_KEY_ID=$(echo $sessionToken | jq -r .Credentials.AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo $sessionToken | jq -r .Credentials.SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo $sessionToken | jq -r .Credentials.SessionToken)
[Windows環境での実行例]PowerShellのConvertFrom-Json
コマンドレットを使えばJSONのパースが可能なので次のようなスクリプトを作成して実行します
$virtualMFADevice = "<仮想MFAデバイスのリソースネーム(ARN)>"
$profileName = "cli-user"
$tokenCode = Read-Host "MFAデバイスに表示されている6桁の数字を入力してください"
$sessionToken = $(& aws sts get-session-token --serial-number "$virtualMFADevice" --token-code "$tokenCode" --profile "$profileName" | ConvertFrom-Json)
$env:AWS_ACCESS_KEY_ID=$sessionToken.Credentials.AccessKeyID
$env:AWS_SECRET_ACCESS_KEY=$sessionToken.Credentials.SecretAccessKey
$env:AWS_SESSION_TOKEN=$sessionToken.Credentials.SessionToken
□手順 4-8: この状態で「AWS CLI」を実行し Access Denied などのエラーメッセージが表示されなくなっていれば成功です
※この時--profile
オプションの付与は不要です
[user@workstaion ~]$ aws s3 ls
yyyy-MM-dd HH:mm:ss xxxx
:
5. 特定の接続IPアドレス(←場所の要素)によるMFA(多要素認証)の有効化 (「管理者」側手順)
続いて、特定の接続IPアドレスからのアクセス時のみは、ワンタイムパスワードの入力なしでアクセスできるように設定します。
□手順 5-1: 作成したIAMグループ(MyUsers
)をクリックします
□手順 5-2: [アクセス許可]タブをクリックします
□手順 5-3: [インラインポリシー]の”ポリシーの編集”部分をクリックします
□手順 5-4: ポリシードキュメントの ”Condition” 句を次のように修正して[ポリシーの適用]をクリックします
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
},
"NotIpAddress": {
"aws:SourceIp": [
"xxx.xxx.xxx.xxx",
"yyy.yyy.yyy.yyy"
]
}
}
□手順 5-5: 「管理者」側手順はこれで終了です
6. 「AWS CLI」の実行(「ユーザー」側手順)
再び「AWS CLI」を使用する「ユーザー」側の手順です
□手順 6-1: --profile
オプションを付与して「AWS CLI」を実行し、問題なく実行できれば成功です
[user@workstaion ~]$ aws s3 ls --proflie "cli-user"
yyyy-MM-dd HH:mm:ss xxxx
:
以上、特定の接続元IPアドレス以外から「AWSコマンドラインインターフェイス(AWS CLI v2)」を実行した際のみMFA(Multi-Factor Authentication)が必要になるようにIAMの設定をした際の手順でした。