From 89955f9cdf82aba0e3c828e148e721d2b0441779 Mon Sep 17 00:00:00 2001 From: eL0ck Date: Mon, 12 Nov 2018 10:00:58 +1100 Subject: [PATCH 1/5] make PEP8 --- src/lambda.py | 634 +++++++++++++++++++++++++------------------------- 1 file changed, 314 insertions(+), 320 deletions(-) diff --git a/src/lambda.py b/src/lambda.py index 3182587..ca883fe 100644 --- a/src/lambda.py +++ b/src/lambda.py @@ -1,18 +1,21 @@ import json import traceback + def isIPv6NetACL(cidr): if cidr == "::/0": return "Ipv6CidrBlock" else: return "CidrBlock" + def isIPv6Route(cidr): if cidr == "::/0": return "DestinationIpv6CidrBlock" else: return "DestinationCidrBlock" + def handler(event, context): print(json.dumps(event)) @@ -22,12 +25,6 @@ def handler(event, context): "status": "success" } try: - params = { - "params": event["templateParameterValues"], - "template": event["fragment"], - "account_id": event["accountId"], - "region": event["region"] - } resources = {} outputs = {} response = event["fragment"] @@ -53,12 +50,12 @@ def handler(event, context): outputs[properties["Details"]["VPCName"]] = { "Description": properties["Details"]["VPCName"], - "Value": { - "Ref" : properties["Details"]["VPCName"] + "Value": { + "Ref": properties["Details"]["VPCName"] }, - "Export" : { - "Name" : { - "Fn::Sub": "${AWS::StackName}-VPCid" + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-VPCid" } } } @@ -74,7 +71,7 @@ def handler(event, context): "AmazonProvidedIpv6CidrBlock": "true" } } - + resources["EgressGateway"] = { "Type": "AWS::EC2::EgressOnlyInternetGateway", "Properties": { @@ -84,184 +81,185 @@ def handler(event, context): } } - resources[properties["DHCP"]["Name"]] = { - "Type": "AWS::EC2::DHCPOptions", - "Properties": { - "DomainNameServers": [properties["DHCP"]["DNSServers"]], - "NtpServers": [properties["DHCP"]["NTPServers"]], - "NetbiosNodeType": properties["DHCP"]["NTBType"], - "Tags": [{ - "Key": "Name", - "Value": properties["DHCP"]["Name"] - }] - } - } - - resources[properties["DHCP"]["Name"]+"Association"] = { - "Type": "AWS::EC2::VPCDHCPOptionsAssociation", - "Properties": { - "DhcpOptionsId": { - "Ref": properties["DHCP"]["Name"] - }, - "VpcId": { - "Ref": properties["Details"]["VPCName"] + resources[properties["DHCP"]["Name"]] = { + "Type": "AWS::EC2::DHCPOptions", + "Properties": { + "DomainNameServers": [properties["DHCP"]["DNSServers"]], + "NtpServers": [properties["DHCP"]["NTPServers"]], + "NetbiosNodeType": properties["DHCP"]["NTBType"], + "Tags": [{ + "Key": "Name", + "Value": properties["DHCP"]["Name"] + }] + } } - } - } - resources["InternetGateway"] = { - "Type": "AWS::EC2::InternetGateway", - "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": "InternetGateway" + resources[properties["DHCP"]["Name"] + "Association"] = { + "Type": "AWS::EC2::VPCDHCPOptionsAssociation", + "Properties": { + "DhcpOptionsId": { + "Ref": properties["DHCP"]["Name"] + }, + "VpcId": { + "Ref": properties["Details"]["VPCName"] + } } - ] - } - } + } - resources["IGWVPCGatewayAttachment"] = { - "Type": "AWS::EC2::VPCGatewayAttachment", - "Properties": { - "InternetGatewayId": { - "Ref": "InternetGateway" - }, - "VpcId": { - "Ref": properties["Details"]["VPCName"] + resources["InternetGateway"] = { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "InternetGateway" + } + ] + } } - } - } - resources["VPCGatewayAttachment"] = { - "Type": "AWS::EC2::VPCGatewayAttachment", - "Properties": { - "VpcId": { - "Ref": properties["Details"]["VPCName"] - }, - "VpnGatewayId": { - "Ref": "VGW" + resources["IGWVPCGatewayAttachment"] = { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "InternetGatewayId": { + "Ref": "InternetGateway" + }, + "VpcId": { + "Ref": properties["Details"]["VPCName"] + } + } } - } - } - resources["VPCFlowLogsRole"] = { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": { - "Service": [ - "vpc-flow-logs.amazonaws.com" - ] - }, - "Action": [ - "sts:AssumeRole" - ] + resources["VPCGatewayAttachment"] = { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": properties["Details"]["VPCName"] + }, + "VpnGatewayId": { + "Ref": "VGW" } - ] - }, - "Path": "/", - "Policies": [ - { - "PolicyName": "root", - "PolicyDocument": { + } + } + + resources["VPCFlowLogsRole"] = { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", + "Principal": { + "Service": [ + "vpc-flow-logs.amazonaws.com" + ] + }, "Action": [ - "logs:*" - ], - "Resource": "arn:aws:logs:*:*:*" + "sts:AssumeRole" + ] } ] - } + }, + "Path": "/", + "Policies": [ + { + "PolicyName": "root", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "logs:*" + ], + "Resource": "arn:aws:logs:*:*:*" + } + ] + } + } + ] } - ] - } - } - - resources["VPCFlowLogs"] = { - "Type" : "AWS::EC2::FlowLog", - "Properties" : { - "DeliverLogsPermissionArn" : { - "Fn::GetAtt" : ["VPCFlowLogsRole", "Arn"] - }, - "LogGroupName" : "FlowLogsGroup", - "ResourceId" : { - "Ref" : properties["Details"]["VPCName"] - }, - "ResourceType" : "VPC", - "TrafficType" : "ALL" - } - } + } - if "RouteTables" in properties: - for routetable, objects in properties["RouteTables"].iteritems(): - resources[routetable] = { - "Type": "AWS::EC2::RouteTable", + resources["VPCFlowLogs"] = { + "Type": "AWS::EC2::FlowLog", "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": routetable - } - ], - "VpcId": { + "DeliverLogsPermissionArn": { + "Fn::GetAtt": ["VPCFlowLogsRole", "Arn"] + }, + "LogGroupName": "FlowLogsGroup", + "ResourceId": { "Ref": properties["Details"]["VPCName"] - } + }, + "ResourceType": "VPC", + "TrafficType": "ALL" } } - outputs[routetable] = { - "Description": routetable, - "Value": { - "Ref" : routetable - }, - "Export" : { - "Name" : { - "Fn::Sub": "${AWS::StackName}-RouteTable-"+routetable + if "RouteTables" in properties: + for routetable, objects in properties["RouteTables"].iteritems(): + resources[routetable] = { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": routetable + } + ], + "VpcId": { + "Ref": properties["Details"]["VPCName"] + } + } } - } - } - resources[routetable + "RoutePropagation"] = { - "Type": "AWS::EC2::VPNGatewayRoutePropagation", - "Properties": { - "RouteTableIds": [ - { + outputs[routetable] = { + "Description": routetable, + "Value": { "Ref": routetable + }, + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-RouteTable-" + routetable + } } - ], - "VpnGatewayId": { - "Ref": "VGW" } - }, - "DependsOn": [ - "VPCGatewayAttachment" - ] - } - if objects is not None: - for route in objects: - resources[route["RouteName"]] = { - "Type": "AWS::EC2::Route", + + resources[routetable + "RoutePropagation"] = { + "Type": "AWS::EC2::VPNGatewayRoutePropagation", "Properties": { - isIPv6Route(route["RouteCIDR"]): route["RouteCIDR"], - "GatewayId": { - "Ref": route["RouteGW"] - }, - "RouteTableId": { - "Ref": routetable + "RouteTableIds": [ + { + "Ref": routetable + } + ], + "VpnGatewayId": { + "Ref": "VGW" } - } + }, + "DependsOn": [ + "VPCGatewayAttachment" + ] } + if objects is not None: + for route in objects: + resources[route["RouteName"]] = { + "Type": "AWS::EC2::Route", + "Properties": { + isIPv6Route(route["RouteCIDR"]): route["RouteCIDR"], + "GatewayId": { + "Ref": route["RouteGW"] + }, + "RouteTableId": { + "Ref": routetable + } + } + } + + if "Subnets" in properties: + subnet_count = 0 - if "Subnets" in properties: - subnet_count = 0 for subnet, objects in properties["Subnets"].iteritems(): resources[subnet] = { "Type": "AWS::EC2::Subnet", @@ -275,12 +273,10 @@ def handler(event, context): ] }, "CidrBlock": objects["CIDR"], - "Tags": [ - { - "Key": "Name", - "Value": subnet - } - ], + "Tags": [{ + "Key": "Name", + "Value": subnet + }], "VpcId": { "Ref": properties["Details"]["VPCName"] } @@ -289,11 +285,11 @@ def handler(event, context): outputs[subnet] = { "Description": subnet, - "Value": { - "Ref" : subnet + "Value": { + "Ref": subnet }, - "Export" : { - "Name" : { + "Export": { + "Name": { "Fn::Sub": "${AWS::StackName}-Subnet-" + subnet } } @@ -325,46 +321,44 @@ def handler(event, context): subnet_count = subnet_count + 1 if "IPv6" in properties["Details"]: subnet_itr = 0 + for subnet, objects in properties["Subnets"].iteritems(): if properties["Details"]["IPv6"]: resources[subnet]["DependsOn"] = "IPv6Block" resources[subnet]["Properties"]["AssignIpv6AddressOnCreation"] = True - resources[subnet]["Properties"]["Ipv6CidrBlock"] = { - "Fn::Select": [ - subnet_itr, - { + resources[subnet]["Properties"]["Ipv6CidrBlock"] = { + "Fn::Select": [ + subnet_itr, + { "Fn::Cidr": [ - { + { "Fn::Select": [ - 0, - { - "Fn::GetAtt": [ + 0, + { + "Fn::GetAtt": [ properties["Details"]["VPCName"], - "Ipv6CidrBlocks" + "Ipv6CidrBlocks" ] } ] - }, - subnet_count, - 64 + }, + subnet_count, + 64 ] } ] } - subnet_itr = subnet_itr +1 - - + subnet_itr = subnet_itr + 1 + if "NetworkACLs" in properties: for networkacl, objects in properties["NetworkACLs"].iteritems(): resources[networkacl] = { "Type": "AWS::EC2::NetworkAcl", "Properties": { - "Tags": [ - { - "Key": "Name", - "Value": networkacl - } - ], + "Tags": [{ + "Key": "Name", + "Value": networkacl + }], "VpcId": { "Ref": properties["Details"]["VPCName"] } @@ -373,12 +367,12 @@ def handler(event, context): outputs[networkacl] = { "Description": networkacl, - "Value": { - "Ref" : networkacl + "Value": { + "Ref": networkacl }, - "Export" : { - "Name" : { - "Fn::Sub": "${AWS::StackName}-NACL-" + networkacl + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-NACL-" + networkacl } } } @@ -403,136 +397,136 @@ def handler(event, context): } } - if "NATGateways" in properties: - for natgw, objects in properties["NATGateways"].iteritems(): - resources["EIP"+natgw] = { - "Type": "AWS::EC2::EIP", - "Properties": { - "Domain": "vpc" - } - } + if "NATGateways" in properties: + for natgw, objects in properties["NATGateways"].iteritems(): + resources["EIP" + natgw] = { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc" + } + } - outputs["EIP"+natgw] = { - "Description": "EIP for " + natgw, - "Value": { - "Ref" : "EIP"+natgw - }, - "Export" : { - "Name" : { - "Fn::Sub": "${AWS::StackName}-EIP-"+natgw - } - } - } - - resources[natgw] = { - "Type": "AWS::EC2::NatGateway", - "Properties": { - "AllocationId": { - "Fn::GetAtt": [ - "EIP"+natgw, - "AllocationId" - ] - }, - "SubnetId": { - "Ref": objects["Subnet"] - }, - "Tags": [ - { - "Key": "Name", - "Value": natgw + outputs["EIP" + natgw] = { + "Description": "EIP for " + natgw, + "Value": { + "Ref": "EIP" + natgw + }, + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-EIP-" + natgw + } + } } - ] - } - } - outputs[natgw] = { - "Description": natgw, - "Value": { - "Ref" : natgw - }, - "Export" : { - "Name" : { - "Fn::Sub": "${AWS::StackName}-NATGW-"+natgw - } - } - } - - resources["Route"+natgw] = { - "Type": "AWS::EC2::Route", - "Properties": { - "DestinationCidrBlock": "0.0.0.0/0", - "NatGatewayId": { - "Ref": natgw - }, - "RouteTableId": { - "Ref": objects["Routetable"] - } - } - } - if "IPv6" in properties["Details"]: - if properties["Details"]["IPv6"]: - resources["Route"+natgw+"IPv6"] = { - "Type": "AWS::EC2::Route", - "Properties": { - "DestinationIpv6CidrBlock": "::/0", - "EgressOnlyInternetGatewayId": { - "Ref": "EgressGateway" + resources[natgw] = { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "EIP" + natgw, + "AllocationId" + ] + }, + "SubnetId": { + "Ref": objects["Subnet"] + }, + "Tags": [ + { + "Key": "Name", + "Value": natgw + } + ] + } + } + + outputs[natgw] = { + "Description": natgw, + "Value": { + "Ref": natgw }, - "RouteTableId": { - "Ref": objects["Routetable"] + "Export": { + "Name": { + "Fn::Sub": "${AWS::StackName}-NATGW-" + natgw + } } } - } - - if "SecurityGroups" in properties: - for secgroup, objects in properties["SecurityGroups"].iteritems(): - resources[secgroup] = { - "Type" : "AWS::EC2::SecurityGroup", - "Properties" : { - "GroupName": secgroup, - "GroupDescription" : objects["GroupDescription"], - "VpcId": { - "Ref": properties["Details"]["VPCName"] - } - } - } - if "SecurityGroupIngress" in objects: - resources[secgroup]["Properties"]["SecurityGroupIngress"] = [] + resources["Route" + natgw] = { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": natgw + }, + "RouteTableId": { + "Ref": objects["Routetable"] + } + } + } + if "IPv6" in properties["Details"]: + if properties["Details"]["IPv6"]: + resources["Route" + natgw + "IPv6"] = { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationIpv6CidrBlock": "::/0", + "EgressOnlyInternetGatewayId": { + "Ref": "EgressGateway" + }, + "RouteTableId": { + "Ref": objects["Routetable"] + } + } + } + + if "SecurityGroups" in properties: + for secgroup, objects in properties["SecurityGroups"].iteritems(): + resources[secgroup] = { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupName": secgroup, + "GroupDescription": objects["GroupDescription"], + "VpcId": { + "Ref": properties["Details"]["VPCName"] + } + } + } + + if "SecurityGroupIngress" in objects: + resources[secgroup]["Properties"]["SecurityGroupIngress"] = [] for rule in objects["SecurityGroupIngress"]: resources[secgroup]["Properties"]["SecurityGroupIngress"].append({ - "IpProtocol" : rule[0], - "FromPort" : rule[1], - "ToPort" : rule[2], - "CidrIp" : rule[3], - "Description" : rule[4] - }) - - if "SecurityGroupEgress" in objects: - resources[secgroup]["Properties"]["SecurityGroupEgress"] = [] + "IpProtocol": rule[0], + "FromPort": rule[1], + "ToPort": rule[2], + "CidrIp": rule[3], + "Description": rule[4] + }) + + if "SecurityGroupEgress" in objects: + resources[secgroup]["Properties"]["SecurityGroupEgress"] = [] for rule in objects["SecurityGroupEgress"]: resources[secgroup]["Properties"]["SecurityGroupEgress"].append({ - "IpProtocol" : rule[0], - "FromPort" : rule[1], - "ToPort" : rule[2], - "CidrIp" : rule[3], - "Description" : rule[4] - }) - if "Tags" in objects: - resources[secgroup]["Properties"]["Tags"] = [] - for k,v in objects["Tags"].iteritems(): + "IpProtocol": rule[0], + "FromPort": rule[1], + "ToPort": rule[2], + "CidrIp": rule[3], + "Description": rule[4] + }) + if "Tags" in objects: + resources[secgroup]["Properties"]["Tags"] = [] + for k, v in objects["Tags"].iteritems(): resources[secgroup]["Properties"]["Tags"].append({ - "Key" : k, - "Value" : v - }) - - if "Endpoints" in properties: - for endpoint, objects in properties["Endpoints"].iteritems(): - santisedendpoint = endpoint.replace("-", "").replace(".", "") - resources[santisedendpoint+"EndPoint"] = { + "Key": k, + "Value": v + }) + + if "Endpoints" in properties: + for endpoint, objects in properties["Endpoints"].iteritems(): + santisedendpoint = endpoint.replace("-", "").replace(".", "") + resources[santisedendpoint + "EndPoint"] = { "Type": "AWS::EC2::VPCEndpoint", "Properties": { - "ServiceName": { "Fn::Join": [ "", [ "com.amazonaws.", { "Ref": "AWS::Region" }, "."+endpoint ] ] }, + "ServiceName": {"Fn::Join": ["", ["com.amazonaws.", {"Ref": "AWS::Region"}, "." + endpoint]]}, "VpcEndpointType": objects["Type"], "VpcId": { "Ref": properties["Details"]["VPCName"] @@ -542,23 +536,23 @@ def handler(event, context): if objects["Type"] == "Gateway": if "PolicyDocument" in objects: - resources[santisedendpoint+"EndPoint"]["Properties"]["PolicyDocument"] = objects["PolicyDocument"] + resources[santisedendpoint + "EndPoint"]["Properties"]["PolicyDocument"] = objects["PolicyDocument"] if "RouteTableIds" in objects: - resources[santisedendpoint+"EndPoint"]["Properties"]["RouteTableIds"] = [] + resources[santisedendpoint + "EndPoint"]["Properties"]["RouteTableIds"] = [] for routetable in objects["RouteTableIds"]: - resources[santisedendpoint+"EndPoint"]["Properties"]["RouteTableIds"].append({"Ref": routetable }) + resources[santisedendpoint + "EndPoint"]["Properties"]["RouteTableIds"].append({"Ref": routetable}) if objects["Type"] == "Interface": - resources[santisedendpoint+"EndPoint"]["Properties"]["PrivateDnsEnabled"] = True + resources[santisedendpoint + "EndPoint"]["Properties"]["PrivateDnsEnabled"] = True if "SubnetIds" in objects: - resources[santisedendpoint+"EndPoint"]["Properties"]["SubnetIds"] = [] + resources[santisedendpoint + "EndPoint"]["Properties"]["SubnetIds"] = [] for subnet in objects["SubnetIds"]: - resources[santisedendpoint+"EndPoint"]["Properties"]["SubnetIds"].append({"Ref": subnet }) + resources[santisedendpoint + "EndPoint"]["Properties"]["SubnetIds"].append({"Ref": subnet}) if "SecurityGroupIds" in objects: - resources[santisedendpoint+"EndPoint"]["Properties"]["SecurityGroupIds"] = [] + resources[santisedendpoint + "EndPoint"]["Properties"]["SecurityGroupIds"] = [] for secgroup in objects["SecurityGroupIds"]: - resources[santisedendpoint+"EndPoint"]["Properties"]["SecurityGroupIds"].append({"Ref": secgroup }) - + resources[santisedendpoint + "EndPoint"]["Properties"]["SecurityGroupIds"].append({"Ref": secgroup}) + # consider `else` to print error response["Resources"] = resources response["Outputs"] = outputs macro_response["fragment"] = response @@ -568,4 +562,4 @@ def handler(event, context): macro_response["errorMessage"] = str(e) print(json.dumps(macro_response)) - return macro_response \ No newline at end of file + return macro_response From 944bef2269071e1bf8a614ab475cd2a5d8f73b5d Mon Sep 17 00:00:00 2001 From: eL0ck Date: Wed, 14 Nov 2018 16:00:47 +1100 Subject: [PATCH 2/5] Suggest Cosmetic Changes - Change resource Type `Kablamo` -> `Elendel` - Add make command to deploy Transform - Add instructions on how to use transform - Add instructions on how to deploy example vpc --- README.md | 72 ++++++++++++++++++++++++++++----------- makefile | 17 ++++++--- src/lambda.py | 2 +- tests/transform_call.json | 4 +-- transform.yaml | 4 +-- example.yaml => vpc.yaml | 15 ++++---- 6 files changed, 77 insertions(+), 37 deletions(-) rename example.yaml => vpc.yaml (98%) diff --git a/README.md b/README.md index ecdf5fb..1bcc7e2 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,60 @@ Builds out a "fully" featured VPC summarising the complexity associated with a VPC such as Internet & Customer Gateways, Subnets, Routetables and NATGateways. -It also adds in VPC Flowlogs with an IAM role and supports full dynamic allocation of IPv6 with the VPC and to each subnet. +It also adds in VPC Flowlogs with an IAM role and supports full dynamic allocation of IPv6 with the VPC and to each subnet. The IPv6 handles Egress Internet Gateway and default route against ::/0 -## Build Package +## Deployment +Notice that in [`vpc.yaml`](./vpc.yaml) the resources is not and AWS supported type. Its specification is defined in [`transform.yaml`](./transform.yaml). In order to submit cloudformation templates using this `Type` you must have the transform deployed first. -make buildPackage +### Deploy the Transform -## Upload package to S3 -Fill in your bucket and profile (utilises a crude aws cli s3 upload command) +First make an S3 bucket and add it to the `makefile` at `BUCKET_NAME`. In order for the deployment to work you must also set `USER_PROFILE` (use `default` if not required). -make uploadToS3 +Deploy the transform: + +```bash +make deployTransform +``` + +### Use the transform to build a VPC + +#### Configure your Template + +Open `vpc.yaml` and replace the account number with your own so that the template knows which transform to apply: + +```yaml +Transform: "::VPC" +``` + +#### Virtual Private Gateway + +Ideally you should never spin up a VPGW in Cloudformation. If you ever plan to attach it to a Direct Connect Virtual Interface you wont be able to tear up & down the VPC without destorying the VIF attachment. Either by hand in the console (shudder) or ideally via the CLI/SDK call with the following + +```bash +aws ec2 create-vpn-gateway --type ipsec.1 --amazon-side-asn +``` + +You can omit the AWS BGP ASN if you're not sure what you would like to make it and can happily utilise the standard ASN provided by AWS. + +```bash +aws ec2 create-vpn-gateway --type ipsec.1 +``` + +**N.B the "VpnGatewayId" that is returned, you will need it in the final step** + +#### Build the VPC + +Now that the transform is deployed, you have created a VPN gateway and you have enabled the `vpc.yaml` to use it you are ready to build the VPC. + +```bash +aws cloudformation deploy \ + --capabilities CAPABILITY_IAM \ + --template-file vpc.yaml \ + --stack-name 'VPC' \ + --parameter-overrides VGW=vgw-05811955cb8607072 +``` ## To Do @@ -27,16 +69,6 @@ Adding proper IPv6 regex and handling with NetworkACLs Utilise the yaml structure below as a template, changing the Account ID in the transformation definiton. It will support the removal of Subnets, RouteTables, NATGateways and NetworkACLs. -## Virtual Private Gateway - -Ideally you should never spin up a VPGW in Cloudformation. If you ever plan to attach it to a Direct Connect Virtual Interface you wont be able to tear up & down the VPC without destorying the VIF attachment. Either by hand in the console (shudder) or ideally via the CLI/SDK call with the following - -```yaml -Command: aws ec2 create-vpn-gateway --type ipsec.1 --amazon-side-asn -``` - -You can omit the AWS BGP ASN if you're not sure what you would like to make it and can happily utilise the standard ASN provided by AWS. - ## Network ACL Breakdown ```yaml @@ -51,12 +83,12 @@ Parameters: Mappings: {} Resources: - KABLAMOBUILDVPC: - Type: Kablamo::Network::VPC + ELENDELBUILDVPC: + Type: Elendel::Network::VPC Properties: CIDR: 172.16.0.0/20 Details: {VPCName: PRIVATEEGRESSVPC, VPCDesc: Private Egress VPC, Region: ap-southeast-2, IPv6: True} - Tags: {Name: PRIVATE-EGRESS-VPC, Template: VPC for private endpoints egress only} + Tags: {Name: PRIVATE-EGRESS-VPC, Template: VPC for private endpoints egress only} DHCP: {Name: DhcpOptions, DNSServers: 172.16.0.2, NTPServers: 169.254.169.123, NTBType: 2} Subnets: ReservedMgmt1: {CIDR: 172.16.0.0/26, AZ: 0, NetACL: InternalSubnetAcl, RouteTable: InternalRT1 } @@ -302,7 +334,7 @@ Resources: SecurityGroupIds: - VPCEndpoint NetworkACLs: - RestrictedSubnetAcl: + RestrictedSubnetAcl: RestrictedSubnetAclEntryInTCPUnReserved: "90,6,allow,false,0.0.0.0/0,1024,65535" RestrictedSubnetAclEntryInUDPUnReserved: "91,17,allow,false,0.0.0.0/0,1024,65535" RestrictedSubnetAclEntryInTCPUnReservedIPv6: "92,6,allow,false,::/0,1024,65535" diff --git a/makefile b/makefile index d83c043..acb5e87 100644 --- a/makefile +++ b/makefile @@ -1,10 +1,11 @@ # Makefile for building python lambda PROJECT = vpcbuilder +USER_PROFILE = DevAdmin VERSION = $(shell whoami) DIR = $(shell pwd) GITHASH = $(shell git rev-parse HEAD | cut -c 1-7) -BUCKET_NAME = ap.southeast.2.lambda.functions.elendel.com.au -CONTAINER = python:2.7.14-alpine3.6 +BUCKET_NAME = loopplus-dev-lambdas +CONTAINER = python:2.7.14-alpine3.6 WORKING_DIR = /opt/app buildDeps: @@ -16,6 +17,14 @@ buildPackage: .PHONY: buildPackage uploadToS3: buildPackage - aws s3 cp ./$(PROJECT).zip s3://$(BUCKET_NAME)/$(PROJECT)/$(PROJECT)-$(GITHASH).zip --acl bucket-owner-full-control --profile yourprofile + aws s3 cp ./$(PROJECT).zip s3://$(BUCKET_NAME)/$(PROJECT)/$(PROJECT)-$(GITHASH).zip --acl bucket-owner-full-control --profile $(USER_PROFILE) echo 'File version is $(PROJECT)-$(GITHASH).zip' -.PHONY: uploadToS3 \ No newline at end of file +.PHONY: uploadToS3 + +deployTransform: uploadToS3 + aws --profile $(USER_PROFILE) cloudformation deploy \ + --capabilities CAPABILITY_IAM \ + --template-file transform.yaml \ + --stack-name 'VPC-transform' \ + --parameter-overrides LambdaBucket=$(BUCKET_NAME) LambdaVersion=$(GITHASH) +.PHONY: deployTransform diff --git a/src/lambda.py b/src/lambda.py index ca883fe..0c69cb8 100644 --- a/src/lambda.py +++ b/src/lambda.py @@ -29,7 +29,7 @@ def handler(event, context): outputs = {} response = event["fragment"] for k in list(response["Resources"].keys()): - if response["Resources"][k]["Type"] == "Kablamo::Network::VPC": + if response["Resources"][k]["Type"] == "Elendel::Network::VPC": if "Properties" in response["Resources"][k]: properties = response["Resources"][k]["Properties"] resources[properties["Details"]["VPCName"]] = { diff --git a/tests/transform_call.json b/tests/transform_call.json index f10e95c..f18bf83 100644 --- a/tests/transform_call.json +++ b/tests/transform_call.json @@ -6,8 +6,8 @@ "fragment": { "AWSTemplateFormatVersion": "2010-09-09", "Resources": { - "KABLAMOBUILDVPC": { - "Type": "Kablamo::Network::VPC", + "ELENDELBUILDVPC": { + "Type": "Elendel::Network::VPC", "Properties": { "Subnets": { "ReservedMgmt1": { diff --git a/transform.yaml b/transform.yaml index 5ed790b..bef7393 100644 --- a/transform.yaml +++ b/transform.yaml @@ -1,7 +1,7 @@ AWSTemplateFormatVersion: 2010-09-09 Parameters: - LambdaBucket: {Description: Lambda Bucket Location, Type: String, Default: yourbucket.lambda.functions} - LambdaVersion: {Description: Lambda Bucket Location, Type: String, Default: release-tag} + LambdaBucket: {Description: Lambda Bucket Location, Type: String} + LambdaVersion: {Description: Lambda Bucket Location, Type: String} Resources: VPCTransformExecutionRole: Type: AWS::IAM::Role diff --git a/example.yaml b/vpc.yaml similarity index 98% rename from example.yaml rename to vpc.yaml index 45abea4..50868eb 100644 --- a/example.yaml +++ b/vpc.yaml @@ -1,16 +1,15 @@ AWSTemplateFormatVersion: 2010-09-09 Description: Private VPC Template Parameters: - VGW: {Description: VPC Gateway, Type: String, Default: vgw-012345678} + VGW: {Description: VPC Gateway, Type: String} Mappings: {} Resources: - - KABLAMOBUILDVPC: - Type: Kablamo::Network::VPC + ELENDELBUILDVPC: + Type: Elendel::Network::VPC Properties: CIDR: 172.16.0.0/20 - Details: {VPCName: PRIVATEEGRESSVPC, VPCDesc: Private Egress VPC, Region: ap-southeast-2, IPv6: True} - Tags: {Name: PRIVATE-EGRESS-VPC, Template: VPC for private endpoints egress only} + Details: {VPCName: PRIVATEEGRESSVPC, VPCDesc: Private Egress VPC, Region: ap-southeast-2, IPv6: true} + Tags: {Name: PRIVATE-EGRESS-VPC, Template: VPC for private endpoints egress only} DHCP: {Name: DhcpOptions, DNSServers: 172.16.0.2, NTPServers: 169.254.169.123, NTBType: 2} Subnets: ReservedMgmt1: {CIDR: 172.16.0.0/26, AZ: 0, NetACL: InternalSubnetAcl, RouteTable: InternalRT1 } @@ -256,7 +255,7 @@ Resources: SecurityGroupIds: - VPCEndpoint NetworkACLs: - RestrictedSubnetAcl: + RestrictedSubnetAcl: RestrictedSubnetAclEntryInTCPUnReserved: "90,6,allow,false,0.0.0.0/0,1024,65535" RestrictedSubnetAclEntryInUDPUnReserved: "91,17,allow,false,0.0.0.0/0,1024,65535" RestrictedSubnetAclEntryInTCPUnReservedIPv6: "92,6,allow,false,::/0,1024,65535" @@ -308,4 +307,4 @@ Resources: InternalSubnetAclEntryOutTCPDNSIPv6: "112,6,allow,true,::/0,53,53" InternalSubnetAclEntryOutUDPDNSIPv6: "113,17,allow,true,::/0,53,53" InternalSubnetAclEntryOutSSH: "150,6,allow,true,0.0.0.0/0,22,22" -Transform: "801604450668::VPC" \ No newline at end of file +Transform: "073042351244::VPC" From e367a11aa23ac5d85bf98eaa3363e80914516678 Mon Sep 17 00:00:00 2001 From: eL0ck Date: Wed, 14 Nov 2018 16:09:41 +1100 Subject: [PATCH 3/5] Minor readme changes --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1bcc7e2..e1a86fc 100644 --- a/README.md +++ b/README.md @@ -26,24 +26,24 @@ make deployTransform Open `vpc.yaml` and replace the account number with your own so that the template knows which transform to apply: ```yaml -Transform: "::VPC" +Transform: "::VPC" ``` #### Virtual Private Gateway -Ideally you should never spin up a VPGW in Cloudformation. If you ever plan to attach it to a Direct Connect Virtual Interface you wont be able to tear up & down the VPC without destorying the VIF attachment. Either by hand in the console (shudder) or ideally via the CLI/SDK call with the following +Ideally you should never spin up a VPGW in Cloudformation. If you ever plan to attach it to a Direct Connect Virtual Interface you wont be able to tear up & down the VPC without destroying the VIF attachment. Either by hand in the console (shudder) or ideally via the CLI/SDK call with the following ```bash aws ec2 create-vpn-gateway --type ipsec.1 --amazon-side-asn ``` -You can omit the AWS BGP ASN if you're not sure what you would like to make it and can happily utilise the standard ASN provided by AWS. +You can omit the AWS BOP ASN if you're not sure what you would like to make it and can happily utilise the standard ASN provided by AWS. ```bash aws ec2 create-vpn-gateway --type ipsec.1 ``` -**N.B the "VpnGatewayId" that is returned, you will need it in the final step** +**Make a note of the "VpnGatewayId" that is returned, you will need it in the final step** #### Build the VPC @@ -54,7 +54,7 @@ aws cloudformation deploy \ --capabilities CAPABILITY_IAM \ --template-file vpc.yaml \ --stack-name 'VPC' \ - --parameter-overrides VGW=vgw-05811955cb8607072 + --parameter-overrides VGW=vgw-05811955cb8607072 # Replace with your VpnGatewayId ``` ## To Do @@ -66,7 +66,7 @@ Adding proper IPv6 regex and handling with NetworkACLs ## Basic Usage -Utilise the yaml structure below as a template, changing the Account ID in the transformation definiton. +Utilise the yaml structure below as a template, changing the Account ID in the transformation definition. It will support the removal of Subnets, RouteTables, NATGateways and NetworkACLs. ## Network ACL Breakdown From 652a5e0a56b0e960590b38b6724e93c3e4e45627 Mon Sep 17 00:00:00 2001 From: eL0ck Date: Mon, 19 Nov 2018 15:13:37 +1000 Subject: [PATCH 4/5] Account number is implied --- vpc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpc.yaml b/vpc.yaml index 50868eb..3040949 100644 --- a/vpc.yaml +++ b/vpc.yaml @@ -307,4 +307,4 @@ Resources: InternalSubnetAclEntryOutTCPDNSIPv6: "112,6,allow,true,::/0,53,53" InternalSubnetAclEntryOutUDPDNSIPv6: "113,17,allow,true,::/0,53,53" InternalSubnetAclEntryOutSSH: "150,6,allow,true,0.0.0.0/0,22,22" -Transform: "073042351244::VPC" +Transform: "VPC" From 162d6457da6cc71140580773928a540f528d388c Mon Sep 17 00:00:00 2001 From: eL0ck Date: Mon, 19 Nov 2018 15:14:12 +1000 Subject: [PATCH 5/5] Use 4 space indent accross all feilds --- vpc.yaml | 202 +++++++++++++++++++++++++++---------------------------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/vpc.yaml b/vpc.yaml index 3040949..e057dad 100644 --- a/vpc.yaml +++ b/vpc.yaml @@ -26,12 +26,12 @@ Resources: PerimeterInternal3: {CIDR: 172.16.8.0/24, AZ: 2, NetACL: InternalSubnetAcl, RouteTable: InternalRT3 } RouteTables: PublicRT: - - RouteName: PublicRoute - RouteCIDR: 0.0.0.0/0 - RouteGW: InternetGateway - - RouteName: PublicRouteIPv6 - RouteCIDR: ::/0 - RouteGW: InternetGateway + - RouteName: PublicRoute + RouteCIDR: 0.0.0.0/0 + RouteGW: InternetGateway + - RouteName: PublicRouteIPv6 + RouteCIDR: ::/0 + RouteGW: InternetGateway InternalRT1: InternalRT2: InternalRT3: @@ -46,55 +46,55 @@ Resources: VPCEndpoint: GroupDescription: VPC Endpoint Interface Firewall Rules SecurityGroupIngress: - - [icmp,-1,-1,172.16.0.0/20, All ICMP Traffic] - - [tcp,0,65535,172.16.0.0/20, All TCP Traffic] - - [udp,0,65535,172.16.0.0/20, All UDP Traffic] + - [icmp, -1, -1, 172.16.0.0/20, All ICMP Traffic] + - [tcp, 0, 65535, 172.16.0.0/20, All TCP Traffic] + - [udp, 0, 65535, 172.16.0.0/20, All UDP Traffic] SecurityGroupEgress: - - [icmp,-1,-1,172.16.0.0/20, All ICMP Traffic] - - [tcp,0,65535,172.16.0.0/20, All TCP Traffic] - - [udp,0,65535,172.16.0.0/20, All UDP Traffic] + - [icmp, -1, -1, 172.16.0.0/20, All ICMP Traffic] + - [tcp, 0, 65535, 172.16.0.0/20, All TCP Traffic] + - [udp, 0, 65535, 172.16.0.0/20, All UDP Traffic] Tags: - Name: VPCEndpoint + Name: VPCEndpoint Endpoints: cloudformation: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint cloudtrail: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint codebuild: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint config: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint dynamodb: Type: Gateway RouteTableIds: - - PublicRT - - InternalRT1 - - InternalRT2 - - InternalRT3 + - PublicRT + - InternalRT1 + - InternalRT2 + - InternalRT3 PolicyDocument: | { "Version":"2012-10-17", @@ -110,98 +110,98 @@ Resources: ec2: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint ec2messages: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint elasticloadbalancing: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint events: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint execute-api: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint kinesis-streams: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint kms: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint logs: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint monitoring: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint sagemaker.api: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint sagemaker.runtime: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint s3: Type: Gateway RouteTableIds: - - PublicRT - - InternalRT1 - - InternalRT2 - - InternalRT3 + - PublicRT + - InternalRT1 + - InternalRT2 + - InternalRT3 PolicyDocument: | { "Version":"2012-10-17", @@ -217,43 +217,43 @@ Resources: secretsmanager: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint servicecatalog: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint sns: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint ssm: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint ssmmessages: Type: Interface SubnetIds: - - ReservedMgmt1 - - ReservedMgmt2 - - ReservedMgmt3 + - ReservedMgmt1 + - ReservedMgmt2 + - ReservedMgmt3 SecurityGroupIds: - - VPCEndpoint + - VPCEndpoint NetworkACLs: RestrictedSubnetAcl: RestrictedSubnetAclEntryInTCPUnReserved: "90,6,allow,false,0.0.0.0/0,1024,65535"