CF - Support for VPCEndpoint (#4908)

This commit is contained in:
Bert Blommers 2022-03-03 21:43:25 -01:00 committed by GitHub
parent dc5353f1ae
commit 86e1fe8f1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 110 additions and 4 deletions

View File

@ -4142,7 +4142,7 @@ class VPCBackend(object):
for vpce_id in vpce_ids or []:
vpc_endpoint = self.vpc_end_points.get(vpce_id, None)
if vpc_endpoint:
if vpc_endpoint.type.lower() == "interface":
if vpc_endpoint.endpoint_type.lower() == "interface":
for eni_id in vpc_endpoint.network_interface_ids:
self.enis.pop(eni_id, None)
else:
@ -5446,7 +5446,7 @@ class Route(CloudFormationModel):
return route_table
class VPCEndPoint(TaggedEC2Resource):
class VPCEndPoint(TaggedEC2Resource, CloudFormationModel):
def __init__(
self,
ec2_backend,
@ -5469,7 +5469,7 @@ class VPCEndPoint(TaggedEC2Resource):
self.id = endpoint_id
self.vpc_id = vpc_id
self.service_name = service_name
self.type = endpoint_type
self.endpoint_type = endpoint_type
self.state = "available"
self.policy_document = policy_document
self.route_table_ids = route_table_ids
@ -5488,6 +5488,46 @@ class VPCEndPoint(TaggedEC2Resource):
def owner_id(self):
return ACCOUNT_ID
@property
def physical_resource_id(self):
return self.id
@staticmethod
def cloudformation_name_type():
return None
@staticmethod
def cloudformation_type():
return "AWS::EC2::VPCEndpoint"
@classmethod
def create_from_cloudformation_json(
cls, resource_name, cloudformation_json, region_name, **kwargs
):
properties = cloudformation_json["Properties"]
service_name = properties.get("ServiceName")
subnet_ids = properties.get("SubnetIds")
vpc_endpoint_type = properties.get("VpcEndpointType")
vpc_id = properties.get("VpcId")
policy_document = properties.get("PolicyDocument")
private_dns_enabled = properties.get("PrivateDnsEnabled")
route_table_ids = properties.get("RouteTableIds")
security_group_ids = properties.get("SecurityGroupIds")
ec2_backend = ec2_backends[region_name]
vpc_endpoint = ec2_backend.create_vpc_endpoint(
vpc_id=vpc_id,
service_name=service_name,
endpoint_type=vpc_endpoint_type,
subnet_ids=subnet_ids,
policy_document=policy_document,
private_dns_enabled=private_dns_enabled,
route_table_ids=route_table_ids,
security_group_ids=security_group_ids,
)
return vpc_endpoint
class ManagedPrefixList(TaggedEC2Resource):
def __init__(

View File

@ -669,7 +669,7 @@ DESCRIBE_VPC_ENDPOINT_RESPONSE = """<DescribeVpcEndpointsResponse xmlns="http://
<serviceName>{{ vpc_end_point.service_name }}</serviceName>
<vpcId>{{ vpc_end_point.vpc_id }}</vpcId>
<vpcEndpointId>{{ vpc_end_point.id }}</vpcEndpointId>
<vpcEndpointType>{{ vpc_end_point.type }}</vpcEndpointType>
<vpcEndpointType>{{ vpc_end_point.endpoint_type }}</vpcEndpointType>
{% if vpc_end_point.subnet_ids %}
<subnetIdSet>
{% for subnet_id in vpc_end_point.subnet_ids %}

View File

@ -694,3 +694,69 @@ def get_secgroup_by_tag(ec2, sg_):
return ec2.describe_security_groups(
Filters=[{"Name": "tag:sg-name", "Values": [sg_]}]
)["SecurityGroups"][0]
@mock_cloudformation
@mock_ec2
def test_vpc_endpoint_creation():
ec2 = boto3.resource("ec2", region_name="us-west-1")
ec2_client = boto3.client("ec2", region_name="us-west-1")
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
subnet1 = ec2.create_subnet(
VpcId=vpc.id, CidrBlock="10.0.0.0/24", AvailabilityZone=f"us-west-1a"
)
subnet_template = {
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"EndpointSubnetId": {"Type": "String",},
"EndpointVpcId": {"Type": "String",},
"EndpointServiceName": {"Type": "String",},
},
"Resources": {
"GwlbVpcEndpoint": {
"Type": "AWS::EC2::VPCEndpoint",
"Properties": {
"ServiceName": {"Ref": "EndpointServiceName"},
"SubnetIds": [{"Ref": "EndpointSubnetId"}],
"VpcEndpointType": "GatewayLoadBalancer",
"VpcId": {"Ref": "EndpointVpcId"},
},
}
},
"Outputs": {
"EndpointId": {
"Description": "Id of the endpoint created",
"Value": {"Ref": "GwlbVpcEndpoint"},
},
},
}
cf = boto3.client("cloudformation", region_name="us-west-1")
template_json = json.dumps(subnet_template)
stack_name = str(uuid4())[0:6]
cf.create_stack(
StackName=stack_name,
TemplateBody=template_json,
Parameters=[
{"ParameterKey": "EndpointSubnetId", "ParameterValue": subnet1.id},
{"ParameterKey": "EndpointVpcId", "ParameterValue": vpc.id},
{"ParameterKey": "EndpointServiceName", "ParameterValue": "serv_name"},
],
)
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
resources.should.have.length_of(1)
resources[0].should.have.key("LogicalResourceId").equals("GwlbVpcEndpoint")
vpc_endpoint_id = resources[0]["PhysicalResourceId"]
outputs = cf.describe_stacks(StackName=stack_name)["Stacks"][0]["Outputs"]
outputs.should.have.length_of(1)
outputs[0].should.equal({"OutputKey": "EndpointId", "OutputValue": vpc_endpoint_id})
endpoint = ec2_client.describe_vpc_endpoints(VpcEndpointIds=[vpc_endpoint_id])[
"VpcEndpoints"
][0]
endpoint.should.have.key("VpcId").equals(vpc.id)
endpoint.should.have.key("ServiceName").equals("serv_name")
endpoint.should.have.key("State").equals("available")
endpoint.should.have.key("SubnetIds").equals([subnet1.id])
endpoint.should.have.key("VpcEndpointType").equals("GatewayLoadBalancer")