--- AWSTemplateFormatVersion: '2010-09-09' Description: "VPC w/2 public, 2 private, and independent routing tables for each subnet" Parameters: VPCCIDRBlock: AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Type: String VPCName: Type: String # Depends on unfiedlogging-single # VPCFlowLogDestination: # Description: S3 bucket arn for the VPC Flow logs # Type: String fckNatAmi: Type: String Default: ami-0d241d0ba6ea2f8f4 ## general subnets SubnetAZs: Description: Specify comma delimited list of AZs for public/private subnets 1-2 Type: CommaDelimitedList Default: "us-east-1a,us-east-1b" ## private subnets PrivateSubnet1CIDRBlock: AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Description: CIDRBlock for Private Subnet 1 Type: String PrivateSubnet1Name: Description: Name of Subnet Type: String PrivateSubnet2CIDRBlock: AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Description: CIDRBlock for Private Subnet 2 Type: String PrivateSubnet2Name: Description: Name of Subnet Type: String ## public subnets PublicSubnet1CIDRBlock: AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Description: CIDRBlock for Public Subnet 1 Type: String PublicSubnet1Name: Description: Name of Subnet Type: String PublicSubnet2CIDRBlock: AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28 Description: CIDRBlock for Public Subnet 2 Type: String PublicSubnet2Name: Description: Name of Subnet Type: String ## routetables Private1RouteTableName: Description: Name for route table Type: String Private2RouteTableName: Description: Name for route table Type: String Public1RouteTableName: Description: Name for route table Type: String Public2RouteTableName: Description: Name for route table Type: String Resources: ## VPC Start ## aVPC: Type: "AWS::EC2::VPC" Properties: CidrBlock: !Ref VPCCIDRBlock EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Ref VPCName # Depends on unfiedlogging-single # VPCFlowLog: # Type: AWS::EC2::FlowLog # Properties: # LogDestinationType: s3 # LogDestination: !Ref VPCFlowLogDestination # ResourceId: !Ref aVPC # ResourceType: VPC # TrafficType: ALL IGW: Type: "AWS::EC2::InternetGateway" IGWAttach: Type: "AWS::EC2::VPCGatewayAttachment" Properties: VpcId: !Ref aVPC InternetGatewayId: !Ref IGW # NatGatewayEIP: # Type: "AWS::EC2::EIP" # Properties: # Domain: vpc # NatGatewayEIP2: # Type: "AWS::EC2::EIP" # Properties: # Domain: vpc ## VPC Finsih ## ## Private Subnets Start ## PrivateSubnet1: Type: "AWS::EC2::Subnet" Properties: CidrBlock: !Ref PrivateSubnet1CIDRBlock VpcId: !Ref aVPC AvailabilityZone: !Select [ 0, !Ref SubnetAZs ] MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Ref PrivateSubnet1Name PrivateSubnet2: Type: "AWS::EC2::Subnet" Properties: CidrBlock: !Ref PrivateSubnet2CIDRBlock VpcId: !Ref aVPC AvailabilityZone: !Select [ 1, !Ref SubnetAZs ] MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Ref PrivateSubnet2Name ## Private Subnets Finish ## ## Public Subnets Start PublicSubnet1: Type: "AWS::EC2::Subnet" Properties: CidrBlock: !Ref PublicSubnet1CIDRBlock VpcId: !Ref aVPC AvailabilityZone: !Select [ 0, !Ref SubnetAZs ] MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Ref PublicSubnet1Name PublicSubnet2: Type: "AWS::EC2::Subnet" Properties: CidrBlock: !Ref PublicSubnet2CIDRBlock VpcId: !Ref aVPC AvailabilityZone: !Select [ 1, !Ref SubnetAZs ] MapPublicIpOnLaunch: false Tags: - Key: Name Value: !Ref PublicSubnet2Name ## Public Subnets End ## NAT Gateway Start ## FckNatInterface: Type: AWS::EC2::NetworkInterface Properties: SubnetId: !Sub "${PublicSubnet1}" GroupSet: - Fn::GetAtt: - NatSecurityGroup - GroupId SourceDestCheck: false FckNatAsgInstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref NatRole FckNatLaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: FckNatLaunchTemplate LaunchTemplateData: ImageId: !Ref fckNatAmi InstanceType: t4g.nano IamInstanceProfile: Arn: !GetAtt FckNatAsgInstanceProfile.Arn SecurityGroupIds: - !GetAtt NatSecurityGroup.GroupId UserData: Fn::Base64: Fn::Join: - "" - - |- #!/bin/bash echo "eni_id= - Ref: FckNatInterface - |- " >> /etc/fck-nat.conf service fck-nat restart DependsOn: - NatRole FckNatAsg: Type: AWS::AutoScaling::AutoScalingGroup Properties: MaxSize: "1" MinSize: "1" DesiredCapacity: "1" LaunchTemplate: LaunchTemplateId: !Ref FckNatLaunchTemplate Version: !GetAtt FckNatLaunchTemplate.LatestVersionNumber VPCZoneIdentifier: - !Sub "${PublicSubnet1}" UpdatePolicy: AutoScalingScheduledAction: IgnoreUnmodifiedGroupSizeProperties: true NatSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security Group for NAT SecurityGroupIngress: - CidrIp: !Sub "${VPCCIDRBlock}" IpProtocol: "-1" SecurityGroupEgress: - CidrIp: 0.0.0.0/0 Description: Allow all outbound traffic by default IpProtocol: "-1" VpcId: !Sub "${aVPC}" NatRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: ec2.amazonaws.com Version: "2012-10-17" Policies: - PolicyDocument: Statement: - Action: - ec2:AttachNetworkInterface - ec2:ModifyNetworkInterfaceAttribute Effect: Allow Resource: "*" Version: "2012-10-17" PolicyName: attachNatEniPolicy - PolicyDocument: Statement: - Action: - ec2:AssociateAddress - ec2:DisassociateAddress Effect: Allow Resource: "*" Version: "2012-10-17" PolicyName: associateNatAddressPolicy ## NAT Gateway End ## ## RouteTables start Private1RT: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref aVPC Tags: - Key: Name Value: !Ref Private1RouteTableName Priv1RTAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: RouteTableId: !Ref Private1RT SubnetId: !Ref PrivateSubnet1 Priv1Route: Type: "AWS::EC2::Route" Properties: DestinationCidrBlock: "0.0.0.0/0" NetworkInterfaceId: !Ref FckNatInterface RouteTableId: !Ref Private1RT # Private2RT: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref aVPC Tags: - Key: Name Value: !Ref Private2RouteTableName Priv2RTAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: RouteTableId: !Ref Private2RT SubnetId: !Ref PrivateSubnet2 Priv2Route: Type: "AWS::EC2::Route" Properties: DestinationCidrBlock: "0.0.0.0/0" NetworkInterfaceId: !Ref FckNatInterface RouteTableId: !Ref Private2RT # Public1RT: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref aVPC Tags: - Key: Name Value: !Ref Public1RouteTableName Pub1RTAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: RouteTableId: !Ref Public1RT SubnetId: !Ref PublicSubnet1 Pub1Route: Type: "AWS::EC2::Route" Properties: DestinationCidrBlock: "0.0.0.0/0" GatewayId: !Ref IGW RouteTableId: !Ref Public1RT # Public2RT: Type: "AWS::EC2::RouteTable" Properties: VpcId: !Ref aVPC Tags: - Key: Name Value: !Ref Public2RouteTableName Pub2RTAssociation: Type: "AWS::EC2::SubnetRouteTableAssociation" Properties: RouteTableId: !Ref Public2RT SubnetId: !Ref PublicSubnet2 Pub2Route: Type: "AWS::EC2::Route" Properties: DestinationCidrBlock: "0.0.0.0/0" GatewayId: !Ref IGW RouteTableId: !Ref Public2RT ## RouteTables end #Default SecurityGroup VpcSg: Type: AWS::EC2::SecurityGroup Properties: VpcId: !Ref aVPC GroupDescription: provides access to all resources within this Sg Tags: - Key: Name Value: VpcSg VpcSgIngress: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref VpcSg IpProtocol: "-1" SourceSecurityGroupId: !Ref VpcSg ###################### ### VPC ENDPOINTS ### https://aws.amazon.com/blogs/architecture/reduce-cost-and-increase-security-with-amazon-vpc-endpoints/ ############ VpcEndpointSg: Type: "AWS::EC2::SecurityGroup" Properties: GroupName: VPCEndpoints GroupDescription: DefaultVpcEndpointSg VpcId: !Ref aVPC SecurityGroupIngress: - IpProtocol: "-1" CidrIp: !Ref VPCCIDRBlock SecurityGroupEgress: - IpProtocol: "-1" CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: Default VPC Endpoint Sg S3VpcEndpoint: Type: AWS::EC2::VPCEndpoint Properties: PolicyDocument: Version: 2012-10-17 Statement: - Principal: '*' Effect: 'Allow' Action: 's3:*' Resource: - 'arn:aws:s3:::*' - 'arn:aws:s3:::*/*' VpcEndpointType: Gateway VpcId: !Ref aVPC ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3' RouteTableIds: - !Ref Public1RT - !Ref Public2RT - !Ref Private1RT - !Ref Private2RT Outputs: ## VPC Outputs # NatGatewayEIP: # Description: IP of the NAT Gateway # Value: !Ref NatGatewayEIP # Export: # Name: !Sub "${AWS::StackName}-NatGatewayEIP" VPCId: Description: VPC Id Value: !Ref aVPC Export: Name: !Sub "${AWS::StackName}-VPCId" VPCCIDR: Description: CIDR Block of the VPC Value: !Ref VPCCIDRBlock Export: Name: !Sub "${AWS::StackName}-VPCCIDRBlock" IGWId: Value: !Ref IGW Export: Name: !Sub "${AWS::StackName}-IGWId" StackName: Value: !Ref AWS::StackName ## private subnets PrivateSubnet1Id: Description: Private Subnet 1 ID Value: !Ref PrivateSubnet1 Export: Name: !Sub "${AWS::StackName}-PrivateSubnet1Id" PrivateSubnet1CIDRBlock: Description: Private Subnet 1 CIDR block Value: !Ref PrivateSubnet1CIDRBlock Export: Name: !Sub "${AWS::StackName}-PrivateSubnet1CIDRBlock" PrivateSubnet2Id: Description: Private Subnet2 ID Value: !Ref PrivateSubnet2 Export: Name: !Sub "${AWS::StackName}-PrivateSubnet2Id" PrivateSubnet2CIDRBlock: Description: Private Subnet 2 CIDR block Value: !Ref PrivateSubnet2CIDRBlock Export: Name: !Sub "${AWS::StackName}-PrivateSubnet2CIDRBlock" ## public subnets PublicSubnet1Id: Description: Public Subnet 1 ID Value: !Ref PublicSubnet1 Export: Name: !Sub "${AWS::StackName}-PublicSubnet1Id" PublicSubnet1CIDRBlock: Description: Public Subnet 1 CIDR block Value: !Ref PublicSubnet1CIDRBlock Export: Name: !Sub "${AWS::StackName}-PublicSubnet1CIDRBlock" PublicSubnet2Id: Description: Public Subnet2 ID Value: !Ref PublicSubnet2 Export: Name: !Sub "${AWS::StackName}-PublicSubnet2Id" PublicSubnet2CIDRBlock: Description: Public Subnet 2 CIDR block Value: !Ref PublicSubnet2CIDRBlock Export: Name: !Sub "${AWS::StackName}-PublicSubnet2CIDRBlock" DefaultSgName: Description: Default Security Group Value: !Ref VpcSg Export: Name: !Sub "${AWS::StackName}-DefaultSgName" DefaultSgId: Description: Default Security Group Value: !GetAtt VpcSg.GroupId Export: Name: !Sub "${AWS::StackName}-DefaultSgId" Private1RTId: Description: Route Table Private 1 Value: !Ref Private1RT Export: Name: !Sub "${AWS::StackName}-Private1RT" Private2RTId: Description: Route Table Private 2 Value: !Ref Private2RT Export: Name: !Sub "${AWS::StackName}-Private2RT" Public1RTId: Description: Route Table Public 1 Value: !Ref Public1RT Export: Name: !Sub "${AWS::StackName}-Public1RT" Public2RTId: Description: Route Table Public 2 Value: !Ref Public2RT Export: Name: !Sub "${AWS::StackName}-Public2RT"