部署 VPC 架构和 Microsoft Active Directory 域控制器 - Amazon Systems Manager
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

部署 VPC 架构和 Microsoft Active Directory 域控制器

要提高效率并实现常见任务的标准化,可以选择自动执行部署。如果您定期在多个账户和 Amazon Web Services 区域 中部署相同的架构,此操作会很有帮助。自动进行架构部署还可以降低在手动部署架构时发生人为错误的可能性。Amazon Systems Manager自动化操作可帮助您做到这一点。自动化是 Amazon Systems Manager 的一项功能。

以下示例 Amazon Systems Manager 运行手册执行这些操作:

  • 使用 Systems Manager Parameter Store 检索最新的 Windows Server 2016 Amazon Machine Image (AMI),以在启动将配置作为域控制器的 EC2 实例时使用。Parameter Store 是 Amazon Systems Manager 的一项功能。

  • 使用 aws:executeAwsApi 自动化操作调用多个 Amazon API 操作来创建 VPC 架构。域控制器实例在私有子网中启动,使用 NAT 网关连接到 Internet。这允许实例上的 SSM Agent 以访问必需的 Systems Manager 端点。

  • 使用 aws:waitForAwsResourceProperty 自动化操作确认上一个操作所启动的实例对于 Online 处于 Amazon Systems Manager 状态。

  • 使用 aws:runCommand 自动化操作配置作为 Microsoft Active Directory 域控制器启动的实例。

