AWSTemplateFormatVersion: '2010-09-09' Description: >- This template is intended to be installed into an existing VPC with two public subnets and an Active Directory domain. It will create an auto-scaling group of RD Gateway instances in the public VPC subnets. **WARNING** This template creates Amazon EC2 Windows instance and related resources. You will be billed for the AWS resources used if you create a stack from this template. QS(0006) Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Network Configuration Parameters: - VPCID - PublicSubnet1ID - PublicSubnet2ID - RDGWCIDR - Label: default: Amazon EC2 Configuration Parameters: - KeyPairName - RDGWInstanceType - LatestAmiId - Label: default: Microsoft Active Directory Configuration Parameters: - DomainDNSName - DomainNetBIOSName - DomainMemberSGID - DomainAdminUser - DomainAdminPassword - Label: default: Microsoft Remote Desktop Gateway Configuration Parameters: - NumberOfRDGWHosts - Label: default: AWS Quick Start Configuration Parameters: - QSS3BucketName - QSS3KeyPrefix ParameterLabels: DomainAdminPassword: default: Domain Admin Password DomainAdminUser: default: Domain Admin User Name DomainDNSName: default: Domain DNS Name DomainMemberSGID: default: Domain Member Security Group ID DomainNetBIOSName: default: Domain NetBIOS Name KeyPairName: default: Key Pair Name LatestAmiId: default: SSM Parameter to Grab Latest AMI ID NumberOfRDGWHosts: default: Number of RDGW Hosts PublicSubnet1ID: default: Public Subnet 1 ID PublicSubnet2ID: default: Public Subnet 2 ID QSS3BucketName: default: Quick Start S3 Bucket Name QSS3KeyPrefix: default: Quick Start S3 Key Prefix RDGWInstanceType: default: Remote Desktop Gateway Instance Type RDGWCIDR: default: Allowed Remote Desktop Gateway External Access CIDR VPCID: default: VPC ID Parameters: DomainAdminPassword: AllowedPattern: (?=^.{6,255}$)((?=.*\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))^.* Description: Password for the domain admin user. Must be at least 8 characters containing letters, numbers and symbols MaxLength: '32' MinLength: '8' NoEcho: 'true' Type: String DomainAdminUser: AllowedPattern: '[a-zA-Z0-9]*' Default: StackAdmin Description: User name for the Domain Administrator. This is separate from the default "Administrator" account MaxLength: '25' MinLength: '5' Type: String DomainDNSName: Description: Fully qualified domain name (FQDN) e.g. example.com Type: String Default: example.com MinLength: '2' MaxLength: '255' AllowedPattern: '[a-zA-Z0-9\-]+\..+' DomainMemberSGID: Description: ID of the Domain Member Security Group (e.g., sg-7f16e910) Type: AWS::EC2::SecurityGroup::Id DomainNetBIOSName: AllowedPattern: '[a-zA-Z0-9\-]+' Default: example Description: NetBIOS name of the domain (up to 15 characters) for users of earlier versions of Windows e.g. EXAMPLE MaxLength: '15' MinLength: '1' Type: String KeyPairName: Description: Public/private key pairs allow you to securely connect to your instance after it launches Type: AWS::EC2::KeyPair::KeyName LatestAmiId: Type: AWS::SSM::Parameter::Value Default: /aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base NumberOfRDGWHosts: AllowedValues: - '1' - '2' - '3' - '4' Default: '1' Description: Enter the number of Remote Desktop Gateway hosts to create Type: String PublicSubnet1ID: Description: ID of the public subnet 1 that you want to provision the first Remote Desktop Gateway into (e.g., subnet-a0246dcd) Type: AWS::EC2::Subnet::Id PublicSubnet2ID: Description: ID of the public subnet 2 you want to provision the second Remote Desktop Gateway into (e.g., subnet-e3246d8e) Type: AWS::EC2::Subnet::Id QSS3BucketName: AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ ConstraintDescription: Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Default: aws-quickstart Description: S3 bucket name for the Quick Start assets. Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String QSS3KeyPrefix: AllowedPattern: ^[0-9a-zA-Z-/]*$ ConstraintDescription: Quick Start key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/). Default: quickstart-microsoft-rdgateway/ Description: S3 key prefix for the Quick Start assets. Quick Start key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/). Type: String RDGWInstanceType: Description: Amazon EC2 instance type for the Remote Desktop Gateway instances Type: String Default: t2.large AllowedValues: - t2.small - t2.medium - t2.large - m5.large - m5.xlarge - m5.2xlarge - m5.4xlarge RDGWCIDR: AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$ Description: Allowed CIDR Block for external access to the Remote Desktop Gateways Type: String VPCID: Description: ID of the VPC (e.g., vpc-0343606e) Type: AWS::EC2::VPC::Id Rules: SubnetsInVPC: Assertions: - Assert: !EachMemberIn - !ValueOfAll - AWS::EC2::Subnet::Id - VpcId - !RefAll 'AWS::EC2::VPC::Id' AssertDescription: All subnets must in the VPC CheckSupportedInstances: RuleCondition: !Contains - - m4.large - m4.xlarge - m4.2xlarge - m4.4xlarge - !Ref 'RDGWInstanceType' Assertions: - Assert: !Not - !Contains - - eu-west-3 - !Ref 'AWS::Region' AssertDescription: M4 instances are not available in the Paris region Conditions: 2RDGWCondition: !Or - !Equals - !Ref 'NumberOfRDGWHosts' - '2' - !Condition '3RDGWCondition' - !Condition '4RDGWCondition' 3RDGWCondition: !Or - !Equals - !Ref 'NumberOfRDGWHosts' - '3' - !Condition '4RDGWCondition' 4RDGWCondition: !Equals - !Ref 'NumberOfRDGWHosts' - '4' GovCloudCondition: !Equals - !Ref 'AWS::Region' - us-gov-west-1 Resources: EIP1: Type: AWS::EC2::EIP Properties: Domain: vpc EIP2: Type: AWS::EC2::EIP Condition: 2RDGWCondition Properties: Domain: vpc EIP3: Type: AWS::EC2::EIP Condition: 3RDGWCondition Properties: Domain: vpc EIP4: Type: AWS::EC2::EIP Condition: 4RDGWCondition Properties: Domain: vpc RDGWHostRole: Type: AWS::IAM::Role Properties: Policies: - PolicyDocument: Version: '2012-10-17' Statement: - Action: - s3:GetObject Resource: !Sub - arn:${Partition}:s3:::${QSS3BucketName}/${QSS3KeyPrefix}* - Partition: !If - GovCloudCondition - aws-us-gov - aws Effect: Allow PolicyName: aws-quick-start-s3-policy - PolicyDocument: Version: '2012-10-17' Statement: - Action: - ec2:AssociateAddress - ec2:DescribeAddresses Resource: - '*' Effect: Allow PolicyName: rdgw-eip-policy Path: / AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Principal: Service: - ec2.amazonaws.com Effect: Allow Version: '2012-10-17' RDGWHostProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref 'RDGWHostRole' Path: / RDGWAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: LaunchConfigurationName: !Ref 'RDGWLaunchConfiguration' VPCZoneIdentifier: - !Ref 'PublicSubnet1ID' - !Ref 'PublicSubnet2ID' MinSize: !Ref 'NumberOfRDGWHosts' MaxSize: !Ref 'NumberOfRDGWHosts' Cooldown: '300' DesiredCapacity: !Ref 'NumberOfRDGWHosts' Tags: - Key: Name Value: RDGW PropagateAtLaunch: true CreationPolicy: ResourceSignal: Count: !Ref 'NumberOfRDGWHosts' Timeout: PT30M RDGWLaunchConfiguration: Type: AWS::AutoScaling::LaunchConfiguration Metadata: AWS::CloudFormation::Authentication: S3AccessCreds: type: S3 roleName: !Ref 'RDGWHostRole' buckets: - !Ref 'QSS3BucketName' AWS::CloudFormation::Init: configSets: config: - setup - join - installRDS - finalize setup: files: c:\cfn\cfn-hup.conf: content: !Join - '' - - "[main]\n" - stack= - !Ref 'AWS::StackName' - "\n" - region= - !Ref 'AWS::Region' - "\n" c:\cfn\hooks.d\cfn-auto-reloader.conf: content: !Join - '' - - "[cfn-auto-reloader-hook]\n" - "triggers=post.update\n" - "path=Resources.RDGWLaunchConfiguration.Metadata.AWS::CloudFormation::Init\n" - 'action=cfn-init.exe -v -c config -s ' - !Ref 'AWS::StackId' - ' -r RDGWLaunchConfiguration' - ' --region ' - !Ref 'AWS::Region' - "\n" C:\cfn\scripts\Unzip-Archive.ps1: source: !Sub - https://${QSS3BucketName}.${QSS3Region}.amazonaws.com/${QSS3KeyPrefix}submodules/quickstart-microsoft-utilities/scripts/Unzip-Archive.ps1 - QSS3Region: !If - GovCloudCondition - s3.us-gov-west-1 - s3.us-east-1 authentication: S3AccessCreds C:\cfn\modules\AWSQuickStart.zip: source: !Sub - https://${QSS3BucketName}.${QSS3Region}.amazonaws.com/${QSS3KeyPrefix}submodules/quickstart-microsoft-utilities/modules/AWSQuickStart.zip - QSS3Region: !If - GovCloudCondition - s3.us-gov-west-1 - s3.us-east-1 authentication: S3AccessCreds C:\cfn\scripts\Join-Domain.ps1: source: !Sub - https://${QSS3BucketName}.${QSS3Region}.amazonaws.com/${QSS3KeyPrefix}submodules/quickstart-microsoft-utilities/scripts/Join-Domain.ps1 - QSS3Region: !If - GovCloudCondition - s3.us-gov-west-1 - s3.us-east-1 authentication: S3AccessCreds c:\cfn\scripts\Initialize-RDGW.ps1: source: !Sub - https://${QSS3BucketName}.${QSS3Region}.amazonaws.com/${QSS3KeyPrefix}scripts/Initialize-RDGW.ps1 - QSS3Region: !If - GovCloudCondition - s3.us-gov-west-1 - s3.us-east-1 authentication: S3AccessCreds c:\cfn\scripts\Set-EIP.ps1: source: !Sub - https://${QSS3BucketName}.${QSS3Region}.amazonaws.com/${QSS3KeyPrefix}scripts/Set-EIP.ps1 - QSS3Region: !If - GovCloudCondition - s3.us-gov-west-1 - s3.us-east-1 authentication: S3AccessCreds services: windows: cfn-hup: enabled: 'true' ensureRunning: 'true' files: - c:\cfn\cfn-hup.conf - c:\cfn\hooks.d\cfn-auto-reloader.conf commands: a-set-execution-policy: command: powershell.exe -Command "Set-ExecutionPolicy RemoteSigned -Force" waitAfterCompletion: '0' b-unpack-quickstart-module: command: powershell.exe -Command C:\cfn\scripts\Unzip-Archive.ps1 -Source C:\cfn\modules\AWSQuickStart.zip -Destination C:\Windows\system32\WindowsPowerShell\v1.0\Modules\ waitAfterCompletion: '0' c-init-quickstart-module: command: !Join - '' - - powershell.exe -Command " - New-AWSQuickStartResourceSignal -Stack ' - !Ref 'AWS::StackName' - ''' -Resource ''RDGWAutoScalingGroup'' -Region ''' - !Ref 'AWS::Region' - '''"' waitAfterCompletion: '0' join: commands: a-join-domain: command: !Join - '' - - powershell.exe -Command "C:\cfn\scripts\Join-Domain.ps1 -DomainName ' - !Ref 'DomainDNSName' - ''' -UserName ''' - !Ref 'DomainNetBIOSName' - \ - !Ref 'DomainAdminUser' - ''' -Password ''' - !Ref 'DomainAdminPassword' - '''"' waitAfterCompletion: forever installRDS: commands: a-install-rds: command: !Join - '' - - powershell.exe -Command "Install-WindowsFeature RDS-Gateway,RSAT-RDS-Gateway" waitAfterCompletion: '0' b-configure-rdgw: command: !Join - '' - - 'powershell.exe -ExecutionPolicy RemoteSigned ' - C:\cfn\scripts\Initialize-RDGW.ps1 -ServerFQDN $($env:COMPUTERNAME + '. - !Ref 'DomainDNSName' - ''') -DomainNetBiosName ' - !Ref 'DomainNetBIOSName' - ' -GroupName ''domain admins''' waitAfterCompletion: '0' c-assign-eip: command: !Join - '' - - 'powershell.exe -ExecutionPolicy RemoteSigned ' - C:\cfn\scripts\Set-EIP.ps1 -EIPs @(' - !Ref 'EIP1' - ''',''' - !If - 2RDGWCondition - !Ref 'EIP2' - 'Null' - ''',''' - !If - 3RDGWCondition - !Ref 'EIP3' - 'Null' - ''',''' - !If - 4RDGWCondition - !Ref 'EIP4' - 'Null' - ''')' waitAfterCompletion: '0' finalize: commands: 1-signal-success: command: powershell.exe -Command "Write-AWSQuickStartStatus" waitAfterCompletion: '0' Properties: ImageId: !Ref 'LatestAmiId' SecurityGroups: - !Ref 'RemoteDesktopGatewaySG' - !Ref 'DomainMemberSGID' IamInstanceProfile: !Ref 'RDGWHostProfile' InstanceType: !Ref 'RDGWInstanceType' BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: VolumeSize: 50 VolumeType: gp2 KeyName: !Ref 'KeyPairName' UserData: !Base64 Fn::Join: - '' - - "\n" RemoteDesktopGatewaySG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enable RDP access from the Internet VpcId: !Ref 'VPCID' SecurityGroupIngress: - IpProtocol: tcp FromPort: 3389 ToPort: 3389 CidrIp: !Ref 'RDGWCIDR' - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: !Ref 'RDGWCIDR' - IpProtocol: udp FromPort: 3391 ToPort: 3391 CidrIp: !Ref 'RDGWCIDR' - IpProtocol: icmp FromPort: -1 ToPort: -1 CidrIp: !Ref 'RDGWCIDR' Outputs: EIP1: Description: Elastic IP 1 for RDGW Value: !Ref 'EIP1' EIP2: Condition: 2RDGWCondition Description: Elastic IP 2 for RDGW Value: !Ref 'EIP2' EIP3: Condition: 3RDGWCondition Description: Elastic IP 3 for RDGW Value: !Ref 'EIP3' EIP4: Condition: 4RDGWCondition Description: Elastic IP 4 for RDGW Value: !Ref 'EIP4' RemoteDesktopGatewaySGID: Value: !Ref 'RemoteDesktopGatewaySG' Description: Remote Desktop Gateway Security Group ID