S3 ゲートウェイ型 VPC エンドポイントのエンドポイントポリシーは "Principal" ではなく "Condition" の使用が推奨されている

記事タイトルとURLをコピーする


コーヒーが好きな木谷映見です。

S3 ゲートウェイ型 VPC エンドポイントポリシー、使っていますか?
S3 ゲートウェイ型 VPC エンドポイントは、プライベートサブネットのリソースから S3 バケットに接続するために無料で使用でき、冗長性の考慮不要で帯域幅の制限もない便利なリソースです。
このS3 ゲートウェイ型 VPC エンドポイントへのアクセスを制御する VPC エンドポイントポリシーの設定に推奨事項がありましたので、本記事に記載します。

結論

特定の呼び出し元に対してS3 ゲートウェイ型 VPC エンドポイントの使用を制限する場合、VPC エンドポイントポリシーで "Principal" ではなく "Condition" の使用が推奨されている。

具体的には

こうじゃなくて

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::xxxxxxxxxxxx:role/instance-b-role"
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::20221020-s3-gw-endpoint-test-emikitani",
                "arn:aws:s3:::20221020-s3-gw-endpoint-test-emikitani/*"
            ]
        }
    ]
}

こう

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::20221020-s3-gw-endpoint-test-emikitani",
                "arn:aws:s3:::20221020-s3-gw-endpoint-test-emikitani/*"
            ],
            "Condition": {
                "ArnEquals": {
                    "aws:PrincipalArn": "arn:aws:iam::xxxxxxxxxxxx:role/instance-b-role"
                }
            }
        }
    ]
}

こちらのドキュメントに記載されています。

docs.aws.amazon.com

AWS では、特定の呼び出し元に対してエンドポイントの使用を制限する場合は、VPC エンドポイントポリシーで IAM Principal 要素ではなく IAM 条件を使用することをお勧めします。このような条件の例としては aws:PrincipalArn、aws:PrincipalAccount、aws:PrincipalOrgId や aws:PrincipalOrgPaths があります。

検証

構成図

以下のような構成でリソースを作成し、S3 バケット通信します。
instance-a からは S3 バケットに接続できず、instance-b からは S3 バケットに接続できるよう、VPC エンドポイントポリシーで制御します。

事前準備

  • VPC、サブネット、ルートテーブルを作成しておきます。
  • セッションマネージャーで EC2 インスタンスに接続するため、NAT Gateway や踏み台サーバーなどを作成して経路を確保します。
  • S3 バケットを作成し、適当にオブジェクトをアップロードしておきます。

IAM ロールの作成

EC2 インスタンスに付与する IAM ロールを 2 つ作成します。

instance-a-role、instance-b-role という 2 つの IAM ロールを作成します。
IAM ロール名は異なりますが、2 つとも同じ許可ポリシーを付与しておきます。

  • instance-a-role

    • AmazonSSMManagedInstanceCore
    • AmazonS3ReadOnlyAccess
  • instance-b-role

    • AmazonSSMManagedInstanceCore
    • AmazonS3ReadOnlyAccess

AmazonSSMManagedInstanceCore は セッションマネージャーで EC2 インスタンスに接続するためのポリシー、AmazonS3ReadOnlyAccess は S3 バケットに対する読み取り許可ポリシーです。

EC2 インスタンスの作成

Amazon Linux 2 のデフォルト AMI を使用して EC2 インスタンスを 2 台作成します。 IAM ロールの作成 で作成した IAM ロールをそれぞれの EC2 インスタンスに付与します。
セキュリティグループでは VPC 内の通信を許可しておきます。

ゲートウェイ型 S3 エンドポイントの作成

VPC マネジメントコンソールから作成します。

名前タグに自由に名前を入力し、サービスカテゴリでは「AWS のサービス」を選択します。
サービスは com.amazonaws.ap-northeast-1.s3 の Gateway タイプにチェックします。

作成した VPC と、 EC2 インスタンスが作成されているプライベートサブネットに紐づいているルートテーブルを選択します。

ポリシーで、カスタムにチェックを入れます。
以下のポリシーを入力します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::(S3 バケット名)",
                "arn:aws:s3:::(S3 バケット名)/*"
            ],
            "Condition": {
                "ArnEquals": {
                    "aws:PrincipalArn": "arn:aws:iam::xxxxxxxxxxxx:role/instance-b-role"
                }
            }
        }
    ]
}

"Condition" 句を使い、instance-b-role が付与されたEC2 インスタンスから、特定の S3 バケットへのアクションを許可するポリシーを記載しています。
"aws:PrincipalArn" には、instance-b-role の ARN を入れています。

「エンドポイントを作成」をクリックすると、S3 ゲートウェイ型 VPC エンドポイントが作成されます。