YAML
--- description: Custom Automation Deployment Example schemaVersion: '0.3' parameters: AutomationAssumeRole: type: String default: '' description: >- (Optional) The ARN of the role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to run this runbook. mainSteps: - name: getLatestWindowsAmi action: aws:executeAwsApi onFailure: Abort inputs: Service: ssm Api: GetParameter Name: >- /aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base outputs: - Name: amiId Selector: $.Parameter.Value Type: String nextStep: createSSMInstanceRole - name: createSSMInstanceRole action: aws:executeAwsApi onFailure: Abort inputs: Service: iam Api: CreateRole AssumeRolePolicyDocument: >- {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":["ec2.amazonaws.com"]},"Action":["sts:AssumeRole"]}]} RoleName: sampleSSMInstanceRole nextStep: attachManagedSSMPolicy - name: attachManagedSSMPolicy action: aws:executeAwsApi onFailure: Abort inputs: Service: iam Api: AttachRolePolicy PolicyArn: 'arn:aws:iam::aws:policy/service-role/AmazonSSMManagedInstanceCore' RoleName: sampleSSMInstanceRole nextStep: createSSMInstanceProfile - name: createSSMInstanceProfile action: aws:executeAwsApi onFailure: Abort inputs: Service: iam Api: CreateInstanceProfile InstanceProfileName: sampleSSMInstanceRole outputs: - Name: instanceProfileArn Selector: $.InstanceProfile.Arn Type: String nextStep: addSSMInstanceRoleToProfile - name: addSSMInstanceRoleToProfile action: aws:executeAwsApi onFailure: Abort inputs: Service: iam Api: AddRoleToInstanceProfile InstanceProfileName: sampleSSMInstanceRole RoleName: sampleSSMInstanceRole nextStep: createVpc - name: createVpc action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: CreateVpc CidrBlock: 10.0.100.0/22 outputs: - Name: vpcId Selector: $.Vpc.VpcId Type: String nextStep: getMainRtb - name: getMainRtb action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: DescribeRouteTables Filters: - Name: vpc-id Values: - '{{ createVpc.vpcId }}' outputs: - Name: mainRtbId Selector: '$.RouteTables[0].RouteTableId' Type: String nextStep: verifyMainRtb - name: verifyMainRtb action: aws:assertAwsResourceProperty onFailure: Abort inputs: Service: ec2 Api: DescribeRouteTables RouteTableIds: - '{{ getMainRtb.mainRtbId }}' PropertySelector: '$.RouteTables[0].Associations[0].Main' DesiredValues: - 'True' nextStep: createPubSubnet - name: createPubSubnet action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: CreateSubnet CidrBlock: 10.0.103.0/24 AvailabilityZone: us-west-2c VpcId: '{{ createVpc.vpcId }}' outputs: - Name: pubSubnetId Selector: $.Subnet.SubnetId Type: String nextStep: createPubRtb - name: createPubRtb action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: CreateRouteTable VpcId: '{{ createVpc.vpcId }}' outputs: - Name: pubRtbId Selector: $.RouteTable.RouteTableId Type: String nextStep: createIgw - name: createIgw action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: CreateInternetGateway outputs: - Name: igwId Selector: $.InternetGateway.InternetGatewayId Type: String nextStep: attachIgw - name: attachIgw action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: AttachInternetGateway InternetGatewayId: '{{ createIgw.igwId }}' VpcId: '{{ createVpc.vpcId }}' nextStep: allocateEip - name: allocateEip action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: AllocateAddress Domain: vpc outputs: - Name: eipAllocationId Selector: $.AllocationId Type: String nextStep: createNatGw - name: createNatGw action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: CreateNatGateway AllocationId: '{{ allocateEip.eipAllocationId }}' SubnetId: '{{ createPubSubnet.pubSubnetId }}' outputs: - Name: natGwId Selector: $.NatGateway.NatGatewayId Type: String nextStep: verifyNatGwAvailable - name: verifyNatGwAvailable action: aws:waitForAwsResourceProperty timeoutSeconds: 150 inputs: Service: ec2 Api: DescribeNatGateways NatGatewayIds: - '{{ createNatGw.natGwId }}' PropertySelector: '$.NatGateways[0].State' DesiredValues: - available nextStep: createNatRoute - name: createNatRoute action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: CreateRoute DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: '{{ createNatGw.natGwId }}' RouteTableId: '{{ getMainRtb.mainRtbId }}' nextStep: createPubRoute - name: createPubRoute action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: CreateRoute DestinationCidrBlock: 0.0.0.0/0 GatewayId: '{{ createIgw.igwId }}' RouteTableId: '{{ createPubRtb.pubRtbId }}' nextStep: setPubSubAssoc - name: setPubSubAssoc action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: AssociateRouteTable RouteTableId: '{{ createPubRtb.pubRtbId }}' SubnetId: '{{ createPubSubnet.pubSubnetId }}' - name: createDhcpOptions action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: CreateDhcpOptions DhcpConfigurations: - Key: domain-name-servers Values: - '10.0.100.50,10.0.101.50' - Key: domain-name Values: - sample.com outputs: - Name: dhcpOptionsId Selector: $.DhcpOptions.DhcpOptionsId Type: String nextStep: createDCSubnet1 - name: createDCSubnet1 action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: CreateSubnet CidrBlock: 10.0.100.0/24 AvailabilityZone: us-west-2a VpcId: '{{ createVpc.vpcId }}' outputs: - Name: firstSubnetId Selector: $.Subnet.SubnetId Type: String nextStep: createDCSubnet2 - name: createDCSubnet2 action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: CreateSubnet CidrBlock: 10.0.101.0/24 AvailabilityZone: us-west-2b VpcId: '{{ createVpc.vpcId }}' outputs: - Name: secondSubnetId Selector: $.Subnet.SubnetId Type: String nextStep: createDCSecGroup - name: createDCSecGroup action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: CreateSecurityGroup GroupName: SampleDCSecGroup Description: Security Group for Sample Domain Controllers VpcId: '{{ createVpc.vpcId }}' outputs: - Name: dcSecGroupId Selector: $.GroupId Type: String nextStep: authIngressDCTraffic - name: authIngressDCTraffic action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: AuthorizeSecurityGroupIngress GroupId: '{{ createDCSecGroup.dcSecGroupId }}' IpPermissions: - FromPort: -1 IpProtocol: '-1' IpRanges: - CidrIp: 0.0.0.0/0 Description: Allow all traffic between Domain Controllers nextStep: verifyInstanceProfile - name: verifyInstanceProfile action: aws:waitForAwsResourceProperty maxAttempts: 5 onFailure: Abort inputs: Service: iam Api: ListInstanceProfilesForRole RoleName: sampleSSMInstanceRole PropertySelector: '$.InstanceProfiles[0].Arn' DesiredValues: - '{{ createSSMInstanceProfile.instanceProfileArn }}' nextStep: iamEventualConsistency - name: iamEventualConsistency action: aws:sleep inputs: Duration: PT2M nextStep: launchDC1 - name: launchDC1 action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: RunInstances BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: DeleteOnTermination: true VolumeSize: 50 VolumeType: gp2 - DeviceName: xvdf Ebs: DeleteOnTermination: true VolumeSize: 100 VolumeType: gp2 IamInstanceProfile: Arn: '{{ createSSMInstanceProfile.instanceProfileArn }}' ImageId: '{{ getLatestWindowsAmi.amiId }}' InstanceType: t2.micro MaxCount: 1 MinCount: 1 PrivateIpAddress: 10.0.100.50 SecurityGroupIds: - '{{ createDCSecGroup.dcSecGroupId }}' SubnetId: '{{ createDCSubnet1.firstSubnetId }}' TagSpecifications: - ResourceType: instance Tags: - Key: Name Value: SampleDC1 outputs: - Name: pdcInstanceId Selector: '$.Instances[0].InstanceId' Type: String nextStep: launchDC2 - name: launchDC2 action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: RunInstances BlockDeviceMappings: - DeviceName: /dev/sda1 Ebs: DeleteOnTermination: true VolumeSize: 50 VolumeType: gp2 - DeviceName: xvdf Ebs: DeleteOnTermination: true VolumeSize: 100 VolumeType: gp2 IamInstanceProfile: Arn: '{{ createSSMInstanceProfile.instanceProfileArn }}' ImageId: '{{ getLatestWindowsAmi.amiId }}' InstanceType: t2.micro MaxCount: 1 MinCount: 1 PrivateIpAddress: 10.0.101.50 SecurityGroupIds: - '{{ createDCSecGroup.dcSecGroupId }}' SubnetId: '{{ createDCSubnet2.secondSubnetId }}' TagSpecifications: - ResourceType: instance Tags: - Key: Name Value: SampleDC2 outputs: - Name: adcInstanceId Selector: '$.Instances[0].InstanceId' Type: String nextStep: verifyDCInstanceState - name: verifyDCInstanceState action: aws:waitForAwsResourceProperty inputs: Service: ec2 Api: DescribeInstanceStatus IncludeAllInstances: true InstanceIds: - '{{ launchDC1.pdcInstanceId }}' - '{{ launchDC2.adcInstanceId }}' PropertySelector: '$.InstanceStatuses[0].InstanceState.Name' DesiredValues: - running nextStep: verifyInstancesOnlineSSM - name: verifyInstancesOnlineSSM action: aws:waitForAwsResourceProperty timeoutSeconds: 600 inputs: Service: ssm Api: DescribeInstanceInformation InstanceInformationFilterList: - key: InstanceIds valueSet: - '{{ launchDC1.pdcInstanceId }}' - '{{ launchDC2.adcInstanceId }}' PropertySelector: '$.InstanceInformationList[0].PingStatus' DesiredValues: - Online nextStep: installADRoles - name: installADRoles action: aws:runCommand inputs: DocumentName: AWS-RunPowerShellScript InstanceIds: - '{{ launchDC1.pdcInstanceId }}' - '{{ launchDC2.adcInstanceId }}' Parameters: commands: |- try { Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools } catch { Write-Error "Failed to install ADDS Role." } nextStep: setAdminPassword - name: setAdminPassword action: aws:runCommand inputs: DocumentName: AWS-RunPowerShellScript InstanceIds: - '{{ launchDC1.pdcInstanceId }}' Parameters: commands: - net user Administrator "sampleAdminPass123!" nextStep: createForest - name: createForest action: aws:runCommand inputs: DocumentName: AWS-RunPowerShellScript InstanceIds: - '{{ launchDC1.pdcInstanceId }}' Parameters: commands: |- $dsrmPass = 'sample123!' | ConvertTo-SecureString -asPlainText -Force try { Install-ADDSForest -DomainName "sample.com" -DomainMode 6 -ForestMode 6 -InstallDNS -DatabasePath "D:\NTDS" -SysvolPath "D:\SYSVOL" -SafeModeAdministratorPassword $dsrmPass -Force } catch { Write-Error $_ } try { Add-DnsServerForwarder -IPAddress "10.0.100.2" } catch { Write-Error $_ } nextStep: associateDhcpOptions - name: associateDhcpOptions action: aws:executeAwsApi onFailure: Abort inputs: Service: ec2 Api: AssociateDhcpOptions DhcpOptionsId: '{{ createDhcpOptions.dhcpOptionsId }}' VpcId: '{{ createVpc.vpcId }}' nextStep: waitForADServices - name: waitForADServices action: aws:sleep inputs: Duration: PT1M nextStep: promoteADC - name: promoteADC action: aws:runCommand inputs: DocumentName: AWS-RunPowerShellScript InstanceIds: - '{{ launchDC2.adcInstanceId }}' Parameters: commands: |- ipconfig /renew $dsrmPass = 'sample123!' | ConvertTo-SecureString -asPlainText -Force $domAdminUser = "sample\Administrator" $domAdminPass = "sampleAdminPass123!" | ConvertTo-SecureString -asPlainText -Force $domAdminCred = New-Object System.Management.Automation.PSCredential($domAdminUser,$domAdminPass) try { Install-ADDSDomainController -DomainName "sample.com" -InstallDNS -DatabasePath "D:\NTDS" -SysvolPath "D:\SYSVOL" -SafeModeAdministratorPassword $dsrmPass -Credential $domAdminCred -Force } catch { Write-Error $_ }
JSON
{ "description": "Custom Automation Deployment Example", "schemaVersion": "0.3", "assumeRole": "{{ AutomationAssumeRole }}", "parameters": { "AutomationAssumeRole": { "type": "String", "description": "(Optional) The ARN of the role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to run this runbook.", "default": "" } }, "mainSteps": [ { "name": "getLatestWindowsAmi", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ssm", "Api": "GetParameter", "Name": "/aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base" }, "outputs": [ { "Name": "amiId", "Selector": "$.Parameter.Value", "Type": "String" } ], "nextStep": "createSSMInstanceRole" }, { "name": "createSSMInstanceRole", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "iam", "Api": "CreateRole", "AssumeRolePolicyDocument": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}", "RoleName": "sampleSSMInstanceRole" }, "nextStep": "attachManagedSSMPolicy" }, { "name": "attachManagedSSMPolicy", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "iam", "Api": "AttachRolePolicy", "PolicyArn": "arn:aws:iam::aws:policy/service-role/AmazonSSMManagedInstanceCore", "RoleName": "sampleSSMInstanceRole" }, "nextStep": "createSSMInstanceProfile" }, { "name": "createSSMInstanceProfile", "action":"aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "iam", "Api": "CreateInstanceProfile", "InstanceProfileName": "sampleSSMInstanceRole" }, "outputs": [ { "Name": "instanceProfileArn", "Selector": "$.InstanceProfile.Arn", "Type": "String" } ], "nextStep": "addSSMInstanceRoleToProfile" }, { "name": "addSSMInstanceRoleToProfile", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "iam", "Api": "AddRoleToInstanceProfile", "InstanceProfileName": "sampleSSMInstanceRole", "RoleName": "sampleSSMInstanceRole" }, "nextStep": "createVpc" }, { "name": "createVpc", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "CreateVpc", "CidrBlock": "10.0.100.0/22" }, "outputs": [ { "Name": "vpcId", "Selector": "$.Vpc.VpcId", "Type": "String" } "nextStep": "getMainRtb" }, { "name": "getMainRtb", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "DescribeRouteTables", "Filters": [ { "Name": "vpc-id", "Values": ["{{ createVpc.vpcId }}"] } ] }, "outputs": [ { "Name": "mainRtbId", "Selector": "$.RouteTables[0].RouteTableId", "Type": "String" } ], "nextStep": "verifyMainRtb" }, { "name": "verifyMainRtb", "action": "aws:assertAwsResourceProperty", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "DescribeRouteTables", "RouteTableIds": ["{{ getMainRtb.mainRtbId }}"], "PropertySelector": "$.RouteTables[0].Associations[0].Main", "DesiredValues": ["True"] }, "nextStep": "createPubSubnet" }, { "name": "createPubSubnet", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "CreateSubnet", "CidrBlock": "10.0.103.0/24", "AvailabilityZone": "us-west-2c", "VpcId": "{{ createVpc.vpcId }}" }, "outputs":[ { "Name": "pubSubnetId", "Selector": "$.Subnet.SubnetId", "Type": "String" } ], "nextStep": "createPubRtb" }, { "name": "createPubRtb", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "CreateRouteTable", "VpcId": "{{ createVpc.vpcId }}" }, "outputs": [ { "Name": "pubRtbId", "Selector": "$.RouteTable.RouteTableId", "Type": "String" } ], "nextStep": "createIgw" }, { "name": "createIgw", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "CreateInternetGateway" }, "outputs": [ { "Name": "igwId", "Selector": "$.InternetGateway.InternetGatewayId", "Type": "String" } ], "nextStep": "attachIgw" }, { "name": "attachIgw", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "AttachInternetGateway", "InternetGatewayId": "{{ createIgw.igwId }}", "VpcId": "{{ createVpc.vpcId }}" }, "nextStep": "allocateEip" }, { "name": "allocateEip", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "AllocateAddress", "Domain": "vpc" }, "outputs": [ { "Name": "eipAllocationId", "Selector": "$.AllocationId", "Type": "String" } ], "nextStep": "createNatGw" }, { "name": "createNatGw", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "CreateNatGateway", "AllocationId": "{{ allocateEip.eipAllocationId }}", "SubnetId": "{{ createPubSubnet.pubSubnetId }}" }, "outputs":[ { "Name": "natGwId", "Selector": "$.NatGateway.NatGatewayId", "Type": "String" } ], "nextStep": "verifyNatGwAvailable" }, { "name": "verifyNatGwAvailable", "action": "aws:waitForAwsResourceProperty", "timeoutSeconds": 150, "inputs": { "Service": "ec2", "Api": "DescribeNatGateways", "NatGatewayIds": [ "{{ createNatGw.natGwId }}" ], "PropertySelector": "$.NatGateways[0].State", "DesiredValues": [ "available" ] }, "nextStep": "createNatRoute" }, { "name": "createNatRoute", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "CreateRoute", "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": "{{ createNatGw.natGwId }}", "RouteTableId": "{{ getMainRtb.mainRtbId }}" }, "nextStep": "createPubRoute" }, { "name": "createPubRoute", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "CreateRoute", "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": "{{ createIgw.igwId }}", "RouteTableId": "{{ createPubRtb.pubRtbId }}" }, "nextStep": "setPubSubAssoc" }, { "name": "setPubSubAssoc", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "AssociateRouteTable", "RouteTableId": "{{ createPubRtb.pubRtbId }}", "SubnetId": "{{ createPubSubnet.pubSubnetId }}" } }, { "name": "createDhcpOptions", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "CreateDhcpOptions", "DhcpConfigurations": [ { "Key": "domain-name-servers", "Values": ["10.0.100.50,10.0.101.50"] }, { "Key": "domain-name", "Values": ["sample.com"] } ] }, "outputs": [ { "Name": "dhcpOptionsId", "Selector": "$.DhcpOptions.DhcpOptionsId", "Type": "String" } ], "nextStep": "createDCSubnet1" }, { "name": "createDCSubnet1", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "CreateSubnet", "CidrBlock": "10.0.100.0/24", "AvailabilityZone": "us-west-2a", "VpcId": "{{ createVpc.vpcId }}" }, "outputs": [ { "Name": "firstSubnetId", "Selector": "$.Subnet.SubnetId", "Type": "String" } ], "nextStep": "createDCSubnet2" }, { "name": "createDCSubnet2", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "CreateSubnet", "CidrBlock": "10.0.101.0/24", "AvailabilityZone": "us-west-2b", "VpcId": "{{ createVpc.vpcId }}" }, "outputs": [ { "Name": "secondSubnetId", "Selector": "$.Subnet.SubnetId", "Type": "String" } ], "nextStep": "createDCSecGroup" }, { "name": "createDCSecGroup", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "CreateSecurityGroup", "GroupName": "SampleDCSecGroup", "Description": "Security Group for Example Domain Controllers", "VpcId": "{{ createVpc.vpcId }}" }, "outputs": [ { "Name": "dcSecGroupId", "Selector": "$.GroupId", "Type": "String" } ], "nextStep": "authIngressDCTraffic" }, { "name": "authIngressDCTraffic", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "AuthorizeSecurityGroupIngress", "GroupId": "{{ createDCSecGroup.dcSecGroupId }}", "IpPermissions": [ { "FromPort": -1, "IpProtocol": "-1", "IpRanges": [ { "CidrIp": "0.0.0.0/0", "Description": "Allow all traffic between Domain Controllers" } ] } ] }, "nextStep": "verifyInstanceProfile" }, { "name": "verifyInstanceProfile", "action": "aws:waitForAwsResourceProperty", "maxAttempts": 5, "onFailure": "Abort", "inputs": { "Service": "iam", "Api": "ListInstanceProfilesForRole", "RoleName": "sampleSSMInstanceRole", "PropertySelector": "$.InstanceProfiles[0].Arn", "DesiredValues": [ "{{ createSSMInstanceProfile.instanceProfileArn }}" ] }, "nextStep": "iamEventualConsistency" }, { "name": "iamEventualConsistency", "action": "aws:sleep", "inputs": { "Duration": "PT2M" }, "nextStep": "launchDC1" }, { "name": "launchDC1", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "RunInstances", "BlockDeviceMappings": [ { "DeviceName": "/dev/sda1", "Ebs": { "DeleteOnTermination": true, "VolumeSize": 50, "VolumeType": "gp2" } }, { "DeviceName": "xvdf", "Ebs": { "DeleteOnTermination": true, "VolumeSize": 100, "VolumeType": "gp2" } } ], "IamInstanceProfile": { "Arn": "{{ createSSMInstanceProfile.instanceProfileArn }}" }, "ImageId": "{{ getLatestWindowsAmi.amiId }}", "InstanceType": "t2.micro", "MaxCount": 1, "MinCount": 1, "PrivateIpAddress": "10.0.100.50", "SecurityGroupIds": [ "{{ createDCSecGroup.dcSecGroupId }}" ], "SubnetId": "{{ createDCSubnet1.firstSubnetId }}", "TagSpecifications": [ { "ResourceType": "instance", "Tags": [ { "Key": "Name", "Value": "SampleDC1" } ] } ] }, "outputs": [ { "Name": "pdcInstanceId", "Selector": "$.Instances[0].InstanceId", "Type": "String" } ], "nextStep": "launchDC2" }, { "name": "launchDC2", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "RunInstances", "BlockDeviceMappings": [ { "DeviceName": "/dev/sda1", "Ebs": { "DeleteOnTermination": true, "VolumeSize": 50, "VolumeType": "gp2" } }, { "DeviceName": "xvdf", "Ebs": { "DeleteOnTermination": true, "VolumeSize": 100, "VolumeType": "gp2" } } ], "IamInstanceProfile": { "Arn": "{{ createSSMInstanceProfile.instanceProfileArn }}" }, "ImageId": "{{ getLatestWindowsAmi.amiId }}", "InstanceType": "t2.micro", "MaxCount": 1, "MinCount": 1, "PrivateIpAddress": "10.0.101.50", "SecurityGroupIds": [ "{{ createDCSecGroup.dcSecGroupId }}" ], "SubnetId": "{{ createDCSubnet2.secondSubnetId }}", "TagSpecifications": [ { "ResourceType": "instance", "Tags": [ { "Key": "Name", "Value": "SampleDC2" } ] } ] }, "outputs": [ { "Name": "adcInstanceId", "Selector": "$.Instances[0].InstanceId", "Type": "String" } ], "nextStep": "verifyDCInstanceState" }, { "name": "verifyDCInstanceState", "action": "aws:waitForAwsResourceProperty", "inputs": { "Service": "ec2", "Api": "DescribeInstanceStatus", "IncludeAllInstances": true, "InstanceIds": [ "{{ launchDC1.pdcInstanceId }}", "{{ launchDC2.adcInstanceId }}" ], "PropertySelector": "$.InstanceStatuses[0].InstanceState.Name", "DesiredValues": [ "running" ] }, "nextStep": "verifyInstancesOnlineSSM" }, { "name": "verifyInstancesOnlineSSM", "action": "aws:waitForAwsResourceProperty", "timeoutSeconds": 600, "inputs": { "Service": "ssm", "Api": "DescribeInstanceInformation", "InstanceInformationFilterList": [ { "key": "InstanceIds", "valueSet": [ "{{ launchDC1.pdcInstanceId }}", "{{ launchDC2.adcInstanceId }}" ] } ], "PropertySelector": "$.InstanceInformationList[0].PingStatus", "DesiredValues": [ "Online" ] }, "nextStep": "installADRoles" }, { "name": "installADRoles", "action": "aws:runCommand", "inputs": { "DocumentName": "AWS-RunPowerShellScript", "InstanceIds": [ "{{ launchDC1.pdcInstanceId }}", "{{ launchDC2.adcInstanceId }}" ], "Parameters": { "commands": [ "try {", " Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools", "}", "catch {", " Write-Error \"Failed to install ADDS Role.\"", "}" ] } }, "nextStep": "setAdminPassword" }, { "name": "setAdminPassword", "action": "aws:runCommand", "inputs": { "DocumentName": "AWS-RunPowerShellScript", "InstanceIds": [ "{{ launchDC1.pdcInstanceId }}" ], "Parameters": { "commands": [ "net user Administrator \"sampleAdminPass123!\"" ] } }, "nextStep": "createForest" }, { "name": "createForest", "action": "aws:runCommand", "inputs": { "DocumentName": "AWS-RunPowerShellScript", "InstanceIds": [ "{{ launchDC1.pdcInstanceId }}" ], "Parameters": { "commands": [ "$dsrmPass = 'sample123!' | ConvertTo-SecureString -asPlainText -Force", "try {", " Install-ADDSForest -DomainName \"sample.com\" -DomainMode 6 -ForestMode 6 -InstallDNS -DatabasePath \"D:\\NTDS\" -SysvolPath \"D:\\SYSVOL\" -SafeModeAdministratorPassword $dsrmPass -Force", "}", "catch {", " Write-Error $_", "}", "try {", " Add-DnsServerForwarder -IPAddress \"10.0.100.2\"", "}", "catch {", " Write-Error $_", "}" ] } }, "nextStep": "associateDhcpOptions" }, { "name": "associateDhcpOptions", "action": "aws:executeAwsApi", "onFailure": "Abort", "inputs": { "Service": "ec2", "Api": "AssociateDhcpOptions", "DhcpOptionsId": "{{ createDhcpOptions.dhcpOptionsId }}", "VpcId": "{{ createVpc.vpcId }}" }, "nextStep": "waitForADServices" }, { "name": "waitForADServices", "action": "aws:sleep", "inputs": { "Duration": "PT1M" }, "nextStep": "promoteADC" }, { "name": "promoteADC", "action": "aws:runCommand", "inputs": { "DocumentName": "AWS-RunPowerShellScript", "InstanceIds": [ "{{ launchDC2.adcInstanceId }}" ], "Parameters": { "commands": [ "ipconfig /renew", "$dsrmPass = 'sample123!' | ConvertTo-SecureString -asPlainText -Force", "$domAdminUser = \"sample\\Administrator\"", "$domAdminPass = \"sampleAdminPass123!\" | ConvertTo-SecureString -asPlainText -Force", "$domAdminCred = New-Object System.Management.Automation.PSCredential($domAdminUser,$domAdminPass)", "try {", " Install-ADDSDomainController -DomainName \"sample.com\" -InstallDNS -DatabasePath \"D:\\NTDS\" -SysvolPath \"D:\\SYSVOL\" -SafeModeAdministratorPassword $dsrmPass -Credential $domAdminCred -Force", "}", "catch {", " Write-Error $_", "}" ] } } } ] }