Amazon AWS CloudFormation Template

In order to provide a redundant proxy configuration, the following guide can be followed.

  • Deploy a Heimdall Central Manager via the AWS Marketplace. This instance doesn't need to be particularly large
  • Ensure the application works appropriately through a proxy instance hosted on the management server
  • Once the application is validated, you can un-check the proxy option "management server proxy" which will terminate the proxy on this management server
  • Deploy a cluster of proxy-only nodes using the below template

Note: Support for this template is exclusively provided for Heimdall Enterprise Edition customers as customers that require this level of redundancy also typically require 24/7 support. Heimdall offers private offer pricing to customers on a negotiated basis if needed. The AMI ID provided below is the current Enterprise AMI ID that is available, however the current AMI ID may change over time. To find the current Enterprise AMI, please search in the "community ami" section of the EC2 launcher, and search for the string "5d2be2df-c328-4d9b-8d6e-badc5705e9a7". This will provide the current marketplace AMI ID to use, i.e.:

Here, the AMI ID to use is: ami-06b8b11db8101d023

Please note, the AMI ID will be region dependent--you will need to update what AMI is used depending on what region you are in.

If none are found, ensure that you have subscribed to the Heimdall Enterprise Edition offering in the AWS Marketplace, as it may be hidden until subscribed, or won't let you start them via the script.

The resources created by this template are:

  • Network Load Balancer with Listener billable Note: We support both database protocol load balancing as well as distributing traffic via DNS queries. In the DNS case, the NLB costs will be significantly less, but overall traffic distribution may not be as even across nodes.
  • Autoscaling configuration with Target Group
  • Scale up and down policies with alarms
  • Launch Configuration with instance policy and IAM role
  • Security group for proxy EC2 instances

In the case of the DNS based NLB setup, the template will also configure: * A record pointing to the NLB target hostname * An NS record that points to the A record pointing to the NLB target hostname

It depends on: * Existing VPC & Subnets * An existing Heimdall Central Manager * SSH Key

All resources will be named based on the stack name as appropriate, and their creation can be reversed by deleting the stack.

Heimdall assumes no responsibility for the charges that may be charged by AWS through the use of this template, as in particular, outside of the EC2 instances, the network load balancer may incur charges, as explained "here".

Autoscaling Proxy Template

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  HeimdallProxyAMIID:
    Type: String
    Default: ami-0496a2e9f2d6890ec
    Description: The Enterprise Edition AMI ID to use
  HeimdallProxyVPC:
    Type: 'AWS::EC2::VPC::Id'
    Description: >-
      VPC ID for Proxy Use, should generally match the database's VPC being
      accessed
  HeimdallProxyAvailabilityZones:
    Type: 'List<AWS::EC2::AvailabilityZone::Name>'
    Description: Availability zones for NLB Deployment
  HeimdallProxySubnetList:
    Type: 'List<AWS::EC2::Subnet::Id>'
    Description: >-
      Subnet IDs for ELB for Proxy Deployment (ensure to match the AZ's and
      availability zones selected)
  hdHost:
    Type: String
    Description: >-
      Private Hostname of Heimdall Central Manager, do not use the public
      hostname if present
  hdUser:
    Type: String
    Default: admin
    Description: Central Manager Username OR proxy access key from vdb configuration
  hdPassword:
    Type: String
    Description: Central Manager Password OR proxy secret key from vdb configuration
  vdbName:
    Type: String
    Description: VDB Name configured in central manager.  Multiple names can be provided, comma seperated, to run more than one proxy on a single instance
  ProxyPort:
    Description: Database Proxy port
    Type: Number
    Default: 5432
    ConstraintDescription: >-
      Provide the port the proxies are expected to run on (typically the same as
      the back-end database, i.e. 3306 for mysql, 5432 for postgres, or 1433 for
      SQL Server), needed to create a security group for the proxies
  ProxyMinimum:
    Description: Minimum number of proxies
    Type: Number
    Default: 2
    ConstraintDescription: How many proxies should be in operation at minimum
  ProxyMaximum:
    Description: Maximum number of proxies
    Type: Number
    Default: 4
    ConstraintDescription: How many proxies should be in operation at most
  InstanceTypeParameterProxy:
    Type: String
    Default: c5.xlarge
    AllowedValues:
      - t3.medium
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
    Description: Enter Proxy instance type (autoscaling)
  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
    Type: 'AWS::EC2::KeyPair::KeyName'
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
Metadata:
  Generator: ''
  'AWS::CloudFormation::Designer':
    d2b3fbb5-c87c-490d-b0ff-5c0804f855f0:
      size:
        width: 60
        height: 60
      position:
        x: 630
        'y': 450
      z: 1
      embeds: []
    dc671d3b-807c-4ea9-b368-7e3d534e22e1:
      size:
        width: 60
        height: 60
      position:
        x: 630
        'y': 330
      z: 1
      embeds: []
    5311a68f-b7ab-48e1-b1d7-9038174cf489:
      size:
        width: 60
        height: 60
      position:
        x: 530
        'y': 330
      z: 1
      embeds: []
      isassociatedwith:
        - 0e9f449e-767d-4419-aac9-2e7fe29f4fd4
        - dc671d3b-807c-4ea9-b368-7e3d534e22e1
    fbdc2e18-b910-405e-aeed-433c01a5a71b:
      size:
        width: 60
        height: 60
      position:
        x: 530
        'y': 450
      z: 1
      embeds: []
      isassociatedwith:
        - d2b3fbb5-c87c-490d-b0ff-5c0804f855f0
    34e5960d-26f6-4d11-aae1-85c02c36b986:
      size:
        width: 60
        height: 60
      position:
        x: 420
        'y': 450
      z: 1
      embeds: []
      isassociatedwith:
        - fbdc2e18-b910-405e-aeed-433c01a5a71b
        - ded7f98f-10d3-4e44-a367-bd3cb1ea347e
    ded7f98f-10d3-4e44-a367-bd3cb1ea347e:
      size:
        width: 60
        height: 60
      position:
        x: 420
        'y': 310
      z: 1
      embeds: []
    57399634-3282-4398-94cd-e5b1ab3455bf:
      size:
        width: 60
        height: 60
      position:
        x: 220
        'y': 310
      z: 1
      embeds: []
    f5ca956b-6572-44a5-99d9-17899f5a826a:
      size:
        width: 60
        height: 60
      position:
        x: 320
        'y': 310
      z: 1
      embeds: []
      isassociatedwith:
        - 57399634-3282-4398-94cd-e5b1ab3455bf
    662a6ed5-4d47-488d-89b0-4ff2eba99817:
      size:
        width: 60
        height: 60
      position:
        x: 220
        'y': 490
      z: 1
      embeds: []
      isassociatedwith:
        - 34e5960d-26f6-4d11-aae1-85c02c36b986
    fbb5ee8e-a3ea-4616-a3ab-bf77a0f0f012:
      size:
        width: 60
        height: 60
      position:
        x: 320
        'y': 500
      z: 1
      embeds: []
    a91d43f5-bb88-4305-8220-8621e84771a4:
      size:
        width: 60
        height: 60
      position:
        x: 220
        'y': 400
      z: 1
      embeds: []
      isassociatedwith:
        - 34e5960d-26f6-4d11-aae1-85c02c36b986
    f13bafeb-8014-489d-a066-9910c4554ee2:
      size:
        width: 60
        height: 60
      position:
        x: 320
        'y': 400
      z: 1
      embeds: []
