3 ways to access S3 from private subnet
There are three ways to access S3 buckets from an EC2 instance in a private subnet.
- NAT Gateway
- VPC Endpoint (Gateway Type)
- VPC Endpoint (interface type)
This page will review how to access S3 buckets via the above three.
Environment
Create one private subnet in each of the three AZs.
Place an EC2 instance on each subnet.
The instance will be the latest Amazon Linux 2.
Create NAT gateways and gateway/interface type VPC endpoints.
Configure security groups, route tables, etc. to allow each instance to communicate to S3 through them.
This configuration will be built in the ap-northeast-1 (Tokyo) region.
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-saa/tree/main/03/003
Explanation of key points of template files
NAT Gateway
Resources:
IGW:
Type: AWS::EC2::InternetGateway
IGWAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref IGW
EIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NATGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt EIP.AllocationId
SubnetId: !Ref PublicSubnet
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !Ref CidrIp1
VpcId: !Ref VPC
AvailabilityZone: !Sub "${AWS::Region}${AvailabilityZone1}"
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !Ref CidrIp2
VpcId: !Ref VPC
AvailabilityZone: !Sub "${AWS::Region}${AvailabilityZone1}"
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
RouteToInternet:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref IGW
PublicSubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet
RouteTableId: !Ref PublicRouteTable
PrivateRouteTable1:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
RouteToNATGateway:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable1
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NATGateway
PrivateSubnetRouteTableAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet1
RouteTableId: !Ref PrivateRouteTable1
Code language: YAML (yaml)
Create a NAT gateway on the public subnet.
Configure the route table as follows so that instances on the private subnet can communicate with the S3 bucket via the NAT gateway.
- Route table for private subnets: set default route for NAT Gateway
- Route table for public subnets: set default route for Internet Gateway
VPC Endpoints
Gateway Type
Resources:
GatewayS3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
RouteTableIds:
- !Ref PrivateRouteTable2
ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
VpcEndpointType: Gateway
VpcId: !Ref VPC
PrivateRouteTable2:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Code language: YAML (yaml)
To create a gateway type endpoint, specify a route table for the RouteTableIds property.
No special routes need to be specified for the route table.
By associating it with a VPC endpoint, the route will automatically be registered.
Interface Type
Resources:
InterfaceS3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PrivateDnsEnabled: false
SecurityGroupIds:
- !Ref EndpointSecurityGroup
ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
SubnetIds:
- !Ref PrivateSubnet3
VpcEndpointType: Interface
VpcId: !Ref VPC
EndpointSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub "${Prefix}-EndpointSecurityGroup"
GroupDescription: Allow HTTPS from InstanceSecurityGroup.
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: !Ref HTTPSPort
ToPort: !Ref HTTPSPort
SourceSecurityGroupId: !Ref InstanceSecurityGroup
Code language: YAML (yaml)
When creating an interface type endpoint, specify a security group in the SecurityGroupIds property.
This content allows 443/tcp to be sent from the security group applied to the instance.
When creating a VPC endpoint for S3 of interface type, the PrivateDnsEnabled property is the key.
Amazon S3 interface endpoints do not support the private DNS feature of interface endpoints.
Accessing Amazon S3 interface endpoints
In accordance with the above, this property is set to “false”.
(Reference) S3 bucket
Resources:
Bucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
BucketName: !Ref Prefix
Code language: YAML (yaml)
Create an S3 bucket.
No special configuration is required.
(Reference) EC2 instance
Resources:
Instance1:
Type: AWS::EC2::Instance
Properties:
IamInstanceProfile: !Ref InstanceProfile
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
NetworkInterfaces:
- DeviceIndex: 0
SubnetId: !Ref PrivateSubnet1
GroupSet:
- !Ref InstanceSecurityGroup
Instance2:
Type: AWS::EC2::Instance
Properties:
IamInstanceProfile: !Ref InstanceProfile
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
NetworkInterfaces:
- DeviceIndex: 0
SubnetId: !Ref PrivateSubnet2
GroupSet:
- !Ref InstanceSecurityGroup
Instance3:
Type: AWS::EC2::Instance
Properties:
IamInstanceProfile: !Ref InstanceProfile
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
NetworkInterfaces:
- DeviceIndex: 0
SubnetId: !Ref PrivateSubnet3
GroupSet:
- !Ref InstanceSecurityGroup
Code language: YAML (yaml)
Place one EC2 instance on each subnet.
The following are the IAM roles for the instance
Resources:
InstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- ec2.amazonaws.com
Policies:
- PolicyName: AccessS3Policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:*
Resource:
- !Ref BucketArn
- !Sub "${BucketArn}/*"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Code language: YAML (yaml)
The contents allow all actions to the aforementioned S3 bucket.
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 refer to the following pages.
After reviewing the resources in each stack, information on the main resources created in this case is as follows
- Instance 1: i-08d2a290c677f6f0a
- Instance 2: i-0986da9c1408db96d
- Instance 3: i-0b53eeb09bd833752
- S3 bucket: saa-03-003
- NAT gateway: nat-053aa8d5766c63a66
- Gateway type VPC endpoint: vpce-03a8194a5c16630d4
- Interface type VPC endpoint: vpce-0c1106da79eb97528
Check each resource from the AWS Management Console.
Check the NAT gateway.
It has been created successfully.
You can also see that the EIP created by CloudFormation has been successfully attached.
Check the two VPC endpoints.
You can indeed see that a gateway type/interface type VPC endpoint has been created.
operation check
Access S3 bucket via NAT Gateway
Now that you are ready, access instance 1.
SSM Session Manager is used for access.
% aws ssm start-session --target i-08d2a290c677f6f0a
...
sh-4.2$
Code language: Bash (bash)
For more information on SSM Session Manager, please refer to the following page.
After creating the file for testing, check the contents of the bucket.
sh-4.2$ touch /home/ssm-user/test1.txt
sh-4.2$ aws s3 cp /home/ssm-user/test1.txt s3://saa-03-003
upload: /home/ssm-user/test1.txt to s3://saa-03-003/test1.txt
sh-4.2$ aws s3 ls s3://saa-03-003
2023-01-23 13:03:01 0 test1.txt
Code language: Bash (bash)
Indeed, we were able to access the S3 bucket via the NAT gateway.
Access S3 buckets via Gateway Type VPC endpoint
Similarly, use SSM Session Manager to access instance 2.
% aws ssm start-session --target i-0986da9c1408db96d
...
sh-4.2$
sh-4.2$ touch /home/ssm-user/test2.txt
Code language: Bash (bash)
Follow the same procedure as before to check for communication.
There is one caveat when accessing S3 via gateway type VPC endpoints.
AWS CLI を使用して Amazon S3 にリクエストを実行する場合は、デフォルトリージョンをバケットと同じリージョンに設定するか、またはリクエストで –region パラメータを使用します。
Amazon S3 におけるエンドポイント
The official AWS explanation of why a region must be specified is as follows
Traffic that’s destined for the service (Amazon S3 or DynamoDB) in a different Region goes to the internet gateway because prefix lists are specific to a Region.
Gateway endpoints
In other words, if you do not explicitly specify a region, traffic will be routed to Internet Gateway.
However, if the instance is on a private subnet and there is no route to the Internet Gateway, as in this configuration, even if a VPC endpoint is provided, the traffic will not be routed to it and will not be accessible.
Specify the region according to the above.
In this configuration, the region is “ap-northeast-1”.
sh-4.2$ aws s3 cp /home/ssm-user/test2.txt s3://saa-03-003 --region ap-northeast-1
upload: /home/ssm-user/test2.txt to s3://saa-03-003/test2.txt
sh-4.2$ aws s3 ls s3://saa-03-003 --region ap-northeast-1
2023-01-23 13:03:01 0 test1.txt
2023-01-24 11:03:59 0 test2.txt
Code language: Bash (bash)
We were indeed able to access the S3 bucket via a gateway-type VPC endpoint.
Access S3 buckets via Interface Type VPC endpoint
Similarly, use SSM Session Manager to access instance 3.
% aws ssm start-session --target i-0b53eeb09bd833752
...
sh-4.2$
sh-4.2$ touch /home/ssm-user/test3.txt
Code language: Bash (bash)
Follow the same procedure as before to check for communication.
There are two caveats when accessing S3 via an interface type VPC endpoint.
The first is the need to specify the region and endpoint URL.
Use the –region and –endpoint-url parameters to access S3 buckets, S3 access points, or S3 control APIs through S3 interface endpoints.
Accessing buckets and S3 access points from S3 interface endpoints
Second, the value specified in the endpoint URL is the endpoint-specific S3 DNS name.
you can find the DNS name of a VPC endpoint. In this example, the VPC endpoint ID (vpce-id) is vpce-0e25b8cdd720f900e and the DNS name is *.vpce-0e25b8cdd720f900e-argc85vg.s3.us-east-1.vpce.amazonaws.com. Remember to replace * when using the DNS name. For example, to access a bucket, use a DNS name like this bucket.vpce-0e25b8cdd720f900e-argc85vg.s3.us-east-1.vpce.amazonaws.com.
Accessing buckets and S3 access points from S3 interface endpoints
Specify the region and endpoint URL according to the above. In this configuration, the region is “ap-northeast-1” and the endpoint URL is “https://bucket.vpce-0c1106da79eb97528-h8nms9fr.s3.ap-northeast-1.vpce.amazonaws.com”.
sh-4.2$ aws s3 cp /home/ssm-user/test3.txt s3://saa-03-003/ --region ap-northeast-1 --endpoint-url https://bucket.vpce-0c1106da79eb97528-h8nms9fr.s3.ap-northeast-1.vpce.amazonaws.com
upload: ../../home/ssm-user/test3.txt to s3://saa-03-003/test3.txt
sh-4.2$ aws s3 ls s3://saa-03-003/ --region ap-northeast-1 --endpoint-url https://bucket.vpce-0c1106da79eb97528-h8nms9fr.s3.ap-northeast-1.vpce.amazonaws.com
2023-01-23 13:03:01 0 test1.txt
2023-01-24 11:03:59 0 test2.txt
2023-01-24 11:18:26 0 test3.txt
Code language: Bash (bash)
We were indeed able to access the S3 bucket via an interface type VPC endpoint.
summary
We identified three ways to access S3 from a private subnet (NAT gateway, gateway type VPC endpoint, interface type VPC endpoint).