Project: KICS (Provisioning / Security & Compliance)
File: e415f8d3-fc2b-4f52-88ab-1129e8c8d3f5.md

title: Fully Open Ingress hide: toc: true navigation: true <style> .highlight .hll { background-color: #ff171742; } .md-content { max-width: 1100px; margin: 0 auto; } </style> Query id: e415f8d3-fc2b-4f52-88ab-1129e8c8d3f5 Query name: Fully Open Ingress Platform: CloudFormation Severity: <span style="color:#bb2124">High</span> Category: Networking and Firewall URL: ECS Service's security group should not allow unrestricted access to all ports from all IPv4 addresses<br> ```yaml title="Positive test num. 1 - yaml file" hl_lines="32 24" AWSTemplateFormatVersion: '2010-09-09' Parameters: VpcId: Type: AWS::EC2::VPC::Id Description: Select a VPC that allows instances access to the Internet. SubnetId: Type: List<AWS::EC2::Subnet::Id> Description: Select at two subnets in your selected VPC. Resources: ECSCluster: Type: AWS::ECS::Cluster EcsSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ECS Security Group VpcId: !Ref 'VpcId' EcsSecurityGroupHTTPinbound02: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref 'EcsSecurityGroup' IpProtocol: tcp FromPort: 80 ToPort: 0 CidrIp: 0.0.0.0/0 EcsSecurityGroupSSHinbound: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref 'EcsSecurityGroup' IpProtocol: tcp FromPort: 22 ToPort: 0 CidrIp: 0.0.0.0/0 EcsSecurityGroupALBports: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref 'EcsSecurityGroup' IpProtocol: tcp FromPort: 31000 ToPort: 61000 SourceSecurityGroupId: !Ref 'EcsSecurityGroup' CloudwatchLogsGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Join ['-', [ECSLogGroup, !Ref 'AWS::StackName']] RetentionInDays: 14 TaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Join ['', [!Ref 'AWS::StackName', -ecs-demo-app]] ContainerDefinitions: Name: simple-app Cpu: 10 Essential: true Image: httpd:2.4 Memory: 300 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref 'CloudwatchLogsGroup' awslogs-region: !Ref 'AWS::Region' awslogs-stream-prefix: ecs-demo-app MountPoints: ContainerPath: /usr/local/apache2/htdocs SourceVolume: my-vol PortMappings: ContainerPort: 80 Name: busybox Cpu: 10 Command: ['/bin/sh -c "while true; do echo ''<html> <head> <title>Amazon ECS Sample App</title></head></html>'' > bottom; cat top date bottom > /usr/local/apache2/htdocs/index.html ; sleep 1; done"'] EntryPoint: [sh, -c] Essential: false Image: busybox Memory: 200 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref 'CloudwatchLogsGroup' awslogs-region: !Ref 'AWS::Region' awslogs-stream-prefix: ecs-demo-app VolumesFrom: SourceContainer: simple-app Volumes: Name: my-vol ECSALB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: ECSALB Scheme: internet-facing LoadBalancerAttributes: Key: idletimeout.timeoutseconds Value: '30' Subnets: !Ref 'SubnetId' SecurityGroups: [!Ref 'EcsSecurityGroup'] ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: Type: forward TargetGroupArn: !Ref 'ECSTG' LoadBalancerArn: !Ref 'ECSALB' Port: 80 Protocol: HTTP ECSALBListenerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: Type: forward TargetGroupArn: !Ref 'ECSTG' Conditions: Field: path-pattern Values: [/] ListenerArn: !Ref 'ALBListener' Priority: 1 ECSTG: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 10 HealthCheckPath: / HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 Name: ECSTG Port: 80 Protocol: HTTP UnhealthyThresholdCount: 2 VpcId: !Ref 'VpcId' ECSAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: VPCZoneIdentifier: !Ref 'SubnetId' LaunchConfigurationName: !Ref 'ContainerInstances' MinSize: '1' MaxSize: 4 DesiredCapacity: 2 CreationPolicy: ResourceSignal: Timeout: PT15M UpdatePolicy: AutoScalingReplacingUpdate: WillReplace: true ContainerInstances: Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: ami-128731982dhash SecurityGroups: [!Ref 'EcsSecurityGroup'] InstanceType: t2.small IamInstanceProfile: !Ref 'EC2InstanceProfile' KeyName: my-ssh-key UserData: Fn::Base64: !Sub | echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config yum install -y aws-cfn-bootstrap /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region} service: Type: AWS::ECS::Service Properties: Cluster: !Ref 'ECSCluster' DesiredCount: 1 LoadBalancers: ContainerName: simple-app ContainerPort: 80 TargetGroupArn: !Ref 'ECSTG' Role: !Ref 'ECSServiceRole' TaskDefinition: !Ref 'TaskDefinition' ECSServiceRole: Type: AWS::IAM::Role 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: '*' ServiceScalingTarget: Type: AWS::ApplicationAutoScaling::ScalableTarget Properties: MaxCapacity: 2 MinCapacity: 1 ResourceId: !Join ['', [service/, !Ref 'ECSCluster', /, !GetAtt [service, Name]]] RoleARN: !GetAtt [AutoscalingRole, Arn] ScalableDimension: ecs:service:DesiredCount ServiceNamespace: ecs ServiceScalingPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: AStepPolicy PolicyType: StepScaling ScalingTargetId: !Ref 'ServiceScalingTarget' StepScalingPolicyConfiguration: AdjustmentType: PercentChangeInCapacity Cooldown: 60 MetricAggregationType: Average StepAdjustments: MetricIntervalLowerBound: 0 ScalingAdjustment: 200 ALB500sAlarmScaleUp: Type: AWS::CloudWatch::Alarm Properties: EvaluationPeriods: 1 Statistic: Average Threshold: 10 AlarmDescription: Alarm if our ALB generates too many HTTP 500s. Period: 60 AlarmActions: [!Ref 'ServiceScalingPolicy'] Namespace: AWS/ApplicationELB Dimensions: Name: LoadBalancer Value: !GetAtt ECSALB LoadBalancerFullName ComparisonOperator: GreaterThanThreshold MetricName: HTTPCodeELB5XX_Count EC2Role: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: Effect: Allow Principal: Service: [ec2.amazonaws.com] Action: ['sts:AssumeRole'] Path: / Policies: PolicyName: ecs-service PolicyDocument: Statement: Effect: Allow Action: ['ecs:CreateCluster', 'ecs:DeregisterContainerInstance', 'ecs:DiscoverPollEndpoint', 'ecs:Poll', 'ecs:RegisterContainerInstance', 'ecs:StartTelemetrySession', 'ecs:Submit*', 'logs:CreateLogStream', 'logs:PutLogEvents'] Resource: '*' AutoscalingRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: Effect: Allow Principal: Service:

Action: ['sts:AssumeRole'] Path: / Policies: PolicyName: service-autoscaling PolicyDocument: Statement: Effect: Allow Action: ['application-autoscaling:*', 'cloudwatch:DescribeAlarms', 'cloudwatch:PutMetricAlarm', 'ecs:DescribeServices', 'ecs:UpdateService'] Resource: '*' EC2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: [!Ref 'EC2Role'] Outputs: ecsservice: Value: !Ref 'service' ecscluster: Value: !Ref 'ECSCluster' ECSALB: Description: Your ALB DNS URL Value: !Join ['', [!GetAtt [ECSALB, DNSName]]] taskdef: Value: !Ref 'TaskDefinition' ``` ```yaml title="Positive test num. 2 - yaml file" hl_lines="24" AWSTemplateFormatVersion: '2010-09-09' Parameters: VpcId: Type: AWS::EC2::VPC::Id Description: Select a VPC that allows instances access to the Internet. SubnetId: Type: List<AWS::EC2::Subnet::Id> Description: Select at two subnets in your selected VPC. Resources: ECSCluster: Type: AWS::ECS::Cluster EcsSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ECS Security Group VpcId: !Ref 'VpcId' EcsSecurityGroupHTTPinbound: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref 'EcsSecurityGroup' IpProtocol: tcp FromPort: 80 ToPort: 0 CidrIp: 0.0.0.0/0 EcsSecurityGroupSSHinbound: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref 'EcsSecurityGroup' IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 EcsSecurityGroupALBports: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref 'EcsSecurityGroup' IpProtocol: tcp FromPort: 31000 ToPort: 61000 SourceSecurityGroupId: !Ref 'EcsSecurityGroup' CloudwatchLogsGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Join ['-', [ECSLogGroup, !Ref 'AWS::StackName']] RetentionInDays: 14 TaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Join ['', [!Ref 'AWS::StackName', -ecs-demo-app]] ContainerDefinitions: Name: simple-app Cpu: 10 Essential: true Image: httpd:2.4 Memory: 300 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref 'CloudwatchLogsGroup' awslogs-region: !Ref 'AWS::Region' awslogs-stream-prefix: ecs-demo-app MountPoints: ContainerPath: /usr/local/apache2/htdocs SourceVolume: my-vol PortMappings: ContainerPort: 80 Name: busybox Cpu: 10 Command: ['/bin/sh -c "while true; do echo ''<html> <head> <title>Amazon ECS Sample App</title></head><body></body></html>'' > bottom; cat top date bottom > /usr/local/apache2/htdocs/index.html ; sleep 1; done"'] EntryPoint: [sh, -c] Essential: false Image: busybox Memory: 200 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref 'CloudwatchLogsGroup' awslogs-region: !Ref 'AWS::Region' awslogs-stream-prefix: ecs-demo-app VolumesFrom: SourceContainer: simple-app Volumes: Name: my-vol ECSALB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: ECSALB Scheme: internet-facing LoadBalancerAttributes: Key: idletimeout.timeoutseconds Value: '30' Subnets: !Ref 'SubnetId' SecurityGroups: [!Ref 'EcsSecurityGroup'] ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: Type: forward TargetGroupArn: !Ref 'ECSTG' LoadBalancerArn: !Ref 'ECSALB' Port: 80 Protocol: HTTP ECSALBListenerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: Type: forward TargetGroupArn: !Ref 'ECSTG' Conditions: Field: path-pattern Values: [/] ListenerArn: !Ref 'ALBListener' Priority: 1 ECSTG: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 10 HealthCheckPath: / HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 Name: ECSTG Port: 80 Protocol: HTTP UnhealthyThresholdCount: 2 VpcId: !Ref 'VpcId' ECSAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: VPCZoneIdentifier: !Ref 'SubnetId' LaunchConfigurationName: !Ref 'ContainerInstances' MinSize: '1' MaxSize: 4 DesiredCapacity: 2 CreationPolicy: ResourceSignal: Timeout: PT15M UpdatePolicy: AutoScalingReplacingUpdate: WillReplace: true ContainerInstances: Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: ami-09bee01cc997a78a6 SecurityGroups: [!Ref 'EcsSecurityGroup'] InstanceType: t2.small IamInstanceProfile: !Ref 'EC2InstanceProfile' KeyName: my-ssh-key UserData: Fn::Base64: !Sub | echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config yum install -y aws-cfn-bootstrap /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region} service: Type: AWS::ECS::Service Properties: Cluster: !Ref 'ECSCluster' DesiredCount: 1 LoadBalancers: ContainerName: simple-app ContainerPort: 80 TargetGroupArn: !Ref 'ECSTG' Role: !Ref 'ECSServiceRole' TaskDefinition: !Ref 'TaskDefinition' ECSServiceRole: Type: AWS::IAM::Role 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: '*' ServiceScalingTarget: Type: AWS::ApplicationAutoScaling::ScalableTarget Properties: MaxCapacity: 2 MinCapacity: 1 ResourceId: !Join ['', [service/, !Ref 'ECSCluster', /, !GetAtt [service, Name]]] RoleARN: !GetAtt [AutoscalingRole, Arn] ScalableDimension: ecs:service:DesiredCount ServiceNamespace: ecs ServiceScalingPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: AStepPolicy PolicyType: StepScaling ScalingTargetId: !Ref 'ServiceScalingTarget' StepScalingPolicyConfiguration: AdjustmentType: PercentChangeInCapacity Cooldown: 60 MetricAggregationType: Average StepAdjustments: MetricIntervalLowerBound: 0 ScalingAdjustment: 200 ALB500sAlarmScaleUp: Type: AWS::CloudWatch::Alarm Properties: EvaluationPeriods: 1 Statistic: Average Threshold: 10 AlarmDescription: Alarm if our ALB generates too many HTTP 500s. Period: 60 AlarmActions: [!Ref 'ServiceScalingPolicy'] Namespace: AWS/ApplicationELB Dimensions: Name: LoadBalancer Value: !GetAtt ECSALB LoadBalancerFullName ComparisonOperator: GreaterThanThreshold MetricName: HTTPCodeELB5XX_Count EC2Role: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: Effect: Allow Principal: Service: [ec2.amazonaws.com] Action: ['sts:AssumeRole'] Path: / Policies: PolicyName: ecs-service PolicyDocument: Statement: Effect: Allow Action: ['ecs:CreateCluster', 'ecs:DeregisterContainerInstance', 'ecs:DiscoverPollEndpoint', 'ecs:Poll', 'ecs:RegisterContainerInstance', 'ecs:StartTelemetrySession', 'ecs:Submit*', 'logs:CreateLogStream', 'logs:PutLogEvents'] Resource: '*' AutoscalingRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: Effect: Allow Principal: Service:

