AWSTemplateFormatVersion: '2010-09-09'
Description: This template creates a VPC infrastructure for a multi-AZ, multi-tier
  deployment of a Windows based Application infrastructure. It installs 2 Windows
  2016 Active Directory Domain Controllers into private subnets in separate Availability
  Zones inside a VPC, as well as Remote Desktop Gateway instances and managed NAT
  gateways into the public subnet for each Availability Zone. The default Domain Administrator
  password will be the one retrieved from the instance.  For adding members to the
  domain, ensure that they are launched into the domain member security group created
  by this template and then configure them to use the AD instances fixed private IP
  addresses as the DNS server. **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.
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Network Configuration
        Parameters:
          - AvailabilityZones
          - NumberOfAZs
          - VPCCIDR
          - PrivateSubnet1CIDR
          - PrivateSubnet1ID
          - PrivateSubnet2CIDR
          - PrivateSubnet3CIDR
          - PrivateSubnet2ID
          - PublicSubnet1CIDR
          - PublicSubnet2CIDR
          - PublicSubnet3CIDR
          - RDGWCIDR
      - Label:
          default: Amazon EC2 Configuration
        Parameters:
          - KeyPairName
          - ADServer1InstanceType
          - ADServer1NetBIOSName
          - ADServer1PrivateIP
          - ADServer2InstanceType
          - ADServer2NetBIOSName
          - ADServer2PrivateIP
          - RDGWInstanceType
      - Label:
          default: Microsoft Active Directory Configuration
        Parameters:
          - DomainDNSName
          - DomainNetBIOSName
          - DomainAdminUser
          - DomainAdminPassword
      - Label:
          default: Microsoft Remote Desktop Gateway Configuration
        Parameters:
          - NumberOfRDGWHosts
      - Label:
          default: AWS Quick Start Configuration
        Parameters:
          - QSS3BucketName
          - QSS3KeyPrefix
    ParameterLabels:
      ADServer1InstanceType:
        default: Domain Controller 1 Instance Type
      ADServer1NetBIOSName:
        default: Domain Controller 1 NetBIOS Name
      ADServer1PrivateIP:
        default: Domain Controller 1 Private IP Address
      ADServer2InstanceType:
        default: Domain Controller 2 Instance Type
      ADServer2NetBIOSName:
        default: Domain Controller 2 NetBIOS Name
      ADServer2PrivateIP:
        default: Domain Controller 2 Private IP Address
      AvailabilityZones:
        default: Availability Zones
      DomainAdminPassword:
        default: Domain Admin Password
      DomainAdminUser:
        default: Domain Admin User Name
      DomainDNSName:
        default: Domain DNS Name
      DomainNetBIOSName:
        default: Domain NetBIOS Name
      KeyPairName:
        default: Key Pair Name
      NumberOfRDGWHosts:
        default: Number of RDGW hosts
      NumberOfAZs:
        default: Number of Availability Zones
      PrivateSubnet1CIDR:
        default: Private Subnet 1 CIDR
      PrivateSubnet2CIDR:
        default: Private Subnet 2 CIDR
      PrivateSubnet3CIDR:
        default: (Optional) Private Subnet 3 CIDR
      PublicSubnet1CIDR:
        default: Public Subnet 1 CIDR
      PublicSubnet2CIDR:
        default: Public Subnet 2 CIDR
      PublicSubnet3CIDR:
        default: (Optional) Public Subnet 3 CIDR
      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
      VPCCIDR:
        default: VPC CIDR
