AWSTemplateFormatVersion: '2010-09-09'
Description: This stack deploys a private VPC needed for Shotgun Virtual Cloud. This version also create public subnets to deploy the public S3 proxy.
Metadata: 
  AWS::CloudFormation::Interface: 
    ParameterGroups: 
      - Label: 
          default: "Network Configuration"
        Parameters: 
          - VPCCIDR
          - SubnetOneCIDR
          - SubnetTwoCIDR
Parameters:
  VPCCIDR:
    Description: The VPC CIDR block.
    Default: '10.100.0.0/16'
    Type: String
  SubnetOneCIDR:
    Description: Subnet One CIDR block.
    Default: '10.100.0.0/24'
    Type: String
  SubnetTwoCIDR:
    Description: Subnet Two CIDR block.
    Default: '10.100.1.0/24'
    Type: String
  PublicSubnetOneCIDR:
    Description: Subnet One CIDR block.
    Default: '10.100.2.0/24'
    Type: String
  PublicSubnetTwoCIDR:
    Description: Subnet Two CIDR block.
    Default: '10.100.3.0/24'
    Type: String
  CustomerBucketName:
    AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$
    ConstraintDescription: Bucket name can include numbers, lowercase letters, uppercase letters, and hyphens. It
      cannot start of end with a hyphen (-).
    Description: The existing S3 Bucket where Shotgun media will be stored.
    Type: String
  ShotgunPrivateServiceName:
    Description: "OPTIONAL: Shotgun private service name for your AWS region if needed."
    Type: String
Conditions:
  CreateShotgunEndpoint: !Not [ !Equals [ !Ref ShotgunPrivateServiceName, "" ]]
Resources:
  # VPC in which containers will be networked.
  # It has two private subnets and 2 public subnets
  # We distribute the subnets across the first two available subnets
  # for the region, for high availability.
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      EnableDnsSupport: true
      EnableDnsHostnames: true
      CidrBlock: !Ref 'VPCCIDR'
      Tags:
        - Key: Name
          Value: !Ref 'AWS::StackName'

  InternetGateway:
    Type: AWS::EC2::InternetGateway

  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

  # Two private subnets where containers will only have private
  # IP addresses, and will only be reachable by other members of the
  # VPC
  PrivateSubnetOne:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 0
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !Ref 'SubnetOneCIDR'
      Tags:
        - Key: Name
          Value: !Join [ '-', [ !Ref 'AWS::StackName', "PrivateSubnetOne" ]]
  PrivateSubnetTwo:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 1
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !Ref 'SubnetTwoCIDR'
      Tags:
        - Key: Name
          Value: !Join [ '-', [ !Ref 'AWS::StackName', "PrivateSubnetTwo" ]]
  # Two public subnets
  PublicSubnetOne:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 0
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !Ref 'PublicSubnetOneCIDR'
      Tags:
        - Key: Name
          Value: !Join [ '-', [ !Ref 'AWS::StackName', "PublicSubnetOne" ]]
  PublicSubnetTwo:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 1
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !Ref 'PublicSubnetTwoCIDR'
      Tags:
        - Key: Name
          Value: !Join [ '-', [ !Ref 'AWS::StackName', "PublicSubnetTwo" ]]

  # Setup networking resources for the private subnets.
  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref 'VPC'
  PrivateRouteTableOneAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnetOne
  PrivateRouteTableTwoAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      SubnetId: !Ref PrivateSubnetTwo

  # Setup networking resources for the public subnets.
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC

  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 PublicSubnetOne

  PublicSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnetTwo

  # VPC EndPoint
  EndpointSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Access to VPC Endpoint
      VpcId: !Ref 'VPC'
  EndpointSecurityGroupIngressFromVPC:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      Description: Ingress from VPC
      GroupId: !Ref 'EndpointSecurityGroup'
      IpProtocol: -1
      CidrIp: !Ref 'VPCCIDR'

  S3Endpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      PolicyDocument: !Sub '{
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": "*",
                "Effect": "Allow",
                "Resource": [
                  "arn:aws:s3:::${CustomerBucketName}/*",
                  "arn:aws:s3:::prod-${AWS::Region}-starport-layer-bucket/*"
                ],
                "Principal": "*"
            }
        ]
      }'
      RouteTableIds:
        - !Ref PrivateRouteTable
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcId: !Ref VPC
  ECRApiEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties: 
      PrivateDnsEnabled: true
      SecurityGroupIds: 
        - !Ref EndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ecr.api
      SubnetIds: 
        - !Ref PrivateSubnetOne
        - !Ref PrivateSubnetTwo
      VpcEndpointType: Interface
      VpcId: !Ref VPC
  ECRDkrEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties: 
      PrivateDnsEnabled: true
      SecurityGroupIds: 
        - !Ref EndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.ecr.dkr
      SubnetIds: 
        - !Ref PrivateSubnetOne
        - !Ref PrivateSubnetTwo
      VpcEndpointType: Interface
      VpcId: !Ref VPC
  LogsEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties: 
      PrivateDnsEnabled: true
      SecurityGroupIds: 
        - !Ref EndpointSecurityGroup
      ServiceName: !Sub com.amazonaws.${AWS::Region}.logs
      SubnetIds: 
        - !Ref PrivateSubnetOne
        - !Ref PrivateSubnetTwo
      VpcEndpointType: Interface
      VpcId: !Ref VPC
  ShotgunEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Condition: CreateShotgunEndpoint
    Properties: 
      PrivateDnsEnabled: false
      SecurityGroupIds: 
        - !Ref EndpointSecurityGroup
      ServiceName: !Ref ShotgunPrivateServiceName
      SubnetIds: 
        - !Ref PrivateSubnetOne
        - !Ref PrivateSubnetTwo
      VpcEndpointType: Interface
      VpcId: !Ref VPC
Outputs:
  VPCId:
    Description: The ID of the VPC that this stack is deployed in
    Value: !Ref 'VPC'
    Export:
      Name: !Join [ ':', [ !Ref 'AWS::StackName', 'VPCId' ] ]
  PrivateSubnetOne:
    Description: Private subnet one
    Value: !Ref 'PrivateSubnetOne'
    Export:
      Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PrivateSubnetOne' ] ]
  PrivateSubnetTwo:
    Description: Private subnet two
    Value: !Ref 'PrivateSubnetTwo'
    Export:
      Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PrivateSubnetTwo' ] ]
  PublicSubnetOne:
    Description: Public subnet one
    Value: !Ref 'PublicSubnetOne'
    Export:
      Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetOne' ] ]
  PublicSubnetTwo:
    Description: Public subnet two
    Value: !Ref 'PublicSubnetTwo'
    Export:
      Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetTwo' ] ]