Description: HA Template for Heimdall Data Access Platform
Resources:
  HeimdallProxyIAM:
    Type: 'AWS::IAM::Role'
    Properties:
      Path: /
      AssumeRolePolicyDocument: >-
        {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}]}
      MaxSessionDuration: 3600
      RoleName: !Join 
        - '-'
        - - !Ref 'AWS::StackName'
          - proxy
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/CloudWatchFullAccess'
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: dc671d3b-807c-4ea9-b368-7e3d534e22e1
  HeimdallProxyIAMInstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      Path: /
      Roles:
        - !Ref HeimdallProxyIAM
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 5311a68f-b7ab-48e1-b1d7-9038174cf489
  HeimdallProxySecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupName: !Join 
        - '-'
        - - !Ref 'AWS::StackName'
          - proxySG
      GroupDescription: Security group for Heimdall Proxy
      VpcId: !Ref HeimdallProxyVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          CidrIp: 0.0.0.0/0
          FromPort: 22
          ToPort: 22
        - IpProtocol: tcp
          CidrIp: 0.0.0.0/0
          FromPort: !Ref ProxyPort
          ToPort: !Ref ProxyPort
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: d2b3fbb5-c87c-490d-b0ff-5c0804f855f0
  ProxyLaunchConfig:
    Type: 'AWS::AutoScaling::LaunchConfiguration'
    Properties:
      AssociatePublicIpAddress: false
      IamInstanceProfile: !Ref HeimdallProxyIAMInstanceProfile
      ImageId: !Ref HeimdallProxyAMIID
      InstanceMonitoring: true
      InstanceType: !Ref InstanceTypeParameterProxy
      KeyName: !Ref KeyName
      SecurityGroups:
        - !Ref HeimdallProxySecurityGroup
      LaunchConfigurationName: !Join 
        - '-'
        - - !Ref 'AWS::StackName'
          - proxy
      UserData: !Base64 
        'Fn::Join':
          - ''
          - - '#!/bin/bash'
            - |-

              echo "hdRole=proxy
              hdPort=8087
            - |-

              vdbName=
            - !Ref vdbName
            - |-

              hdHost=
            - !Ref hdHost
            - |-

              hdUser=
            - !Ref hdUser
            - |-

              hdPassword=
            - !Ref hdPassword
            - |-

              " > /etc/heimdall.conf
            - |-

              yum -y update
            - |-

              systemctl restart heimdall
    Metadata:
      'AWS::CloudFormation::Designer':
        id: fbdc2e18-b910-405e-aeed-433c01a5a71b
  HeimdallProxyAutoScalingGroup:
    Type: 'AWS::AutoScaling::AutoScalingGroup'
    Version: 2020-04-22
    Properties:
      AvailabilityZones: !Ref HeimdallProxyAvailabilityZones
      VPCZoneIdentifier: !Ref HeimdallProxySubnetList
      LaunchConfigurationName: !Ref ProxyLaunchConfig
      TargetGroupARNs:
        - !Ref HeimdallProxyTargetGroup
      MinSize: !Ref ProxyMinimum
      MaxSize: !Ref ProxyMaximum
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
          PropagateAtLaunch: true
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 34e5960d-26f6-4d11-aae1-85c02c36b986
  HeimdallProxyTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      Port: !Ref ProxyPort
      Protocol: TCP
      VpcId: !Ref HeimdallProxyVPC
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: 60
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: ded7f98f-10d3-4e44-a367-bd3cb1ea347e
  HeimdallProxyLoadBalancer:
    Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
    Properties:
      Scheme: internal
      Type: network
      Subnets: !Ref HeimdallProxySubnetList
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 57399634-3282-4398-94cd-e5b1ab3455bf
  HeimdallProxyLoadBalancerListener:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref HeimdallProxyTargetGroup
      LoadBalancerArn: !Ref HeimdallProxyLoadBalancer
      Port: !Ref ProxyPort
      Protocol: TCP
    Metadata:
      'AWS::CloudFormation::Designer':
        id: f5ca956b-6572-44a5-99d9-17899f5a826a
  HeimdallProxyScaleUpPolicy:
    Type: 'AWS::AutoScaling::ScalingPolicy'
    Properties:
      AdjustmentType: ChangeInCapacity
      AutoScalingGroupName: !Ref HeimdallProxyAutoScalingGroup
      Cooldown: '60'
      ScalingAdjustment: '1'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a91d43f5-bb88-4305-8220-8621e84771a4
  HeimdallProxyScaleDownPolicy:
    Type: 'AWS::AutoScaling::ScalingPolicy'
    Properties:
      AdjustmentType: ChangeInCapacity
      AutoScalingGroupName: !Ref HeimdallProxyAutoScalingGroup
      Cooldown: '60'
      ScalingAdjustment: '-1'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 662a6ed5-4d47-488d-89b0-4ff2eba99817
  HeimdallProxyCPUAlarmHigh:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      AlarmDescription: Scale-up if CPU > 65% for 3 minutes
      MetricName: CPUUtilization
      Namespace: AWS/EC2
      Statistic: Average
      Period: '60'
      EvaluationPeriods: '3'
      Threshold: '65'
      AlarmActions:
        - !Ref HeimdallProxyScaleUpPolicy
      Dimensions:
        - Name: AutoScalingGroupName
          Value: !Ref HeimdallProxyAutoScalingGroup
      ComparisonOperator: GreaterThanThreshold
    Metadata:
      'AWS::CloudFormation::Designer':
        id: f13bafeb-8014-489d-a066-9910c4554ee2
  HeimdallProxyCPUAlarmLow:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      AlarmDescription: Scale-down if CPU < 40% for 6 minutes
      MetricName: CPUUtilization
      Namespace: AWS/EC2
      Statistic: Average
      Period: '60'
      EvaluationPeriods: '6'
      Threshold: '40'
      AlarmActions:
        - !Ref HeimdallProxyScaleDownPolicy
      Dimensions:
        - Name: AutoScalingGroupName
          Value: !Ref HeimdallProxyAutoScalingGroup
      ComparisonOperator: LessThanThreshold
    Metadata:
      'AWS::CloudFormation::Designer':
        id: fbb5ee8e-a3ea-4616-a3ab-bf77a0f0f012
Outputs:
  LoadBalancerUrl:
    Description: The hostname for load balanced db access
    Value: !GetAtt 
      - HeimdallProxyLoadBalancer
      - DNSName


Autoscaling Proxy Template via DNS Delegation

This template leverages the new auto-scaling feature to allow any name to be delegated to the Heimdall proxies, and they will return the actual IP address of the proxy to connect to.
The benefit of this template is that it only uses NLB for DNS traffic, so reduces the cost of NLB significantly, at the cost of slightly less even distribution of connections across the proxies.
This configuration requires the DNS port to be specified to port 54 in the Advanced features, and a monitoring port of 80 to be specified, which is used to monitor the proxies for the NLB, as DNS health checks are not present in NLB. To allow for comparison with the NLB feature however, it ALSO provides NLB, and further, includes two names in route53, one to do an auto-failover to bypass the DNS resolution and one to auto-fail, bypassing the NLB.

