S3バケットポリシーを使って、アドレスベースでアクセスを許可・拒否する – aws:SourceIp

S3バケットポリシーを使って、アドレスベースでアクセスを許可・拒否する - aws:SourceIp

S3バケットポリシーを使って、アドレスベースでアクセスを許可・拒否する – aws:SourceIp

S3バケットポリシーにおいて、グローバルアドレスに基づいたアクセス制限を設定することを考えます。

今回の用件では、IP アドレス条件演算子(IpAddress, NotIpAddress)が使用できます。

IP アドレス条件演算子では、キーと IPv4 または IPv6 アドレスまたは IP アドレス範囲の比較に基づいてアクセスを制限する Condition 要素を構築できます。これらを aws:SourceIp キーと合わせて使用します。

IP アドレス条件演算子

今回はEC2インスタンスからバケットポリシーを設定したS3バケットにアクセスし、挙動を確認します。

構築する環境

Diagram of using S3 bucket policy to allow or deny access on address basis - aws:SourceIp

4つのEC2インスタンスを作成します。
インスタンスは最新のAmazon Linux 2で、2つのプライベートサブネット内に2つずつ配置します。
各サブネットの一方のインスタンスには、S3に対するフルアクセスを与え、もう一方には全く権限を与えません。
全インスタンスは、各AZのパブリックサブネットに配置したNAT Gateway経由でインターネットにアクセスします。
つまり各インスタンスが外部にアクセスする際は、NAT Gatewayに割り当てたEIPを使用して通信することになります。

4つのバケットを作成します。
それぞれ以下の通りにバケットポリシーを設定します。

設定バケット1バケット2バケット3バケット4
ActionAllowDenyAllowDeny
IP アドレス条件演算子IpAddressIpAddressNotIpAddressNotIpAddress
aws:SourceIpEIP1EIP1EIP1EIP1

IP アドレス条件演算子とaws:SourceIpキーを使用して、アドレスベースの制限を設定します。対象のアドレスには、NAT Gatewayに割り当てたEIP1を指定します。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。以下のURLにCloudFormationテンプレートを配置しています。

https://github.com/awstut-an-r/awstut-soa/tree/main/04/004

テンプレートファイルのポイント解説

S3

バケット

Resources:
  Bucket1:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${Prefix}-bucket-01"

  Bucket2:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${Prefix}-bucket-02"

  Bucket3:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${Prefix}-bucket-03"
      PublicAccessBlockConfiguration:
        BlockPublicAcls: false
        BlockPublicPolicy: false
        IgnorePublicAcls: false
        RestrictPublicBuckets: false

  Bucket4:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${Prefix}-bucket-04"
Code language: YAML (yaml)

4つのバケットを作成します。

バケット3だけ他と設定が異なります。
これはパブリックアクセスを許可するための設定です。
デフォルトでは、パブリックアクセスブロック機能によって、パブリックアクセスは制限されています。

2023 年 4 月から、Amazon S3 はすべての新しい S3 バケットの S3 パブリックアクセスブロックとオブジェクト所有権 (ACL 無効) のデフォルト設定を変更します。この更新後に作成された新しいバケットでは、S3 パブリックアクセスブロック設定はすべて有効になり、S3 アクセス制御リスト (ACL) は無効になります。

Amazon S3 ストレージへのパブリックアクセスのブロック

しかし後述するバケット3用のバケットポリシーは、広い範囲でアクセスを許可することになるため、設定に矛盾が生じます。
この矛盾を解決するために、パブリックアクセスブロック機能を無効化します。

なお本設定を実施しない場合、バケット3およびバケットポリシーの作成は失敗し、以下のエラーメッセージが表示されます。

You either don’t have permissions to edit the bucket policy, or your bucket policy grants a level of public access that conflicts with your Block Public Access settings. To edit a bucket policy, you need s3:PutBucketPolicy permissions. To review which Block Public Access settings are turned on, view your account and bucket settings. Learn more about Identity and access management in Amazon S3

バケットポリシー

1つずつバケットポリシーを確認します。

Resources:
  BucketPolicy1:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref Bucket1
      PolicyDocument:
        Statement:
          - Principal: "*"
            Action: s3:*
            Effect: Allow
            Resource:
              - !Sub "arn:aws:s3:::${Bucket1}"
              - !Sub "arn:aws:s3:::${Bucket1}/*"
            Condition:
              IpAddress:
                aws:SourceIp:
                  - !Ref EIPPublicIp1
Code language: YAML (yaml)

バケット1用のバケットポリシーです。
EIP1からのアクセスの場合は、フルアクセスを許可します。

Resources:
  BucketPolicy2:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref Bucket2
      PolicyDocument:
        Statement:
          - Principal: "*"
            Action: s3:*
            Effect: Deny
            Resource:
              - !Sub "arn:aws:s3:::${Bucket2}"
              - !Sub "arn:aws:s3:::${Bucket2}/*"
            Condition:
              IpAddress:
                aws:SourceIp:
                  - !Ref EIPPublicIp1
