Use S3 bucket policy to allow or deny access on an address basis – aws:SourceIp
In the S3 bucket policy, consider setting access restrictions based on global addresses.
In this case, the IP address condition operators (IpAddress, NotIpAddress) can be used.
IP address condition operators let you construct Condition elements that restrict access based on comparing a key to an IPv4 or IPv6 address or range of IP addresses. You use these with the aws:SourceIp key.
IP address condition operators
This time, access the S3 bucket with the bucket policy set from an EC2 instance to check the behavior.
Environment
Create four EC2 instances.
The instances will be the latest Amazon Linux 2, two in each of two private subnets.
One instance on each subnet will be given full access to S3 and the other will have no privileges at all.
All instances access the Internet via a NAT Gateway located on the public subnet of each AZ.
This means that when each instance accesses the outside world, it will communicate using the EIP assigned to the NAT Gateway.
Create four buckets.
Set the bucket policy for each as follows
setting | Bucket 1 | Bucket 2 | Bucket 3 | Bucket 4 |
Action | Allow | Deny | Allow | Deny |
IP address condition operators | IpAddress | IpAddress | NotIpAddress | NotIpAddress |
aws:SourceIp | EIP1 | EIP1 | EIP1 | EIP1 |
Use the IP address condition operator and the aws:SourceIp key to set address-based restrictions.
The target address is the EIP1 assigned to the NAT Gateway.
CloudFormation template files
The above configuration is built with CloudFormation.
The CloudFormation templates are placed at the following URL
https://github.com/awstut-an-r/awstut-soa/tree/main/04/004
Explanation of key points of template files
S3
Bucket
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)
Create four buckets.
Only bucket 3 is configured differently from the others.
This is a setting to allow public access.
By default, public access is restricted by the S3 Block Public Access.
However, the bucket policy for bucket 3, described below, would allow access on a wide range, resulting in a configuration inconsistency.
To resolve this inconsistency, disable the public access block feature.
If this setting is not made, the creation of bucket 3 and bucket policy will fail and the following error message will be displayed.
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
Bucket Policy
Check the bucket policies one by one.
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)
Bucket policy for bucket 1.
Full access is allowed for access from 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)
Bucket policy for bucket 2.
Deny all actions if accessed from 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)
Bucket policy for bucket 3.
Full access is allowed when accessing from other than 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)
Bucket policy for bucket 4.
Reject all actions if accessed from other than 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)
We will create four EC2 instances, but we will cover two instances in one subnet.
The remaining instances are only different subnets, as the configuration itself is identical.
The IAM role is the key point.
The IAM role for one instance allows full access to S3.
The IAM role for the other instance will not allow anything regarding S3.
(Reference) 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)
Place one NAT Gateway in each of the two AZs.
Attach an EIP to each gateway.
The bucket policy settings described above refer to this EIP1 address.
Architecting
Use CloudFormation to build this environment and check its actual behavior.
Create CloudFormation stacks and check the resources in the stacks
Create CloudFormation stacks.
For information on how to create stacks and check each stack, please see the following page.
After reviewing the resources in each stack, information on the main resources created in this case is as follows
- Bucket 1: soa-04-004-bucket-01
- Bucket 2: soa-04-004-bucket-02
- Bucket 3: soa-04-004-bucket-03
- Bucket 4: soa-04-004-bucket-04
- Instance 1: i-04dbf87640c773eec
- Instance 2: i-0d716220234453122
- Instance 3: i-0ac64c5ec684c0501
- Instance 4: i-059a4434e92df1367
- NAT Gateway1: nat-0a3531dbe283cec59
- NAT Gateway2: nat-0e9a9f6e5a324ac4d
- EIP1: 35.74.75.17
- EIP2: 52.194.136.88
Check each resource from the AWS Management Console.
Check the NAT gateway.
Two NAT Gateways have been created.
You can see that each has an EIP attached.
Check the bucket policy.
Each bucket policy is set as specified in the CloudFormation templates.
Operation Check
Now that we are ready, we can access each instance and check the actual behavior.
The instances are accessed using SSM Session Manager.
For more information on Session Manager, please see the following pages
Instance 1
Access each bucket from instance 1.
The IAM role on instance 1 allows full S3 access.
And when accessing the buckets, EIP1 (35.74.75.17) attached to the NAT Gateway is used.
Access to the bucket is performed via the 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)
Bucket 1 was accessible.
This is because the IAM role and bucket policy explicitly allow access.
Bucket 2 was not accessible.
This is because the IAM role allows access but the bucket policy explicitly denies access.
Bucket 3 was accessible.
This is not explicitly allowed in the bucket policy, but is explicitly allowed in the IAM role.
Bucket 4 was accessible.
This is not explicitly allowed in the bucket policy, but is explicitly allowed in the IAM role.
Instance 2
Access each bucket from instance 2.
The IAM role on instance 2 does not allow access to S3.
And when accessing the buckets, EIP1 (35.74.75.17) attached to the NAT Gateway is used.
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)
Bucket 1 was accessible.
This is because the bucket policy explicitly allows access.
Bucket 2 was not accessible.
This is because the bucket policy explicitly denies access.
Bucket 3 was not accessible.
This is because access is not explicitly allowed by the IAM role and bucket policy.
Access is denied because there is no setting that explicitly allows it.
Bucket 4 was not accessible.
This is because access is not explicitly allowed by the IAM role and bucket policy.
Access is denied because there is no setting that explicitly allows it.
Instance 3
Access each bucket from instance 3.
The IAM role for instance 3 allows full S3 access. Also, when accessing the buckets, EIP2 (52.194.136.88) attached to the NAT Gateway is used.
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)
Bucket 1 was accessible.
This is not explicitly allowed in the bucket policy, but is explicitly allowed in the IAM role.
Bucket 2 was accessible.
This is because it is not explicitly allowed in the bucket policy, but is explicitly allowed in the IAM role.
Bucket 3 was accessible.
This is because the IAM role and bucket policy explicitly allow access.
Bucket 4 was not accessible.
This is because the IAM role allows access but the bucket policy explicitly denies access.
Instance 4
Access each bucket from instance 4.
The IAM role on instance 4 does not allow access to S3.
And when accessing the buckets, EIP2 (52.194.136.88) attached to the NAT Gateway is used.
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)
Bucket 1 was not accessible.
This is because access is not explicitly allowed by the IAM role and bucket policy.
Access is denied because there is no setting that explicitly allows it.
Bucket 2 was not accessible.
This is because access is not explicitly allowed by the IAM role and bucket policy.
Access is denied because there is no setting that explicitly allows it.
Bucket 3 was accessible.
This is not explicitly allowed in the IAM role, but is explicitly allowed in the bucket policy.
Bucket 4 was not accessible.
This is because access is explicitly denied by the bucket policy.
Summary
The following is a summary of the results of the operation checks.
Instance | NAT Gateway | Bucket1 Allow from EIP 1 | Bucket2 Deny from EIP 1 | Bucket3 Allow from Not EIP 1 | Bucket4 Deny from Not EIP 1 |
Instance1 IAM Role: S3 Full Access | EIP 1 | OK | NG | OK | OK |
Instance2 IAM Role: S3 None | EIP 1 | OK | NG | NG | NG |
Instance3 IAM Role: S3 Full Access | EIP 2 | OK | OK | OK | NG |
Instance4 IAM Role: S3 None | EIP 2 | NG | NG | OK | NG |