This template should be considered more advanced, and in general, you should use it with assistance from Heimdall support.

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  HeimdallProxyAMIID:
    Type: String
    Default: ami-03be693a813561f6e
    Description: The Enterprise Edition AMI ID to use
  HeimdallProxyVPC:
    Type: 'AWS::EC2::VPC::Id'
    Description: >-
      VPC ID for Proxy Use, should generally match the database's VPC being
      accessed
  HeimdallProxyAvailabilityZones:
    Type: 'List<AWS::EC2::AvailabilityZone::Name>'
    Description: Availability zones for NLB Deployment
  HeimdallProxySubnetList:
    Type: 'List<AWS::EC2::Subnet::Id>'
    Description: >-
      Subnet IDs for ELB for Proxy Deployment (ensure to match the AZ's and
      availability zones selected)
  hdHost:
    Type: String
    Default: ip-172-31-54-43.ec2.internal
    Description: >-
      Private Hostname of Heimdall Central Manager, do not use the public
      hostname if present
  hdUser:
    Type: String
    Default: admin
    Description: Central Manager Username OR proxy access key from vdb configuration
  hdPassword:
    Type: String
    Description: Central Manager Password OR proxy secret key from vdb configuration
  vdbName:
    Type: String
    Default: Odoo-vdb
    Description: >-
      VDB Name configured in central manager.  Multiple names can be provided,
      comma seperated, to run more than one proxy on a single instance
  dbEndpointName:
    Type: String
    Default: database-1.cluster-cfjxl5jnvj49.us-east-1.rds.amazonaws.com
    Description: >-
      Name of the Database writer endpoint to fail to in the event the proxies
      fail for some reason
  DnsPort:
    Description: >-
      Database DNS port--note, this should NOT be port 53, to avoid conflicting
      with systemd-resolve
    Type: Number
    Default: 54
    ConstraintDescription: Provide the DNS port (default 54)
  HttpPort:
    Description: 'HTTP health check port, as configured in the advanced section'
    Type: Number
    Default: 80
    ConstraintDescription: Provide the HTTP health check port
  ProxyPort:
    Description: Proxy port used to access the database
    Type: Number
    ConstraintDescription: proxy port to setup for the security group
  ProxyMinimum:
    Description: Minimum number of proxies
    Type: Number
    Default: 2
    ConstraintDescription: How many proxies should be in operation at minimum
  ProxyMaximum:
    Description: Maximum number of proxies
    Type: Number
    Default: 4
    ConstraintDescription: How many proxies should be in operation at most
  InstanceTypeParameterProxy:
    Type: String
    Default: t3.medium
    AllowedValues:
      - t3.medium
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
      - c5n.large
      - c5n.xlarge
      - c5n.2xlarge
      - c5n.4xlarge
    Description: Enter Proxy instance type (autoscaling)
  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
    Type: 'AWS::EC2::KeyPair::KeyName'
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
  DNSZoneName:
    Description: DNS Zone to add proxy hostname to (must end in a .)
    Type: String
    Default: test.heimdalldata.com.
    ConstraintDescription: DNS Zone (already existing) to publish the proxy alias to
Metadata:
  Generator: ''
  'AWS::CloudFormation::Designer':
    d2b3fbb5-c87c-490d-b0ff-5c0804f855f0:
      size:
        width: 60
        height: 60
      position:
        x: 660
        'y': 480
      z: 1
      embeds: []
    dc671d3b-807c-4ea9-b368-7e3d534e22e1:
      size:
        width: 60
        height: 60
      position:
        x: 660
        'y': 390
      z: 1
      embeds: []
    5311a68f-b7ab-48e1-b1d7-9038174cf489:
      size:
        width: 60
        height: 60
      position:
        x: 540
        'y': 390
      z: 1
      embeds: []
      isassociatedwith:
        - 0e9f449e-767d-4419-aac9-2e7fe29f4fd4
        - dc671d3b-807c-4ea9-b368-7e3d534e22e1
    fbdc2e18-b910-405e-aeed-433c01a5a71b:
      size:
        width: 60
        height: 60
      position:
        x: 540
        'y': 480
      z: 1
      embeds: []
      isassociatedwith:
        - d2b3fbb5-c87c-490d-b0ff-5c0804f855f0
    34e5960d-26f6-4d11-aae1-85c02c36b986:
      size:
        width: 60
        height: 60
      position:
        x: 420
        'y': 480
      z: 1
      embeds: []
      isassociatedwith:
        - fbdc2e18-b910-405e-aeed-433c01a5a71b
        - ded7f98f-10d3-4e44-a367-bd3cb1ea347e
        - a5c43870-1e9e-4581-b418-cbd133f52876
        - 207e796b-3b6a-4fa5-ba3d-77fd21933d57
    ded7f98f-10d3-4e44-a367-bd3cb1ea347e:
      size:
        width: 60
        height: 60
      position:
        x: 300
        'y': 300
      z: 1
      embeds: []
    57399634-3282-4398-94cd-e5b1ab3455bf:
      size:
        width: 60
        height: 60
      position:
        x: 70
        'y': 260
      z: 1
      embeds: []
    f5ca956b-6572-44a5-99d9-17899f5a826a:
      size:
        width: 60
        height: 60
      position:
        x: 180
        'y': 300
      z: 1
      embeds: []
    662a6ed5-4d47-488d-89b0-4ff2eba99817:
      size:
        width: 60
        height: 60
      position:
        x: 180
        'y': 540
      z: 1
      embeds: []
      isassociatedwith:
        - 34e5960d-26f6-4d11-aae1-85c02c36b986
    fbb5ee8e-a3ea-4616-a3ab-bf77a0f0f012:
      size:
        width: 60
        height: 60
      position:
        x: 300
        'y': 600
      z: 1
      embeds: []
    a91d43f5-bb88-4305-8220-8621e84771a4:
      size:
        width: 60
        height: 60
      position:
        x: 180
        'y': 450
      z: 1
      embeds: []
      isassociatedwith:
        - 34e5960d-26f6-4d11-aae1-85c02c36b986
    f13bafeb-8014-489d-a066-9910c4554ee2:
      size:
        width: 60
        height: 60
      position:
        x: 300
        'y': 390
      z: 1
      embeds: []
    0b44a3b8-3e72-4842-b623-aabc47720f16:
      size:
        width: 60
        height: 60
      position:
        x: 70
        'y': 370
      z: 1
      embeds: []
    ba093db1-0be8-47f0-bbf6-1aa822d7a1ed:
      size:
        width: 60
        height: 60
      position:
        x: -60
        'y': 210
      z: 1
      embeds: []
    a5c43870-1e9e-4581-b418-cbd133f52876:
      size:
        width: 60
        height: 60
      position:
        x: 300
        'y': 210
      z: 1
      embeds: []
    48e11edd-a43c-451c-9fc3-90eb329d11f9:
      size:
        width: 60
        height: 60
      position:
        x: 180
        'y': 210
      z: 1
      embeds: []
    050c1571-1da4-409e-be2f-56abd1f824f5:
      size:
        width: 60
        height: 60
      position:
        x: -200
        'y': 320
      z: 1
      embeds: []
    238769a0-93c4-4a2d-b66a-01efa9b6ec8e:
      size:
        width: 60
        height: 60
      position:
        x: -60
        'y': 320
      z: 1
      embeds: []
      isassociatedwith:
        - 050c1571-1da4-409e-be2f-56abd1f824f5
    feaba556-827c-4448-94bf-8495c8abbe3d:
      size:
        width: 60
        height: 60
      position:
        x: -60
        'y': 410
      z: 1
      embeds: []
    8db8f5cb-05a3-47a9-b2b5-77d9442554b1:
      size:
        width: 60
        height: 60
      position:
        x: -60
        'y': 40
      z: 1
      embeds: []
    db4bb256-25a0-4c56-8c2a-8705f9ed0235:
      size:
        width: 60
        height: 60
      position:
        x: 70
        'y': 120
      z: 1
      embeds: []
    207e796b-3b6a-4fa5-ba3d-77fd21933d57:
      size:
        width: 60
        height: 60
      position:
        x: 300
        'y': 120
      z: 1
      embeds: []
    a88d7daf-3d42-4f38-a99a-d19e461102c9:
      size:
        width: 60
        height: 60
      position:
        x: 180
        'y': 120
      z: 1
      embeds: []
    210a3d78-edfc-448a-8dd8-590fa5cedb8f:
      size:
        width: 60
        height: 60
      position:
        x: -60
        'y': 120
      z: 1
      embeds: []
      isassociatedwith:
        - 050c1571-1da4-409e-be2f-56abd1f824f5
