AWSTemplateFormatVersion: '2010-09-09' Description: This template creates 2 Windows 2019 Server Active Directory Ceritificate Services CAs 1 Offline Root CA and 1 Enterprise Subordinate CA into a private subnet inside a VPC. **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-1qup6rae5) Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Network Configuration Parameters: - VPCCIDR - VPCID - OrCaServerSubnet - SubCaServerSubnet - DomainMembersSG - Label: default: Amazon EC2 Configuration Parameters: - OrCaServerInstanceType - OrCaDataDriveSizeGiB - SubCaServerInstanceType - SubCaDataDriveSizeGiB - KeyPairName - Ami - AdministratorSecret - Label: default: Microsoft Active Directory Certificate Services Configuration Parameters: - OrCaServerNetBIOSName - SubCaServerNetBIOSName - DomainController1IP - DomainController2IP - DomainDNSName - DomainNetBIOSName - OrCaKeyLength - OrCaHashAlgorithm - OrCaValidityPeriodUnits - SubCaKeyLength - SubCaHashAlgorithm - SubCaValidityPeriodUnits - UseS3ForCRL - S3CRLBucketName - DirectoryType - Label: default: AWS Quick Start Configuration Parameters: - QSS3BucketName - QSS3KeyPrefix - QSS3BucketRegion ParameterLabels: VPCCIDR: default: VPC CIDR VPCID: default: VPC ID OrCaServerSubnet: default: Offline Root CA Subnet ID SubCaServerSubnet: default: Subordinate CA Subnet ID DomainMembersSG: default: Security Group ID for Domain Members Security Group. OrCaServerInstanceType: default: Offline Root CA Instance Type OrCaDataDriveSizeGiB: default: Size of the Data Drive in GiB SubCaServerInstanceType: default: Subordinate CA Instance Type SubCaDataDriveSizeGiB: default: Size of the Data Drive in GiB KeyPairName: default: Public/private key pairs allow you to securely connect to your instance Ami: default: AMI ID passed in from parent stack AdministratorSecret: default: The arn for the Secret containing the Administrator Credentials OrCaServerNetBIOSName: default: Offline Root CA NetBIOS Name SubCaServerNetBIOSName: default: Subordinate CA NetBIOS Name DomainController1IP: default: IP For Domain Controller that Offline Root & Subordinate CA Instance will use for DNS DomainController2IP: default: IP For Domain Controller that Offline Root & Subordinate CA Instance will use for DNS DomainDNSName: default: Domain DNS Name DomainNetBIOSName: default: Domain NetBIOS Name OrCaKeyLength: default: Offline Root CA Key Length OrCaHashAlgorithm: default: Offline Root CA Hash Algorithm OrCaValidityPeriodUnits: default: Offline Root CA Certificate Validity Period in Years SubCaKeyLength: default: Subordinate CA Key Length SubCaHashAlgorithm: default: Subordinate CA Hash Algorithm SubCaValidityPeriodUnits: default: Subordinate CA Certificate Validity Period in Years UseS3ForCRL: default: Use S3 for Offline Root and Subordinate CA CRL location S3CRLBucketName: default: S3 bucket name for Offline Root and Subordinate CA CRL DirectoryType: default: Type of Active Directory CA(s) will be integrated with QSS3BucketName: default: Quick Start S3 Bucket Name QSS3KeyPrefix: default: Quick Start S3 Key Prefix QSS3BucketRegion: default: Quick Start S3 Bucket Region Parameters: 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 Description: CIDR Block for the VPC Type: String Default: 10.0.0.0/16 VPCID: Description: ID of the VPC (e.g., vpc-0343606e) Type: AWS::EC2::VPC::Id OrCaServerSubnet: Description: ID of the Offline Root CA subnet (e.g., subnet-a0246dcd) Type: AWS::EC2::Subnet::Id SubCaServerSubnet: Description: ID of the Subordinate CA subnet (e.g., subnet-a0246dcd) Type: AWS::EC2::Subnet::Id DomainMembersSG: Description: Security Group ID for Domain Members Security Group. Type: AWS::EC2::SecurityGroup::Id OrCaServerInstanceType: AllowedValues: - t2.small - t3.small - t2.medium - t3.medium - t2.large - t3.large Default: t3.medium Description: Amazon EC2 instance type for the Offline Root CA instance Type: String OrCaDataDriveSizeGiB: Type: 'Number' Default: '2' Description: Size of the Offline Root CA Data Drive in GiB SubCaServerInstanceType: AllowedValues: - t2.small - t3.small - t2.medium - t3.medium - t2.large - t3.large Default: t3.medium Description: Amazon EC2 instance type for the Subordinate CA instance Type: String SubCaDataDriveSizeGiB: Type: 'Number' Default: '2' Description: Size of the Subordinate CA Data Drive in GiB KeyPairName: Description: Public/private key pairs allow you to securely connect to your instance after it launches Type: AWS::EC2::KeyPair::KeyName Ami: Type: 'AWS::SSM::Parameter::Value' Description: Offline Root CA SSM Parameter Value to grab the lastest AMI ID Default: '/aws/service/ami-windows-latest/Windows_Server-2019-English-Full-Base' AdministratorSecret: Description: The arn for the Secret containing the Administrator Credentials Type: String OrCaServerNetBIOSName: AllowedPattern: '[a-zA-Z0-9\-]+' Description: NetBIOS name of the Offline Root CA server (up to 15 characters) MaxLength: '15' MinLength: '1' Default: 'ORCA1' Type: String SubCaServerNetBIOSName: AllowedPattern: '[a-zA-Z0-9\-]+' Description: NetBIOS name of the Subordinate CA server (up to 15 characters) MaxLength: '15' MinLength: '1' Default: 'SUBCA1' Type: String DomainController1IP: 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])$ Description: IP For Domain Controller that Offline Root & Subordinate CA Instances will use for DNS Type: String DomainController2IP: 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])$ Description: IP For Domain Controller that Offline Root CA Instance will use for DNS Type: String DomainDNSName: AllowedPattern: '[a-zA-Z0-9\-]+\..+' Description: IP For Domain Controller that Offline Root & Subordinate CA Instances will use for DNS MaxLength: '255' MinLength: '2' Type: String DomainNetBIOSName: AllowedPattern: '[a-zA-Z0-9\-]+' 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 OrCaKeyLength: Description: Offline Root CA Key Length AllowedValues: - '2048' - '4096' Default: '2048' Type: String OrCaHashAlgorithm: Description: Offline Root CA Hash Algorithm AllowedValues: - 'SHA256' - 'SHA384' - 'SHA512' Default: 'SHA256' Type: String OrCaValidityPeriodUnits: Description: Offline Root CA Certificate Validity Period in Years Default: '10' Type: String SubCaKeyLength: Description: SubordinateCA Key Length AllowedValues: - '2048' - '4096' Default: '2048' Type: String SubCaHashAlgorithm: Description: Subordinate CA Hash Algorithm AllowedValues: - 'SHA256' - 'SHA384' - 'SHA512' Default: 'SHA256' Type: String SubCaValidityPeriodUnits: Description: Subordinate CA Certificate Validity Period in Years Default: '5' Type: String UseS3ForCRL: Description: Use S3 for Offline Root and Subordinate CA CRL location AllowedValues: - 'Yes' - 'No' Default: 'No' Type: String S3CRLBucketName: AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ Default: examplebucket Description: S3 bucket name for Offline Root and Subordinate CA CRL. Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String DirectoryType: Description: Type of Active Directory CA(s) will be integrated with, AWS Managed Microsoft AD or Self Managed AD AllowedValues: - 'AWSManaged' - 'SelfManaged' Default: 'AWSManaged' 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 Rules: SubnetsInVPC: Assertions: - Assert: !EachMemberIn - !ValueOfAll - AWS::EC2::Subnet::Id - VpcId - !RefAll 'AWS::EC2::VPC::Id' AssertDescription: All subnets must in the VPC S3CRLBucketNameValidation: RuleCondition: !Equals - !Ref UseS3ForCRL - 'Yes' Assertions: - AssertDescription: CRL BucketName cannot must be valid BucketName Assert: !Not [!Equals [!Ref S3CRLBucketName, 'examplebucket']] Conditions: UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] UsingS3BucketForCrl: !Equals [!Ref UseS3ForCRL, 'Yes'] Resources: InstanceRole: Type: AWS::IAM::Role Properties: Policies: - PolicyDocument: Version: '2012-10-17' Statement: - Action: - s3:ListBucket Resource: - !Sub ['arn:${AWS::Partition}:s3:::${S3Bucket}', S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName]] Effect: Allow - Action: - s3:GetObject Resource: - !Sub ['arn:${AWS::Partition}:s3:::${S3Bucket}/${QSS3KeyPrefix}*', S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName]] Effect: Allow - Action: - ec2:DescribeInstances - ssm:DescribeInstanceInformation - ssm:ListCommands - ssm:ListCommandInvocations - ssm:SendCommand - ssm:StartAutomationExecution Resource: '*' Effect: Allow - Action: - cloudformation:SignalResource Resource: !Sub 'arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AWS::StackName}/*' Effect: Allow PolicyName: AWS-Mgmt-Quick-Start-Policy - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - secretsmanager:GetSecretValue - secretsmanager:DescribeSecret Resource: - !Ref 'AdministratorSecret' PolicyName: AWS-Mgd-AD-Secret-Policy Path: / ManagedPolicyArns: - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore' - !Sub 'arn:${AWS::Partition}:iam::aws:policy/CloudWatchAgentServerPolicy' AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Principal: Service: - ec2.amazonaws.com Effect: Allow Version: '2012-10-17' InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref 'InstanceRole' Path: / S3CrlRolePolicy: Type: AWS::IAM::Policy Condition: UsingS3BucketForCrl Properties: PolicyName: S3-CRL-PublishRole PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - s3:GetBucketLocation - s3:ListBucket Resource: !Sub 'arn:aws:s3:::${S3CRLBucketName}' - Effect: Allow Action: - s3:PutObject - s3:GetObject - s3:PutObjectAcl - s3:DeleteObject Resource: !Sub 'arn:aws:s3:::${S3CRLBucketName}/*' Roles: - !Ref 'InstanceRole' AWSQuickstartCA: Type: AWS::SSM::Document Properties: DocumentType: Automation Content: schemaVersion: "0.3" description: "Deploy AD with SSM Automation" # Gathering parameters needed to configure DCs in the Quick Start parameters: VPCCIDR: default: '10.0.0.0/16' description: "CIDR block for private subnet 1 located in Availability Zone 1." type: "String" OrCaServerNetBIOSName: description: "NetBIOS name of the Offline Root CA server (up to 15 characters)" type: "String" SubCaServerNetBIOSName: description: "NetBIOS name of the Subordinate CA server (up to 15 characters)" type: "String" DomainController1IP: description: "Fixed private IP for the first Active Directory server located in Availability Zone 1" type: "String" DomainController2IP: description: "Fixed private IP for the first Active Directory server located in Availability Zone 1" type: "String" AdministratorSecret: description: "AWS Secrets Parameter Name that has Password and User namer for the domain administrator." type: "String" DomainDNSName: description: "Fully qualified domain name (FQDN) of the forest root domain e.g. example.com" type: "String" DomainNetBIOSName: description: "NetBIOS name of the domain (up to 15 characters) for users of earlier versions of Windows e.g. EXAMPLE" type: "String" OrCaKeyLength: description: Offline Root CA Key Length type: String OrCaHashAlgorithm: description: Offline Root CA Hash Algorithm type: String OrCaValidityPeriodUnits: description: Offline Root CA Certificate Validity Period in Years type: String SubCaKeyLength: description: Subordinate CA Key Length type: String SubCaHashAlgorithm: description: Subordinate CA Hash Algorithm type: String SubCaValidityPeriodUnits: description: Subordinate CA Certificate Validity Period in Years type: String UseS3ForCRL: description: Use S3 for Enterprise Root CA CRL location type: String S3CRLBucketName: description: S3 bucket name for Enterprise Root CA CRL type: String DirectoryType: description: Type of Active Directory CA will be integrated with type: String QSS3BucketName: 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: 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" StackName: default: "" description: "Stack Name Input for cfn resource signal" type: "String" URLSuffix: default: "amazonaws.com" description: "AWS URL suffix" type: "String" mainSteps: # This step grabs the Instance IDs for both nodes that will be configured as CAs in the Quick Start and Instance IDs for the for next steps. - name: "CaInstanceIds" action: aws:executeAwsApi onFailure: "step:signalfailure" nextStep: "CaInstallDscModules" inputs: Service: ec2 Api: DescribeInstances Filters: - Name: "tag:Name" Values: [ "{{OrCaServerNetBIOSName}}","{{SubCaServerNetBIOSName}}" ] - Name: "tag:aws:cloudformation:stack-name" Values: ["{{StackName}}"] - Name: "instance-state-name" Values: [ "running" ] outputs: - Name: InstanceIds Selector: "$.Reservations..Instances..InstanceId" Type: "StringList" # Installs needed Powershell DSC Modules and components on both nodes. - name: "CaInstallDscModules" action: "aws:runCommand" onFailure: "step:signalfailure" nextStep: "CaLCMConfig" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: - "{{CaInstanceIds.InstanceIds}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Sub '/aws/Quick_Start/${AWS::StackName}' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/install-ad-modules.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./install-ad-modules.ps1" # Configures Local Configuration Manager on each of the nodes. - name: "CaLCMConfig" action: "aws:runCommand" onFailure: "step:signalfailure" nextStep: "OrcaInstanceId" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: - "{{CaInstanceIds.InstanceIds}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Sub '/aws/Quick_Start/${AWS::StackName}' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/LCM-Config.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./LCM-Config.ps1" # This step grabs the Instance ID for the node that will be configured as the Offline Root CA. - name: "OrcaInstanceId" action: aws:executeAwsApi onFailure: "step:signalfailure" nextStep: "TwoTierOrCaPreConfig" inputs: Service: ec2 Api: DescribeInstances Filters: - Name: "tag:Name" Values: [ "{{OrCaServerNetBIOSName}}" ] - Name: "tag:aws:cloudformation:stack-name" Values: ["{{StackName}}"] - Name: "instance-state-name" Values: [ "running" ] outputs: - Name: InstanceId Selector: "$.Reservations[0].Instances[0].InstanceId" Type: "String" # Generates MOF file on first Offline Root CA Node to be processed by LCM. - name: "TwoTierOrCaPreConfig" action: "aws:runCommand" onFailure: "step:signalfailure" nextStep: "ConfigOrCa" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: - "{{OrcaInstanceId.InstanceId}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Sub '/aws/Quick_Start/${AWS::StackName}' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/Invoke-TwoTierOrCaPreConfig.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./Invoke-TwoTierOrCaPreConfig.ps1 -OrCaNetBIOSName {{OrCaServerNetBIOSName}} -DomainController1IP {{DomainController1IP}} -DomainController2IP {{DomainController2IP}}" # Kicks off DSC Configuration and loops\reboots until Node matches Configuration defined in MOF file. - name: "ConfigOrCa" action: aws:runCommand onFailure: "step:signalfailure" nextStep: "TwoTierOrCaConfig" inputs: DocumentName: AWS-RunPowerShellScript InstanceIds: - "{{OrcaInstanceId.InstanceId}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Sub '/aws/Quick_Start/${AWS::StackName}' Parameters: commands: - | function DscStatusCheck () { $LCMState = (Get-DscLocalConfigurationManager).LCMState if ($LCMState -eq 'PendingConfiguration' -Or $LCMState -eq 'PendingReboot') { 'returning 3010, should continue after reboot' exit 3010 } else { 'Completed' } } Start-DscConfiguration 'C:\AWSQuickstart\ConfigOrCa' -Wait -Verbose -Force DscStatusCheck # Finalizes and cleans up Offline Root CA configuration. - name: "TwoTierOrCaConfig" action: "aws:runCommand" onFailure: "step:signalfailure" nextStep: "SubCaInstanceId" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: - "{{OrcaInstanceId.InstanceId}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Sub '/aws/Quick_Start/${AWS::StackName}' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/Invoke-TwoTierOrCaConfig.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./Invoke-TwoTierOrCaConfig.ps1 -DomainDNSName {{DomainDNSName}} -OrCaCommonName {{OrCaServerNetBIOSName}} -OrCaKeyLength {{OrCaKeyLength}} -OrCaHashAlgorithm {{OrCaHashAlgorithm}} -OrCaValidityPeriodUnits {{OrCaValidityPeriodUnits}} -ADAdminSecParam {{AdministratorSecret}} -UseS3ForCRL {{UseS3ForCRL}} -S3CRLBucketName {{S3CRLBucketName}} -DirectoryType {{DirectoryType}} -VPCCIDR {{VPCCIDR}} -SubCaServerNetBIOSName {{SubCaServerNetBIOSName}}" # This step grabs the Instance ID for the node that will be configured as the second DC in the new domain. - name: "SubCaInstanceId" action: aws:executeAwsApi onFailure: "step:signalfailure" nextStep: "TwoTierSubCaPreConfig" inputs: Service: ec2 Api: DescribeInstances Filters: - Name: "tag:Name" Values: [ "{{SubCaServerNetBIOSName}}" ] - Name: "tag:aws:cloudformation:stack-name" Values: ["{{StackName}}"] - Name: "instance-state-name" Values: [ "running" ] outputs: - Name: InstanceId Selector: "$.Reservations[0].Instances[0].InstanceId" Type: "String" # Generates MOF file on second DC Node to be processed by LCM. - name: "TwoTierSubCaPreConfig" action: "aws:runCommand" onFailure: "step:signalfailure" nextStep: "ConfigSubCa" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: - "{{SubCaInstanceId.InstanceId}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Sub '/aws/Quick_Start/${AWS::StackName}' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/Invoke-TwoTierSubCaPreConfig.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./Invoke-TwoTierSubCaPreConfig.ps1 -SubCaNetBIOSName {{SubCaServerNetBIOSName}} -DomainNetBIOSName {{DomainNetBIOSName}} -DomainDNSName {{DomainDNSName}} -DomainController1IP {{DomainController1IP}} -DomainController2IP {{DomainController2IP}} -ADAdminSecParam {{AdministratorSecret}} -UseS3ForCRL {{UseS3ForCRL}}" # Kicks off DSC Configuration and loops\reboots until Node matches Configuration defined in MOF file. - name: "ConfigSubCa" action: aws:runCommand onFailure: "step:signalfailure" nextStep: "TwoTierSubCaInstall" inputs: DocumentName: AWS-RunPowerShellScript InstanceIds: - "{{SubCaInstanceId.InstanceId}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Sub '/aws/Quick_Start/${AWS::StackName}' Parameters: commands: - | function DscStatusCheck () { $LCMState = (Get-DscLocalConfigurationManager).LCMState if ($LCMState -eq 'PendingConfiguration' -Or $LCMState -eq 'PendingReboot') { 'returning 3010, should continue after reboot' exit 3010 } else { 'Completed' } } Start-DscConfiguration 'C:\AWSQuickstart\ConfigSubCa' -Wait -Verbose -Force DscStatusCheck # Generates MOF file on second DC Node to be processed by LCM. - name: "TwoTierSubCaInstall" action: "aws:runCommand" onFailure: "step:signalfailure" nextStep: "TwoTierSubCaCertIssue" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: - "{{SubCaInstanceId.InstanceId}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Sub '/aws/Quick_Start/${AWS::StackName}' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/Invoke-TwoTierSubCaInstall.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./Invoke-TwoTierSubCaInstall.ps1 -SubCaCommonName {{SubCaServerNetBIOSName}} -SubCaKeyLength {{SubCaKeyLength}} -SubCaHashAlgorithm {{SubCaHashAlgorithm}} -SubCaValidityPeriodUnits {{SubCaValidityPeriodUnits}} -ADAdminSecParam {{AdministratorSecret}} -UseS3ForCRL {{UseS3ForCRL}} -S3CRLBucketName {{S3CRLBucketName}} -DirectoryType {{DirectoryType}}" # Issues SubCa cert from Offline Root CA configuration. - name: "TwoTierSubCaCertIssue" action: "aws:runCommand" onFailure: "step:signalfailure" nextStep: "TwoTierSubCaConfig" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: - "{{OrcaInstanceId.InstanceId}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Sub '/aws/Quick_Start/${AWS::StackName}' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/Invoke-TwoTierSubCaCertIssue.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./Invoke-TwoTierSubCaCertIssue.ps1 -DomainDNSName {{DomainDNSName}} -ADAdminSecParam {{AdministratorSecret}} -UseS3ForCRL {{UseS3ForCRL}} -DirectoryType {{DirectoryType}}" - name: "TwoTierSubCaConfig" action: "aws:runCommand" onFailure: "step:signalfailure" nextStep: "CFNSignalEnd" inputs: DocumentName: "AWS-RunRemoteScript" InstanceIds: - "{{SubCaInstanceId.InstanceId}}" CloudWatchOutputConfig: CloudWatchOutputEnabled: "true" CloudWatchLogGroupName: !Sub '/aws/Quick_Start/${AWS::StackName}' Parameters: sourceType: "S3" sourceInfo: !Sub - '{"path": "https://${S3Bucket}.s3.${S3Region}.{{URLSuffix}}/{{QSS3KeyPrefix}}scripts/Invoke-TwoTierSubCaConfig.ps1"}' - S3Bucket: !If - UsingDefaultBucket - !Sub '${QSS3BucketName}-${AWS::Region}' - !Ref QSS3BucketName S3Region: !If - UsingDefaultBucket - !Ref AWS::Region - !Ref QSS3BucketRegion commandLine: "./Invoke-TwoTierSubCaConfig.ps1 -ADAdminSecParam {{AdministratorSecret}} -UseS3ForCRL {{UseS3ForCRL}} -S3CRLBucketName {{S3CRLBucketName}} -DirectoryType {{DirectoryType}} -VPCCIDR {{VPCCIDR}}" # Determines if CFN Needs to be Signaled or if Work flow should just end - name: CFNSignalEnd action: aws:branch inputs: Choices: - NextStep: signalsuccess Not: Variable: "{{StackName}}" StringEquals: "" - NextStep: sleepend Variable: "{{StackName}}" StringEquals: "" # If all steps complete successfully signals CFN of Success - name: "signalsuccess" action: "aws:executeAwsApi" isEnd: True inputs: Service: cloudformation Api: SignalResource LogicalResourceId: "SubCA" StackName: "{{StackName}}" Status: SUCCESS UniqueId: "{{SubCaInstanceId.InstanceId}}" # If CFN Signl Not Needed this sleep ends work flow - name: "sleepend" action: "aws:sleep" isEnd: True inputs: Duration: PT1S # If any steps fails signals CFN of Failure - name: "signalfailure" action: "aws:executeAwsApi" inputs: Service: cloudformation Api: SignalResource LogicalResourceId: "SubCA" StackName: "{{StackName}}" Status: FAILURE UniqueId: "{{SubCaInstanceId.InstanceId}}" ORCA: Type: AWS::EC2::Instance Properties: ImageId: !Ref 'Ami' IamInstanceProfile: !Ref 'InstanceProfile' InstanceType: !Ref 'OrCaServerInstanceType' SubnetId: !Ref 'OrCaServerSubnet' Tags: - Key: Name Value: !Ref 'OrCaServerNetBIOSName' BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: VolumeSize: 60 VolumeType: gp3 - DeviceName: /dev/xvdf Ebs: VolumeSize: !Ref 'OrCaDataDriveSizeGiB' VolumeType: gp3 SecurityGroupIds: - !Ref 'CaSG' - !Ref 'DomainMembersSG' KeyName: !Ref 'KeyPairName' SubCA: Type: AWS::EC2::Instance DependsOn: ORCA CreationPolicy: ResourceSignal: Timeout: PT45M Count: 1 Properties: ImageId: !Ref 'Ami' IamInstanceProfile: !Ref 'InstanceProfile' InstanceType: !Ref 'SubCaServerInstanceType' SubnetId: !Ref 'SubCaServerSubnet' Tags: - Key: Name Value: !Ref 'SubCaServerNetBIOSName' BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: VolumeSize: 60 VolumeType: gp3 - DeviceName: /dev/xvdf Ebs: VolumeSize: !Ref 'SubCaDataDriveSizeGiB' VolumeType: gp3 SecurityGroupIds: - !Ref 'CaSG' - !Ref 'DomainMembersSG' KeyName: !Ref 'KeyPairName' UserData: !Base64 Fn::Join: - '' - - "\n" - 'Start-SSMAutomationExecution -DocumentName ' - !Sub '"${AWSQuickstartCA}"' - ' -Parameter @{' - '"VPCCIDR"=' - !Sub '"${VPCCIDR}"' - ';"AdministratorSecret"=' - !Sub '"${AdministratorSecret}"' - ';"OrCaServerNetBIOSName"=' - !Sub '"${OrCaServerNetBIOSName}"' - ';"SubCaServerNetBIOSName"=' - !Sub '"${SubCaServerNetBIOSName}"' - ';"DomainController1IP"=' - !Sub '"${DomainController1IP}"' - ';"DomainController2IP"=' - !Sub '"${DomainController2IP}"' - ';"DomainDNSName"=' - !Sub '"${DomainDNSName}"' - ';"DomainNetBIOSName"=' - !Sub '"${DomainNetBIOSName}"' - ';"OrCaKeyLength"=' - !Sub '"${OrCaKeyLength}"' - ';"OrCaHashAlgorithm"=' - !Sub '"${OrCaHashAlgorithm}"' - ';"OrCaValidityPeriodUnits"=' - !Sub '"${OrCaValidityPeriodUnits}"' - ';"SubCaKeyLength"=' - !Sub '"${SubCaKeyLength}"' - ';"SubCaHashAlgorithm"=' - !Sub '"${SubCaHashAlgorithm}"' - ';"SubCaValidityPeriodUnits"=' - !Sub '"${SubCaValidityPeriodUnits}"' - ';"UseS3ForCRL"=' - !Sub '"${UseS3ForCRL}"' - ';"S3CRLBucketName"=' - !Sub '"${S3CRLBucketName}"' - ';"DirectoryType"=' - !Sub '"${DirectoryType}"' - ';"QSS3BucketName"=' - !If [UsingDefaultBucket, !Sub '"${QSS3BucketName}-${AWS::Region}"', !Sub '"${QSS3BucketName}"'] - ';"QSS3BucketRegion"=' - !If [UsingDefaultBucket, !Sub '"${AWS::Region}"', !Sub '"${QSS3BucketRegion}"'] - ';"QSS3KeyPrefix"=' - !Sub '"${QSS3KeyPrefix}"' - ';"StackName"=' - !Sub '"${AWS::StackName}"' - ';"URLSuffix"=' - !Sub '"${AWS::URLSuffix}"' - '}' - "\n" - "\n" CaSG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: CA Security Group VpcId: !Ref VPCID SecurityGroupIngress: - IpProtocol: tcp Description: Certificate Enrollment FromPort: 135 ToPort: 135 CidrIp: !Ref VPCCIDR - IpProtocol: tcp Description: RDP FromPort: 3389 ToPort: 3389 SourceSecurityGroupId: !Ref DomainMembersSG - IpProtocol: tcp Description: Random RPC FromPort: 49152 ToPort: 65535 CidrIp: !Ref VPCCIDR Outputs: CASGID: Value: !Ref 'CaSG' Description: CA Security Group ID OrCaInstanceId: Value: !Ref 'ORCA' Description: ORCA instance ID SubCAInstanceId: Value: !Ref 'SubCA' Description: SubCA instance ID