AWSTemplateFormatVersion: '2010-09-09'
Description: This template create NLB and TargetGroup which does TCP passthrough to the Redshift cluster endpoint's IP address.
Parameters:
  VPCId:
    Description: Typically Redshift & NLB located in the same VPC.
    Type: AWS::EC2::VPC::Id
  NLBSubnetId:
    Description: NLB & Redshift subnet need to be in the same AZ.
    Type: AWS::EC2::Subnet::Id
  NLBSubnetCIDR:
    Description: We dont have to whitelist entire subnet. Preferably , find the private IP of the NLB once it created and then whitelist in Redshift SG.
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,3})"
    Type: String
  NLBPort:
    Description: Preferably mention same port as Redshift is using.
    AllowedPattern: "(\\d{1,4})"
    Type: String
  RedshiftPrivateIPProducer:
    Description: This IP never change during the life of Redshift cluster.
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})"
    Type: String
  RedshiftPrivateIPConsumer:
    Description: This IP never change during the life of Redshift cluster.
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})"
    Type: String
  RedshiftPort:
    Description: Port on which Redshift cluster listen for connections. default 5439.
    AllowedPattern: "(\\d{1,4})"
    Type: String
  RedshiftSecurityGroup:
    Description: Used to control inbound access to Redshift from NLB private IP
    Type: "AWS::EC2::SecurityGroup::Id"

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: NLB & RS Configuration properties
      Parameters:
      - VPCId
      - NLBSubnetId
      - NLBSubnetCIDR
      - NLBPort
      - RedshiftPrivateIPProducer
      - RedshiftPrivateIPConsumer
      - RedshiftPort
      - RedshiftSecurityGroup
    ParameterLabels:
      VPCId:
        default: Mention a VPC to deploy the solution into.
      NLBSubnetId:
        default: Mention the subnet where NLB ENI will be created.
      NLBSubnetCIDR:
        default: CIDR of the subnet, used for whitelisting inbound access in Redshift Security group
      NLBPort:
        default: Port to be used by NLB Listener.
      RedshiftPrivateIPProducer:
        default: IP Address of Redshift Producer cluster. This is the IP address the cluster endpoint resolve to.
      RedshiftPrivateIPConsumer:
        default: IP Address of Redshift Consumer cluster. This is the IP address the cluster endpoint resolve to.
      RedshiftPort:
        default: Port used by Redshift cluster.
      RedshiftSecurityGroup:
        default: Redshift Security Group.

Resources:
  NetworkLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Join ["-" , [!Ref 'AWS::StackName', NLB]]
      Scheme: internet-facing
      IpAddressType: ipv4
      Subnets:
        - !Ref NLBSubnetId
      Type: network
  NetworkLoadBalancerTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Join ["-" , [!Ref 'AWS::StackName', Target]]
      Port: !Ref RedshiftPort
      Protocol: TCP
      VpcId: !Ref VPCId
      HealthCheckEnabled: True
      HealthCheckIntervalSeconds: 30
      HealthCheckPort: !Ref RedshiftPort
      HealthCheckTimeoutSeconds: 10
      HealthyThresholdCount: 3
      TargetGroupAttributes:
        - Key: proxy_protocol_v2.enabled
          Value: false
        - Key: deregistration_delay.timeout_seconds
          Value: 3600
      Targets:
        - Id: !Ref RedshiftPrivateIPProducer
          Port: !Ref RedshiftPort
        - Id: !Ref RedshiftPrivateIPConsumer
          Port: !Ref RedshiftPort
      TargetType: ip
  NetworkLoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref NetworkLoadBalancerTargetGroup
      LoadBalancerArn: !Ref NetworkLoadBalancer
      Port: !Ref NLBPort
      Protocol: TCP
  RedshiftSecurityGroupIngress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref RedshiftSecurityGroup
      IpProtocol: tcp
      FromPort: !Ref RedshiftPort
      ToPort: !Ref RedshiftPort
      CidrIp: !Ref NLBSubnetCIDR
      Description: Allow inbound access from NLB Subnet

Outputs:
  NLBEndpoint:
    Description: NLB public endpoint
    Value: !GetAtt NetworkLoadBalancer.DNSName