Description: HA Template for Heimdall Data Access Platform
Resources:
  HeimdallProxyHealthCheck:
    Type: 'AWS::Route53::HealthCheck'
    Properties:
      HealthCheckConfig:
        Port: 80
        Type: HTTP
        ResourcePath: /status
        FullyQualifiedDomainName: !GetAtt 
          - HeimdallProxyLoadBalancer
          - DNSName
        RequestInterval: 10
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 050c1571-1da4-409e-be2f-56abd1f824f5
  HeimdallProxyIAM:
    Type: 'AWS::IAM::Role'
    Properties:
      Path: /
      AssumeRolePolicyDocument: >-
        {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}]}
      MaxSessionDuration: 3600
      RoleName: !Join 
        - '-'
        - - !Ref 'AWS::StackName'
          - proxy
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/CloudWatchFullAccess'
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: dc671d3b-807c-4ea9-b368-7e3d534e22e1
  HeimdallProxyIAMInstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      Path: /
      Roles:
        - !Ref HeimdallProxyIAM
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 5311a68f-b7ab-48e1-b1d7-9038174cf489
  HeimdallProxySecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupName: !Join 
        - '-'
        - - !Ref 'AWS::StackName'
          - proxySG
      GroupDescription: Security group for Heimdall Proxy
      VpcId: !Ref HeimdallProxyVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          CidrIp: 0.0.0.0/0
          FromPort: 22
          ToPort: 22
        - IpProtocol: tcp
          CidrIp: 0.0.0.0/0
          FromPort: !Ref HttpPort
          ToPort: !Ref HttpPort
        - IpProtocol: udp
          CidrIp: 0.0.0.0/0
          FromPort: !Ref DnsPort
          ToPort: !Ref DnsPort
        - IpProtocol: tcp
          CidrIp: 0.0.0.0/0
          FromPort: !Ref ProxyPort
          ToPort: !Ref ProxyPort
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: d2b3fbb5-c87c-490d-b0ff-5c0804f855f0
  ProxyLaunchConfig:
    Type: 'AWS::AutoScaling::LaunchConfiguration'
    Properties:
      AssociatePublicIpAddress: false
      IamInstanceProfile: !Ref HeimdallProxyIAMInstanceProfile
      ImageId: !Ref HeimdallProxyAMIID
      InstanceMonitoring: true
      InstanceType: !Ref InstanceTypeParameterProxy
      KeyName: !Ref KeyName
      SecurityGroups:
        - !Ref HeimdallProxySecurityGroup
      LaunchConfigurationName: !Join 
        - '-'
        - - !Ref 'AWS::StackName'
          - proxy
      UserData: !Base64 
        'Fn::Join':
          - ''
          - - '#!/bin/bash'
            - |-

              echo "hdRole=proxy
              hdPort=8087
            - |-

              vdbName=
            - !Ref vdbName
            - |-

              hdHost=
            - !Ref hdHost
            - |-

              hdUser=
            - !Ref hdUser
            - |-

              hdPassword=
            - !Ref hdPassword
            - |-

              " > /etc/heimdall.conf
            - |-

              yum -y update
            - |-

              systemctl restart heimdall
    Metadata:
      'AWS::CloudFormation::Designer':
        id: fbdc2e18-b910-405e-aeed-433c01a5a71b
  HeimdallProxyAutoScalingGroup:
    Type: 'AWS::AutoScaling::AutoScalingGroup'
    Version: 2020-04-22
    Properties:
      AvailabilityZones: !Ref HeimdallProxyAvailabilityZones
      VPCZoneIdentifier: !Ref HeimdallProxySubnetList
      LaunchConfigurationName: !Ref ProxyLaunchConfig
      TargetGroupARNs:
        - !Ref HeimdallProxyTargetGroup
        - !Ref HeimdallProxyHTTPTargetGroup
        - !Ref HeimdallProxyDBProtoTargetGroup
      MinSize: !Ref ProxyMinimum
      MaxSize: !Ref ProxyMaximum
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
          PropagateAtLaunch: true
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 34e5960d-26f6-4d11-aae1-85c02c36b986
  HeimdallProxyTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      Port: !Ref DnsPort
      Protocol: UDP
      HealthCheckProtocol: HTTP
      HealthCheckPort: 80
      HealthCheckPath: /status
      HealthCheckIntervalSeconds: 10
      HealthyThresholdCount: 3
      VpcId: !Ref HeimdallProxyVPC
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: 60
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: ded7f98f-10d3-4e44-a367-bd3cb1ea347e
  HeimdallProxyHTTPTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      Port: !Ref HttpPort
      Protocol: TCP
      HealthCheckProtocol: HTTP
      HealthCheckPort: 80
      HealthCheckPath: /status
      HealthCheckIntervalSeconds: 10
      HealthyThresholdCount: 3
      VpcId: !Ref HeimdallProxyVPC
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: 60
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - httpproxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a5c43870-1e9e-4581-b418-cbd133f52876
  HeimdallProxyDBProtoTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      Port: !Ref ProxyPort
      Protocol: TCP
      HealthCheckProtocol: HTTP
      HealthCheckPort: 80
      HealthCheckPath: /status
      HealthCheckIntervalSeconds: 10
      HealthyThresholdCount: 3
      VpcId: !Ref HeimdallProxyVPC
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: 60
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - dbproxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 207e796b-3b6a-4fa5-ba3d-77fd21933d57
  HeimdallProxyLoadBalancer:
    Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
    Properties:
      Scheme: internet-facing
      Type: network
      Subnets: !Ref HeimdallProxySubnetList
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 57399634-3282-4398-94cd-e5b1ab3455bf
  HeimdallDBProxyLoadBalancer:
    Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
    Properties:
      Scheme: internal
      Type: network
      Subnets: !Ref HeimdallProxySubnetList
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: db4bb256-25a0-4c56-8c2a-8705f9ed0235
  HeimdallProxyLoadBalancerListener:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref HeimdallProxyTargetGroup
      LoadBalancerArn: !Ref HeimdallProxyLoadBalancer
      Port: 53
      Protocol: UDP
    Metadata:
      'AWS::CloudFormation::Designer':
        id: f5ca956b-6572-44a5-99d9-17899f5a826a
  HeimdallProxyHTTPLoadBalancerListener:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref HeimdallProxyHTTPTargetGroup
      LoadBalancerArn: !Ref HeimdallProxyLoadBalancer
      Port: !Ref HttpPort
      Protocol: TCP
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 48e11edd-a43c-451c-9fc3-90eb329d11f9
  HeimdallProxyDBLoadBalancerListener:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref HeimdallProxyDBProtoTargetGroup
      LoadBalancerArn: !Ref HeimdallDBProxyLoadBalancer
      Port: !Ref ProxyPort
      Protocol: TCP
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a88d7daf-3d42-4f38-a99a-d19e461102c9
  HeimdallProxyScaleUpPolicy:
    Type: 'AWS::AutoScaling::ScalingPolicy'
    Properties:
      AdjustmentType: ChangeInCapacity
      AutoScalingGroupName: !Ref HeimdallProxyAutoScalingGroup
      Cooldown: '60'
      ScalingAdjustment: '1'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a91d43f5-bb88-4305-8220-8621e84771a4
  HeimdallProxyScaleDownPolicy:
    Type: 'AWS::AutoScaling::ScalingPolicy'
    Properties:
      AdjustmentType: ChangeInCapacity
      AutoScalingGroupName: !Ref HeimdallProxyAutoScalingGroup
      Cooldown: '60'
      ScalingAdjustment: '-1'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 662a6ed5-4d47-488d-89b0-4ff2eba99817
  HeimdallProxyCPUAlarmHigh:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      AlarmDescription: Scale-up if CPU > 65% for 2 minutes
      MetricName: CPUUtilization
      Namespace: AWS/EC2
      Statistic: Average
      Period: '60'
      EvaluationPeriods: '2'
      Threshold: '65'
      AlarmActions:
        - !Ref HeimdallProxyScaleUpPolicy
      Dimensions:
        - Name: AutoScalingGroupName
          Value: !Ref HeimdallProxyAutoScalingGroup
      ComparisonOperator: GreaterThanThreshold
    Metadata:
      'AWS::CloudFormation::Designer':
        id: f13bafeb-8014-489d-a066-9910c4554ee2
  HeimdallProxyCPUAlarmLow:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      AlarmDescription: Scale-down if CPU < 40% for 6 minutes
      MetricName: CPUUtilization
      Namespace: AWS/EC2
      Statistic: Average
      Period: '60'
      EvaluationPeriods: '6'
      Threshold: '40'
      AlarmActions:
        - !Ref HeimdallProxyScaleDownPolicy
      Dimensions:
        - Name: AutoScalingGroupName
          Value: !Ref HeimdallProxyAutoScalingGroup
      ComparisonOperator: LessThanThreshold
    Metadata:
      'AWS::CloudFormation::Designer':
        id: fbb5ee8e-a3ea-4616-a3ab-bf77a0f0f012
  HeimdallDNSNLB:
    Type: 'AWS::Route53::RecordSetGroup'
    Properties:
      HostedZoneName: !Ref DNSZoneName
      Comment: Zone apex alias targeted to HeimdallProxyLoadBalancer LoadBalancer.
      RecordSets:
        - Name: !Join 
            - ''
            - - !Ref 'AWS::StackName'
              - '-dns.'
              - !Ref DNSZoneName
          Type: A
          AliasTarget:
            HostedZoneId: !GetAtt 
              - HeimdallProxyLoadBalancer
              - CanonicalHostedZoneID
            DNSName: !GetAtt 
              - HeimdallProxyLoadBalancer
              - DNSName
    Metadata:
      'AWS::CloudFormation::Designer':
        id: ba093db1-0be8-47f0-bbf6-1aa822d7a1ed
  HeimdallDNSProxy:
    Type: 'AWS::Route53::RecordSetGroup'
    Properties:
      HostedZoneName: !Ref DNSZoneName
      Comment: proxy name to delegate to the proxies themselves
      RecordSets:
        - Name: !Join 
            - ''
            - - !Ref 'AWS::StackName'
              - '-proxy.'
              - !Ref DNSZoneName
          Type: NS
          TTL: '3600'
          ResourceRecords:
            - !Join 
              - ''
              - - !Ref 'AWS::StackName'
                - '-dns.'
                - !Ref DNSZoneName
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 0b44a3b8-3e72-4842-b623-aabc47720f16
  HeimdallDBNamePrimary:
    Type: 'AWS::Route53::RecordSet'
    Properties:
      HostedZoneName: !Ref DNSZoneName
      Comment: 'Name to use to actually connect to the database, includes failover'
      Name: !Join 
        - ''
        - - !Ref 'AWS::StackName'
          - '-db.'
          - !Ref DNSZoneName
      Type: CNAME
      TTL: '30'
      ResourceRecords:
        - !Join 
          - ''
          - - !Ref 'AWS::StackName'
            - '-proxy.'
            - !Ref DNSZoneName
      Failover: PRIMARY
      SetIdentifier: Primary
      HealthCheckId: !Ref HeimdallProxyHealthCheck
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 238769a0-93c4-4a2d-b66a-01efa9b6ec8e
  HeimdallDBNameSecondary:
    Type: 'AWS::Route53::RecordSet'
    Properties:
      HostedZoneName: !Ref DNSZoneName
      Name: !Join 
        - ''
        - - !Ref 'AWS::StackName'
          - '-db.'
          - !Ref DNSZoneName
      Comment: >-
        Name to use to actually connect to the database, includes failover
        (secondary)
      Failover: SECONDARY
      SetIdentifier: Backup
      Type: CNAME
      TTL: '30'
      ResourceRecords:
        - !Join 
          - ''
          - - !Ref dbEndpointName
    Metadata:
      'AWS::CloudFormation::Designer':
        id: feaba556-827c-4448-94bf-8495c8abbe3d
  HeimdallDBNLBNamePrimary:
    Type: 'AWS::Route53::RecordSet'
    Properties:
      HostedZoneName: !Ref DNSZoneName
      Comment: >-
        Name to use to actually connect to the database, includes failover, via
        NLB
      Name: !Join 
        - ''
        - - !Ref 'AWS::StackName'
          - '-dbnlb.'
          - !Ref DNSZoneName
      Type: CNAME
      TTL: '30'
      ResourceRecords: 
        - !Join 
          - ''
          - - !GetAtt 
              - HeimdallDBProxyLoadBalancer
              - DNSName
      Failover: PRIMARY
      SetIdentifier: Primary
      HealthCheckId: !Ref HeimdallProxyHealthCheck
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 210a3d78-edfc-448a-8dd8-590fa5cedb8f
  HeimdallDBNLBNameSecondary:
    Type: 'AWS::Route53::RecordSet'
    Properties:
      HostedZoneName: !Ref DNSZoneName
      Name: !Join 
        - ''
        - - !Ref 'AWS::StackName'
          - '-dbnlb.'
          - !Ref DNSZoneName
      Comment: >-
        Name to use to actually connect to the database, includes failover
        (secondary)
      Failover: SECONDARY
      SetIdentifier: Backup
      Type: CNAME
      TTL: '30'
      ResourceRecords:
        - !Join 
          - ''
          - - !Ref dbEndpointName
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 8db8f5cb-05a3-47a9-b2b5-77d9442554b1