Parameters:
  ADServer1InstanceType:
    AllowedValues:
      - t2.large
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5.4xlarge
    Default: m4.xlarge
    Description: Amazon EC2 instance type for the first Active Directory instance
    Type: String
  ADServer1NetBIOSName:
    AllowedPattern: '[a-zA-Z0-9\-]+'
    Default: DC1
    Description: NetBIOS name of the first Active Directory server (up to 15 characters)
    MaxLength: '15'
    MinLength: '1'
    Type: String
  ADServer1PrivateIP:
    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])$
    Default: 10.0.0.10
    Description: Fixed private IP for the first Active Directory server located in
      Availability Zone 1
    Type: String
  ADServer2InstanceType:
    AllowedValues:
      - t2.large
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5.4xlarge
    Default: m4.xlarge
    Description: Amazon EC2 instance type for the second Active Directory instance
    Type: String
  ADServer2NetBIOSName:
    AllowedPattern: '[a-zA-Z0-9\-]+'
    Default: DC2
    Description: NetBIOS name of the second Active Directory server (up to 15 characters)
    MaxLength: '15'
    MinLength: '1'
    Type: String
  ADServer2PrivateIP:
    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])$
    Default: 10.0.32.10
    Description: Fixed private IP for the second Active Directory server located in
      Availability Zone 2
    Type: String
  AvailabilityZones:
    Description: 'List of Availability Zones to use for the subnets in the VPC. Note:
      The logical order is preserved and only 2 AZs are used for this deployment.'
    Type: List<AWS::EC2::AvailabilityZone::Name>
  NumberOfAZs:
    AllowedValues:
      - '2'
      - '3'
    Default: '2'
    Description: Number of Availability Zones to use in the VPC. This must match your
      selections in the list of Availability Zones parameter.
    Type: String
  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 account that will be added as Domain Administrator.
      This is separate from the default "Administrator" account
    MaxLength: '25'
    MinLength: '5'
    Type: String
  DomainDNSName:
    AllowedPattern: '[a-zA-Z0-9\-]+\..+'
    Default: example.com
    Description: Fully qualified domain name (FQDN) of the forest root domain e.g.
      example.com
    MaxLength: '255'
    MinLength: '2'
    Type: String
  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
  NumberOfRDGWHosts:
    AllowedValues:
      - '1'
      - '2'
      - '3'
      - '4'
    Default: '1'
    Description: Enter the number of Remote Desktop Gateway hosts to create
    Type: String
  PrivateSubnet1CIDR:
    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])(\/(1[6-9]|2[0-8]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
    Default: 10.0.0.0/19
    Description: CIDR block for private subnet 1 located in Availability Zone 1.
    Type: String
  PrivateSubnet2CIDR:
    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])(\/(1[6-9]|2[0-8]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
    Default: 10.0.32.0/19
    Description: CIDR block for private subnet 2 located in Availability Zone 2.
    Type: String
  PrivateSubnet3CIDR:
    Default: ''
    Description: CIDR block for private subnet 3 located in Availability Zone 3.
    Type: String
  PublicSubnet1CIDR:
    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])(\/(1[6-9]|2[0-8]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
    Default: 10.0.128.0/20
    Description: CIDR Block for the public DMZ subnet 1 located in Availability Zone
      1
    Type: String
  PublicSubnet2CIDR:
    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])(\/(1[6-9]|2[0-8]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
    Default: 10.0.144.0/20
    Description: CIDR Block for the public DMZ subnet 2 located in Availability Zone
      2
    Type: String
  PublicSubnet3CIDR:
    Default: ''
    Description: CIDR Block for the public DMZ subnet 3 located in Availability Zone
      3
    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
  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
  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]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/x
    Description: Allowed CIDR Block for external access to the Remote Desktop Gateways
    Type: String
  VPCCIDR:
    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])(\/(1[6-9]|2[0-8]))$
    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
    Default: 10.0.0.0/16
    Description: CIDR Block for the VPC
    Type: String
Conditions:
  GovCloudCondition: !Equals [!Ref 'AWS::Region', us-gov-west-1]
Rules:
  CheckSupportedInstances:
    RuleCondition: !Or [!Contains [[m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge],
        !Ref 'ADServer1InstanceType'], !Contains [[m4.large, m4.xlarge, m4.2xlarge,
          m4.4xlarge], !Ref 'ADServer2InstanceType']]
    Assertions:
      - Assert: !Not [!Contains [[eu-west-3], !Ref 'AWS::Region']]
        AssertDescription: M4 instances are not available in the Paris region
