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

  "Description": "CloudFormation template for a generic VPC with public and private subnets (with private network Internet access via NAT)",

  "Parameters": {
    "Environment": {
      "Description": "Type Your Environment",
      "Type": "String",
      "Default": "wsi"
    }
  },

  "Mappings": {
    "SubnetConfig": {
      "VPC": {
        "CIDR": "10.0.0.0/16"
      },
      "Public1": {
        "CIDR": "10.0.0.0/24"
      },
      "Public2": {
        "CIDR": "10.0.1.0/24"
      },
      "Private1": {
        "CIDR": "10.0.2.0/24"
      },
      "Private2": {
        "CIDR": "10.0.3.0/24"
      }
    }
  },

  "Resources": {
    "VPC": {
      "Type": "AWS::EC2::VPC",
      "Properties": {
        "CidrBlock": {
          "Fn::FindInMap": ["SubnetConfig", "VPC", "CIDR"]
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Fn::Sub": [
                "${Environment}-vpc",
                { "Environment": { "Ref": "Environment" } }
              ]
            }
          }
        ]
      }
    },

    "PublicSubnet1": {
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "CidrBlock": {
          "Fn::FindInMap": ["SubnetConfig", "Public1", "CIDR"]
        },
        "AvailabilityZone": {
          "Fn::Select": [
            "0",
            {
              "Fn::GetAZs": ""
            }
          ]
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Fn::Sub": [
                "${Environment}-public-a",
                { "Environment": { "Ref": "Environment" } }
              ]
            }
          }
        ]
      }
    },

    "PublicSubnet2": {
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "CidrBlock": {
          "Fn::FindInMap": ["SubnetConfig", "Public2", "CIDR"]
        },
        "AvailabilityZone": {
          "Fn::Select": [
            "1",
            {
              "Fn::GetAZs": ""
            }
          ]
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Fn::Sub": [
                "${Environment}-public-b",
                { "Environment": { "Ref": "Environment" } }
              ]
            }
          }
        ]
      }
    },

    "InternetGateway": {
      "Type": "AWS::EC2::InternetGateway",
      "Properties": {
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Fn::Sub": [
                "${Environment}-igw",
                { "Environment": { "Ref": "Environment" } }
              ]
            }
          }
        ]
      }
    },

    "GatewayToInternet": {
      "DependsOn": ["VPC", "InternetGateway"],
      "Type": "AWS::EC2::VPCGatewayAttachment",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "InternetGatewayId": {
          "Ref": "InternetGateway"
        }
      }
    },

    "PublicRouteTable": {
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Fn::Sub": [
                "${Environment}-public-rt",
                { "Environment": { "Ref": "Environment" } }
              ]
            }
          }
        ]
      }
    },

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

    "PublicSubnetRouteTableAssociation1": {
      "DependsOn": ["PublicSubnet1", "PublicRouteTable"],
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PublicSubnet1"
        },
        "RouteTableId": {
          "Ref": "PublicRouteTable"
        }
      }
    },

    "PublicSubnetRouteTableAssociation2": {
      "DependsOn": ["PublicSubnet2", "PublicRouteTable"],
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PublicSubnet2"
        },
        "RouteTableId": {
          "Ref": "PublicRouteTable"
        }
      }
    },

    "PrivateSubnet1": {
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "CidrBlock": {
          "Fn::FindInMap": ["SubnetConfig", "Private1", "CIDR"]
        },
        "AvailabilityZone": {
          "Fn::Select": [
            "0",
            {
              "Fn::GetAZs": ""
            }
          ]
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Fn::Sub": [
                "${Environment}-private-a",
                { "Environment": { "Ref": "Environment" } }
              ]
            }
          }
        ]
      }
    },

    "PrivateSubnet2": {
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::Subnet",
      "Properties": {
        "VpcId": {
          "Ref": "VPC"
        },
        "CidrBlock": {
          "Fn::FindInMap": ["SubnetConfig", "Private2", "CIDR"]
        },
        "AvailabilityZone": {
          "Fn::Select": [
            "1",
            {
              "Fn::GetAZs": ""
            }
          ]
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Fn::Sub": [
                "${Environment}-private-b",
                { "Environment": { "Ref": "Environment" } }
              ]
            }
          }
        ]
      }
    },

    "NatGateway1": {
      "DependsOn": "VPC",
      "Type": "AWS::EC2::NatGateway",
      "Properties": {
        "AllocationId": { "Fn::GetAtt": ["EIP1", "AllocationId"] },
        "SubnetId": { "Ref": "PublicSubnet1" },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Fn::Sub": [
                "${Environment}-nat-a",
                { "Environment": { "Ref": "Environment" } }
              ]
            }
          }
        ]
      }
    },

    "NatGateway2": {
      "DependsOn": "VPC",
      "Type": "AWS::EC2::NatGateway",
      "Properties": {
        "AllocationId": { "Fn::GetAtt": ["EIP2", "AllocationId"] },
        "SubnetId": { "Ref": "PublicSubnet2" },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Fn::Sub": [
                "${Environment}-nat-b",
                { "Environment": { "Ref": "Environment" } }
              ]
            }
          }
        ]
      }
    },

    "EIP1": {
      "Type": "AWS::EC2::EIP",
      "Properties": {
        "Domain": "VPC"
      }
    },

    "EIP2": {
      "Type": "AWS::EC2::EIP",
      "Properties": {
        "Domain": "VPC"
      }
    },

    "PrivateRouteTable1": {
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": { "Ref": "VPC" },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Fn::Sub": [
                "${Environment}-private-a-rt",
                { "Environment": { "Ref": "Environment" } }
              ]
            }
          }
        ]
      }
    },

    "PrivateRouteTable2": {
      "DependsOn": ["VPC"],
      "Type": "AWS::EC2::RouteTable",
      "Properties": {
        "VpcId": { "Ref": "VPC" },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Fn::Sub": [
                "${Environment}-private-b-rt",
                { "Environment": { "Ref": "Environment" } }
              ]
            }
          }
        ]
      }
    },

    "PrivateRoute1": {
      "Type": "AWS::EC2::Route",
      "Properties": {
        "RouteTableId": { "Ref": "PrivateRouteTable1" },
        "DestinationCidrBlock": "0.0.0.0/0",
        "NatGatewayId": { "Ref": "NatGateway1" }
      }
    },

    "PrivateRoute2": {
      "Type": "AWS::EC2::Route",
      "Properties": {
        "RouteTableId": { "Ref": "PrivateRouteTable2" },
        "DestinationCidrBlock": "0.0.0.0/0",
        "NatGatewayId": { "Ref": "NatGateway2" }
      }
    },

    "PrivateSubnetRouteTableAssociation1": {
      "DependsOn": ["PrivateSubnet1", "PrivateRouteTable1"],
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PrivateSubnet1"
        },
        "RouteTableId": {
          "Ref": "PrivateRouteTable1"
        }
      }
    },

    "PrivateSubnetRouteTableAssociation2": {
      "DependsOn": ["PrivateSubnet2", "PrivateRouteTable2"],
      "Type": "AWS::EC2::SubnetRouteTableAssociation",
      "Properties": {
        "SubnetId": {
          "Ref": "PrivateSubnet2"
        },
        "RouteTableId": {
          "Ref": "PrivateRouteTable2"
        }
      }
    }
  },
  "Outputs": {
    "VPC": {
      "Description": "VPC",
      "Value": { "Ref": "VPC" },
      "Export": {
        "Name": { "Fn::Sub": "${AWS::StackName}-VPC" }
      }
    },
    "publicSubnet1": {
      "Description": "public-1",
      "Value": { "Ref": "PublicSubnet1" },
      "Export": {
        "Name": { "Fn::Sub": "${AWS::StackName}-public-a" }
      }
    },
    "publicSubnet2": {
      "Description": "public-2",
      "Value": { "Ref": "PublicSubnet2" },
      "Export": {
        "Name": { "Fn::Sub": "${AWS::StackName}-public-b" }
      }
    },
    "pirvateSubnet1": {
      "Description": "private-subnet-1",
      "Value": { "Ref": "PrivateSubnet1" },
      "Export": {
        "Name": { "Fn::Sub": "${AWS::StackName}-private-a" }
      }
    },
    "pirvateSubnet2": {
      "Description": "private-subnet-2",
      "Value": { "Ref": "PrivateSubnet2" },
      "Export": {
        "Name": { "Fn::Sub": "${AWS::StackName}-private-b" }
      }
    }
  }
}