AWSTemplateFormatVersion: '2010-09-09'
Metadata:
  License: Apache-2.0
Description: 'AWS CloudFormation Template to deploy NCXSG'
Parameters:
  AvailabilityZone1:
    Description: First Availability Zone where subnet and EC2 instance will be created for HA Pair.
    Type: AWS::EC2::AvailabilityZone::Name
    AllowedPattern: ".+"
  AvailabilityZone2:
    Description: Second Availability Zone where subnet and EC2 instance will be created for HA Pair.
    Type: AWS::EC2::AvailabilityZone::Name
    AllowedPattern: ".+"
  ImageId:
    Description: AWS AMI-ID shown in NCM Image Management page (Networks -> Secure Networks -> Image Management -> Cloud Image ID)
    Type: String
    AllowedPattern: '^(ami-).*'
    ConstraintDescription: must be a valid ami-id.
  InstanceType:
    Description: EC2 instance type
    Type: String
    Default: c5.2xlarge
    ConstraintDescription: must be a valid EC2 instance type.
Resources:
  # First, a VPC:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.1.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
      - Key: Name
        Value:  !Join ['', [!Ref "AWS::StackName", "-VPC" ]]
  # Our VPC will need internet access:
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    DependsOn: VPC
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    # Notice how you can't attach an IGW to a VPC unless both are created:
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  # Now some subnets, 2 public(WAN + MGMT) and 1 private(LAN) in AZ0:
  Wan0Subnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.1.10.0/24
      AvailabilityZone: !Select [ 0, !GetAZs ]    # Get the first AZ in the list
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-Wan0
  Mgmt0Subnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.1.20.0/24
      AvailabilityZone: !Select [ 0, !GetAZs ]    # Get the first AZ in the list
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-Mgmt0
  Lan0Subnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.1.50.0/24
      AvailabilityZone: !Select [ 0, !GetAZs ]    # Get the first AZ in the list
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-Lan0

  # Now some subnets, 2 public(WAN + MGMT) and 1 private(LAN) in AZ1:
  Wan1Subnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.1.11.0/24
      AvailabilityZone: !Select [ 1, !GetAZs ]    # Get the second AZ in the list
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-Wan1
  Mgmt1Subnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.1.21.0/24
      AvailabilityZone: !Select [ 1, !GetAZs ]    # Get the second AZ in the list
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-Mgmt1
  Lan1Subnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.1.51.0/24
      AvailabilityZone: !Select [ 1, !GetAZs ]    # Get the second AZ in the list
      Tags:
      - Key: Name
        Value: !Sub ${AWS::StackName}-Lan1

  # Some route tables for our subnets:
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: Public
  PublicRoute1:   # Public route table has direct routing to IGW:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  # Attach the Wan and Mgmt subnets to public route tables.
  Wan0SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Wan0Subnet
      RouteTableId: !Ref PublicRouteTable
  Wan1SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Wan1Subnet
      RouteTableId: !Ref PublicRouteTable
  Mgmt0SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Mgmt0Subnet
      RouteTableId: !Ref PublicRouteTable
  Mgmt1SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Mgmt1Subnet
      RouteTableId: !Ref PublicRouteTable

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
      - Key: Name
        Value: Private
  Lan0SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Lan0Subnet
      RouteTableId: !Ref PrivateRouteTable
  Lan1SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref Lan1Subnet
      RouteTableId: !Ref PrivateRouteTable

  WANSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC
      GroupDescription: NCXSG WAN Ingress and Egress Rules
      SecurityGroupIngress:
      - IpProtocol: udp
        FromPort: '4500'
        ToPort: '4500'
        CidrIp: 0.0.0.0/0
      - IpProtocol: udp
        FromPort: '500'
        ToPort: '500'
        CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
      - IpProtocol: -1
        CidrIp: 0.0.0.0/0
  MGMTSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC
      GroupDescription: NCXSG MGMT Ingress and Egress Rules
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: '22'
        ToPort: '22'
        CidrIp: 0.0.0.0/0
      - IpProtocol: tcp
        FromPort: '80'
        ToPort: '80'
        CidrIp: 0.0.0.0/0
      - IpProtocol: tcp
        FromPort: '443'
        ToPort: '443'
        CidrIp: 0.0.0.0/0
      - IpProtocol: tcp
        FromPort: '6379'
        ToPort: '6379'
        CidrIp: 0.0.0.0/0
      - IpProtocol: icmp
        FromPort: '-1'
        ToPort: '-1'
        CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
      - IpProtocol: -1
        CidrIp: 0.0.0.0/0
  LANSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref VPC
      GroupDescription: NCXSG LAN Ingress and Egress Rules
      SecurityGroupIngress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0

  WAN0Interface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      Description: wan0
      GroupSet: [!Ref 'WANSecurityGroup']
      SourceDestCheck: 'false'
      SubnetId: !Ref 'Wan0Subnet'
      Tags:
      - Key: Name
        Value: !Join ['', [!Ref "AWS::StackName", "WAN0" ]]
      - Key: Interface
        Value: wan0
      - Key: CPResource
        Value: true
  MGMT0Interface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      Description: mgmt0
      GroupSet: [!Ref 'MGMTSecurityGroup']
      SourceDestCheck: 'false'
      SubnetId: !Ref 'Mgmt0Subnet'
      Tags:
      - Key: Name
        Value: !Join ['', [!Ref "AWS::StackName", "MGMT0" ]]
      - Key: Interface
        Value: mgmt0
  LAN0Interface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      Description: lan0
      GroupSet: [!Ref 'LANSecurityGroup']
      SourceDestCheck: 'false'
      SubnetId: !Ref 'Lan0Subnet'
      Tags:
        - Key: Name
          Value: !Join ['', [!Ref "AWS::StackName", "LAN0" ]]
        - Key: Interface
          Value: lan0

  WAN1Interface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      Description: wan1
      GroupSet: [!Ref 'WANSecurityGroup']
      SourceDestCheck: 'false'
      SubnetId: !Ref 'Wan1Subnet'
      Tags:
      - Key: Name
        Value: !Join ['', [!Ref "AWS::StackName", "WAN1" ]]
      - Key: Interface
        Value: wan1
      - Key: CPResource
        Value: true
  MGMT1Interface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      Description: mgmt1
      GroupSet: [!Ref 'MGMTSecurityGroup']
      SourceDestCheck: 'false'
      SubnetId: !Ref 'Mgmt1Subnet'
      Tags:
      - Key: Name
        Value: !Join ['', [!Ref "AWS::StackName", "MGMT1" ]]
      - Key: Interface
        Value: mgmt1
  LAN1Interface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      Description: lan1
      GroupSet: [!Ref 'LANSecurityGroup']
      SourceDestCheck: 'false'
      SubnetId: !Ref 'Lan1Subnet'
      Tags:
        - Key: Name
          Value: !Join ['', [!Ref "AWS::StackName", "LAN1" ]]
        - Key: Interface
          Value: lan1

  WAN0EIP:
    Type: AWS::EC2::EIP
    DependsOn: AttachGateway
    Properties:
      Domain: vpc
      Tags:
      - Key: Name
        Value: !Join ['', [!Ref "AWS::StackName", "Wan0EIP" ]]
      - Key: CPResource
        Value: true

  WAN1EIP:
    Type: AWS::EC2::EIP
    DependsOn: AttachGateway
    Properties:
      Domain: vpc
      Tags:
      - Key: Name
        Value: !Join ['', [!Ref "AWS::StackName", "Wan1EIP" ]]
      - Key: CPResource
        Value: true

  WANVIPEIP:
    Type: AWS::EC2::EIP
    DependsOn: AttachGateway
    Properties:
      Domain: vpc
      Tags:
      - Key: Name
        Value: !Join ['', [!Ref "AWS::StackName", "WanVIPEIP" ]]
      - Key: CPResource
        Value: true

  EC2NcxsgInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: !Join ['', [!Ref "AWS::StackName", "ec2-instance-profile" ]]
      Path: /
      Roles:
       - !Ref EC2NcxsgRole
  EC2NcxsgRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Join ['', [!Ref "AWS::StackName", "ec2-instance-role" ]]
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
  Ec2NcxsgRolePolicy:
    Type: 'AWS::IAM::Policy'
    Properties:
      PolicyName: !Join ['', [!Ref "AWS::StackName", "Ec2ReadPolicy" ]]
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - 'ec2:Describe*'
            Resource: '*'
          - Effect: Allow
            Action:
              - 'ec2:CreateTags'
              - 'ec2:DeleteTags'
              - 'ec2:CreateRouteTable'
              - 'ec2:DeleteRouteTable'
              - 'ec2:AssociateRouteTable'
              - 'ec2:DisassociateRouteTable'
              - 'ec2:CreateRoute'
              - 'ec2:DeleteRoute'
              - 'ec2:ReplaceRoute'
            Resource: '*'
          - Effect: Allow
            Action:
              - 'ec2:AssociateAddress'
              - 'ec2:CreateTags'
              - 'ec2:DeleteTags'
            Resource:
              - !Join ['', ["arn:", !Ref "AWS::Partition", ":ec2:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId",":elastic-ip/*" ]]
              - !Join ['', ["arn:", !Ref "AWS::Partition", ":ec2:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId",":network-interface/*" ]]
            Condition: { "StringEquals": { "aws:ResourceTag/CPResource": "true" } }
      Roles:
        - !Ref EC2NcxsgRole

  EC2Instance0:
    Type: AWS::EC2::Instance
    DependsOn:
      - WAN0Interface
      - MGMT0Interface
      - LAN0Interface
    Properties:
      ImageId: !Ref 'ImageId'
      InstanceType: !Ref 'InstanceType'
      IamInstanceProfile: !Ref 'EC2NcxsgInstanceProfile'
      AvailabilityZone: !Select [ 0, !GetAZs ]
      NetworkInterfaces:
      - NetworkInterfaceId: !Ref 'WAN0Interface'
        DeviceIndex: '0'
      - NetworkInterfaceId: !Ref 'MGMT0Interface'
        DeviceIndex: '1'
      - NetworkInterfaceId: !Ref 'LAN0Interface'
        DeviceIndex: '2'
      Tags:
      - Key: Name
        Value: !Join ['', [!Ref "AWS::StackName", "-NCXSG-Primary" ]]
      # For ICMP testing
      # post config/data_path/config/vrf/0/routing/static/ipv4-route {"destination": "10.1.21.0/24", "next-hop":[{ "next-hop": "10.1.20.1"}]}
      # set config/data_path/config/vrf/0/firewall/ipv4/filter/input/policy "accept"

  EC2Instance1:
    Type: AWS::EC2::Instance
    DependsOn:
      - WAN1Interface
      - MGMT1Interface
      - LAN1Interface
    Properties:
      ImageId: !Ref 'ImageId'
      InstanceType: !Ref 'InstanceType'
      IamInstanceProfile: !Ref 'EC2NcxsgInstanceProfile'
      AvailabilityZone: !Select [ 1, !GetAZs ]
      NetworkInterfaces:
      - NetworkInterfaceId: !Ref 'WAN1Interface'
        DeviceIndex: '0'
      - NetworkInterfaceId: !Ref 'MGMT1Interface'
        DeviceIndex: '1'
      - NetworkInterfaceId: !Ref 'LAN1Interface'
        DeviceIndex: '2'
      Tags:
      - Key: Name
        Value: !Join ['', [!Ref "AWS::StackName", "-NCXSG-Secondary" ]]
      # For ICMP testing
      # post config/data_path/config/vrf/0/routing/static/ipv4-route {"destination": "10.1.20.0/24", "next-hop":[{ "next-hop": "10.1.21.1"}]}
      # set config/data_path/config/vrf/0/firewall/ipv4/filter/input/policy "accept"

  AssociateWan0EIP:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId: !GetAtt WAN0EIP.AllocationId
      NetworkInterfaceId: !Ref 'WAN0Interface'

  AssociateWan1EIP:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId: !GetAtt WAN1EIP.AllocationId
      NetworkInterfaceId: !Ref 'WAN1Interface'

Outputs:
  PrimaryWanEIP:
    Value: !Ref WAN0EIP
    Description: Wan0 EIP for Primary NCXSG-AWS
  SecondaryWanEIP:
    Value: !Ref WAN1EIP
    Description: Wan0 EIP for Secondary NCXSG-AWS
  WanVirtualIP:
    Value: !Ref WANVIPEIP
    Description: Wan Virtual Public IP
  PrimaryManagementIP:
    Value: !GetAtt 'MGMT0Interface.PrimaryPrivateIpAddress'
    Description: Primary NCXSG-AWS Management IP
  SecondaryManagementIP:
    Value: !GetAtt 'MGMT1Interface.PrimaryPrivateIpAddress'
    Description: Secondary NCXSG-AWS Management IP