Action: ['sts:AssumeRole'] Path: / Policies: PolicyName: service-autoscaling PolicyDocument: Statement: Effect: Allow Action: ['application-autoscaling:*', 'cloudwatch:DescribeAlarms', 'cloudwatch:PutMetricAlarm', 'ecs:DescribeServices', 'ecs:UpdateService'] Resource: '*' EC2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: [!Ref 'EC2Role'] ``` ```json title="Positive test num. 3 - json file" hl_lines="115 326" { "AWSTemplateFormatVersion": "2010-09-09", "Parameters": { "VpcId": { "Type": "AWS::EC2::VPC::Id", "Description": "Select a VPC that allows instances access to the Internet." }, "SubnetId": { "Type": "List\u003cAWS::EC2::Subnet::Id\u003e", "Description": "Select at two subnets in your selected VPC." } }, "Resources": { "ECSCluster": { "Type": "AWS::ECS::Cluster" }, "EcsSecurityGroupALBports": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { "IpProtocol": "tcp", "FromPort": 31000, "ToPort": 61000, "SourceSecurityGroupId": "EcsSecurityGroup", "GroupId": "EcsSecurityGroup" } }, "ECSServiceRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "ecs.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "ecs-service", "PolicyDocument": { "Statement": [ { "Action": [ "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", "elasticloadbalancing:DeregisterTargets", "elasticloadbalancing:Describe*", "elasticloadbalancing:RegisterInstancesWithLoadBalancer", "elasticloadbalancing:RegisterTargets", "ec2:Describe*", "ec2:AuthorizeSecurityGroupIngress" ], "Resource": "*", "Effect": "Allow" } ] } } ] } }, "AutoscalingRole": { "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": "*" } ] } } ] } }, "EcsSecurityGroupSSHinbound": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { "ToPort": 0, "CidrIp": "0.0.0.0/0", "GroupId": "EcsSecurityGroup", "IpProtocol": "tcp", "FromPort": 22 } }, "ECSALB": { "Properties": { "Name": "ECSALB", "Scheme": "internet-facing", "LoadBalancerAttributes": [ { "Key": "idletimeout.timeoutseconds", "Value": "30" } ], "Subnets": "SubnetId", "SecurityGroups": [ "EcsSecurityGroup" ] }, "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer" }, "ECSAutoScalingGroup": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { "VPCZoneIdentifier": "SubnetId", "LaunchConfigurationName": "ContainerInstances", "MinSize": "1", "MaxSize": 4, "DesiredCapacity": 2 }, "CreationPolicy": { "ResourceSignal": { "Timeout": "PT15M" } }, "UpdatePolicy": { "AutoScalingReplacingUpdate": { "WillReplace": true } } }, "ServiceScalingTarget": { "Type": "AWS::ApplicationAutoScaling::ScalableTarget", "Properties": { "MaxCapacity": 2, "MinCapacity": 1, "ResourceId": [ "", [ "service/", "ECSCluster", "/", [ "service", "Name" ] ] ], "RoleARN": [ "AutoscalingRole", "Arn" ], "ScalableDimension": "ecs:service:DesiredCount", "ServiceNamespace": "ecs" } }, "ServiceScalingPolicy": { "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", "Properties": { "PolicyType": "StepScaling", "ScalingTargetId": "ServiceScalingTarget", "StepScalingPolicyConfiguration": { "StepAdjustments": [ { "MetricIntervalLowerBound": 0, "ScalingAdjustment": 200 } ], "AdjustmentType": "PercentChangeInCapacity", "Cooldown": 60, "MetricAggregationType": "Average" }, "PolicyName": "AStepPolicy" } }, "EC2Role": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "ec2.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "ecs-service", "PolicyDocument": { "Statement": [ { "Action": [ "ecs:CreateCluster", "ecs:DeregisterContainerInstance", "ecs:DiscoverPollEndpoint", "ecs:Poll", "ecs:RegisterContainerInstance", "ecs:StartTelemetrySession", "ecs:Submit*", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "*", "Effect": "Allow" } ] } } ] } }, "ECSTG": { "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", "Properties": { "HealthCheckIntervalSeconds": 10, "HealthCheckProtocol": "HTTP", "HealthCheckTimeoutSeconds": 5, "Name": "ECSTG", "Port": 80, "Protocol": "HTTP", "HealthCheckPath": "/", "HealthyThresholdCount": 2, "UnhealthyThresholdCount": 2, "VpcId": "VpcId" } }, "service": { "Type": "AWS::ECS::Service", "Properties": { "Cluster": "ECSCluster", "DesiredCount": 1, "LoadBalancers": [ { "ContainerName": "simple-app", "ContainerPort": 80, "TargetGroupArn": "ECSTG" } ], "Role": "ECSServiceRole", "TaskDefinition": "TaskDefinition" } }, "ALB500sAlarmScaleUp": { "Properties": { "Threshold": 10, "Dimensions": [ { "Name": "LoadBalancer", "Value": [ "ECSALB", "LoadBalancerFullName" ] } ], "ComparisonOperator": "GreaterThanThreshold", "MetricName": "HTTPCodeELB5XX_Count", "EvaluationPeriods": 1, "AlarmDescription": "Alarm if our ALB generates too many HTTP 500s.", "Period": 60, "AlarmActions": [ "ServiceScalingPolicy" ], "Namespace": "AWS/ApplicationELB", "Statistic": "Average" }, "Type": "AWS::CloudWatch::Alarm" }, "EC2InstanceProfile": { "Type": "AWS::IAM::InstanceProfile", "Properties": { "Path": "/", "Roles": [ "EC2Role" ] } }, "EcsSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "VpcId": "VpcId", "GroupDescription": "ECS Security Group" } }, "EcsSecurityGroupHTTPinbound02": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { "GroupId": "EcsSecurityGroup", "IpProtocol": "tcp", "FromPort": 80, "ToPort": 0, "CidrIp":

} }, "CloudwatchLogsGroup": { "Type": "AWS::Logs::LogGroup", "Properties": { "LogGroupName": [ "-", [ "ECSLogGroup", "AWS::StackName" ] ], "RetentionInDays": 14 } }, "TaskDefinition": { "Type": "AWS::ECS::TaskDefinition", "Properties": { "Family": [ "", [ "AWS::StackName", "-ecs-demo-app" ] ], "ContainerDefinitions": [ { "Name": "simple-app", "Cpu": 10, "Essential": true, "Image": "httpd:2.4", "Memory": 300, "LogConfiguration": { "LogDriver": "awslogs", "Options": { "awslogs-group": "CloudwatchLogsGroup", "awslogs-region": "AWS::Region", "awslogs-stream-prefix": "ecs-demo-app" } }, "MountPoints": [ { "ContainerPath": "/usr/local/apache2/htdocs", "SourceVolume": "my-vol" } ], "PortMappings": [ { "ContainerPort": 80 } ] }, { "VolumesFrom": [ { "SourceContainer": "simple-app" } ], "Name": "busybox", "Cpu": 10, "Command": [ "/bin/sh -c \"while true; do echo '\u003chtml\u003e \u003chead\u003e \u003ctitle\u003eAmazon ECS Sample App\u003c/title\u003e\u003c/head\u003e\u003c/html\u003e' \u003e bottom; cat top date bottom \u003e /usr/local/apache2/htdocs/index.html ; sleep 1; done\"" ], "Image": "busybox", "Memory": 200, "LogConfiguration": { "LogDriver": "awslogs", "Options": { "awslogs-stream-prefix": "ecs-demo-app", "awslogs-group": "CloudwatchLogsGroup", "awslogs-region": "AWS::Region" } }, "EntryPoint": [ "sh", "-c" ], "Essential": false } ], "Volumes": [ { "Name": "my-vol" } ] } }, "ALBListener": { "Type": "AWS::ElasticLoadBalancingV2::Listener", "Properties": { "LoadBalancerArn": "ECSALB", "Port": 80, "Protocol": "HTTP", "DefaultActions": [ { "Type": "forward", "TargetGroupArn": "ECSTG" } ] } }, "ECSALBListenerRule": { "Type": "AWS::ElasticLoadBalancingV2::ListenerRule", "Properties": { "Actions": [ { "Type": "forward", "TargetGroupArn": "ECSTG" } ], "Conditions": [ { "Values": [ "/" ], "Field": "path-pattern" } ], "ListenerArn": "ALBListener", "Priority": 1 } }, "ContainerInstances": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": "ami-128731982dhash", "SecurityGroups": [ "EcsSecurityGroup" ], "InstanceType": "t2.small", "IamInstanceProfile": "EC2InstanceProfile", "KeyName": "my-ssh-key", "UserData": { "Fn::Base64": "#!/bin/bash -xe\necho ECS_CLUSTER=${ECSCluster} \u003e\u003e /etc/ecs/ecs.config\nyum install -y aws-cfn-bootstrap\n/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region}\n" } } } }, "Outputs": { "ecscluster": { "Value": "ECSCluster" }, "ECSALB": { "Description": "Your ALB DNS URL", "Value": [ "", [ [ "ECSALB", "DNSName" ] ] ] }, "taskdef": { "Value": "TaskDefinition" }, "ecsservice": { "Value": "service" } } } ``` <details><summary>Positive test num. 4 - json file</summary> ```json hl_lines="268" { "Resources": { "TaskDefinition": { "Type": "AWS::ECS::TaskDefinition", "Properties": { "Family": [ "", [ "AWS::StackName", "-ecs-demo-app" ] ], "ContainerDefinitions": [ { "Essential": true, "Image": "httpd:2.4", "Memory": 300, "LogConfiguration": { "LogDriver": "awslogs", "Options": { "awslogs-group": "CloudwatchLogsGroup", "awslogs-region": "AWS::Region", "awslogs-stream-prefix": "ecs-demo-app" } }, "MountPoints": [ { "SourceVolume": "my-vol", "ContainerPath": "/usr/local/apache2/htdocs" } ], "PortMappings": [ { "ContainerPort": 80 } ], "Name": "simple-app", "Cpu": 10 }, { "EntryPoint": [ "sh", "-c" ], "Essential": false, "Memory": 200, "Command": [ "/bin/sh -c \"while true; do echo '\u003chtml\u003e \u003chead\u003e \u003ctitle\u003eAmazon ECS Sample App\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003c/body\u003e\u003c/html\u003e' \u003e bottom; cat top date bottom \u003e /usr/local/apache2/htdocs/index.html ; sleep 1; done\"" ], "Cpu": 10, "Image": "busybox", "LogConfiguration": { "LogDriver": "awslogs", "Options": { "awslogs-stream-prefix": "ecs-demo-app", "awslogs-group": "CloudwatchLogsGroup", "awslogs-region": "AWS::Region" } }, "VolumesFrom": [ { "SourceContainer": "simple-app" } ], "Name": "busybox" } ], "Volumes": [ { "Name": "my-vol" } ] } }, "ALBListener": { "Type": "AWS::ElasticLoadBalancingV2::Listener", "Properties": { "DefaultActions": [ { "Type": "forward", "TargetGroupArn": "ECSTG" } ], "LoadBalancerArn": "ECSALB", "Port": 80, "Protocol": "HTTP" } }, "ECSServiceRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "ecs.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "ecs-service", "PolicyDocument": { "Statement": [ { "Action": [ "elasticloadbalancing:DeregisterInstancesFromLoadBalancer", "elasticloadbalancing:DeregisterTargets", "elasticloadbalancing:Describe*", "elasticloadbalancing:RegisterInstancesWithLoadBalancer", "elasticloadbalancing:RegisterTargets", "ec2:Describe*", "ec2:AuthorizeSecurityGroupIngress" ], "Resource": "*", "Effect": "Allow" } ] } } ] } }, "ALB500sAlarmScaleUp": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "Period": 60, "Dimensions": [ { "Name": "LoadBalancer", "Value": [ "ECSALB", "LoadBalancerFullName" ] } ], "ComparisonOperator": "GreaterThanThreshold", "AlarmDescription": "Alarm if our ALB generates too many HTTP 500s.", "Statistic": "Average", "Threshold": 10, "AlarmActions": [ "ServiceScalingPolicy" ], "Namespace": "AWS/ApplicationELB", "MetricName": "HTTPCodeELB5XX_Count", "EvaluationPeriods": 1 } }, "service": { "Type": "AWS::ECS::Service", "Properties": { "TaskDefinition": "TaskDefinition", "Cluster": "ECSCluster", "DesiredCount": 1, "LoadBalancers": [ { "ContainerName": "simple-app", "ContainerPort": 80, "TargetGroupArn": "ECSTG" } ], "Role": "ECSServiceRole" } }, "EcsSecurityGroupSSHinbound": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { "GroupId": "EcsSecurityGroup", "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "CidrIp":

} }, "EcsSecurityGroupALBports": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { "FromPort": 31000, "ToPort": 61000, "SourceSecurityGroupId": "EcsSecurityGroup", "GroupId": "EcsSecurityGroup", "IpProtocol": "tcp" } }, "CloudwatchLogsGroup": { "Type": "AWS::Logs::LogGroup", "Properties": { "RetentionInDays": 14, "LogGroupName": [ "-", [ "ECSLogGroup", "AWS::StackName" ] ] } }, "ECSALB": { "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", "Properties": { "Scheme": "internet-facing", "LoadBalancerAttributes": [ { "Key": "idletimeout.timeoutseconds", "Value": "30" } ], "Subnets": "SubnetId", "SecurityGroups": [ "EcsSecurityGroup" ], "Name": "ECSALB" } }, "ECSALBListenerRule": { "Type": "AWS::ElasticLoadBalancingV2::ListenerRule", "Properties": { "Actions": [ { "Type": "forward", "TargetGroupArn": "ECSTG" } ], "Conditions": [ { "Field": "path-pattern", "Values": [ "/" ] } ], "ListenerArn": "ALBListener", "Priority": 1 } }, "ContainerInstances": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "IamInstanceProfile": "EC2InstanceProfile", "KeyName": "my-ssh-key", "UserData": { "Fn::Base64": "#!/bin/bash -xe\necho ECS_CLUSTER=${ECSCluster} \u003e\u003e /etc/ecs/ecs.config\nyum install -y aws-cfn-bootstrap\n/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region}\n" }, "ImageId": "ami-09bee01cc997a78a6", "SecurityGroups": [ "EcsSecurityGroup" ], "InstanceType": "t2.small" } }, "ECSCluster": { "Type": "AWS::ECS::Cluster" }, "EcsSecurityGroupHTTPinbound": { "Properties": { "GroupId": "EcsSecurityGroup", "IpProtocol": "tcp", "FromPort": 80, "ToPort": 0, "CidrIp": "0.0.0.0/0" }, "Type": "AWS::EC2::SecurityGroupIngress" }, "ECSTG": { "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", "Properties": { "Name": "ECSTG", "Port": 80, "VpcId": "VpcId", "HealthCheckPath": "/", "HealthCheckProtocol": "HTTP", "HealthyThresholdCount": 2, "Protocol": "HTTP", "UnhealthyThresholdCount": 2, "HealthCheckIntervalSeconds": 10, "HealthCheckTimeoutSeconds": 5 } }, "ServiceScalingTarget": { "Type": "AWS::ApplicationAutoScaling::ScalableTarget", "Properties": { "MaxCapacity": 2, "MinCapacity": 1, "ResourceId": [ "", [ "service/", "ECSCluster", "/", [ "service", "Name" ] ] ], "RoleARN": [ "AutoscalingRole", "Arn" ], "ScalableDimension": "ecs:service:DesiredCount", "ServiceNamespace": "ecs" } }, "AutoscalingRole": { "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": "*" } ] } } ] } }, "EcsSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "ECS Security Group", "VpcId": "VpcId" } }, "ECSAutoScalingGroup": { "CreationPolicy": { "ResourceSignal": { "Timeout": "PT15M" } }, "UpdatePolicy": { "AutoScalingReplacingUpdate": { "WillReplace": true } }, "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { "VPCZoneIdentifier": "SubnetId", "LaunchConfigurationName": "ContainerInstances", "MinSize": "1", "MaxSize": 4, "DesiredCapacity": 2 } }, "ServiceScalingPolicy": { "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", "Properties": { "PolicyName": "AStepPolicy", "PolicyType": "StepScaling", "ScalingTargetId": "ServiceScalingTarget", "StepScalingPolicyConfiguration": { "AdjustmentType": "PercentChangeInCapacity", "Cooldown": 60, "MetricAggregationType": "Average", "StepAdjustments": [ { "MetricIntervalLowerBound": 0, "ScalingAdjustment": 200 } ] } } }, "EC2Role": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Principal": { "Service": [ "ec2.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ], "Effect": "Allow" } ] }, "Path": "/", "Policies": [ { "PolicyName": "ecs-service", "PolicyDocument": { "Statement": [ { "Effect": "Allow", "Action": [ "ecs:CreateCluster", "ecs:DeregisterContainerInstance", "ecs:DiscoverPollEndpoint", "ecs:Poll", "ecs:RegisterContainerInstance", "ecs:StartTelemetrySession", "ecs:Submit*", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "*" } ] } } ] } }, "EC2InstanceProfile": { "Properties": { "Path": "/", "Roles": [ "EC2Role" ] }, "Type": "AWS::IAM::InstanceProfile" } }, "AWSTemplateFormatVersion": "2010-09-09", "Parameters": { "VpcId": { "Type": "AWS::EC2::VPC::Id", "Description": "Select a VPC that allows instances access to the Internet." }, "SubnetId": { "Type": "List\u003cAWS::EC2::Subnet::Id\u003e", "Description": "Select at two subnets in your selected VPC." } } } ``` </details> ```yaml title="Negative test num. 1 - yaml file" AWSTemplateFormatVersion: '2010-09-09' Parameters: VpcId: Type: AWS::EC2::VPC::Id Description: Select a VPC that allows instances access to the Internet. SubnetId: Type: List<AWS::EC2::Subnet::Id> Description: Select at two subnets in your selected VPC. Resources: ECSCluster: Type: AWS::ECS::Cluster EcsSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: ECS Security Group VpcId: !Ref 'VpcId' EcsSecurityGroupHTTPinbound: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref 'EcsSecurityGroup' IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 EcsSecurityGroupSSHinbound: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref 'EcsSecurityGroup' IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 EcsSecurityGroupALBports: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !Ref 'EcsSecurityGroup' IpProtocol: tcp FromPort: 31000 ToPort: 61000 SourceSecurityGroupId: !Ref 'EcsSecurityGroup' CloudwatchLogsGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Join ['-', [ECSLogGroup, !Ref 'AWS::StackName']] RetentionInDays: 14 TaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Join ['', [!Ref 'AWS::StackName', -ecs-demo-app]] ContainerDefinitions: Name: simple-app Cpu: 10 Essential: true Image:

