Deploy HA Gateways with CloudFormation

Last modified on October 4, 2023

The following guide shows an example of how to quickly create a pair of StrongDM gateways using AWS’s CloudFormation. The only requirement is a StrongDM admin token with the ability to list and create gateways. The following screenshot shows the permissions required by the key in order to deploy gateways with CloudFormation.

StrongDM Admin Token for CloudFormation deployment
StrongDM Admin Token for CloudFormation deployment

Procedure

  1. Navigate to your AWS console.
  2. Search for and open the CloudFormation service.
  3. Click Create stack.
  4. Choose Upload a template file.
  5. Upload the below YAML file.
  6. Follow on-screen instructions.

Parameters

When launched, this stack will prompt you for the following parameters:

  1. PublicSubnet1: Designates the subnet in which to launch the EC2 instance. This subnet needs to be public.
  2. PublicSubnet2: Designates the subnet in which to launch a second EC2 instance for high availability. This subnet needs to be public.
  3. VPC: Select the VPC that the subnet above belongs to. This VPC needs DNS hostnames enabled for the gateway to properly register.
  4. SDMListenPort: This port number will be used for clients to connect to the this gateway.
  5. SDMAdminToken: Input a StrongDM admin token that has the Relays / Create permission.

Resources

This template will create the following resources

  1. EC2 Instance Gateway One

    • Instance type t3.medium
    • Operating system Amazon Linux 2
  2. EC2 Instance Gateway Two

    • Instance type t3.medium
    • Operating system Amazon Linux 2
  3. Security group

    • This security group allows connections from StrongDM clients into your VPC
    • The SDMlistenPort specified during creation time will be open from anywhere

Outputs

This template exports the EC2 security group so that it may be used as an input rule for your databases and servers in other templates.

CloudFormation Template

AWSTemplateFormatVersion: '2010-09-09'
Description: StrongDM self-registering gateway
Parameters:
  # Network information
  PublicSubnet1:
    Description: Subnet to use as an access point into your AWS network. Must contain a route open to the internet.
    Type: AWS::EC2::Subnet::Id
  PublicSubnet2:
    Description: Subnet to use as an access point into your AWS network. Must contain a route open to the internet.
    Type: AWS::EC2::Subnet::Id
  VPC:
    Description: The VPC that contains the public subnet listed above
    Type: AWS::EC2::VPC::Id
  # StrongDM variables
  SDMListenPort:
    Type: Number
    Default: 5000
    MinValue: 1024
    MaxValue: 65535
    Description: The TCP port that will be exposed to the internet
  SDMAdminToken:
    AllowedPattern: (.+)
    Type: String
    Description: Paste your StrongDM admin token to create the gateway
  # Get latest Amazon Linux AMI
  LatestAmiId:
    Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
# Organization structure for parameters
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      -
        Label:
          default: "AWS Configuration"
        Parameters:
          - PublicSubnet1
          - PublicSubnet2
          - VPC
      -
        Label:
          default: "StrongDM Configuration"
        Parameters:
          - SDMAdminToken
          - SDMListenPort
      -
        Label:
          default: "This will grab the latest Amazon Linux 2 AMI ID"
        Parameters:
          - LatestAmiId
# Resources to be created
Resources:
  SDMGWONE:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.medium
      Tags: 
        - Key: "Name"
          Value: "StrongDM Gateway One"
      NetworkInterfaces:
        - DeviceIndex: '0'
          SubnetId: !Ref 'PublicSubnet1'
          AssociatePublicIpAddress: 'true'
          DeleteOnTermination: 'true'
          GroupSet: [!GetAtt [ EC2SecurityGroup, GroupId ]]
      ImageId: !Ref LatestAmiId
      UserData:
        Fn::Base64:
          !Sub |
            #!/bin/bash -xe
            # set environment variables
            mkdir -p /home/ec2-user/.sdm
            touch /home/ec2-user/.sdm/sdm.log
            export TARGET_USER=ec2-user
            export SDM_LISTEN_PORT=${SDMListenPort}
            export SDM_GATEWAY_NAME=AWS-CloudFormation-One-$(date +%s)
            export SDM_HOSTNAME="$(curl http://169.254.169.254/latest/meta-data/public-hostname)"
            export SDM_HOME="/home/ec2-user/.sdm"
            # downloads sdm binary
            yum update -y && yum install -y unzip curl
            curl -J -O -L https://app.strongdm.com/releases/cli/linux && unzip sdmcli* && rm sdmcli*
            # Generate a gateway token
            export SDM_RELAY_TOKEN="$(./sdm --admin-token=${SDMAdminToken} relay create-gateway --name $SDM_GATEWAY_NAME $SDM_HOSTNAME:$SDM_LISTEN_PORT 0.0.0.0:$SDM_LISTEN_PORT)"
            chown -R ec2-user:ec2-user /home/ec2-user/.sdm
            # Install SDM
            ./sdm install --relay --token=$SDM_RELAY_TOKEN --user $TARGET_USER
  SDMGWTWO:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3.medium
      Tags: 
        - Key: "Name"
          Value: "StrongDM Gateway Two"
      NetworkInterfaces:
        - DeviceIndex: '0'
          SubnetId: !Ref 'PublicSubnet2'
          AssociatePublicIpAddress: 'true'
          DeleteOnTermination: 'true'
          GroupSet: [!GetAtt [ EC2SecurityGroup, GroupId ]]
      ImageId: !Ref LatestAmiId
      UserData:
        Fn::Base64:
          !Sub |
            #!/bin/bash -xe
            # set environment variables
            mkdir -p /home/ec2-user/.sdm
            touch /home/ec2-user/.sdm/sdm.log
            export TARGET_USER=ec2-user
            export SDM_LISTEN_PORT=${SDMListenPort}
            export SDM_GATEWAY_NAME=AWS-CloudFormation-Two-$(date +%s)
            export SDM_HOSTNAME="$(curl http://169.254.169.254/latest/meta-data/public-hostname)"
            export SDM_HOME="/home/ec2-user/.sdm"
            # downloads sdm binary
            yum update -y && yum install -y unzip curl
            curl -J -O -L https://app.strongdm.com/releases/cli/linux && unzip sdmcli* && rm sdmcli*
            # Generate a gateway token
            export SDM_RELAY_TOKEN="$(./sdm --admin-token=${SDMAdminToken} relay create-gateway --name $SDM_GATEWAY_NAME $SDM_HOSTNAME:$SDM_LISTEN_PORT 0.0.0.0:$SDM_LISTEN_PORT)"
            chown -R ec2-user:ec2-user /home/ec2-user/.sdm
            # Install SDM
            ./sdm install --relay --token=$SDM_RELAY_TOKEN --user $TARGET_USER
  EC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Expose StrongDM listening port"
      GroupName: !Sub "${AWS::StackName}"
      VpcId: !Ref 'VPC'
      Tags: 
        - Key: "Name"
          Value: !Sub "${AWS::StackName}"
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: !Ref 'SDMListenPort'
        ToPort: !Ref 'SDMListenPort'
        CidrIp: 0.0.0.0/0
Outputs:
  SDMGatewaySecurityGroupID:
    Description: Security Group ID for StrongDM gateway
    Value: !GetAtt [ EC2SecurityGroup, GroupId ]
    Export:
      Name: !Join [ ':', [ !Ref 'AWS::StackName', 'SecurityGroupID' ] ]