Skip to content

Commit

Permalink
Make S3 interface endpoint depends on Gateway endpoint
Browse files Browse the repository at this point in the history
The S3 interface must be created after the Gateway endpoint or we
get the following error at deployment:

The VPC vpc-x must have a Gateway endpoint for the service.

ref #2
  • Loading branch information
pierretr committed Oct 21, 2024
1 parent 0db775e commit 4161a2c
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 1 deletion.
41 changes: 40 additions & 1 deletion src/e3/aws/troposphere/ec2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,10 +718,21 @@ def __init__(
self.public_subnet_ip_networks = {
az: next(self.subnet_ip_networks) for az in availability_zones
}

# Handle S3 interface endpoint from this construct instead of from the
# VPCEndpointsSubnet construct as it requires a cross configuration with
# the S3 gateway endpoint
self.s3_interface_endpoint_config = None
if interface_endpoints is not None:
for idx, itf_endpoint in enumerate(interface_endpoints):
if itf_endpoint[0] == "s3":
self.s3_interface_endpoint_config = interface_endpoints.pop(idx)
break

# Add a subnet for VPC endpoints if requested
self.interface_endpoints_subnet = (
None
if interface_endpoints is None
if interface_endpoints is None and self.s3_interface_endpoint_config is None
else VPCEndpointsSubnet(
name=f"{self.name_prefix}Endpoints",
region=self.region,
Expand Down Expand Up @@ -922,6 +933,32 @@ def s3_gateway_endpoint(self) -> ec2.VPCEndpoint | None:
else None
)

@cached_property
def s3_interface_endpoint(self) -> ec2.VPCEndPoint | None:
"""Return S3 VPC interface endpoint."""
if self.s3_interface_endpoint_config:
# If no specific policy is requested use the same policy
# as the S3 gateway endpoint policy.
if not (policy_document := self.s3_interface_endpoint_config[1]):
policy_document = self.s3_endpoint_policy_document
assert policy_document is not None
assert self.s3_gateway_endpoint is not None
assert self.interface_endpoints_subnet is not None
return ec2.VPCEndpoint(
name_to_id(f"{self.name_prefix}S3InterfaceEndpoint"),
PolicyDocument=policy_document.as_dict,
PrivateDnsEnabled="true",
SecurityGroupIds=[Ref(self.interface_endpoints_subnet.security_group)],
ServiceName=f"com.amazonaws.{self.region}.s3",
SubnetIds=[Ref(self.interface_endpoints_subnet.subnet)],
VpcEndpointType="Interface",
VpcId=Ref(self.vpc),
# S3 interface endpoint requires the Gateway endpoint
# to be created first
DependsOn=self.s3_gateway_endpoint.title,
)
return None

@cached_property
def egress_to_vpc_endpoints(self) -> list[ec2.SecurityGroupRule]:
"""Return egress rules allowing traffic to VPC endpoints.
Expand Down Expand Up @@ -989,4 +1026,6 @@ def resources(self, stack: Stack) -> list[AWSObject]:
res.append(self.interface_endpoints_subnet)
if self.s3_gateway_endpoint:
res.append(self.s3_gateway_endpoint)
if self.s3_interface_endpoint:
res.append(self.s3_interface_endpoint)
return res
1 change: 1 addition & 0 deletions tests/tests_e3_aws/troposphere/ec2/ec2_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ def test_vpc_v2_with_endpoints(stack: Stack) -> None:
interface_endpoints=[
("email-smtp", None),
("logs", cloudwatch_endpoint_pd),
("s3", None),
],
s3_endpoint_policy_document=s3_endpoint_pd,
)
Expand Down
42 changes: 42 additions & 0 deletions tests/tests_e3_aws/troposphere/ec2/vpc_v2_with_endpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -406,5 +406,47 @@
}
},
"Type": "AWS::EC2::VPCEndpoint"
},
"TestVPCS3InterfaceEndpoint": {
"Properties": {
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:ListBucket",
"Resource": "*"
}
]
},
"PrivateDnsEnabled": true,
"SecurityGroupIds": [
{
"Ref": "TestVPCEndpointsSecurityGroup"
}
],
"ServiceName": "com.amazonaws.eu-west-1.s3",
"SubnetIds": [
{
"Ref": "TestVPCEndpointsSubnet"
}
],
"VpcEndpointType": "Interface",
"VpcId": {
"Ref": "TestVPCVPC"
}
},
"Type": "AWS::EC2::VPCEndpoint",
"DependsOn": "TestVPCS3Endpoint"
}
}

0 comments on commit 4161a2c

Please sign in to comment.