AWSTemplateFormatVersion: '2010-09-09' Description: Security resources for IIS (qs-1r91fg4f3) Parameters: ConfigBucket: AllowedPattern: '^[a-z0-9]+[a-z0-9\.\-]*[a-z0-9]+$' ConstraintDescription: Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Description: S3 bucket name where PowerShell DSC Mof files exist and HTML web files. Config bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String DomainJoinSecrets: AllowedPattern: '^arn:[^:]+:secretsmanager:[^:]+:\d{12}:secret:[\w\/+=.@-]{1,512}$' Description: "The Secrets Manager name or ARN that will be used to perform all need domain actions." MaxLength: '2048' MinLength: '20' Type: "String" ECSClusterName: AllowedPattern: '^([\w\-]+)?$' Description: Name of ECS cluster. MaxLength: "255" Type: String WebAccessCIDR: 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 ELBs. Type: String SetupConfigurationDocName: AllowedPattern: '^[a-zA-Z0-9\_\\\-\.]{3,128}$' MaxLength: "128" MinLength: "3" Type: String Description: Document name of AWS Systems Manager Automation Document for Setup Config to trigger using EventBridge. RemoveConfigurationDocName: AllowedPattern: ^[a-zA-Z0-9\_\\\-\.]{3,128}$ MaxLength: "128" MinLength: "3" Type: String Description: Document name of AWS Systems Manager Automation Document for Removal Config to trigger using EventBridge. WebBucketName: AllowedPattern: '^([a-z0-9]+[a-z0-9\.\-]*[a-z0-9]+)?$' Type: String Description: Bucket name where html file is located for iis. If left blank, a sample page will be used. Default: "" WebBucketKey: AllowedPattern: '^[0-9a-zA-Z\-\/\.]+$' ConstraintDescription: Can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slashes (/). Description: Bucket Key where html file is located for iis. Only change S3 Bucket Wepage is specified, otherwise leave as default. Default: "webfiles/index.html" Type: String VPCID: Description: "VPC ID where the security groups will reside" Type: AWS::EC2::VPC::Id Conditions: ECSDeploy: !Not - !Equals - !Ref ECSClusterName - '' Resources: ExecutionResourceRole: Type: AWS::IAM::Role Properties: Policies: - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - autoscaling:CompleteLifecycleAction Resource: !If - ECSDeploy - !Sub arn:aws:autoscaling:*:${AWS::AccountId}:autoScalingGroup:*:autoScalingGroupName/ECS-AutoscalingGroup-${AWS::StackName} - !Sub arn:aws:autoscaling:*:${AWS::AccountId}:autoScalingGroup:*:autoScalingGroupName/EC2-AutoscalingGroup-${AWS::StackName} PolicyName: asg-lch-complete AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ssm.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonSSMAutomationRole Description: New IAM Role to allow SSM access. WriteS3LambdaRole: Type: AWS::IAM::Role Properties: Policies: - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - s3:PutObject - s3:DeleteObject - s3:ListBucket Resource: - !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}" - !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}/*" PolicyName: write-mof-s3 Path: / AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - !Sub 'arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' ECSTaskRole: Condition: ECSDeploy Type: AWS::IAM::Role Properties: Policies: - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - s3:GetObject Resource: - !Sub "arn:${AWS::Partition}:s3:::${WebBucketName}/${WebBucketKey}" PolicyName: ecs-get-bucket-info Path: / ManagedPolicyArns: - !Sub 'arn:${AWS::Partition}:iam::aws:policy/CloudWatchAgentServerPolicy' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ecs-tasks.amazonaws.com Action: sts:AssumeRole ECSInstancePolicy: Condition: ECSDeploy Metadata: cfn-lint: config: ignore_checks: - EIAMPolicyActionWildcard ignore_reasons: EIAMPolicyActionWildcard: Multiple ECS actions are needed Type: 'AWS::IAM::Policy' Properties: PolicyName: InstacePolicyForECS PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 'ecs:Poll' - 'ecs:StartTelemetrySession' - 'ecs:UpdateContainerInstancesState' Resource: !Sub arn:${AWS::Partition}:ecs:${AWS::Region}:${AWS::AccountId}:container-instance/* Condition: 'ArnLikeIfExists': 'ecs:cluster': !Sub arn:${AWS::Partition}:ecs:${AWS::Region}:${AWS::AccountId}:cluster/${ECSClusterName} - Effect: Allow Action: - 'ecs:DeregisterContainerInstance' - 'ecs:DiscoverPollEndpoint' - 'ecs:RegisterContainerInstance' - 'ecs:Submit*' Resource: !Sub arn:${AWS::Partition}:ecs:${AWS::Region}:${AWS::AccountId}:cluster/${ECSClusterName} - Effect: Allow Action: - 'ecs:DiscoverPollEndpoint' Resource: '*' Roles: - !Ref SSMInstanceRole SSMInstanceRole: Type : AWS::IAM::Role Properties: Policies: - PolicyDocument: Version: '2012-10-17' Statement: - 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:::${ConfigBucket}/*" - !Sub "arn:${AWS::Partition}:s3:::${WebBucketName}/${WebBucketKey}" Effect: Allow PolicyName: ssm-custom-s3-policy - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - secretsmanager:GetSecretValue - secretsmanager:DescribeSecret Resource: - !Ref 'DomainJoinSecrets' PolicyName: ssm-secrets-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: qs-tags-policy - PolicyDocument: Version: '2012-10-17' Statement: - Action: - s3:ListBucket Resource: - !Sub "arn:${AWS::Partition}:s3:::${ConfigBucket}" Effect: Allow PolicyName: s3-instance-bucket-policy Path: / ManagedPolicyArns: - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AmazonSSMManagedInstanceCore' - !Sub 'arn:${AWS::Partition}:iam::aws:policy/CloudWatchAgentServerPolicy' - !Sub 'arn:${AWS::Partition}:iam::aws:policy/AmazonEC2ReadOnlyAccess' AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: - "ec2.amazonaws.com" - "ssm.amazonaws.com" Action: "sts:AssumeRole" SSMInstanceProfile: Type: "AWS::IAM::InstanceProfile" Properties: Roles: - !Ref SSMInstanceRole EventBridgeSSMAutoRole: Type: AWS::IAM::Role Properties: Policies: - PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ssm:StartAutomationExecution Resource: - !Sub 'arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/${RemoveConfigurationDocName}:$DEFAULT' - !Sub 'arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/${SetupConfigurationDocName}:$DEFAULT' - Effect: Allow Action: - iam:PassRole Resource: - !GetAtt ExecutionResourceRole.Arn Condition: {"StringLikeIfExists": {"iam:PassedToService": "ssm.amazonaws.com"}} PolicyName: "EventBridge_Invoke_SSM_Automation" Path: /service-role/ AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - events.amazonaws.com Action: sts:AssumeRole ALBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for ALB SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: !Ref 'WebAccessCIDR' VpcId: !Ref 'VPCID' ALBListenersSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for listeners of ALB SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !GetAtt ALBSecurityGroup.GroupId VpcId: !Ref 'VPCID' EcsSecurityGroupALBports: Condition: ECSDeploy Type: 'AWS::EC2::SecurityGroupIngress' Properties: GroupId: !Ref ALBListenersSecurityGroup IpProtocol: tcp FromPort: 31000 ToPort: 61000 SourceSecurityGroupId: !GetAtt ALBSecurityGroup.GroupId AutoscalingRole: Condition: ECSDeploy Metadata: cfn-lint: config: ignore_checks: - EIAMPolicyActionWildcard - EIAMPolicyWildcardResource ignore_reasons: EIAMPolicyActionWildcard: Multiple actions are needed for manipulation EIAMPolicyWildcardResource: Multiple actions are needed for manipulation Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - application-autoscaling.amazonaws.com Action: - 'sts:AssumeRole' Path: / Policies: - PolicyName: service-autoscaling PolicyDocument: Statement: - Effect: Allow Action: - 'application-autoscaling:*' - 'cloudwatch:DescribeAlarms' - 'cloudwatch:PutMetricAlarm' - 'ecs:DescribeServices' - 'ecs:UpdateService' Resource: '*' ECSServiceRole: Type: 'AWS::IAM::Role' Metadata: cfn-lint: config: ignore_checks: - EIAMPolicyActionWildcard - EIAMPolicyWildcardResource ignore_reasons: EIAMPolicyActionWildcard: Multiple actions are needed for manipulation EIAMPolicyWildcardResource: Multiple actions are needed for manipulation Condition: ECSDeploy Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - ecs.amazonaws.com Action: - 'sts:AssumeRole' Path: / Policies: - PolicyName: ecs-service PolicyDocument: Statement: - Effect: Allow Action: - 'elasticloadbalancing:DeregisterInstancesFromLoadBalancer' - 'elasticloadbalancing:DeregisterTargets' - 'elasticloadbalancing:Describe*' - 'elasticloadbalancing:RegisterInstancesWithLoadBalancer' - 'elasticloadbalancing:RegisterTargets' - 'ec2:Describe*' - 'ec2:AuthorizeSecurityGroupIngress' Resource: '*' Outputs: ALBSecurityGroup: Value: !GetAtt ALBSecurityGroup.GroupId ALBListenersSecurityGroup: Value: !GetAtt ALBListenersSecurityGroup.GroupId ExecutionResourceArn: Value: !GetAtt ExecutionResourceRole.Arn ExecutionRoleName: Value: !Ref ExecutionResourceRole WriteS3LambdaRoleArn: Value: !GetAtt WriteS3LambdaRole.Arn SSMInstanceRoleArn: Value: !GetAtt SSMInstanceRole.Arn SSMInstanceProfileName: Value: !Ref SSMInstanceProfile EventBridgeSSMAutoRole: Value: !GetAtt EventBridgeSSMAutoRole.Arn AutoscalingRole: Condition: ECSDeploy Value: !GetAtt AutoscalingRole.Arn ECSServiceRole: Condition: ECSDeploy Value: !GetAtt ECSServiceRole.Arn ECSTaskRole: Condition: ECSDeploy Value: !GetAtt ECSTaskRole.Arn AutoScalingGroupName: Value: !If - ECSDeploy - !Sub ECS-AutoscalingGroup-${AWS::StackName} - !Sub EC2-AutoscalingGroup-${AWS::StackName}