S3 ゲートウェイ型 VPC エンドポイント作成時に指定したルートテーブルを確認すると、通信先:pl-61a54008、ターゲット:エンドポイント ID というルートが追加されているのが確認できます。
pl-61a54008 は、東京リージョンの S3 で使用される IP アドレスの集まり(AWS マネージドプレフィックスリスト)です。

接続確認

エンドポイントポリシーに "condition" 句を使用した場合

ゲートウェイ型 S3 エンドポイントの作成 で "condition" 句を使用したエンドポイントポリシー設定しました。この状態で、EC2 インスタンスに接続し、該当の S3 バケットに接続できるか確認します。

以下の AWS CLI コマンドを実行し、S3 バケット 20221020-s3-gw-endpoint-test-emikitani 内のオブジェクトが表示できるか確認します。

aws s3api list-objects \
--bucket 20221020-s3-gw-endpoint-test-emikitani
  • instance-a に接続
[ec2-user@ip-10-0-4-130 ~]$ aws s3api list-objects \
> --bucket 20221020-s3-gw-endpoint-test-emikitani

An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied
[ec2-user@ip-10-0-4-130 ~]$
  • instance-b に接続
[ec2-user@ip-10-0-4-222 ~]$ aws s3api list-objects \
> --bucket 20221020-s3-gw-endpoint-test-emikitani
{
    "Contents": [
        {
            "LastModified": "2022-10-19T16:14:43.000Z",
            "ETag": "\"d0b10ef5d1b8ba1f6f56b3xxxxxxxxxx\"",
            "StorageClass": "STANDARD",
            "Key": "tickitdb/allevents_pipe.txt",
            "Owner": {
                "DisplayName": "kitani",
                "ID": "ad7cca82b66316dcb94ac30d86bd2080625382a11f26b199581141xxxxxxxxxx"
            },
            "Size": 445838
        },
        {
            "LastModified": "2022-10-19T16:14:44.000Z",
          :
          :
          :
[ec2-user@ip-10-0-4-222 ~]$

instance-b からは S3 バケット内のオブジェクトの情報が取得できることが確認できました。

エンドポイントポリシーに "principal" を使用した場合

エンドポイントポリシーを以下のように書き換えます。

{
   "Version": "2012-10-17",
   "Statement": [
       {
           "Effect": "Allow",
           "Principal": {
               "AWS": "arn:aws:iam::123456789012:role/instance-b-role"
           },
           "Action": "s3:*",
           "Resource": [
               "arn:aws:s3:::20221020-s3-gw-endpoint-test-emikitani",
               "arn:aws:s3:::20221020-s3-gw-endpoint-test-emikitani/*"
           ]
       }
   ]
}

呼び出し元の制御に "principal" を使用した書き方に変えました。

エンドポイントポリシーを修正したら、先ほどと同様に各インスタンスから S3 バケット内のオブジェクトが表示できるか確認します。

  • instance-a に接続
[ec2-user@ip-10-0-4-130 ~]$ aws s3api list-objects \
> --bucket 20221020-s3-gw-endpoint-test-emikitani

An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied
[ec2-user@ip-10-0-4-130 ~]$
  • instance-b に接続
[ec2-user@ip-10-0-4-222 ~]$ aws s3api list-objects \
> --bucket 20221020-s3-gw-endpoint-test-emikitani

An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied
[ec2-user@ip-10-0-4-222 ~]$

意図した動作にならないのが確認できました。

おわりに

S3 ゲートウェイ型 VPC エンドポイントのエンドポイントポリシーは "Principal" ではなく "Condition" の使用が推奨されていることをご紹介し、接続検証を行いました。
結果、推奨されている "Condition" 句を使用したエンドポイントポリシーでは意図した接続が確認でき、"Principal" で設定したエンドポイントポリシーでは意図した接続ができないことが確認できました。

今回は S3 ゲートウェイ型 VPC エンドポイントのエンドポイントポリシーでアクセス制御しました。しかし、アクセス制御は AWS サービスに付与する IAM ロールや S3 バケットポリシーなどでも設定可能です。
アクセス制御が重複したり、管理が煩雑になる可能性を考えると、VPC エンドポイントポリシーは使わず IAM ロールやセキュリティグループなどで制御するのも手かと思います。

使用するシステムの運用面も鑑みて、エンドポイントポリシーをうまく利用できるといいですね!

参考

docs.aws.amazon.com

Amazon Simple Storage Service エンドポイントとクォータ - AWS 全般のリファレンス

emi kitani(執筆記事の一覧)

AS部LX課。2022/2入社、コーヒーとサウナが好きです。執筆活動に興味があります。AWS認定12冠。