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-1qup6raf2) Metadata: QuickStartDocumentation: EntrypointName: "Launch into an existing VPC (domain-joined)" AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Network Configuration Parameters: - VPCID - PublicSubnet1ID - RDGWCIDR - Label: default: Amazon EC2 Configuration Parameters: - KeyPairName - RDGWInstanceType - WS2019FULLBASE - Label: default: Microsoft Active Directory Configuration Parameters: - DomainDNSName - DomainNetBIOSName - DomainMemberSGID - Label: default: Microsoft Remote Desktop Gateway Configuration - Label: default: Backup and Patching Configuration Parameters: - BackupPolicy - PatchWindow - Label: default: AWS Quick Start Configuration Parameters: - QSS3BucketName - QSS3KeyPrefix - QSS3BucketRegion - Label: default: Encryption Configuration Parameters: - KMSKeyId ParameterLabels: BackupPolicy: defualt: Backup Policy DomainDNSName: default: Domain DNS Name DomainMemberSGID: default: Domain Member Security Group ID DomainNetBIOSName: default: Domain NetBIOS Name KeyPairName: default: Key Pair Name KMSKeyId: default: KMS Key Id WS2019FULLBASE: default: SSM Parameter to Grab Latest AMI ID PatchWindow: default: Patch Window PublicSubnet1ID: default: Public Subnet 1 ID QSS3BucketName: default: Quick Start S3 Bucket Name QSS3BucketRegion: default: Quick Start S3 Bucket Region 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: BackupPolicy: AllowedValues: - "standard" - "dev" - "none" Default: "standard" Description: Select a valid backup policy to employ. Type: String DomainAdminSecret: Description: Arn for the Domain Admin secret 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 KMSKeyId: Type: String Description: KMS Key Id for use with encryption where appropriate PatchWindow: AllowedValues: - "prod" - "test" - "manual" Default: "prod" Description: Select a valid patch window schema. 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: String Default: "" 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 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 QSS3BucketRegion: Default: us-east-1 Description: The AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted. When using your own bucket, you must specify this value. 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-activedirectory/ 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 VPCID: Description: ID of the VPC (e.g., vpc-0343606e) Type: String WS2019FULLBASE: Type: AWS::EC2::Image::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: UsingDefaultBucket: !Equals [!Ref QSS3BucketName, "aws-quickstart"] Resources: EIP1: Type: AWS::EC2::EIP Properties: Domain: vpc RDGWHostRole: Type: AWS::IAM::Role Properties: ManagedPolicyArns: - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore" - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonSSMDirectoryServiceAccess" - !Sub "arn:${AWS::Partition}:iam::aws:policy/CloudWatchAgentServerPolicy" Policies: - PolicyDocument: Version: "2012-10-17" Statement: - Action: - s3:GetObject Resource: - !Sub "arn:${AWS::Partition}:s3:::${QSS3BucketName}" - !Sub "arn:${AWS::Partition}:s3:::${QSS3BucketName}/*" Effect: Allow PolicyName: rdgw-s3-policy - PolicyDocument: Version: "2012-10-17" Statement: - Action: - ec2:AssociateAddress - ec2:DescribeAddresses Resource: - "*" Effect: Allow PolicyName: rdgw-eip-policy - PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - secretsmanager:GetSecretValue - secretsmanager:DescribeSecret Resource: - !Ref "DomainAdminSecret" - Effect: Allow Action: - kms:GenerateDataKey - kms:Decrypt Resource: - !Sub "arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/${KMSKeyId}" PolicyName: rdgw-secrets 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: / RDGWHost: Type: AWS::EC2::Instance 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.RDGWHost.Metadata.AWS::CloudFormation::Init\n" - "action=cfn-init.exe -v -c config -s " - !Ref "AWS::StackId" - " -r RDGWHost" - " --region " - !Ref "AWS::Region" - "\n" C:\cfn\scripts\Unzip-Archive.ps1: source: Fn::Sub: - "https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}/scripts/Unzip-Archive.ps1" - S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion S3Bucket: !If - UsingDefaultBucket - !Sub "${QSS3BucketName}-${AWS::Region}" - !Ref QSS3BucketName authentication: S3AccessCreds C:\cfn\modules\AWSQuickStart.zip: source: Fn::Sub: - "https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}/archives/AWSQuickStart.zip" - S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion S3Bucket: !If - UsingDefaultBucket - !Sub "${QSS3BucketName}-${AWS::Region}" - !Ref QSS3BucketName authentication: S3AccessCreds C:\cfn\scripts\Join-Domain.ps1: source: Fn::Sub: - "https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}/scripts/Join-Domain.ps1" - S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion S3Bucket: !If - UsingDefaultBucket - !Sub "${QSS3BucketName}-${AWS::Region}" - !Ref QSS3BucketName authentication: S3AccessCreds c:\cfn\scripts\Initialize-RDGW.ps1: source: Fn::Sub: - "https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}/scripts/Initialize-RDGW.ps1" - S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion S3Bucket: !If - UsingDefaultBucket - !Sub "${QSS3BucketName}-${AWS::Region}" - !Ref QSS3BucketName authentication: S3AccessCreds c:\cfn\scripts\Set-EIP.ps1: source: Fn::Sub: - "https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}/scripts/Set-EIP.ps1" - S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion S3Bucket: !If - UsingDefaultBucket - !Sub "${QSS3BucketName}-${AWS::Region}" - !Ref QSS3BucketName 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 'RDGWHost' -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" - "' -DomainAdminSecret '" - !Ref "DomainAdminSecret" - "' -Region '" - !Ref "AWS::Region" - '''"' 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" - "')" waitAfterCompletion: "0" finalize: commands: 1-signal-success: command: powershell.exe -Command "Write-AWSQuickStartStatus" waitAfterCompletion: "0" Properties: ImageId: !Ref WS2019FULLBASE SecurityGroupIds: - !Ref "RemoteDesktopGatewaySG" - !Ref "DomainMemberSGID" SubnetId: !Ref "PublicSubnet1ID" IamInstanceProfile: !Ref "RDGWHostProfile" InstanceType: !Ref "RDGWInstanceType" BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: Encrypted: true KmsKeyId: !Ref "KMSKeyId" VolumeSize: 50 VolumeType: gp2 KeyName: !Ref "KeyPairName" UserData: !Base64 Fn::Join: - "" - - "\n" Tags: - Key: Name Value: RDGW - Key: BackupPolicy Value: !Ref "BackupPolicy" - Key: PatchWindow Value: !Ref "PatchWindow" 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" RemoteDesktopGatewaySGID: Value: !Ref "RemoteDesktopGatewaySG" Description: Remote Desktop Gateway Security Group ID