Autoscaling Proxy Template w/ Distinct Read and Write Ports

An alternate configuration template for a proxy is one where there is a distinct read vs. write port on the LB, which is supported by the following:

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  HeimdallProxyAMIID:
    Type: String
    Default: ami-0496a2e9f2d6890ec
    Description: The Enterprise Edition AMI ID to use
  HeimdallProxyVPC:
    Type: 'AWS::EC2::VPC::Id'
    Description: >-
      VPC ID for Proxy Use, should generally match the database's VPC being
      accessed
  HeimdallProxyAvailabilityZones:
    Type: 'List<AWS::EC2::AvailabilityZone::Name>'
    Description: Availability zones for NLB Deployment
  HeimdallProxySubnetList:
    Type: 'List<AWS::EC2::Subnet::Id>'
    Description: >-
      Subnet IDs for ELB for Proxy Deployment (ensure to match the AZ's and
      availability zones selected)
  hdHost:
    Type: String
    Description: >-
      Private Hostname of Heimdall Central Manager, do not use the public
      hostname if present
  hdUser:
    Type: String
    Default: admin
    Description: Central Manager Username OR proxy access key from vdb configuration
  hdPassword:
    Type: String
    Description: Central Manager Password OR proxy secret key from vdb configuration
  vdbName:
    Type: String
    Description: VDB Name configured in central manager
  WriteProxyPort:
    Description: Database Proxy port for read/write access
    Type: Number
    Default: 3306
    ConstraintDescription: >-
      Provide the port the proxies are expected to run on (typically the same as
      the back-end database, i.e. 3306 for mysql, 5432 for postgres, or 1433 for
      SQL Server), needed to create a security group for the proxies
  ReadProxyPort:
    Description: Database Proxy port for read-only access
    Type: Number
    Default: 3307
    ConstraintDescription: >-
      Provide the port the proxies are expected to run on (typically the same as
      the back-end database, i.e. 3306 for mysql, 5432 for postgres, or 1433 for
      SQL Server), needed to create a security group for the proxies
  ProxyMinimum:
    Description: Minimum number of proxies
    Type: Number
    Default: 2
    ConstraintDescription: How many proxies should be in operation at minimum
  ProxyMaximum:
    Description: Maximum number of proxies
    Type: Number
    Default: 4
    ConstraintDescription: How many proxies should be in operation at most
  InstanceTypeParameterProxy:
    Type: String
    Default: c5.xlarge
    AllowedValues:
      - t3.medium
      - c5.large
      - c5.xlarge
      - c5.2xlarge
      - c5.4xlarge
    Description: Enter Proxy instance type (autoscaling)
  KeyName:
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
    Type: 'AWS::EC2::KeyPair::KeyName'
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
Metadata:
  Generator: ''
  'AWS::CloudFormation::Designer':
    d2b3fbb5-c87c-490d-b0ff-5c0804f855f0:
      size:
        width: 60
        height: 60
      position:
        x: 670
        'y': 360
      z: 1
      embeds: []
    dc671d3b-807c-4ea9-b368-7e3d534e22e1:
      size:
        width: 60
        height: 60
      position:
        x: 670
        'y': 220
      z: 1
      embeds: []
    5311a68f-b7ab-48e1-b1d7-9038174cf489:
      size:
        width: 60
        height: 60
      position:
        x: 560
        'y': 220
      z: 1
      embeds: []
      isassociatedwith:
        - 0e9f449e-767d-4419-aac9-2e7fe29f4fd4
        - dc671d3b-807c-4ea9-b368-7e3d534e22e1
    fbdc2e18-b910-405e-aeed-433c01a5a71b:
      size:
        width: 60
        height: 60
      position:
        x: 560
        'y': 360
      z: 1
      embeds: []
      isassociatedwith:
        - d2b3fbb5-c87c-490d-b0ff-5c0804f855f0
    34e5960d-26f6-4d11-aae1-85c02c36b986:
      size:
        width: 60
        height: 60
      position:
        x: 430
        'y': 360
      z: 1
      embeds: []
      isassociatedwith:
        - fbdc2e18-b910-405e-aeed-433c01a5a71b
        - ded7f98f-10d3-4e44-a367-bd3cb1ea347e
        - 48ab2256-30e8-430c-9ad4-d305b9a7452b
    ded7f98f-10d3-4e44-a367-bd3cb1ea347e:
      size:
        width: 60
        height: 60
      position:
        x: 310
        'y': 180
      z: 1
      embeds: []
    f5ca956b-6572-44a5-99d9-17899f5a826a:
      size:
        width: 60
        height: 60
      position:
        x: 210
        'y': 180
      z: 1
      embeds: []
      isassociatedwith:
        - 57399634-3282-4398-94cd-e5b1ab3455bf
        - e6ff7758-5c9c-45ae-9dad-4879249d8690
    662a6ed5-4d47-488d-89b0-4ff2eba99817:
      size:
        width: 60
        height: 60
      position:
        x: 100
        'y': 560
      z: 1
      embeds: []
      isassociatedwith:
        - 34e5960d-26f6-4d11-aae1-85c02c36b986
    fbb5ee8e-a3ea-4616-a3ab-bf77a0f0f012:
      size:
        width: 60
        height: 60
      position:
        x: 210
        'y': 560
      z: 1
      embeds: []
    a91d43f5-bb88-4305-8220-8621e84771a4:
      size:
        width: 60
        height: 60
      position:
        x: 100
        'y': 410
      z: 1
      embeds: []
      isassociatedwith:
        - 34e5960d-26f6-4d11-aae1-85c02c36b986
    f13bafeb-8014-489d-a066-9910c4554ee2:
      size:
        width: 60
        height: 60
      position:
        x: 210
        'y': 410
      z: 1
      embeds: []
    48ab2256-30e8-430c-9ad4-d305b9a7452b:
      size:
        width: 60
        height: 60
      position:
        x: 310
        'y': 270
      z: 1
      embeds: []
    e6ff7758-5c9c-45ae-9dad-4879249d8690:
      size:
        width: 60
        height: 60
      position:
        x: 80
        'y': 220
      z: 1
      embeds: []
    055ac643-55d8-4451-ac6c-12f50b940b44:
      size:
        width: 60
        height: 60
      position:
        x: 210
        'y': 270
      z: 1
      embeds: []
      isassociatedwith:
        - e6ff7758-5c9c-45ae-9dad-4879249d8690