Code language: YAML (yaml)

バケット2用のバケットポリシーです。
EIP1からのアクセスの場合は、すべてのアクションを拒否します。

Resources:
  BucketPolicy3:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref Bucket3
      PolicyDocument:
        Statement:
          - Principal: "*"
            Action: s3:*
            Effect: Allow
            Resource:
              - !Sub "arn:aws:s3:::${Bucket3}"
              - !Sub "arn:aws:s3:::${Bucket3}/*"
            Condition:
              NotIpAddress:
                aws:SourceIp:
                  - !Ref EIPPublicIp1
Code language: YAML (yaml)

バケット3用のバケットポリシーです。
EIP1以外からのアクセスの場合は、フルアクセスを許可します。

Resources:
  BucketPolicy4:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref Bucket4
      PolicyDocument:
        Statement:
          - Principal: "*"
            Action: s3:*
            Effect: Deny
            Resource:
              - !Sub "arn:aws:s3:::${Bucket4}"
              - !Sub "arn:aws:s3:::${Bucket4}/*"
            Condition:
              NotIpAddress:
                aws:SourceIp:
                  - !Ref EIPPublicIp1
Code language: YAML (yaml)

バケット4用のバケットポリシーです。
EIP1以外からのアクセスの場合は、すべてのアクションを拒否します。

EC2

Resources:
  Instance1:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref InstanceProfile1
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref InstanceSubnet1
          GroupSet:
            - !Ref InstanceSecurityGroup

  Instance2:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref InstanceProfile2
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref InstanceSubnet1
          GroupSet:
            - !Ref InstanceSecurityGroup

  InstanceProfile1:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref InstanceRole1

  InstanceProfile2:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref InstanceRole2

  InstanceRole1:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Policies:
        - PolicyName: AccessS3Policy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: s3:*
                Resource:
                  - !Sub "arn:aws:s3:::${Bucket1}"
                  - !Sub "arn:aws:s3:::${Bucket1}/*"
                  - !Sub "arn:aws:s3:::${Bucket2}"
                  - !Sub "arn:aws:s3:::${Bucket2}/*"
                  - !Sub "arn:aws:s3:::${Bucket3}"
                  - !Sub "arn:aws:s3:::${Bucket3}/*"
                  - !Sub "arn:aws:s3:::${Bucket4}"
                  - !Sub "arn:aws:s3:::${Bucket4}/*"

  InstanceRole2:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ec2.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Code language: YAML (yaml)

4つのEC2インスタンスを作成しますが、1つのサブネット内の2つのインスタンスを取り上げます。
残りのインスタンスはサブネットが異なるだけで、設定自体は同一のためです。

IAMロールがポイントです。
一方のインスタンス用のIAMロールでは、S3へのフルアクセスを許可します。
もう一方のインスタンス用のIAMロールでは、S3に関しては、何も許可しません。

(参考) NAT Gateway

Resources:
  EIP1:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  EIP2:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  NATGateway1:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt EIP1.AllocationId
      SubnetId: !Ref PublicSubnet1

  NATGateway2:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt EIP2.AllocationId
      SubnetId: !Ref PublicSubnet2

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Sub "${AWS::Region}${AvailabilityZone1}"
      CidrBlock: !Ref CidrIp1
      VpcId: !Ref VPC

  PublicSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Sub "${AWS::Region}${AvailabilityZone2}"
      CidrBlock: !Ref CidrIp2
      VpcId: !Ref VPC
Code language: YAML (yaml)

2つのAZに1つずつNAT Gatewayを配置します。
各ゲートウェイには、EIPをアタッチします。
先述のバケットポリシーの設定は、このEIP1のアドレスを参照しています。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • バケット1:soa-04-004-bucket-01
  • バケット2:soa-04-004-bucket-02
  • バケット3:soa-04-004-bucket-03
  • バケット4:soa-04-004-bucket-04
  • インスタンス1:i-04dbf87640c773eec
  • インスタンス2:i-0d716220234453122
  • インスタンス3:i-0ac64c5ec684c0501
  • インスタンス4:i-059a4434e92df1367
  • NAT Gateway1:nat-0a3531dbe283cec59
  • NAT Gateway2:nat-0e9a9f6e5a324ac4d
  • EIP1:35.74.75.17
  • EIP2:52.194.136.88

AWS Management Consoleから各リソースを確認します。

NATゲートウェイを確認します。

Detail of NAT Gateway 1.
Detail of NAT Gateway 2.

2つのNAT Gatewayが作成されています。
それぞれEIPがアタッチされていることがわかります。

バケットポリシーを確認します。

Detail of S3 1.
Detail of S3 2.
Detail of S3 3.
Detail of S3 4.

CloudFormationテンプレートで指定した通りに、各バケットポリシーが設定されています。

