{
  "AWSTemplateFormatVersion" : "2010-09-09",

  "Metadata" : {
    "LICENSE" : "MIT-0"
  },

  "Description" : "Builds a VPC w/ 2 public subnets, 2 private subnets, an IGW, route tables, ACL, etc.",

  "Parameters" : {

    "Environment": {
      "Type" : "String",
      "Default" : "Demo",
      "AllowedValues" : ["Demo", "Dev", "Mgmt", "Prod"],
      "Description" : "Environment to identify resources with."
    }

  },

  "Mappings" : {
    "VPCIpSpace" : {
      "us-east-1" : {"RANGE" : "10.42"},
      "us-east-2" : {"RANGE" : "10.43"},
      "us-west-1" : {"RANGE" : "10.44"},
      "us-west-2" : {"RANGE" : "10.45"},
      "ap-south-1" : {"RANGE" : "10.46"},
      "ap-northeast-1" : {"RANGE" : "10.47"},
      "ap-northeast-2" : {"RANGE" : "10.48"},
      "ap-southeast-1" : {"RANGE" : "10.49"},
      "ap-southeast-2" : {"RANGE" : "10.50"}
    },

    "SubnetTypeIpRanges" : {
      "public" : {"RANGE" : "0.0/17"},
      "private" : {"RANGE" : "128.0/17"}
    },

    "publicSubnetConfig" : {
      "publicSubnet01" : { "CIDR" : "10.0/24" },
      "publicSubnet02" : { "CIDR" : "11.0/24" }
    },

    "privateSubnetConfig" : {
      "privateSubnet01" : { "CIDR" : "224.0/24" },
      "privateSubnet02" : { "CIDR" : "225.0/24" }
    }
  },

  "Resources" : {
    "MyVPC" : {
      "Type" : "AWS::EC2::VPC",
      "Properties" : {
        "CidrBlock" : { "Fn::Join": [ "", [{ "Fn::FindInMap" : [ "VPCIpSpace", {"Ref": "AWS::Region"}, "RANGE" ]}, ".", "0.0/16"]]},
        "EnableDnsSupport" : "true",
        "EnableDnsHostnames" : "true",
        "Tags" : [
          {"Key" : "Environment", "Value" : {"Ref" : "Environment"} },
          {"Key" : "Name", "Value" : { "Fn::Join": [ "", [{"Ref" : "Environment"}, "-VPC" ]]}}
        ]
      }
    },

    "publicSubnet01" : {
      "Type" : "AWS::EC2::Subnet",
      "Properties" : {
        "VpcId" : { "Ref" : "MyVPC" },
        "CidrBlock" : { "Fn::Join": [ "", [{ "Fn::FindInMap" : [ "VPCIpSpace", {"Ref": "AWS::Region"}, "RANGE" ]}, ".", { "Fn::FindInMap" : [ "publicSubnetConfig", "publicSubnet01", "CIDR" ]}]]},
        "AvailabilityZone" : { "Fn::Select" : [ "0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" } }]},
        "Tags" : [
          {"Key" : "Environment", "Value" : {"Ref" : "Environment"} },
          {"Key" : "SubnetType", "Value" : "Public" },
          {"Key" : "Name", "Value" : "publicSubnet01" }
        ]
      }
    },

   "publicSubnet02" : {
      "Type" : "AWS::EC2::Subnet",
      "Properties" : {
        "VpcId" : { "Ref" : "MyVPC" },
        "CidrBlock" : { "Fn::Join": [ "", [{ "Fn::FindInMap" : [ "VPCIpSpace", {"Ref": "AWS::Region"}, "RANGE" ]}, ".", { "Fn::FindInMap" : [ "publicSubnetConfig", "publicSubnet02", "CIDR" ]}]]},
        "AvailabilityZone" : { "Fn::Select" : [ "1", { "Fn::GetAZs" : { "Ref" : "AWS::Region" } }]},
        "Tags" : [
          {"Key" : "Environment", "Value" : {"Ref" : "Environment"} },
          {"Key" : "SubnetType", "Value" : "Public" },
          {"Key" : "Name", "Value" : "publicSubnet02" }
        ]
      }
    },

    "privateSubnet01" : {
      "Type" : "AWS::EC2::Subnet",
      "Properties" : {
        "VpcId" : { "Ref" : "MyVPC" },
        "CidrBlock" : { "Fn::Join": [ "", [{ "Fn::FindInMap" : [ "VPCIpSpace", {"Ref": "AWS::Region"}, "RANGE" ]}, ".", { "Fn::FindInMap" : [ "privateSubnetConfig", "privateSubnet01", "CIDR" ]}]]},
        "AvailabilityZone" : { "Fn::Select" : [ "0", { "Fn::GetAZs" : { "Ref" : "AWS::Region" } }]},
        "Tags" : [
          {"Key" : "Environment", "Value" : {"Ref" : "Environment"} },
          {"Key" : "SubnetType", "Value" : "Private" },
          {"Key" : "Name", "Value" : "privateSubnet01" }
        ]
      }
    },

   "privateSubnet02" : {
      "Type" : "AWS::EC2::Subnet",
      "Properties" : {
        "VpcId" : { "Ref" : "MyVPC" },
        "CidrBlock" : { "Fn::Join": [ "", [{ "Fn::FindInMap" : [ "VPCIpSpace", {"Ref": "AWS::Region"}, "RANGE" ]}, ".", { "Fn::FindInMap" : [ "privateSubnetConfig", "privateSubnet02", "CIDR" ]}]]},
        "AvailabilityZone" : { "Fn::Select" : [ "1", { "Fn::GetAZs" : { "Ref" : "AWS::Region" } }]},
        "Tags" : [
          {"Key" : "Environment", "Value" : {"Ref" : "Environment"} },
          {"Key" : "SubnetType", "Value" : "Private" },
          {"Key" : "Name", "Value" : "privateSubnet02" }
        ]
      }
    },
   
    "InternetGateway" : {
      "Type" : "AWS::EC2::InternetGateway",
      "Properties" : {
        "Tags" : [
          {"Key" : "Environment", "Value" : {"Ref" : "Environment"} },
          {"Key" : "Name", "Value" : "DemoVPCIGW" }
        ]
      }
    },

    "AttachGateway" : {
      "Type" : "AWS::EC2::VPCGatewayAttachment",
      "Properties" : {
         "VpcId" : { "Ref" : "MyVPC" },
         "InternetGatewayId" : { "Ref" : "InternetGateway" }
      }
    },

    "PublicRouteTable" : {
      "Type" : "AWS::EC2::RouteTable",
      "Properties" : {
        "VpcId" : {"Ref" : "MyVPC"},
        "Tags" : [
          {"Key" : "Environment", "Value" : {"Ref" : "Environment"} },
          {"Key" : "Name", "Value" : "PublicRouteTable" }
        ]
      }
    },

    "PublicRoute" : {
      "Type" : "AWS::EC2::Route",
      "Properties" : {
        "RouteTableId" : { "Ref" : "PublicRouteTable" },
        "DestinationCidrBlock" : "0.0.0.0/0",
        "GatewayId" : { "Ref" : "InternetGateway" }
      }
    },

    "PublicSubnetRTAssociation01" : {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "publicSubnet01" },
        "RouteTableId" : { "Ref" : "PublicRouteTable" }
      }
    },

    "PublicSubnetRTAssociation02" : {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "publicSubnet02" },
        "RouteTableId" : { "Ref" : "PublicRouteTable" }
      }
    },

    "PrivateSubnetRTAssociation01" : {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "privateSubnet01" },
        "RouteTableId" : { "Ref" : "PublicRouteTable" }
      }
    },

    "PrivateSubnetRTAssociation02" : {
      "Type" : "AWS::EC2::SubnetRouteTableAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "privateSubnet02" },
        "RouteTableId" : { "Ref" : "PublicRouteTable" }
      }
    },

    "PublicNetworkAcl" : {
      "Type" : "AWS::EC2::NetworkAcl",
      "Properties" : {
        "VpcId" : { "Ref" : "MyVPC" },
        "Tags" : [
          {"Key" : "Environment", "Value" : {"Ref" : "Environment"} },
          {"Key" : "Name", "Value" : "NetworkAcl" }
        ]
      }
    },

    "InboundPublicNAclEntry" : {
      "Type" : "AWS::EC2::NetworkAclEntry",
      "Properties" : {
        "NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
        "RuleNumber" : "2000",
        "Protocol" : "-1",
        "RuleAction" : "allow",
        "Egress" : "false",
        "CidrBlock" : "0.0.0.0/0",
        "PortRange" : { "From" : "0", "To" : "65535" }
      }
    },

    "OutboundPublicNetworkAclEntry" : {
      "Type" : "AWS::EC2::NetworkAclEntry",
      "Properties" : {
        "NetworkAclId" : { "Ref" : "PublicNetworkAcl" },
        "RuleNumber" : "2000",
        "Protocol" : "-1",
        "RuleAction" : "allow",
        "Egress" : "true",
        "CidrBlock" : "0.0.0.0/0",
        "PortRange" : { "From" : "0", "To" : "65535" }
      }
    },

    "publicSubnetNetworkAclAssociation01" : {
      "Type" : "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "publicSubnet01" },
        "NetworkAclId" : { "Ref" : "PublicNetworkAcl" }
      }
    },

    "publicSubnetNetworkAclAssociation02" : {
      "Type" : "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "publicSubnet02" },
        "NetworkAclId" : { "Ref" : "PublicNetworkAcl" }
      }
    },

    "privateSubnetNetworkAclAssociation01" : {
      "Type" : "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "privateSubnet01" },
        "NetworkAclId" : { "Ref" : "PublicNetworkAcl" }
      }
    },

    "privateSubnetNetworkAclAssociation02" : {
      "Type" : "AWS::EC2::SubnetNetworkAclAssociation",
      "Properties" : {
        "SubnetId" : { "Ref" : "privateSubnet02" },
        "NetworkAclId" : { "Ref" : "PublicNetworkAcl" }
      }
    },

    "EndpointSG" : {
      "Type" : "AWS::EC2::SecurityGroup",
      "Properties" : {
        "VpcId" : { "Ref" : "MyVPC" },
        "GroupDescription" : "SG for API Gateway Private endpoint",
        "SecurityGroupIngress" : [ 
          { "IpProtocol" : "tcp", "FromPort" : "443", "ToPort" : "443", "CidrIp" : { "Fn::Join": [ "", [{ "Fn::FindInMap" : [ "VPCIpSpace", {"Ref": "AWS::Region"}, "RANGE" ]}, ".", "0.0/16"]]}}
        ],
        "SecurityGroupEgress" : [
          { "IpProtocol" : "tcp", "FromPort" : "0",  "ToPort" : "65535",  "CidrIp" : "0.0.0.0/0" }
        ],
        "Tags" : [
          {"Key" : "Environment", "Value" : {"Ref" : "Environment"} },
          {"Key" : "Name", "Value" : "EndpointSG" }
        ]
      }
    }

  },

  "Outputs" : {
    "VpcId" : {
      "Value" : {"Ref" : "MyVPC"},
      "Description" : "VPC ID of newly created VPC",
      "Export" : {
        "Name" : { "Fn::Join": [ "", [{"Ref" : "Environment"}, "-MyVPC" ]]}
      }
    },

    "PublicSubnet1" : {
      "Value" : {"Ref" : "publicSubnet01"},
      "Description" : "Public Subnet in AZ 1",
      "Export" : {
        "Name" : { "Fn::Join": [ "", [{"Ref" : "Environment"}, "-publicSubnet01" ]]}
      }
    },

    "PublicSubnet2" : {
      "Value" : {"Ref" : "publicSubnet02"},
      "Description" : "Public Subnet in AZ 2",
      "Export" : {
        "Name" : { "Fn::Join": [ "", [{"Ref" : "Environment"}, "-publicSubnet02" ]]}
      }
    },

    "PrivateSubnet1" : {
      "Value" : {"Ref" : "privateSubnet01"},
      "Description" : "Private Subnet in AZ 1",
      "Export" : {
        "Name" : { "Fn::Join": [ "", [{"Ref" : "Environment"}, "-privateSubnet01" ]]}
      }
    },

    "privateSubnet2" : {
      "Value" : {"Ref" : "privateSubnet02"},
      "Description" : "private Subnet in AZ 2",
      "Export" : {
        "Name" : { "Fn::Join": [ "", [{"Ref" : "Environment"}, "-privateSubnet02" ]]}
      }
    }, 

    "EndpointSG" : {
      "Value" : {"Ref" : "EndpointSG"},
      "Description" : "SG for API Gateway Private endpoint",
      "Export" : {
        "Name" : { "Fn::Join": [ "", [{"Ref" : "Environment"}, "-EndpointSG" ]]}
      }
    }
  }
}