Resources:
  VPCStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub ['https://${QSS3BucketName}.${QSS3Region}.amazonaws.com/${QSS3KeyPrefix}submodules/quickstart-aws-vpc/templates/aws-vpc.template',
        {QSS3Region: !If [GovCloudCondition, s3-us-gov-west-1, s3]}]
      Parameters:
        AvailabilityZones: !Join [',', !Ref 'AvailabilityZones']
        KeyPairName: !Ref 'KeyPairName'
        NumberOfAZs: !Ref 'NumberOfAZs'
        PrivateSubnet1ACIDR: !Ref 'PrivateSubnet1CIDR'
        PrivateSubnet2ACIDR: !Ref 'PrivateSubnet2CIDR'
        PublicSubnet1CIDR: !Ref 'PublicSubnet1CIDR'
        PublicSubnet2CIDR: !Ref 'PublicSubnet2CIDR'
        VPCCIDR: !Ref 'VPCCIDR'
  ADStack:
    DependsOn: VPCStack
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub ['https://${QSS3BucketName}.${QSS3Region}.amazonaws.com/${QSS3KeyPrefix}templates/ad-1-yaml.template',
        {QSS3Region: !If [GovCloudCondition, s3-us-gov-west-1, s3]}]
      Parameters:
        ADServer1InstanceType: !Ref 'ADServer1InstanceType'
        ADServer1NetBIOSName: !Ref 'ADServer1NetBIOSName'
        ADServer1PrivateIP: !Ref 'ADServer1PrivateIP'
        ADServer2InstanceType: !Ref 'ADServer2InstanceType'
        ADServer2NetBIOSName: !Ref 'ADServer2NetBIOSName'
        ADServer2PrivateIP: !Ref 'ADServer2PrivateIP'
        DomainAdminPassword: !Ref 'DomainAdminPassword'
        DomainAdminUser: !Ref 'DomainAdminUser'
        DomainDNSName: !Ref 'DomainDNSName'
        DomainNetBIOSName: !Ref 'DomainNetBIOSName'
        KeyPairName: !Ref 'KeyPairName'
        NumberOfAZs: !Ref 'NumberOfAZs'
        PrivateSubnet1CIDR: !Ref 'PrivateSubnet1CIDR'
        PrivateSubnet1ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet1AID'
        PrivateSubnet2CIDR: !Ref 'PrivateSubnet2CIDR'
        PrivateSubnet2ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet2AID'
        PrivateSubnet3CIDR: !Ref 'PrivateSubnet3CIDR'
        PublicSubnet1CIDR: !Ref 'PublicSubnet1CIDR'
        PublicSubnet2CIDR: !Ref 'PublicSubnet2CIDR'
        PublicSubnet3CIDR: !Ref 'PublicSubnet3CIDR'
        QSS3BucketName: !Ref 'QSS3BucketName'
        QSS3KeyPrefix: !Ref 'QSS3KeyPrefix'
        VPCCIDR: !Ref 'VPCCIDR'
        VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
  RDGWStack:
    DependsOn: ADStack
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub ['https://${QSS3BucketName}.${QSS3Region}.amazonaws.com/${QSS3KeyPrefix}submodules/quickstart-microsoft-rdgateway/templates/rdgw-domain.template',
        {QSS3Region: !If [GovCloudCondition, s3-us-gov-west-1, s3]}]
      Parameters:
        DomainAdminPassword: !Ref 'DomainAdminPassword'
        DomainAdminUser: !Ref 'DomainAdminUser'
        DomainDNSName: !Ref 'DomainDNSName'
        DomainMemberSGID: !GetAtt 'ADStack.Outputs.DomainMemberSGID'
        DomainNetBIOSName: !Ref 'DomainNetBIOSName'
        KeyPairName: !Ref 'KeyPairName'
        NumberOfRDGWHosts: !Ref 'NumberOfRDGWHosts'
        PublicSubnet1ID: !GetAtt 'VPCStack.Outputs.PublicSubnet1ID'
        PublicSubnet2ID: !GetAtt 'VPCStack.Outputs.PublicSubnet2ID'
        QSS3BucketName: !Ref 'QSS3BucketName'
        QSS3KeyPrefix: !Sub '${QSS3KeyPrefix}submodules/quickstart-microsoft-rdgateway/'
        RDGWInstanceType: !Ref 'RDGWInstanceType'
        RDGWCIDR: !Ref 'RDGWCIDR'
        VPCID: !GetAtt 'VPCStack.Outputs.VPCID'