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 particuarly large
  • Ensure the application works appropriately through a proxy instance hosted on the management server
  • Once the application is validated, you can uncheck 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
  • 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

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, ouside of the EC2 instances, the network load balancer may incure charges, as explained "here".

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
  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


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

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"
                ],
                "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"
                ]
            }
        }
    }
}