S3バケットポリシーを使って、アドレスベースでアクセスを許可・拒否する – aws:SourceIp
S3バケットポリシーにおいて、グローバルアドレスに基づいたアクセス制限を設定することを考えます。
今回の用件では、IP アドレス条件演算子(IpAddress, NotIpAddress)が使用できます。
IP アドレス条件演算子では、キーと IPv4 または IPv6 アドレスまたは IP アドレス範囲の比較に基づいてアクセスを制限する Condition 要素を構築できます。これらを aws:SourceIp キーと合わせて使用します。
IP アドレス条件演算子
今回はEC2インスタンスからバケットポリシーを設定したS3バケットにアクセスし、挙動を確認します。
構築する環境
4つのEC2インスタンスを作成します。
インスタンスは最新のAmazon Linux 2で、2つのプライベートサブネット内に2つずつ配置します。
各サブネットの一方のインスタンスには、S3に対するフルアクセスを与え、もう一方には全く権限を与えません。
全インスタンスは、各AZのパブリックサブネットに配置したNAT Gateway経由でインターネットにアクセスします。
つまり各インスタンスが外部にアクセスする際は、NAT Gatewayに割り当てたEIPを使用して通信することになります。
4つのバケットを作成します。
それぞれ以下の通りにバケットポリシーを設定します。
設定 | バケット1 | バケット2 | バケット3 | バケット4 |
Action | Allow | Deny | Allow | Deny |
IP アドレス条件演算子 | IpAddress | IpAddress | NotIpAddress | NotIpAddress |
aws:SourceIp | EIP1 | EIP1 | EIP1 | EIP1 |
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スタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- バケット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ゲートウェイを確認します。
2つのNAT Gatewayが作成されています。
それぞれEIPがアタッチされていることがわかります。
バケットポリシーを確認します。
CloudFormationテンプレートで指定した通りに、各バケットポリシーが設定されています。
動作確認
準備が整いましたので、各インスタンスにアクセスし、実際の挙動を確認します。
インスタンスへのアクセスは、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 Access | EIP 1 | OK | NG | OK | OK |
インスタンス2IAM Role: S3 None | EIP 1 | OK | NG | NG | NG |
インスタンス3IAM Role: S3 Full Access | EIP 2 | OK | OK | OK | NG |
インスタンス4IAM Role: S3 None | EIP 2 | NG | NG | OK | NG |