NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

Amazon S3のシナリオ別(5選)バケットポリシーを考えてみた

本記事は  【Advent Calendar 2023】  12日目の記事です。
🎄  11日目  ▶▶ 本記事 ▶▶  13日目  🎅

今回のテーマについて

AWSを使用するシステムで、S3を使わないことなんてない。と言い切れそうなくらいS3は使用されていますよね。低コストで大容量のオブジェクトを保存できるというメリットがまず思い浮かぶと思いますが、それ以外にもアクセス制限を細かくできるといったセキュリティ面の強みも大きな魅力です。 そのセキュリティ設定の1つとしてバケットポリシーがありますが、正しく理解できていますでしょうか?今回はよく遭遇するシナリオパターン5つを想定し、それに即したバケットポリシーの例を紹介していきたいと思います。
なお、バケットポリシーは同じシナリオであっても複数設定パターンが存在し、今回紹介させていただくものが正解というものではありませんので、あらかじめご了承ください。

バケットポリシーの基本的な考え方

本題に入る前に、1つ考えてみましょう。下記のシナリオの場合、どのバケットポリシーが最も要件に即しているといえるでしょうか?

シナリオ:

  • NetcomBlogRole(IAMRole)のみがオブジェクトにアクセスできれば問題ないバケットポリシーを設定したい(※NetcomBlogRoleはS3と同一アカウントにあるものとする)

  • NetcomBlogRoleには対象のS3バケットに対するDeleteObject以外の操作に関するIAM Policyをアタッチしている

  • DeleteObjectのアクションはNetcomBlogRoleを含むすべてのリソースで不要

案①

{
    "Version": "2012-10-17",
    "Id": "NetcomBLOG-Policy1",
    "Statement": [
        {
            "Sid": "BaseDeny",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "*",
            "Resource": "arn:aws:s3:::BucketName/*",
            "Condition": {
                "StringNotLike": {
                    "aws:userid": [
                        "AROAXXXX(NetcomBlogRoleのRoleID):*" 
                    ]
                }
            }
        }
    ]
}

案②

{
    "Version": "2012-10-17",
    "Id": "NetcomBLOG-Policy2",
    "Statement": [
        {
            "Sid": "BaseAllow",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "*",
            "Resource": "arn:aws:s3:::BucketName/*",
            "Condition": {
                "StringLike": {
                    "aws:userid": [
                        "AROAXXXX(NetcomBlogRoleのRoleID):*"
                    ]
                }
            }
        }
    ]
}

案③

{
    "Version": "2012-10-17",
    "Id": "NetcomBLOG-Policy3",
    "Statement": [
        {
            "Sid": "BaseDeny",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "*",
            "Resource": "arn:aws:s3:::BucketName/*",
            "Condition": {
                "StringNotLike": {
                    "aws:userid": [
                        "AROAXXXX(NetcomBlogRoleのRoleID):*"
                    ]
                }
            }
        },
        {
            "Sid": "BaseAllow",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "*",
            "Resource": "arn:aws:s3:::BucketName/*",
            "Condition": {
                "StringLike": {
                    "aws:userid": [
                        "AROAXXXX(NetcomBlogRoleのRoleID):*"
                    ]
                }
            }
        }
    ]
}

案④

バケットポリシーの記述なし



答えとしては①が最も理想形かと思います。それぞれのバケットポリシーでNetcomBlogRoleができる操作を表にしてみます。

バケットポリシー 設定概要
NetcomBlogRoleのみ、DeleteObject以外の操作が可能
NetcomBlogRoleは全操作が可能、またIAM Policyで権限を与えてられている同一アカウントのリソースは付与された権限の操作が可能
NetcomBlogRoleのみ、全操作が可能
IAM Policyで権限を与えてられている同一アカウントのリソースは付与された権限の操作が可能

こちらの表をみて、想定があっていれば正しくバケットポリシーの挙動を理解できているかと思います。また、バケットポリシーは同一アカウントからのアクセスかどうかで挙動が変わります。

操作元とS3が同一アカウントにある IAMポリシー バケットポリシー S3の可能な操作
どちらか片方でも許可されている操作が可能
× IAMポリシーで許可されている操作が可能
× バケットポリシーで許可されている操作が可能
× IAMポリシーとバケットポリシー両方で許可されている操作が可能
× × 操作不可
× × 操作不可

※明示的なDenyポリシーが含まれている場合はDenyが優先されます。

同一アカウントか異なるアカウントからのアクセスで挙動が変わる

同一アカウントからのアクセスの場合、上述した表のとおりバケットポリシー or IAMポリシーどちらかで許可されていればその操作が可能になります。 一方で、クロスアカウントでのアクセスの場合は双方での許可が必要になるため設計に注意が必要です。

本題

こっから本題のシナリオについて考えていきます。また今回はDenyステートメントを活用したアクセス制限をメインに紹介します。
また、今回紹介する例は基本的にIAMポリシーでの権限付与を前提として紹介します。

シナリオ①:特定のIAMロール並びにWEBサーバからのアクセスのみ許可する(VPCEndPoint経由)

構成イメージ

WEBサーバ並びにIAMロール

必要な権限を付与したIAM Policyをアタッチしておく

バケットポリシー

{
    "Version": "2012-10-17",
    "Id": "NetcomBlog-Policy",
    "Statement": [
        {
            "Sid": "BaseDeny",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "*",
            "Resource": "arn:aws:s3:::BucketName/*",
            "Condition": {
                "StringNotLike": {
                    "aws:userid": [
                        "AROAXXXX(運用ロール1のRoleID):*",
                        "AROAXXXX(運用ロール2のRoleID):*"
                    ]
                },
                "StringNotEquals": {
                    "aws:SourceVpce": "vpce-xxxxxxxxxxxx"
                }
            }
        }
    ]
}

