S3にIPアドレス制限を設定するときにつまづいた話

目次
はじめに
こんにちは、スカイアーチHRソリューションズのsugawaraです。
先日S3バケットに特定のIPアドレスのみを許可するバケットポリシーを設定しようとしたところ、ちょっとつまづいてしまいました。今回はそれを検証していきたいと思います。
先に結論
IAMユーザーにS3フルアクセス権限をつけると、バケットポリシーでIPアドレス制限を設定しても暗黙の拒否は効かない。したがって、ちゃんと明示的に拒否をする設定をしよう!
検証の流れ
- 検証用のIAMユーザーの作成
- アクセスキーとシークレットアクセスキーの取得
- aws configureでプロファイル作成
- 検証用のS3バケットの作成
- バケットポリシーの設定
- VPNの有無によるアクセステスト
- バケットポリシーの修正
- 再度アクセステスト
検証用のIAMユーザーの作成
まず、検証用にs3-test-userというIAMユーザーを作成します。今回はAWS CLIでの検証のみのため、マネジメントコンソールへのアクセスにはチェックを入れていません。

次に、S3のフルアクセス権限のポリシーのみ付与します。

アクセスキーとシークレットアクセスキーの取得
作成したIAMユーザーの画面のセキュリティ認証情報タブを押下します。

アクセスキーの作成を押下して、アクセスキーとシークレットアクセスキーを取得します。

aws configureでプロファイル作成
取得したアクセスキーとシークレットアクセスキーを用いて、テスト用のプロファイルを作成します。ターミナルで下記のコマンドを実行します。
$ aws configure --profile s3-test
$ export AWS_PROFILE=s3-test
検証用のS3バケットの作成
検証に使用するバケットをs3-test-bucket-ip-restrictionという名前で作成します。検証用のテキストファイルを作成してバケット内に保存しておきます。

バケットポリシーの設定
作成したS3バケットの画面より、アクセス許可のタブを開きます。

バケットポリシーの編集を押下して編集画面に遷移します。

下記のようなJSONを貼り付けて変更の保存を押下します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "IPAllow",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::XXXXXXXXXXXX:user/s3-test-user"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::s3-test-bucket-ip-restriction",
"arn:aws:s3:::s3-test-bucket-ip-restriction/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": "XX.XX.XX.XX/32"
}
}
}
]
}
VPNの有無によるアクセステスト
3. で作成したプロファイルを使用して、CLIによる簡単なアクセステストをします。下記のAWS CLIコマンドでS3バケットの中身を表示します。想定では、下記のような挙動になるはずでした。。
・VPN有り→許可されたIPアドレスでアクセス可
・VPN無し→不許可アドレスでアクセス不可
しかし、実際には下記のようにVPN有り無しを問わず、どちらでもアクセスができてしまいます。。
VPN有り
$ aws s3 ls s3://s3-test-bucket-ip-restriction
2023-07-19 23:40:44 6 testfile
VPN無し
$ aws s3 ls s3://s3-test-bucket-ip-restriction
2023-07-19 23:40:44 6 testfile
先に結論のところにも簡単に書きましたが、原因は明示的な拒否をしていないことです。
バケットポリシーに拒否のルールを設定していないため、S3のフルアクセス権限を持つIAMユーザーはIPアドレスに関係なくS3へアクセスができてしまいます。
バケットポリシーの修正
下記のJSONを貼り付けて拒否の設定をします。修正点は二ヵ所で、EffectのAllowをDenyへ、ConditionのIpAddressをNotIpAddressに変更しています。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "IPAllow",
"Effect": "Deny", // Allowから修正
"Principal": {
"AWS": "arn:aws:iam::XXXXXXXXXXXX:user/s3-test-user"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::s3-test-bucket-ip-restriction",
"arn:aws:s3:::s3-test-bucket-ip-restriction/*"
],
"Condition": {
"NotIpAddress": { // IpAddressから修正
"aws:SourceIp": "XX.XX.XX.XX/32"
}
}
}
]
}
再度アクセステスト
上記のJSONで明示的に「指定のIPアドレスでなければ、すべて拒否する」という設定をして再びアクセステストをしてみます。
VPN有り
$ aws s3 ls s3://s3-test-bucket-ip-restriction
2023-07-19 23:40:44 6 testfile
VPN無し
$ aws s3 ls s3-test-bucket-ip-restriction
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
今回はVPN接続無しの場合には、しっかりとAccess Deniedとなりました!
おわりに
フルアクセス権限の前では、暗黙のdenyは無力なのかと学びました。今後はDenyルールの設定をして、ちゃんと明示的に拒否をしていこうと思います!