{
    "Description": "This template deploys a VPC, with a pair of public and private subnets spread across two Availability Zones. It deploys an internet gateway, with a default route on the public subnets. It deploys a pair of NAT gateways (one in each AZ), and default routes for them in the private subnets.",
    "Parameters": {
        "SSHKeyName": {
            "Description": "Name of the ec2 key you need one to use this template",
            "Type": "AWS::EC2::KeyPair::KeyName",
            "Default": "choose-key"
        },
        "EnvironmentName": {
            "Description": "An environment name that is prefixed to resource names",
            "Type": "String",
            "Default": "Ansible"
        },
        "VpcCIDR": {
            "Description": "Please enter the IP range (CIDR notation) for this VPC",
            "Type": "String",
            "Default": "10.192.0.0/16"
        },
        "PublicSubnet1CIDR": {
            "Description": "Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone",
            "Type": "String",
            "Default": "10.192.10.0/24"
        },
        "PublicSubnet2CIDR": {
            "Description": "Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone",
            "Type": "String",
            "Default": "10.192.11.0/24"
        },
        "PrivateSubnet1CIDR": {
            "Description": "Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone",
            "Type": "String",
            "Default": "10.192.20.0/24"
        },
        "PrivateSubnet2CIDR": {
            "Description": "Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone",
            "Type": "String",
            "Default": "10.192.21.0/24"
        }
    },
    "Mappings": {
        "RegionToAmazonAMI": {
            "us-east-1": {
                "HVM64": "ami-03e33c1cefd1d3d74"
            },
            "us-east-2": {
                "HVM64": "ami-07d9419c80dc1113c"
            },
            "us-west-1": {
                "HVM64": "ami-0ee1a20d6b0c6a347"
            },
            "us-west-2": {
                "HVM64": "ami-0813245c0939ab3ca"
            }
        }
    },
    "Resources": {
        "VPC": {
            "Type": "AWS::EC2::VPC",
            "Properties": {
                "CidrBlock": {
                    "Ref": "VpcCIDR"
                },
                "EnableDnsSupport": true,
                "EnableDnsHostnames": true,
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Ref": "EnvironmentName"
                        }
                    }
                ]
            }
        },
        "InternetGateway": {
            "Type": "AWS::EC2::InternetGateway",
            "Properties": {
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Ref": "EnvironmentName"
                        }
                    }
                ]
            }
        },
        "InternetGatewayAttachment": {
            "Type": "AWS::EC2::VPCGatewayAttachment",
            "Properties": {
                "InternetGatewayId": {
                    "Ref": "InternetGateway"
                },
                "VpcId": {
                    "Ref": "VPC"
                }
            }
        },
        "PublicSubnet1": {
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "VpcId": {
                    "Ref": "VPC"
                },
                "AvailabilityZone": {
                    "Fn::Select": [
                        0,
                        {
                            "Fn::GetAZs": ""
                        }
                    ]
                },
                "CidrBlock": {
                    "Ref": "PublicSubnet1CIDR"
                },
                "MapPublicIpOnLaunch": true,
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Sub": "${EnvironmentName} Public Subnet (AZ1)"
                        }
                    }
                ]
            }
        },
        "PublicSubnet2": {
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "VpcId": {
                    "Ref": "VPC"
                },
                "AvailabilityZone": {
                    "Fn::Select": [
                        1,
                        {
                            "Fn::GetAZs": ""
                        }
                    ]
                },
                "CidrBlock": {
                    "Ref": "PublicSubnet2CIDR"
                },
                "MapPublicIpOnLaunch": true,
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Sub": "${EnvironmentName} Public Subnet (AZ2)"
                        }
                    }
                ]
            }
        },
        "PrivateSubnet1": {
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "VpcId": {
                    "Ref": "VPC"
                },
                "AvailabilityZone": {
                    "Fn::Select": [
                        0,
                        {
                            "Fn::GetAZs": ""
                        }
                    ]
                },
                "CidrBlock": {
                    "Ref": "PrivateSubnet1CIDR"
                },
                "MapPublicIpOnLaunch": false,
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Sub": "${EnvironmentName} Private Subnet (AZ1)"
                        }
                    }
                ]
            }
        },
        "PrivateSubnet2": {
            "Type": "AWS::EC2::Subnet",
            "Properties": {
                "VpcId": {
                    "Ref": "VPC"
                },
                "AvailabilityZone": {
                    "Fn::Select": [
                        1,
                        {
                            "Fn::GetAZs": ""
                        }
                    ]
                },
                "CidrBlock": {
                    "Ref": "PrivateSubnet2CIDR"
                },
                "MapPublicIpOnLaunch": false,
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Sub": "${EnvironmentName} Private Subnet (AZ2)"
                        }
                    }
                ]
            }
        },
        "NatGateway1EIP": {
            "Type": "AWS::EC2::EIP",
            "DependsOn": "InternetGatewayAttachment",
            "Properties": {
                "Domain": "vpc"
            }
        },
        "NatGateway2EIP": {
            "Type": "AWS::EC2::EIP",
            "DependsOn": "InternetGatewayAttachment",
            "Properties": {
                "Domain": "vpc"
            }
        },
        "NatGateway1": {
            "Type": "AWS::EC2::NatGateway",
            "Properties": {
                "AllocationId": {
                    "Fn::GetAtt": [
                        "NatGateway1EIP",
                        "AllocationId"
                    ]
                },
                "SubnetId": {
                    "Ref": "PublicSubnet1"
                }
            }
        },
        "NatGateway2": {
            "Type": "AWS::EC2::NatGateway",
            "Properties": {
                "AllocationId": {
                    "Fn::GetAtt": [
                        "NatGateway2EIP",
                        "AllocationId"
                    ]
                },
                "SubnetId": {
                    "Ref": "PublicSubnet2"
                }
            }
        },
        "PublicRouteTable": {
            "Type": "AWS::EC2::RouteTable",
            "Properties": {
                "VpcId": {
                    "Ref": "VPC"
                },
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Sub": "${EnvironmentName} Public Routes"
                        }
                    }
                ]
            }
        },
        "DefaultPublicRoute": {
            "Type": "AWS::EC2::Route",
            "DependsOn": "InternetGatewayAttachment",
            "Properties": {
                "RouteTableId": {
                    "Ref": "PublicRouteTable"
                },
                "DestinationCidrBlock": "0.0.0.0/0",
                "GatewayId": {
                    "Ref": "InternetGateway"
                }
            }
        },
        "PublicSubnet1RouteTableAssociation": {
            "Type": "AWS::EC2::SubnetRouteTableAssociation",
            "Properties": {
                "RouteTableId": {
                    "Ref": "PublicRouteTable"
                },
                "SubnetId": {
                    "Ref": "PublicSubnet1"
                }
            }
        },
        "PublicSubnet2RouteTableAssociation": {
            "Type": "AWS::EC2::SubnetRouteTableAssociation",
            "Properties": {
                "RouteTableId": {
                    "Ref": "PublicRouteTable"
                },
                "SubnetId": {
                    "Ref": "PublicSubnet2"
                }
            }
        },
        "PrivateRouteTable1": {
            "Type": "AWS::EC2::RouteTable",
            "Properties": {
                "VpcId": {
                    "Ref": "VPC"
                },
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Sub": "${EnvironmentName} Private Routes (AZ1)"
                        }
                    }
                ]
            }
        },
        "DefaultPrivateRoute1": {
            "Type": "AWS::EC2::Route",
            "Properties": {
                "RouteTableId": {
                    "Ref": "PrivateRouteTable1"
                },
                "DestinationCidrBlock": "0.0.0.0/0",
                "NatGatewayId": {
                    "Ref": "NatGateway1"
                }
            }
        },
        "PrivateSubnet1RouteTableAssociation": {
            "Type": "AWS::EC2::SubnetRouteTableAssociation",
            "Properties": {
                "RouteTableId": {
                    "Ref": "PrivateRouteTable1"
                },
                "SubnetId": {
                    "Ref": "PrivateSubnet1"
                }
            }
        },
        "PrivateRouteTable2": {
            "Type": "AWS::EC2::RouteTable",
            "Properties": {
                "VpcId": {
                    "Ref": "VPC"
                },
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Sub": "${EnvironmentName} Private Routes (AZ2)"
                        }
                    }
                ]
            }
        },
        "DefaultPrivateRoute2": {
            "Type": "AWS::EC2::Route",
            "Properties": {
                "RouteTableId": {
                    "Ref": "PrivateRouteTable2"
                },
                "DestinationCidrBlock": "0.0.0.0/0",
                "NatGatewayId": {
                    "Ref": "NatGateway2"
                }
            }
        },
        "PrivateSubnet2RouteTableAssociation": {
            "Type": "AWS::EC2::SubnetRouteTableAssociation",
            "Properties": {
                "RouteTableId": {
                    "Ref": "PrivateRouteTable2"
                },
                "SubnetId": {
                    "Ref": "PrivateSubnet2"
                }
            }
        },
        "EC2SecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "SSH, Port 80, Database",
                "VpcId": {
                    "Ref": "VPC"
                },
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 22,
                        "ToPort": 22,
                        "CidrIp": "0.0.0.0/0"
                    },
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 5432,
                        "ToPort": 5432,
                        "CidrIp": "0.0.0.0/0"
                    },
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 8082,
                        "ToPort": 8082,
                        "CidrIp": "0.0.0.0/0"
                    },
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 80,
                        "ToPort": 80,
                        "SourceSecurityGroupId": {
                            "Ref": "ELBSecurityGroup"
                        }
                    }
                ]
            }
        },
        "ELBSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "SSH and Port 80",
                "VpcId": {
                    "Ref": "VPC"
                },
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 80,
                        "ToPort": 80,
                        "CidrIp": "0.0.0.0/0"
                    }
                ]
            }
        },
        "BastionInstance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {
                    "Fn::FindInMap": [
                        "RegionToAmazonAMI",
                        {
                            "Ref": "AWS::Region"
                        },
                        "HVM64"
                    ]
                },
                "InstanceInitiatedShutdownBehavior": "stop",
                "InstanceType": "t2.medium",
                "KeyName": {
                    "Ref": "SSHKeyName"
                },
                "Monitoring": "true",
                "NetworkInterfaces": [
                    {
                        "AssociatePublicIpAddress": "true",
                        "DeviceIndex": "0",
                        "GroupSet": [
                            {
                                "Ref": "EC2SecurityGroup"
                            }
                        ],
                        "SubnetId": {
                            "Ref": "PublicSubnet1"
                        }
                    }
                ],
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": "bastion"
                    }
                ],
                "Tenancy": "default"
            }
        },
        "RTPriInstance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {
                    "Fn::FindInMap": [
                        "RegionToAmazonAMI",
                        {
                            "Ref": "AWS::Region"
                        },
                        "HVM64"
                    ]
                },
                "InstanceInitiatedShutdownBehavior": "stop",
                "InstanceType": "t2.medium",
                "KeyName": {
                    "Ref": "SSHKeyName"
                },
                "Monitoring": "true",
                "NetworkInterfaces": [
                    {
                        "AssociatePublicIpAddress": "false",
                        "DeviceIndex": "0",
                        "GroupSet": [
                            {
                                "Ref": "EC2SecurityGroup"
                            }
                        ],
                        "SubnetId": {
                            "Ref": "PrivateSubnet1"
                        }
                    }
                ],
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": "rtprimary"
                    }
                ],
                "Tenancy": "default"
            }
        },
        "RTSecInstance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {
                    "Fn::FindInMap": [
                        "RegionToAmazonAMI",
                        {
                            "Ref": "AWS::Region"
                        },
                        "HVM64"
                    ]
                },
                "InstanceInitiatedShutdownBehavior": "stop",
                "InstanceType": "t2.medium",
                "KeyName": {
                    "Ref": "SSHKeyName"
                },
                "Monitoring": "true",
                "NetworkInterfaces": [
                    {
                        "AssociatePublicIpAddress": "false",
                        "DeviceIndex": "0",
                        "GroupSet": [
                            {
                                "Ref": "EC2SecurityGroup"
                            }
                        ],
                        "SubnetId": {
                            "Ref": "PrivateSubnet2"
                        }
                    }
                ],
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": "rtsecondary"
                    }
                ],
                "Tenancy": "default"
            }
        },
        "XrayInstance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {
                    "Fn::FindInMap": [
                        "RegionToAmazonAMI",
                        {
                            "Ref": "AWS::Region"
                        },
                        "HVM64"
                    ]
                },
                "InstanceInitiatedShutdownBehavior": "stop",
                "InstanceType": "t2.medium",
                "KeyName": {
                    "Ref": "SSHKeyName"
                },
                "Monitoring": "true",
                "NetworkInterfaces": [
                    {
                        "AssociatePublicIpAddress": "false",
                        "DeviceIndex": "0",
                        "GroupSet": [
                            {
                                "Ref": "EC2SecurityGroup"
                            }
                        ],
                        "SubnetId": {
                            "Ref": "PrivateSubnet1"
                        }
                    }
                ],
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": "xray"
                    }
                ],
                "Tenancy": "default"
            }
        },
        "DBInstance": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": {
                    "Fn::FindInMap": [
                        "RegionToAmazonAMI",
                        {
                            "Ref": "AWS::Region"
                        },
                        "HVM64"
                    ]
                },
                "InstanceInitiatedShutdownBehavior": "stop",
                "InstanceType": "t2.medium",
                "KeyName": {
                    "Ref": "SSHKeyName"
                },
                "Monitoring": "true",
                "NetworkInterfaces": [
                    {
                        "AssociatePublicIpAddress": "false",
                        "DeviceIndex": "0",
                        "GroupSet": [
                            {
                                "Ref": "EC2SecurityGroup"
                            }
                        ],
                        "SubnetId": {
                            "Ref": "PrivateSubnet1"
                        }
                    }
                ],
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": "database"
                    }
                ],
                "Tenancy": "default"
            }
        },
        "EC2TargetGroup": {
            "Type": "AWS::ElasticLoadBalancingV2::TargetGroup",
            "Properties": {
                "HealthCheckIntervalSeconds": 30,
                "HealthCheckProtocol": "HTTP",
                "HealthCheckTimeoutSeconds": 15,
                "HealthyThresholdCount": 2,
                "Matcher": {
                    "HttpCode": "200,302"
                },
                "Name": "EC2TargetGroup",
                "Port": 80,
                "Protocol": "HTTP",
                "TargetGroupAttributes": [
                    {
                        "Key": "deregistration_delay.timeout_seconds",
                        "Value": "20"
                    }
                ],
                "Targets": [
                    {
                        "Id": {
                            "Ref": "RTPriInstance"
                        }
                    },
                    {
                        "Id": {
                            "Ref": "RTSecInstance"
                        },
                        "Port": 80
                    }
                ],
                "UnhealthyThresholdCount": 3,
                "VpcId": {
                    "Ref": "VPC"
                },
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": "EC2TargetGroup"
                    },
                    {
                        "Key": "Port",
                        "Value": 80
                    }
                ]
            }
        },
        "ALBListener": {
            "Type": "AWS::ElasticLoadBalancingV2::Listener",
            "Properties": {
                "DefaultActions": [
                    {
                        "Type": "forward",
                        "TargetGroupArn": {
                            "Ref": "EC2TargetGroup"
                        }
                    }
                ],
                "LoadBalancerArn": {
                    "Ref": "ApplicationLoadBalancer"
                },
                "Port": 80,
                "Protocol": "HTTP"
            }
        },
        "ApplicationLoadBalancer": {
            "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
            "Properties": {
                "Scheme": "internet-facing",
                "Subnets": [
                    {
                        "Ref": "PublicSubnet1"
                    },
                    {
                        "Ref": "PublicSubnet2"
                    }
                ],
                "SecurityGroups": [
                    {
                        "Ref": "ELBSecurityGroup"
                    }
                ]
            }
        }
    },

    "Outputs": {
        "VPC": {
            "Description": "Virtual Private Cloud",
            "Value": {
                "Ref": "VPC"
            }
        },
        "ALBHostName": {
            "Description": "Application Load Balancer Hostname",
            "Value": {
                "Fn::GetAtt": [
                    "ApplicationLoadBalancer",
                    "DNSName"
                ]
            }
        },
        "BastionInstancePublic": {
            "Description": "Bastion",
            "Value": { "Fn::GetAtt" : [ "BastionInstance", "PublicIp" ]}
        },
        "BastionInstancePrivate": {
            "Description": "Bastion",
            "Value": { "Fn::GetAtt" : [ "BastionInstance", "PrivateIp" ]}
        },
        "RTPriInstancePrivate": {
            "Description": "RTPriInstance",
            "Value": { "Fn::GetAtt" : [ "RTPriInstance", "PrivateIp" ]}
        },
        "RTSecInstancePrivate": {
            "Description": "RTSecInstance",
            "Value": { "Fn::GetAtt" : [ "RTSecInstance", "PrivateIp" ]}
        },
        "XrayInstancePrivate": {
            "Description": "XrayInstance",
            "Value": { "Fn::GetAtt" : [ "XrayInstance", "PrivateIp" ]}
        },
        "DBInstancePrivate": {
            "Description": "DBInstance",
            "Value": { "Fn::GetAtt" : [ "DBInstance", "PrivateIp" ]}
        }
    }
}