Memory: 300 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref 'CloudwatchLogsGroup' awslogs-region: !Ref 'AWS::Region' awslogs-stream-prefix: ecs-demo-app MountPoints: ContainerPath: /usr/local/apache2/htdocs SourceVolume: my-vol PortMappings: ContainerPort: 80 Name: busybox Cpu: 10 Command: ['/bin/sh -c "while true; do echo ''<html> <head> <title>Amazon ECS Sample App</title></head><body></body></html>'' > bottom; cat top date bottom > /usr/local/apache2/htdocs/index.html ; sleep 1; done"'] EntryPoint: [sh, -c] Essential: false Image: busybox Memory: 200 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref 'CloudwatchLogsGroup' awslogs-region: !Ref 'AWS::Region' awslogs-stream-prefix: ecs-demo-app VolumesFrom: SourceContainer: simple-app Volumes: Name: my-vol ECSALB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: ECSALB Scheme: internet-facing LoadBalancerAttributes: Key: idletimeout.timeoutseconds Value: '30' Subnets: !Ref 'SubnetId' SecurityGroups: [!Ref 'EcsSecurityGroup'] ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: Type: forward TargetGroupArn: !Ref 'ECSTG' LoadBalancerArn: !Ref 'ECSALB' Port: 80 Protocol: HTTP ECSALBListenerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: Type: forward TargetGroupArn: !Ref 'ECSTG' Conditions: Field: path-pattern Values: [/] ListenerArn: !Ref 'ALBListener' Priority: 1 ECSTG: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 10 HealthCheckPath: / HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 Name: ECSTG Port: 80 Protocol: HTTP UnhealthyThresholdCount: 2 VpcId: !Ref 'VpcId' ECSAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: VPCZoneIdentifier: !Ref 'SubnetId' LaunchConfigurationName: !Ref 'ContainerInstances' MinSize: '1' MaxSize: 4 DesiredCapacity: 2 CreationPolicy: ResourceSignal: Timeout: PT15M UpdatePolicy: AutoScalingReplacingUpdate: WillReplace: true ContainerInstances: Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: ami-09bee01cc997a78a6 SecurityGroups: [!Ref 'EcsSecurityGroup'] InstanceType: t2.small IamInstanceProfile: !Ref 'EC2InstanceProfile' KeyName: my-ssh-key UserData: Fn::Base64: !Sub | echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config yum install -y aws-cfn-bootstrap /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region} service: Type: AWS::ECS::Service Properties: Cluster: !Ref 'ECSCluster' DesiredCount: 1 LoadBalancers: ContainerName: simple-app ContainerPort: 80 TargetGroupArn: !Ref 'ECSTG' Role: !Ref 'ECSServiceRole' TaskDefinition: !Ref 'taskdefinition' ECSServiceRole: Type: AWS::IAM::Role 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: '*' ServiceScalingTarget: Type: AWS::ApplicationAutoScaling::ScalableTarget Properties: MaxCapacity: 2 MinCapacity: 1 ResourceId: !Join ['', [service/, !Ref 'ECSCluster', /, !GetAtt [service, Name]]] RoleARN: !GetAtt [AutoscalingRole, Arn] ScalableDimension: ecs:service:DesiredCount ServiceNamespace: ecs ServiceScalingPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: AStepPolicy PolicyType: StepScaling ScalingTargetId: !Ref 'ServiceScalingTarget' StepScalingPolicyConfiguration: AdjustmentType: PercentChangeInCapacity Cooldown: 60 MetricAggregationType: Average StepAdjustments: MetricIntervalLowerBound: 0 ScalingAdjustment: 200 ALB500sAlarmScaleUp: Type: AWS::CloudWatch::Alarm Properties: EvaluationPeriods: 1 Statistic: Average Threshold: 10 AlarmDescription: Alarm if our ALB generates too many HTTP 500s. Period: 60 AlarmActions: [!Ref 'ServiceScalingPolicy'] Namespace: AWS/ApplicationELB Dimensions: Name: LoadBalancer Value: !GetAtt ECSALB LoadBalancerFullName ComparisonOperator: GreaterThanThreshold MetricName: HTTPCodeELB5XX_Count EC2Role: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: Effect: Allow Principal: Service: [ec2.amazonaws.com] Action: ['sts:AssumeRole'] Path: / Policies: PolicyName: ecs-service PolicyDocument: Statement: Effect: Allow Action: ['ecs:CreateCluster', 'ecs:DeregisterContainerInstance', 'ecs:DiscoverPollEndpoint', 'ecs:Poll', 'ecs:RegisterContainerInstance', 'ecs:StartTelemetrySession', 'ecs:Submit*', 'logs:CreateLogStream', 'logs:PutLogEvents'] Resource: '*' AutoscalingRole: 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: '*' EC2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: [!Ref 'EC2Role'] ``` ```json title="Negative test num. 2 - json file" { "AWSTemplateFormatVersion": "2010-09-09", "Parameters": { "VpcId": { "Type": "AWS::EC2::VPC::Id", "Description": "Select a VPC that allows instances access to the Internet." }, "SubnetId": { "Description": "Select at two subnets in your selected VPC.", "Type": "List\u003cAWS::EC2::Subnet::Id\u003e" } }, "Resources": { "EcsSecurityGroupHTTPinbound": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { "CidrIp": "0.0.0.0/0", "GroupId": "EcsSecurityGroup", "IpProtocol": "tcp", "FromPort": 80, "ToPort": 80 } }, "EcsSecurityGroupALBports": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { "GroupId": "EcsSecurityGroup", "IpProtocol": "tcp", "FromPort": 31000, "ToPort": 61000, "SourceSecurityGroupId": "EcsSecurityGroup" } }, "CloudwatchLogsGroup": { "Type": "AWS::Logs::LogGroup", "Properties": { "LogGroupName": [ "-", [ "ECSLogGroup", "AWS::StackName" ] ], "RetentionInDays": 14 } }, "ALBListener": { "Type": "AWS::ElasticLoadBalancingV2::Listener", "Properties": { "DefaultActions": [ { "Type": "forward", "TargetGroupArn": "ECSTG" } ], "LoadBalancerArn": "ECSALB", "Port": 80, "Protocol": "HTTP" } }, "ECSALBListenerRule": { "Type": "AWS::ElasticLoadBalancingV2::ListenerRule", "Properties": { "Actions": [ { "TargetGroupArn": "ECSTG", "Type": "forward" } ], "Conditions": [ { "Field": "path-pattern", "Values": [ "/" ] } ], "ListenerArn": "ALBListener", "Priority": 1 } }, "ALB500sAlarmScaleUp": { "Properties": { "Dimensions": [ { "Name": "LoadBalancer", "Value": [ "ECSALB", "LoadBalancerFullName" ] } ], "ComparisonOperator": "GreaterThanThreshold", "MetricName": "HTTPCodeELB5XX_Count", "Statistic": "Average", "Threshold": 10, "AlarmDescription": "Alarm if our ALB generates too many HTTP

"Period": 60, "EvaluationPeriods": 1, "AlarmActions": [ "ServiceScalingPolicy" ], "Namespace": "AWS/ApplicationELB" }, "Type": "AWS::CloudWatch::Alarm" }, "AutoscalingRole": { "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": "*" } ] } } ] } }, "ECSCluster": { "Type": "AWS::ECS::Cluster" }, "ECSServiceRole": { "Type": "AWS::IAM::Role", "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": "*" } ] } } ] } }, "ServiceScalingPolicy": { "Type": "AWS::ApplicationAutoScaling::ScalingPolicy", "Properties": { "PolicyName": "AStepPolicy", "PolicyType": "StepScaling", "ScalingTargetId": "ServiceScalingTarget", "StepScalingPolicyConfiguration": { "Cooldown": 60, "MetricAggregationType": "Average", "StepAdjustments": [ { "MetricIntervalLowerBound": 0, "ScalingAdjustment": 200 } ], "AdjustmentType": "PercentChangeInCapacity" } } }, "EC2InstanceProfile": { "Type": "AWS::IAM::InstanceProfile", "Properties": { "Path": "/", "Roles": [ "EC2Role" ] } }, "ECSAutoScalingGroup": { "Type": "AWS::AutoScaling::AutoScalingGroup", "Properties": { "VPCZoneIdentifier": "SubnetId", "LaunchConfigurationName": "ContainerInstances", "MinSize": "1", "MaxSize": 4, "DesiredCapacity": 2 }, "CreationPolicy": { "ResourceSignal": { "Timeout": "PT15M" } }, "UpdatePolicy": { "AutoScalingReplacingUpdate": { "WillReplace": true } } }, "ECSALB": { "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", "Properties": { "Scheme": "internet-facing", "LoadBalancerAttributes": [ { "Key": "idletimeout.timeoutseconds", "Value": "30" } ], "Subnets": "SubnetId", "SecurityGroups": [ "EcsSecurityGroup" ], "Name": "ECSALB" } }, "ECSTG": { "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", "Properties": { "Name": "ECSTG", "Protocol": "HTTP", "HealthCheckPath": "/", "HealthCheckTimeoutSeconds": 5, "HealthyThresholdCount": 2, "UnhealthyThresholdCount": 2, "VpcId": "VpcId", "HealthCheckIntervalSeconds": 10, "HealthCheckProtocol": "HTTP", "Port": 80 } }, "EC2Role": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "ec2.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "ecs-service", "PolicyDocument": { "Statement": [ { "Resource": "*", "Effect": "Allow", "Action": [ "ecs:CreateCluster", "ecs:DeregisterContainerInstance", "ecs:DiscoverPollEndpoint", "ecs:Poll", "ecs:RegisterContainerInstance", "ecs:StartTelemetrySession", "ecs:Submit*", "logs:CreateLogStream", "logs:PutLogEvents" ] } ] } } ] } }, "TaskDefinition": { "Properties": { "Volumes": [ { "Name": "my-vol" } ], "Family": [ "", [ "AWS::StackName", "-ecs-demo-app" ] ], "ContainerDefinitions": [ { "Image": "httpd:2.4", "Memory": 300, "LogConfiguration": { "LogDriver": "awslogs", "Options": { "awslogs-group": "CloudwatchLogsGroup", "awslogs-region": "AWS::Region", "awslogs-stream-prefix": "ecs-demo-app" } }, "MountPoints": [ { "ContainerPath": "/usr/local/apache2/htdocs", "SourceVolume": "my-vol" } ], "PortMappings": [ { "ContainerPort": 80 } ], "Name": "simple-app", "Cpu": 10, "Essential": true }, { "VolumesFrom": [ { "SourceContainer": "simple-app" } ], "Cpu": 10, "EntryPoint": [ "sh", "-c" ], "Essential": false, "Image": "busybox", "Memory": 200, "LogConfiguration": { "LogDriver": "awslogs", "Options": { "awslogs-stream-prefix": "ecs-demo-app", "awslogs-group": "CloudwatchLogsGroup", "awslogs-region": "AWS::Region" } }, "Name": "busybox", "Command": [ "/bin/sh -c \"while true; do echo '\u003chtml\u003e \u003chead\u003e \u003ctitle\u003eAmazon ECS Sample App\u003c/title\u003e\u003c/head\u003e\u003cbody\u003e\u003c/body\u003e\u003c/html\u003e' \u003e bottom; cat top date bottom \u003e /usr/local/apache2/htdocs/index.html ; sleep 1; done\"" ] } ] }, "Type": "AWS::ECS::TaskDefinition" }, "EcsSecurityGroupSSHinbound": { "Type": "AWS::EC2::SecurityGroupIngress", "Properties": { "ToPort": 22, "CidrIp": "0.0.0.0/0", "GroupId": "EcsSecurityGroup", "IpProtocol": "tcp", "FromPort": 22 } }, "ContainerInstances": { "Type": "AWS::AutoScaling::LaunchConfiguration", "Properties": { "ImageId": "ami-09bee01cc997a78a6", "SecurityGroups": [ "EcsSecurityGroup" ], "InstanceType": "t2.small", "IamInstanceProfile": "EC2InstanceProfile", "KeyName": "my-ssh-key", "UserData": { "Fn::Base64": "#!/bin/bash -xe\necho ECS_CLUSTER=${ECSCluster} \u003e\u003e /etc/ecs/ecs.config\nyum install -y aws-cfn-bootstrap\n/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region}\n" } } }, "service": { "Type": "AWS::ECS::Service", "Properties": { "Cluster": "ECSCluster", "DesiredCount": 1, "LoadBalancers": [ { "ContainerPort": 80, "TargetGroupArn": "ECSTG", "ContainerName": "simple-app" } ], "Role": "ECSServiceRole", "TaskDefinition": "taskdefinition" } }, "ServiceScalingTarget": { "Properties": { "MinCapacity": 1, "ResourceId": [ "", [ "service/", "ECSCluster", "/", [ "service", "Name" ] ] ], "RoleARN": [ "AutoscalingRole", "Arn" ], "ScalableDimension": "ecs:service:DesiredCount", "ServiceNamespace": "ecs", "MaxCapacity": 2 }, "Type": "AWS::ApplicationAutoScaling::ScalableTarget" }, "EcsSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "ECS Security Group", "VpcId": "VpcId" } }