特定のIAMロール並びにVPCEndpointからのアクセスはDenyしないようにし、Allow権限はIAMロールにアタッチしたポリシーで付与する

シナリオ②:アクセス元が特定のIPの場合のみ、S3オブジェクトを配信する

構成イメージ

IAMロール

運用で使用するIAMロールには必要な権限を与えておく

バケットポリシー

{
    "Version": "2012-10-17",
    "Id": "NetcomBlog-Policy",
    "Statement": [
        {
            "Sid": "BaseDeny",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "*",
            "Resource": "arn:aws:s3:::BucketName/*",
            "Condition": {
                "StringNotLike": {
                    "aws:userid": [
                        "AROAXXXX(運用ロール1のRoleID):*",
                        "AROAXXXX(運用ロール2のRoleID):*"
                    ]
                },
                "NotIpAddress": {
                    "aws:SourceIp": [
                        "10.10.10.10/32",
                        "11.11.11.11/32"
                    ]
                }
            }
        },
        {
            "Sid": "BaseAllow-IPRestrict",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::BucketName/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "10.10.10.10/32",
                        "11.11.11.11/32"
                    ]
                }
            }
        }
    ]
}

運用で使用するIAMロールからのアクセス並びに特定IPからのアクセスはDeny対象から外しておき、特定IPに対するGetObjectを許可しておけばオブジェクトの読み取りは可能です。ただ、こういったシナリオではCloudFront + S3の構成をとる方が多いかと思います。

シナリオ③:署名付きURLを使って、ユーザーにオブジェクトを配信する

構成イメージ

IAMロール

運用で使用するIAMロールには必要な権限を与えておく
また、コンテナのロールにGetObject等必要になる権限を付与

バケットポリシー

{
    "Version": "2012-10-17",
    "Id": "NetcomBlog-Policy",
    "Statement": [
        {
            "Sid": "BaseDeny",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "*",
            "Resource": "arn:aws:s3:::Bucketname/*",
            "Condition": {
                "StringNotLike": {
                    "aws:userid": [
                        "AROAXXXX(運用ロール1のRoleID):*",
                        "AROAXXXX(コンテナ用ロールのRoleID):*"
                    ]
                },
                "StringNotEquals": {
                    "aws:SourceVpce": "vpce-xxxxxxxxxxxxxx"
                }
            }
        }
    ]
}

VPCEndpointからの経路をDenyしないようにしているため、本来コンテナ用ロールをDeny対象から外す必要がないように見えますが、下記の通りアクセス経路が変わります。

・署名付きURLの発行→VPCEndpoint経由でのアクセス
・署名付きURLへのアクセス→コンテナ用ロールの権限でのアクセス

そのため、コンテナ用ロールからのアクセスをDeny対象から外しておかないと、署名付きURLの発行はできるがアクセスができないURLとなってしまいます

シナリオ④:バケットレベルでのDenyも活用する

バケットポリシー

{
    "Version": "2012-10-17",
    "Id": "NetcomBlog-Policy",
    "Statement": [
        {
            "Sid": "BaseDeny",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "*",
            "Resource": [
                "arn:aws:s3:::BucketName/*",
                "arn:aws:s3:::BucketName"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:userid": [
                        "AROAXXXX(運用ロールのRoleID):*",  
                        "AROAXXXX(GuardDuty用ロールのRoleID):*"
                    ]
                },
                "StringNotEquals": {
                    "aws:SourceVpce": "vpce-xxxxxxxxxxxxxx"
                }
            }
        }
    ]
}

S3のセキュリティを強化する目的で、バケットレベルでのDenyを取り入れることもあるかと思います。
注意点として、GuardDutyを有効化しているような場合、GuardDutyがS3へのアクセスに失敗すると返ってセキュリティ違反になってしまうことがあります。そのため、GuardDutyで使用されるIAMロールはDeny対象から外しておくなど工夫が必要です。

シナリオ⑤:クロスアカウントでS3オブジェクトにアクセスする(インターネット経由でのアクセス)

構成イメージ

IAMロール

運用で使用するIAMロールには必要な権限を与えておく
また、クロスアカウント元のロールにも必要になる権限を付与

バケットポリシー

{
    "Version": "2012-10-17",
    "Id": "NetcomBlog-Policy",
    "Statement": [
        {
            "Sid": "BaseDeny",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "*",
            "Resource": "arn:aws:s3:::BucketName/*",
            "Condition": {
                "StringNotLike": {
                    "aws:userid": [
                        "AROA(運用ロールのRoleID):*", 
                        "AROA(クロスアカウント元のRoleID):*"
                    ]
                }
            }
        },
        {
            "Sid": "CrossAccountAccess",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::AccountID:role/ロール名"
            },
            "Action": [
                "s3:ListBucket",
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::BucketName/*",
                "arn:aws:s3:::BucketName"
            ]
        }
    ]
}

クロスアカウントでのアクセスの場合はバケットポリシー・IAMポリシー双方での許可が必要になるのが注意点です。

まとめ

バケットポリシーはセキュリティ観点で重要な設定になりますが、正しく設定していないと想定していないアクセスが可能になってしまうなど注意が必要です。特に個人情報を扱うようなS3については、KMSで暗号化するなどより強固な構成をとっておいた方がいいようなケースもあります。用途に応じて、適切な設定ができているか改めて確認していただければ幸いです。読んでいただきありがとうございました!

執筆者:西本 悠馬 クラウドエンジニア AWSをメインに触っています