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"
}
}
}
}