この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
コンニチハ、千葉です。
AWSマネジメントコンソール利用時に、コンプライアンス要件によりIP制限をしたい場合があります。
しかし、マネジメントコンソールにIP制限すると、思わぬエラーが発生し操作できなくなる場合があります。
こちらのドキュメントにも記載があります。
aws:SourceIp 条件キーは、リクエストの送信元である IP アドレスに解決します。リクエストが Amazon EC2 インスタンスから送信された場合、aws:SourceIp はインスタンスのパブリック IP アドレスに評価されます。
つまり、APIリクエストの種類は2種類あり
- ユーザー側からのリクエスト
- AWSがユーザーの変わりにリクエスト
2はCloudFromationのようなAWS環境を自動構成するようなサービスで、ユーザーが作成した定義に従ってCloudFormationサービスがEC2のようなサービスを操作します。 IP制限をかけていた場合、CloudFormationは、AWSサービスが利用しているIPアドレスで操作するためエラーとなってしまいます。
IPアドレス制限したまま、制限なくAWSサービスを利用する
前提知識IAMロール
まずは、前提知識としてIAMロールというものが必要になります。IAMロールとは、権限を委譲するための仕組みです。
イメージしやすいのは、テスト用AWSアカウント、ステージング用AWSアカウント、本番用AWSアカウントの3つあったとします。 例えばですが、テスト用AWSアカウントのマネージメントコンソールにログインした状態で、本番環境にスイッチユーザーができるようになります。Linuxでいうsuのようなこともできます。
IAMは奥が深いので、さらに詳細を確認したいかはこの辺の資料をみるといいかと思います。
より深くIAMロールを確認したい方はこちら
IAMに関する記事も沢山ありますので、気になるところだけピックアップしてみるのいいでしょう。
IAMロールを利用した、IPアドレス制限 + CloudFormation等のAWSサービスを利用する方法
長くなりましたが、本題です。まず、IAMユーザー、IAMロールで役割を分けます。
- IAMユーザー:ログイン用途
- IAMロール:ユーザーの操作用途
そして、スイッチロールを別アカウント間ではなく、同じアカウント間で実施します。つまり、このようになります。
今回の設定では以下を実現します
- IPアドレス制限をかける
- スイッチロールを行うことにより、CloudFormationのようなサービスを制約なく利用できる
また、セキュアにするために以下を追加しています
- 指定した特定ユーザーのみスイッチロールできる
- MFA有効化されていないとスイッチロールできない
結果的に、固定したIPアドレスからのログインとIPアドレスの制限を受けずにAWS環境を操作することができるようになります。
やってみた
グループ/IAMユーザー作成
3ユーザー分作成しました。
また、ユーザーはグループに所属させます
グループに必要な権限を付与
グループに対し必要な権限を付与します。 IPアドレス制限、MFA有効化の権限、スイッチロールの権限を付与しました。
インラインポリシーで、カスタムポリシーとしてそれぞれ追加します。
SourceIPRestriction
特定のIPからのみアクセスを受け付けるように制限します。許可するIPアドレスを指定します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "SourceIPRestriction",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"xx.xx.xx.xx"
]
}
}
}
]
}
EnableOnlyOwnYourMFA
MFAを有効化できるように権限付与します。AWSアカウントIDを指定します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowUsersToCreateEnableResyncDeleteTheirOwnVirtualMFADevice",
"Effect": "Allow",
"Action": [
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:ResyncMFADevice",
"iam:DeleteVirtualMFADevice"
],
"Resource": [
"arn:aws:iam::123456789012:mfa/${aws:username}",
"arn:aws:iam::123456789012:user/${aws:username}"
]
},
{
"Sid": "AllowUsersToDeactivateTheirOwnVirtualMFADevice",
"Effect": "Allow",
"Action": [
"iam:DeactivateMFADevice"
],
"Resource": [
"arn:aws:iam::123456789012:mfa/${aws:username}",
"arn:aws:iam::123456789012:user/${aws:username}"
],
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": true
}
}
},
{
"Sid": "AllowUsersToListMFADevicesandUsersForConsole",
"Effect": "Allow",
"Action": [
"iam:ListMFADevices",
"iam:ListVirtualMFADevices",
"iam:ListUsers"
],
"Resource": "*"
}
]
}
AllowSwitchRole
特定のロールへスイッチロールできる権限を付与します。スイッチロールを許可するロール名とAWSアカウントIDを指定します。
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::123456789012:role/ロール名"
}
}
IAMロール作成
AWSリソースの操作を行うロールを作成します。
クロスアカウントアクセスのロールを選択します
AWSアカウントIDを入力、MFAのチェックボックスにチェックを入れます
任意のアクセス権を付与します。
作成したロールを選択し、信頼関係の編集をします
スイッチロールを許可するIAMユーザーと、AWSアカウントIDを指定します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::123456789012:user/user-b",
"arn:aws:iam::123456789012:user/user-a",
"arn:aws:iam::123456789012:user/user-c"
]
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
テスト
以下の動作確認を行い、想定通りの動きでした
- 指定IP以外からログインした場合、何も操作できないこと
- MFA有効化しない状態でスイッチロールができないこと
- 指定していないIAMユーザーからのスイッチロールできないこと
- スイッチロール後に、CloudFormationの実行ができること
検討事項
IAMユーザーとロールを1:1で作成するのか、N:1で作成するのか?
今回はIAMユーザー複数に対して、ロールを1つ用意しましたが、複数やりかたがあります。
1:1で作成
1つのIAMユーザーに対し、1つのIAMロールを紐付けます。
こちらのメリットは、CloudTrailにてユーザー単位でどの操作を行ったかのログが取れるところにあります。
ただし、IAMユーザーを作成したとき、IAMロールを必ず作成する必要があり、管理が煩雑になることが予想されます。
CloudTrailの記録ですが、一時クレデンシャルを使っても詳細情報が記録されて追跡可能なので、N:1でも問題ないと思っています。 by にしざわ
という指摘があり、確認したところCloudTrailにロール名のが記載されていました。
ということで、N:1一択で!
N:1で作成
複数のIAMユーザーに対し、1つのIAMロールを紐付けます。 こちらのメリットは、IAMユーザーを追加するたびにIAMロールを作成する必要が無いことです。
人数規模にもよると思いますが、
- IAMユーザー:個人単位で発行
- IAMロール:組織単位で発行
が、運用煩雑さやログ追跡の観点で一番いい選択なのではないでしょうか。
最後に
大作になった感がありますが、マネージメントコンソールでのIP制限必須なときのワークアラウンドです。誰かの参考になればと!!