AWSTemplateFormatVersion: 2010-09-09 Description: Managing Microsoft Workloads at Scale on AWS (qs-1scnfaifg) Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Network configuration for EC2 and ELB Parameters: - VPCID - PublicSubnet1ID - PublicSubnet2ID - PrivateSubnet1ID - PrivateSubnet2ID - Label: default: Microsoft Active Directory Domain configuration Parameters: - DomainJoinSecrets - Label: default: EC2 Configuration Parameters: - LatestAmiId ParameterLabels: DomainJoinSecrets: default: Secrets Manager Domain Secret ARN PrivateSubnet1ID: default: Private Subnet 1 ID PrivateSubnet2ID: default: Private Subnet 2 ID PublicSubnet1ID: default: Public Subnet 1 ID PublicSubnet2ID: default: Public Subnet 2 ID VPCID: default: VPC ID LatestAmiId: default: Amazon Machine Image (AMI) Id Parameters: DomainJoinSecrets: Description: Arn for for Secret Manager Secret containing password for joining machine to the domain. Type: String PublicSubnet1ID: Description: ID of subnet 1 in Availability Zone 1 (e.g., subnet-a0246dcd) Type: AWS::EC2::Subnet::Id PublicSubnet2ID: Description: ID of subnet 2 in Availability Zone 2 (e.g., subnet-a0246dcd) Type: AWS::EC2::Subnet::Id PrivateSubnet1ID: Description: ID of subnet 1 in Availability Zone 1 (e.g., subnet-a0246dcd) Type: AWS::EC2::Subnet::Id PrivateSubnet2ID: Description: ID of subnet 2 in Availability Zone 2 (e.g., subnet-a0246dcd) Type: AWS::EC2::Subnet::Id WEBCIDR: 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 ELBs. Use https://checkip.amazonaws.com/ to determine you IP and place here. Type: String VPCID: Description: ID of the VPC (e.g., vpc-0343606e) Type: AWS::EC2::VPC::Id LatestAmiId: Type: "AWS::SSM::Parameter::Value" Default: "/aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base" Resources: ###################### # Security Resources # ###################### InstanceRole: Type: AWS::IAM::Role Properties: Policies: - PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - secretsmanager:GetSecretValue - secretsmanager:DescribeSecret Resource: - !Ref "DomainJoinSecrets" PolicyName: secrets-policy - PolicyDocument: Version: "2012-10-17" Statement: - Action: - ssm:GetParameter Resource: - !Sub "arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${LogonMessageParam}" Effect: Allow PolicyName: ssm-param-policy - PolicyDocument: Version: "2012-10-17" Statement: - Action: - s3:GetObject - s3:PutObject - s3:PutObjectAcl - s3:ListBucket Resource: - !Sub "arn:${AWS::Partition}:s3:::${DSCBucket}/*" - !Sub "arn:${AWS::Partition}:s3:::${DSCBucket}" Effect: Allow PolicyName: dsc-bucket-policy - PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: s3:GetObject Resource: - !Sub arn:${AWS::Partition}:s3:::aws-ssm-${AWS::Region}/* - !Sub arn:${AWS::Partition}:s3:::aws-windows-downloads-${AWS::Region}/* - !Sub arn:${AWS::Partition}:s3:::amazon-ssm-${AWS::Region}/* - !Sub arn:${AWS::Partition}:s3:::amazon-ssm-packages-${AWS::Region}/* - !Sub arn:${AWS::Partition}:s3:::${AWS::Region}-birdwatcher-prod/* - !Sub arn:${AWS::Partition}:s3:::patch-baseline-snapshot-${AWS::Region}/* - !Sub arn:${AWS::Partition}:s3:::aws-ssm-distributor-file-${AWS::Region}/* - !Sub arn:${AWS::Partition}:s3:::aws-ssm-document-attachments-${AWS::Region}/* PolicyName: ssm-automation-policy - PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - ec2:CreateTags Resource: "*" Condition: "StringEquals": "aws:ARN": "${ec2:SourceInstanceARN}" "ForAllValues:StringEquals": "aws:TagKeys": Name PolicyName: self-ec2-tag-policy Path: / ManagedPolicyArns: - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEC2ReadOnlyAccess" - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore" - !Sub "arn:${AWS::Partition}:iam::aws:policy/CloudWatchAgentServerPolicy" Tags: - Key: StackName Value: !Ref AWS::StackName AssumeRolePolicyDocument: Statement: - Effect: Allow Action: sts:AssumeRole Principal: Service: - ec2.amazonaws.com Version: "2012-10-17" InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: InstanceProfileName: InstanceProfile Roles: [!Ref InstanceRole] ELBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Limits security group egress traffic VpcId: Ref: VPCID SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: !Ref WEBCIDR EC2SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Limits security group egress traffic VpcId: Ref: VPCID SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !GetAtt ELBSecurityGroup.GroupId ################### # App Resources # ################### DSCBucket: Type: AWS::S3::Bucket Properties: BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true LifecycleConfiguration: Rules: - Id: DeleteAfter30Days ExpirationInDays: 30 Status: Enabled Prefix: "logs" LogonMessageParam: Type: AWS::SSM::Parameter Properties: Description: Logon Message for Interactive Logon Name: LogonMessage Type: String Value: "'This is a Test System.,Testing how to Set a Logon Message with.,PowerShell DSC and AWS Systems Manager.,Parameter Store'" WEB01: Type: AWS::EC2::Instance Properties: InstanceType: t3.large ImageId: !Ref LatestAmiId IamInstanceProfile: !Ref InstanceProfile SubnetId: !Ref PrivateSubnet1ID SecurityGroupIds: - !Ref EC2SecurityGroup - !ImportValue DomainMemberSG Tags: - Key: "Name" Value: "WEB01" - Key: "Role" Value: "WebServer" - Key: "OperatingSystem" Value: "Windows" - Key: "Domain" Value: "example.com" UserData: Fn::Base64: | Install-WindowsFeature -Name WebServer -IncludeAllSubFeature Add-Content c:\inetpub\wwwroot\default.aspx '<%@ Page Title="" Language="C#" Trace="true"%>' del c:\inetpub\wwwroot\iisstart.htm WEB02: Type: AWS::EC2::Instance Properties: InstanceType: t3.large ImageId: !Ref LatestAmiId IamInstanceProfile: !Ref InstanceProfile SubnetId: !Ref PrivateSubnet2ID SecurityGroupIds: - !Ref EC2SecurityGroup - !ImportValue DomainMemberSG Tags: - Key: "Name" Value: "WEB02" - Key: "Role" Value: "WebServer" - Key: "OperatingSystem" Value: "Windows" - Key: "Domain" Value: "example.com" UserData: Fn::Base64: | Install-WindowsFeature -Name WebServer -IncludeAllSubFeature Add-Content c:\inetpub\wwwroot\default.aspx '<%@ Page Title="" Language="C#" Trace="true"%>' del c:\inetpub\wwwroot\iisstart.htm LoadBalancer: Type: AWS::ElasticLoadBalancing::LoadBalancer Properties: Subnets: - !Ref PublicSubnet1ID - !Ref PublicSubnet2ID Instances: - !Ref WEB01 - !Ref WEB02 SecurityGroups: - !Ref ELBSecurityGroup Listeners: - LoadBalancerPort: "80" InstancePort: "80" Protocol: HTTP HealthCheck: Target: HTTP:80/ HealthyThreshold: "3" UnhealthyThreshold: "5" Interval: "30" Timeout: "5" Outputs: URL: Description: The URL for the LoadBalancer Value: !Sub http://${LoadBalancer.DNSName} DSCBucket: Value: !Ref DSCBucket Description: Bucket Name for Mof files Export: Name: DSCBucket InstanceRoleArn: Value: !GetAtt InstanceRole.Arn Description: The Arn for the IAM Role for the Managed Instances Export: Name: InstanceRoleArn InstanceProfileName: Value: !Ref InstanceProfile Description: Instance profile name Export: Name: InstanceProfile EC2SecurityGroup: Value: !Ref EC2SecurityGroup Description: Security Groups between IIS Servers and ELB Export: Name: EC2SecurityGroup ELBSecurityGroup: Value: !Ref ELBSecurityGroup Description: Security Groups between IIS Servers and ELB Export: Name: ELBSecurityGroup