Description: HA Template for Heimdall Data Access Platform
Resources:
  HeimdallProxyIAM:
    Type: 'AWS::IAM::Role'
    Properties:
      Path: /
      AssumeRolePolicyDocument: >-
        {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ec2.amazonaws.com"},"Action":"sts:AssumeRole"}]}
      MaxSessionDuration: 3600
      RoleName: !Join 
        - '-'
        - - !Ref 'AWS::StackName'
          - proxy
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/CloudWatchFullAccess'
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: dc671d3b-807c-4ea9-b368-7e3d534e22e1
  HeimdallProxyIAMInstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      Path: /
      Roles:
        - !Ref HeimdallProxyIAM
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 5311a68f-b7ab-48e1-b1d7-9038174cf489
  HeimdallProxySecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupName: !Join 
        - '-'
        - - !Ref 'AWS::StackName'
          - proxySG
      GroupDescription: Security group for Heimdall Proxy
      VpcId: !Ref HeimdallProxyVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          CidrIp: 0.0.0.0/0
          FromPort: 22
          ToPort: 22
        - IpProtocol: tcp
          CidrIp: 0.0.0.0/0
          FromPort: !Ref WriteProxyPort
          ToPort: !Ref WriteProxyPort
        - IpProtocol: tcp
          CidrIp: 0.0.0.0/0
          FromPort: !Ref ReadProxyPort
          ToPort: !Ref ReadProxyPort
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: d2b3fbb5-c87c-490d-b0ff-5c0804f855f0
  ProxyLaunchConfig:
    Type: 'AWS::AutoScaling::LaunchConfiguration'
    Properties:
      AssociatePublicIpAddress: false
      IamInstanceProfile: !Ref HeimdallProxyIAMInstanceProfile
      ImageId: !Ref HeimdallProxyAMIID
      InstanceMonitoring: true
      InstanceType: !Ref InstanceTypeParameterProxy
      KeyName: !Ref KeyName
      SecurityGroups:
        - !Ref HeimdallProxySecurityGroup
      LaunchConfigurationName: !Join 
        - '-'
        - - !Ref 'AWS::StackName'
          - proxy
      UserData: !Base64 
        'Fn::Join':
          - ''
          - - '#!/bin/bash'
            - |-

              echo "hdRole=proxy
              hdPort=8087
            - |-

              vdbName=
            - !Ref vdbName
            - |-

              hdHost=
            - !Ref hdHost
            - |-

              hdUser=
            - !Ref hdUser
            - |-

              hdPassword=
            - !Ref hdPassword
            - |-

              " > /etc/heimdall.conf
            - |-

              yum -y update
            - |-

              systemctl restart heimdall
    Metadata:
      'AWS::CloudFormation::Designer':
        id: fbdc2e18-b910-405e-aeed-433c01a5a71b
  HeimdallProxyAutoScalingGroup:
    Type: 'AWS::AutoScaling::AutoScalingGroup'
    Version: 2020-04-22
    Properties:
      AvailabilityZones: !Ref HeimdallProxyAvailabilityZones
      VPCZoneIdentifier: !Ref HeimdallProxySubnetList
      LaunchConfigurationName: !Ref ProxyLaunchConfig
      TargetGroupARNs:
        - !Ref HeimdallProxyWriteTargetGroup
        - !Ref HeimdallProxyReadTargetGroup
      MinSize: !Ref ProxyMinimum
      MaxSize: !Ref ProxyMaximum
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
          PropagateAtLaunch: true
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 34e5960d-26f6-4d11-aae1-85c02c36b986
  HeimdallProxyWriteTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      Port: !Ref WriteProxyPort
      Protocol: TCP
      VpcId: !Ref HeimdallProxyVPC
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: 60
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 48ab2256-30e8-430c-9ad4-d305b9a7452b
  HeimdallProxyReadTargetGroup:
    Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
    Properties:
      Port: !Ref ReadProxyPort
      Protocol: TCP
      VpcId: !Ref HeimdallProxyVPC
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: 60
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: ded7f98f-10d3-4e44-a367-bd3cb1ea347e
  HeimdallProxyLoadBalancer:
    Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
    Properties:
      Scheme: internal
      Type: network
      Subnets: !Ref HeimdallProxySubnetList
      Tags:
        - Key: Name
          Value: !Join 
            - '-'
            - - !Ref 'AWS::StackName'
              - proxy
    Metadata:
      'AWS::CloudFormation::Designer':
        id: e6ff7758-5c9c-45ae-9dad-4879249d8690
  HeimdallProxyWriteLoadBalancerListener:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref HeimdallProxyWriteTargetGroup
      LoadBalancerArn: !Ref HeimdallProxyLoadBalancer
      Port: !Ref WriteProxyPort
      Protocol: TCP
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 055ac643-55d8-4451-ac6c-12f50b940b44
  HeimdallProxyReadLoadBalancerListener:
    Type: 'AWS::ElasticLoadBalancingV2::Listener'
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref HeimdallProxyReadTargetGroup
      LoadBalancerArn: !Ref HeimdallProxyLoadBalancer
      Port: !Ref ReadProxyPort
      Protocol: TCP
    Metadata:
      'AWS::CloudFormation::Designer':
        id: f5ca956b-6572-44a5-99d9-17899f5a826a
  HeimdallProxyScaleUpPolicy:
    Type: 'AWS::AutoScaling::ScalingPolicy'
    Properties:
      AdjustmentType: ChangeInCapacity
      AutoScalingGroupName: !Ref HeimdallProxyAutoScalingGroup
      Cooldown: '60'
      ScalingAdjustment: '1'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: a91d43f5-bb88-4305-8220-8621e84771a4
  HeimdallProxyScaleDownPolicy:
    Type: 'AWS::AutoScaling::ScalingPolicy'
    Properties:
      AdjustmentType: ChangeInCapacity
      AutoScalingGroupName: !Ref HeimdallProxyAutoScalingGroup
      Cooldown: '60'
      ScalingAdjustment: '-1'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 662a6ed5-4d47-488d-89b0-4ff2eba99817
  HeimdallProxyCPUAlarmHigh:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      AlarmDescription: Scale-up if CPU > 65% for 3 minutes
      MetricName: CPUUtilization
      Namespace: AWS/EC2
      Statistic: Average
      Period: '60'
      EvaluationPeriods: '3'
      Threshold: '65'
      AlarmActions:
        - !Ref HeimdallProxyScaleUpPolicy
      Dimensions:
        - Name: AutoScalingGroupName
          Value: !Ref HeimdallProxyAutoScalingGroup
      ComparisonOperator: GreaterThanThreshold
    Metadata:
      'AWS::CloudFormation::Designer':
        id: f13bafeb-8014-489d-a066-9910c4554ee2
  HeimdallProxyCPUAlarmLow:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      AlarmDescription: Scale-down if CPU < 40% for 6 minutes
      MetricName: CPUUtilization
      Namespace: AWS/EC2
      Statistic: Average
      Period: '60'
      EvaluationPeriods: '6'
      Threshold: '40'
      AlarmActions:
        - !Ref HeimdallProxyScaleDownPolicy
      Dimensions:
        - Name: AutoScalingGroupName
          Value: !Ref HeimdallProxyAutoScalingGroup
      ComparisonOperator: LessThanThreshold
    Metadata:
      'AWS::CloudFormation::Designer':
        id: fbb5ee8e-a3ea-4616-a3ab-bf77a0f0f012
Outputs:
  LoadBalancerUrl:
    Description: The hostname for load balanced db access (read/write)
    Value: !GetAtt 
      - HeimdallProxyLoadBalancer
      - DNSName

Autoscaling/Redundant Central Manager Template

If redundancy of the central manager is desired, the following CF template can be used:

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Parameters": {
        "HeimdallCentralManagerAMIID": {
            "Type": "String",
            "Default": "ami-0496a2e9f2d6890ec",
            "Description": "The Enterprise Edition AMI ID to use"
        },
        "HeimdallCentralManagerVPC": {
            "Type": "AWS::EC2::VPC::Id",
            "Description": "VPC ID for Central Manager Use, should generally match the database's VPC being accessed"
        },
        "HeimdallCentralManagerAvailabilityZones": {
            "Type": "List<AWS::EC2::AvailabilityZone::Name>",
            "Description": "Availability zones for NLB Deployment"
        },
        "HeimdallCentralManagerSubnetList": {
            "Type": "List<AWS::EC2::Subnet::Id>",
            "Description": "Subnet IDs for ELB for central manager deployment (ensure to match the AZ's and availability zones selected)"
        },
        "configSource": {
            "Type": "String",
            "Default": "s3://mybucket/dir",
            "Description": "Source S3 Bucket URL for Initial Configuration, \"none\" for none"
        },
        "hdUser": {
            "Type": "String",
            "Default": "admin",
            "Description": "Central Manager Default Username"
        },
        "hdPassword": {
            "Type": "String",
            "Description": "Central Manager Default Password"
        },
        "CentralManagerMinimum": {
            "Description": "Minimum Number of Central Managers",
            "Type": "Number",
            "Default": 1,
            "ConstraintDescription": "How many central managers should be in operation at minimum"
        },
        "CentralManagerMaximum": {
            "Description": "Maximum number of Central Managers",
            "Type": "Number",
            "Default": 2,
            "ConstraintDescription": "How many central managers should be in operation at most"
        },
        "InstanceTypeParameterCentralManager": {
            "Type": "String",
            "Default": "c5.xlarge",
            "AllowedValues": [
                "t3.medium",
                "c5.large",
                "c5.xlarge",
                "c5.2xlarge",
                "c5.4xlarge"
            ],
            "Description": "Enter Central Manager instance type"
        },
        "KeyName": {
            "Description": "Name of an existing EC2 KeyPair to enable SSH access to the instance",
            "Type": "AWS::EC2::KeyPair::KeyName",
            "ConstraintDescription": "must be the name of an existing EC2 KeyPair."
        }
    },
    "Metadata": {
        "Generator": "",
        "AWS::CloudFormation::Designer": {
            "d2b3fbb5-c87c-490d-b0ff-5c0804f855f0": {
                "size": {
                    "width": 60,
                    "height": 60
                },
                "position": {
                    "x": 630,
                    "y": 450
                },
                "z": 1,
                "embeds": []
            },
            "dc671d3b-807c-4ea9-b368-7e3d534e22e1": {
                "size": {
                    "width": 60,
                    "height": 60
                },
                "position": {
                    "x": 630,
                    "y": 330
                },
                "z": 1,
                "embeds": []
            },
            "5311a68f-b7ab-48e1-b1d7-9038174cf489": {
                "size": {
                    "width": 60,
                    "height": 60
                },
                "position": {
                    "x": 530,
                    "y": 330
                },
                "z": 1,
                "embeds": [],
                "isassociatedwith": [
                    "0e9f449e-767d-4419-aac9-2e7fe29f4fd4",
                    "dc671d3b-807c-4ea9-b368-7e3d534e22e1"
                ]
            },
            "fbdc2e18-b910-405e-aeed-433c01a5a71b": {
                "size": {
                    "width": 60,
                    "height": 60
                },
                "position": {
                    "x": 530,
                    "y": 450
                },
                "z": 1,
                "embeds": [],
                "isassociatedwith": [
                    "d2b3fbb5-c87c-490d-b0ff-5c0804f855f0"
                ]
            },
            "34e5960d-26f6-4d11-aae1-85c02c36b986": {
                "size": {
                    "width": 60,
                    "height": 60
                },
                "position": {
                    "x": 420,
                    "y": 450
                },
                "z": 1,
                "embeds": [],
                "isassociatedwith": [
                    "fbdc2e18-b910-405e-aeed-433c01a5a71b",
                    "ded7f98f-10d3-4e44-a367-bd3cb1ea347e"
                ]
            },
            "ded7f98f-10d3-4e44-a367-bd3cb1ea347e": {
                "size": {
                    "width": 60,
                    "height": 60
                },
                "position": {
                    "x": 420,
                    "y": 310
                },
                "z": 1,
                "embeds": []
            },
            "57399634-3282-4398-94cd-e5b1ab3455bf": {
                "size": {
                    "width": 60,
                    "height": 60
                },
                "position": {
                    "x": 220,
                    "y": 310
                },
                "z": 1,
                "embeds": []
            },
            "f5ca956b-6572-44a5-99d9-17899f5a826a": {
                "size": {
                    "width": 60,
                    "height": 60
                },
                "position": {
                    "x": 320,
                    "y": 310
                },
                "z": 1,
                "embeds": [],
                "isassociatedwith": [
                    "57399634-3282-4398-94cd-e5b1ab3455bf"
                ]
            }
        }
    },
    "Description": "HA Template for Heimdall Data Access Platform Central Manager",
    "Resources": {
        "HeimdallCentralManagerIAM": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "Path": "/",
                "AssumeRolePolicyDocument": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}",
                "MaxSessionDuration": 3600,
                "RoleName": {
                    "Fn::Join": [
                        "-",
                        [
                            {
                                "Ref": "AWS::StackName"
                            },
                            "centralManager"
                        ]
                    ]
                },
                "ManagedPolicyArns": [
                    "arn:aws:iam::aws:policy/CloudWatchFullAccess",
                    "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess",
                    "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess",
                    "arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess",
                    "arn:aws:iam::aws:policy/AWSMarketplaceMeteringFullAccess",
                    "arn:aws:iam::aws:policy/AmazonS3FullAccess",
                    "arn:aws:iam::aws:policy/SecretsManagerReadWrite"
                ],
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "-",
                                [
                                    {
                                        "Ref": "AWS::StackName"
                                    },
                                    "centralManager"
                                ]
                            ]
                        }
                    }
                ]
            },
            "Metadata": {
                "AWS::CloudFormation::Designer": {
                    "id": "dc671d3b-807c-4ea9-b368-7e3d534e22e1"
                }
            }
        },
        "HeimdallCentralManagerIAMInstanceProfile": {
            "Type": "AWS::IAM::InstanceProfile",
            "Properties": {
                "Path": "/",
                "Roles": [
                    {
                        "Ref": "HeimdallCentralManagerIAM"
                    }
                ]
            },
            "Metadata": {
                "AWS::CloudFormation::Designer": {
                    "id": "5311a68f-b7ab-48e1-b1d7-9038174cf489"
                }
            }
        },
        "HeimdallCentralManagerSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupName": {
                    "Fn::Join": [
                        "-",
                        [
                            {
                                "Ref": "AWS::StackName"
                            },
                            "centralManagerSG"
                        ]
                    ]
                },
                "GroupDescription": "Security group for Heimdall CentralManager",
                "VpcId": {
                    "Ref": "HeimdallCentralManagerVPC"
                },
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "CidrIp": "0.0.0.0/0",
                        "FromPort": 22,
                        "ToPort": 22
                    },
                    {
                        "IpProtocol": "tcp",
                        "CidrIp": "0.0.0.0/0",
                        "FromPort": 8087,
                        "ToPort": 8087
                    }
                ],
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "-",
                                [
                                    {
                                        "Ref": "AWS::StackName"
                                    },
                                    "centralManager"
                                ]
                            ]
                        }
                    }
                ]
            },
            "Metadata": {
                "AWS::CloudFormation::Designer": {
                    "id": "d2b3fbb5-c87c-490d-b0ff-5c0804f855f0"
                }
            }
        },
        "CentralManagerLaunchConfig": {
            "Type": "AWS::AutoScaling::LaunchConfiguration",
            "Properties": {
                "AssociatePublicIpAddress": true,
                "IamInstanceProfile": {
                    "Ref": "HeimdallCentralManagerIAMInstanceProfile"
                },
                "ImageId": {
                    "Ref": "HeimdallCentralManagerAMIID"
                },
                "InstanceMonitoring": true,
                "InstanceType": {
                    "Ref": "InstanceTypeParameterCentralManager"
                },
                "KeyName": {
                    "Ref": "KeyName"
                },
                "SecurityGroups": [
                    {
                        "Ref": "HeimdallCentralManagerSecurityGroup"
                    }
                ],
                "LaunchConfigurationName": {
                    "Fn::Join": [
                        "-",
                        [
                            {
                                "Ref": "AWS::StackName"
                            },
                            "centralManager"
                        ]
                    ]
                },
                "UserData": {
                    "Fn::Base64": {
                        "Fn::Join": [
                            "",
                            [
                                "#!/bin/bash",
                                "\necho \"hdRole=server\nhdPort=8087\nhdUser=",
                                {
                                    "Ref": "hdUser"
                                },
                                "\nhdPassword=",
                                {
                                    "Ref": "hdPassword"
                                },
                                "\nconfigSource=",
                                {
                                    "Ref": "configSource"
                                },
                                "\n\" > /etc/heimdall.conf",
                                "\nyum -y update",
                                "\n. /etc/heimdall.conf",
                                "\nif [ \"$configSource\" != \"none\" ]; then aws s3 sync $configSource /opt/heimdall/config/; fi",
                "\ncurl https://s3.amazonaws.com/s3.heimdalldata.com/heimdall-entrypoint.sh -o /opt/heimdall/heimdall-entrypoint.sh",
                                "\nsystemctl restart heimdall"
                            ]
                        ]
                    }
                }
            },
            "Metadata": {
                "AWS::CloudFormation::Designer": {
                    "id": "fbdc2e18-b910-405e-aeed-433c01a5a71b"
                }
            }
        },
        "HeimdallCentralManagerAutoScalingGroup": {
            "Type": "AWS::AutoScaling::AutoScalingGroup",
            "Version": "2020-04-22",
            "Properties": {
                "AvailabilityZones": {
                    "Ref": "HeimdallCentralManagerAvailabilityZones"
                },
                "VPCZoneIdentifier": {
                    "Ref": "HeimdallCentralManagerSubnetList"
                },
                "LaunchConfigurationName": {
                    "Ref": "CentralManagerLaunchConfig"
                },
                "TargetGroupARNs": [
                    {
                        "Ref": "HeimdallCentralManagerTargetGroup"
                    }
                ],
                "MinSize": {
                    "Ref": "CentralManagerMinimum"
                },
                "MaxSize": {
                    "Ref": "CentralManagerMaximum"
                },
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "-",
                                [
                                    {
                                        "Ref": "AWS::StackName"
                                    },
                                    "centralManager"
                                ]
                            ]
                        },
                        "PropagateAtLaunch": true
                    }
                ]
            },
            "Metadata": {
                "AWS::CloudFormation::Designer": {
                    "id": "34e5960d-26f6-4d11-aae1-85c02c36b986"
                }
            }
        },
        "HeimdallCentralManagerTargetGroup": {
            "Type": "AWS::ElasticLoadBalancingV2::TargetGroup",
            "Properties": {
                "Port": 8087,
                "Protocol": "TCP",
                "VpcId": {
                    "Ref": "HeimdallCentralManagerVPC"
                },
                "TargetGroupAttributes": [
                    {
                        "Key": "deregistration_delay.timeout_seconds",
                        "Value": 60
                    }
                ],
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "-",
                                [
                                    {
                                        "Ref": "AWS::StackName"
                                    },
                                    "centralManager"
                                ]
                            ]
                        }
                    }
                ]
            },
            "Metadata": {
                "AWS::CloudFormation::Designer": {
                    "id": "ded7f98f-10d3-4e44-a367-bd3cb1ea347e"
                }
            }
        },
        "HeimdallCentralManagerLoadBalancer": {
            "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
            "Properties": {
                "Scheme": "internal",
                "Type": "network",
                "Subnets": {
                    "Ref": "HeimdallCentralManagerSubnetList"
                },
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": {
                            "Fn::Join": [
                                "-",
                                [
                                    {
                                        "Ref": "AWS::StackName"
                                    },
                                    "centralManager"
                                ]
                            ]
                        }
                    }
                ]
            },
            "Metadata": {
                "AWS::CloudFormation::Designer": {
                    "id": "57399634-3282-4398-94cd-e5b1ab3455bf"
                }
            }
        },
        "HeimdallCentralManagerLoadBalancerListener": {
            "Type": "AWS::ElasticLoadBalancingV2::Listener",
            "Properties": {
                "DefaultActions": [
                    {
                        "Type": "forward",
                        "TargetGroupArn": {
                            "Ref": "HeimdallCentralManagerTargetGroup"
                        }
                    }
                ],
                "LoadBalancerArn": {
                    "Ref": "HeimdallCentralManagerLoadBalancer"
                },
                "Port": 8087,
                "Protocol": "TCP"
            },
            "Metadata": {
                "AWS::CloudFormation::Designer": {
                    "id": "f5ca956b-6572-44a5-99d9-17899f5a826a"
                }
            }
        }
    },
    "Outputs": {
        "LoadBalancerUrl": {
            "Description": "The hostname for load balanced db access",
            "Value": {
                "Fn::GetAtt": [
                    "HeimdallCentralManagerLoadBalancer",
                    "DNSName"
                ]
            }
        }
    }
}