Fully Open Ingress

  • Query id: e415f8d3-fc2b-4f52-88ab-1129e8c8d3f5
  • Query name: Fully Open Ingress
  • Platform: CloudFormation
  • Severity: High
  • Category: Networking and Firewall
  • URL: Github

Description

ECS Service's security group should not allow unrestricted access to all ports from all IPv4 addresses
Documentation

Code samples

Code samples with security vulnerabilities

Positive 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'
  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: idle_timeout.timeout_seconds
        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 |
          #!/bin/bash -xe
          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: HTTPCode_ELB_5XX_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']
Outputs:
  ecsservice:
    Value: !Ref 'service'
  ecscluster:
    Value: !Ref 'ECSCluster'
  ECSALB:
    Description: Your ALB DNS URL
    Value: !Join ['', [!GetAtt [ECSALB, DNSName]]]
  taskdef:
    Value: !Ref 'TaskDefinition'
Positive test num. 2 - 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: 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: idle_timeout.timeout_seconds
        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 |
          #!/bin/bash -xe
          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: HTTPCode_ELB_5XX_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']
Positive test num. 3 - 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": {
      "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": "idle_timeout.timeout_seconds",
            "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": "HTTPCode_ELB_5XX_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": "0.0.0.0/0"
      }
    },
    "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"
    }
  }
}

Positive test num. 4 - json file
{
  "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": "HTTPCode_ELB_5XX_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": "0.0.0.0/0"
      }
    },
    "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": "idle_timeout.timeout_seconds",
            "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."
    }
  }
}

Code samples without security vulnerabilities

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: 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: idle_timeout.timeout_seconds
        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 |
          #!/bin/bash -xe
          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: HTTPCode_ELB_5XX_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']
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": "HTTPCode_ELB_5XX_Count",
        "Statistic": "Average",
        "Threshold": 10,
        "AlarmDescription": "Alarm if our ALB generates too many HTTP 500s.",
        "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": "idle_timeout.timeout_seconds",
            "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"
      }
    }
  }
}