動作確認

準備が整いましたので、各インスタンスにアクセスし、実際の挙動を確認します。
インスタンスへのアクセスは、SSM Session Managerを使用します。

Session Managerに関する詳細は、以下のページをご確認ください。

あわせて読みたい
LinuxインスタンスにSSM Session Manager経由でアクセスする 【LinuxインスタンスにSSM Session Manager経由でアクセスする】 EC2インスタンスにSSM Session Manager経由でアクセスする構成を確認します。 Session Manager は完全...

インスタンス1

インスタンス1から各バケットにアクセスします。
インスタンス1のIAMロールでは、S3フルアクセスが許可されています。
またバケットへのアクセス時は、NAT GatewayにアタッチされているEIP1(35.74.75.17)を使用します。

バケットへのアクセスは、AWS CLIで実行します。

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-01

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-02
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-03

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-04
Code language: Bash (bash)

バケット1はアクセスできました。
これはIAMロールおよびバケットポリシーで、明示的にアクセスが許可されているためです。

バケット2はアクセスできませんでした。
これはIAMロールではアクセス許可されていますが、バケットポリシーで明示的にアクセス拒否されているためです。

バケット3はアクセスできました。
これはバケットポリシーでは明示的には許可されていませんが、IAMロールで明示的に許可されているためです。

バケット4はアクセスできました。
これはバケットポリシーでは明示的には許可されていませんが、IAMロールで明示的に許可されているためです。

インスタンス2

インスタンス2から各バケットにアクセスします。
インスタンス2のIAMロールでは、S3へのアクセスは許可されていません。
またバケットへのアクセス時は、NAT GatewayにアタッチされているEIP1(35.74.75.17)を使用します。

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-01

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-02
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-03
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-04
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
Code language: Bash (bash)

バケット1はアクセスできました。
これはバケットポリシーによって、明示的にアクセスが許可されているためです。

バケット2はアクセスできませんでした。
これはバケットポリシーによって、明示的にアクセス拒否されているためです。

バケット3はアクセスできませんでした。
これはIAMロールおよびバケットポリシーによって、明示的にアクセスが許可されていないためです。
明示的に許可する設定がないため、アクセスは拒否されます。

バケット4はアクセスできませんでした。
これはIAMロールおよびバケットポリシーによって、明示的にアクセスが許可されていないためです。
明示的に許可する設定がないため、アクセスは拒否されます。

インスタンス3

インスタンス3から各バケットにアクセスします。
インスタンス3のIAMロールでは、S3フルアクセスが許可されています。
またバケットへのアクセス時は、NAT GatewayにアタッチされているEIP2(52.194.136.88)を使用します。

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-01

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-02

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-03

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-04
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
Code language: Bash (bash)

バケット1はアクセスできました。
これはバケットポリシーでは明示的に許可されていませんが、IAMロールで明示的に許可されているためです。

バケット2はアクセスできました。
これはバケットポリシーでは明示的に許可されていませんが、IAMロールで明示的に許可されているためです。

バケット3はアクセスできました。
これはIAMロールおよびバケットポリシーで、明示的にアクセスが許可されているためです。

バケット4はアクセスできませんでした。
これはIAMロールではアクセス許可されていますが、バケットポリシーで明示的にアクセス拒否されているためです。

インスタンス4

インスタンス4から各バケットにアクセスします。
インスタンス4のIAMロールでは、S3へのアクセスは許可されていません。
またバケットへのアクセス時は、NAT GatewayにアタッチされているEIP2(52.194.136.88)を使用します。

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-01
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-02
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-03

sh-4.2$ aws s3 ls s3://soa-04-004-bucket-04
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
Code language: Bash (bash)

バケット1はアクセスできませんでした。
これはIAMロールおよびバケットポリシーによって、明示的にアクセスが許可されていないためです。
明示的に許可する設定がないため、アクセスは拒否されます。

バケット2はアクセスできませんでした。
これはIAMロールおよびバケットポリシーによって、明示的にアクセスが許可されていないためです。
明示的に許可する設定がないため、アクセスは拒否されます。

バケット3はアクセスできました。
これはIAMロールでは明示的には許可されていませんが、バケットポリシーで明示的に許可されているためです。

バケット4はアクセスできませんでした。
これはバケットポリシーによって、明示的にアクセスが拒否されているためです。

まとめ

以下が動作確認の結果のまとめです。

インスタンスNAT Gatewayバケット1Allow from EIP 1バケット2Deny from EIP 1バケット3Allow from Not EIP 1バケット4Deny from Not EIP 1
インスタンス1IAM Role: S3 Full AccessEIP 1OKNGOKOK
インスタンス2IAM Role: S3 NoneEIP 1OKNGNGNG
インスタンス3IAM Role: S3 Full AccessEIP 2OKOKOKNG
インスタンス4IAM Role: S3 NoneEIP 2NGNGOKNG