ECS Cluster Not Encrypted At Rest
- Query id: 6c131358-c54d-419b-9dd6-1f7dd41d180c
- Query name: ECS Cluster Not Encrypted At Rest
- Platform: CloudFormation
- Severity: High
- Category: Encryption
- URL: Github
Description¶
Ensure that AWS ECS clusters are encrypted. Data encryption at rest, prevents unauthorized users from accessing sensitive data on your AWS ECS clusters and associated cache storage systems.
Documentation
Code samples¶
Code samples with security vulnerabilities¶
Positive test num. 1 - yaml file
Resources:
cluster:
Type: AWS::ECS::Cluster
taskdefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Name: !Ref AppName
MountPoints:
- SourceVolume: my-vol
ContainerPath: /var/www/my-vol
Image: amazon/amazon-ecs-sample
Cpu: '10'
PortMappings:
- ContainerPort: !Ref AppContainerPort
HostPort: !Ref AppHostPort
EntryPoint:
- /usr/sbin/apache2
- '-D'
- FOREGROUND
Memory: '500'
Essential: true
- Name: busybox
Image: busybox
Cpu: '10'
EntryPoint:
- sh
- '-c'
Memory: '500'
Command:
- >-
/bin/sh -c "while true; do /bin/date > /var/www/my-vol/date; sleep
1; done"
Essential: false
VolumesFrom:
- SourceContainer: !Ref AppName
Volumes:
- Host:
SourcePath: /var/lib/docker/vfs/dir/
Name: my-vol
EFSVolumeConfiguration:
TransitEncryption: DISABLED
TransitEncryptionPort: 8080
service:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref cluster
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DesiredCount: 0
HealthCheckGracePeriodSeconds: !Ref HealthCheckGracePeriodSeconds
LoadBalancers:
- ContainerName: !Ref AppName
ContainerPort: !Ref AppContainerPort
LoadBalancerName: !Ref elb
PlacementStrategies:
- Type: binpack
Field: memory
- Type: spread
Field: host
PlacementConstraints:
- Type: memberOf
Expression: 'attribute:ecs.availability-zone != us-east-1d'
- Type: distinctInstance
TaskDefinition: !Ref taskdefinition
ServiceName: !Ref ServiceName
Role: !Ref Role
elb:
Type: AWS::ElasticLoadBalancing::LoadBalancer
Properties:
LoadBalancerName: !Ref LoadBalancerName
Listeners:
- InstancePort: !Ref AppHostPort
LoadBalancerPort: '80'
Protocol: HTTP
Subnets:
- !Ref Subnet1
DependsOn: GatewayAttachment
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/24
Subnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.0.0/25
InternetGateway:
Type: AWS::EC2::InternetGateway
GatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2008-10-17
Statement:
- Sid: ''
Effect: Allow
Principal:
Service: ecs.amazonaws.com
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole'
Positive test num. 2 - yaml file
Resources:
cluster:
Type: AWS::ECS::Cluster
service:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref cluster
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DesiredCount: 0
HealthCheckGracePeriodSeconds: !Ref HealthCheckGracePeriodSeconds
LoadBalancers:
- ContainerName: !Ref AppName
ContainerPort: !Ref AppContainerPort
LoadBalancerName: !Ref elb
PlacementStrategies:
- Type: binpack
Field: memory
- Type: spread
Field: host
PlacementConstraints:
- Type: memberOf
Expression: 'attribute:ecs.availability-zone != us-east-1d'
- Type: distinctInstance
TaskDefinition: !Ref taskdefinition1
ServiceName: !Ref ServiceName
Role: !Ref Role
elb:
Type: AWS::ElasticLoadBalancing::LoadBalancer
Properties:
LoadBalancerName: !Ref LoadBalancerName
Listeners:
- InstancePort: !Ref AppHostPort
LoadBalancerPort: '80'
Protocol: HTTP
Subnets:
- !Ref Subnet1
DependsOn: GatewayAttachment
VPC2:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/24
Subnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.0.0/25
InternetGateway:
Type: AWS::EC2::InternetGateway
GatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2008-10-17
Statement:
- Sid: ''
Effect: Allow
Principal:
Service: ecs.amazonaws.com
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole'
Positive test num. 3 - json file
{
"Resources": {
"cluster": {
"Type": "AWS::ECS::Cluster"
},
"service": {
"Type": "AWS::ECS::Service",
"Properties": {
"LoadBalancers": [
{
"ContainerName": "AppName",
"ContainerPort": "AppContainerPort",
"LoadBalancerName": "elb"
}
],
"PlacementStrategies": [
{
"Type": "binpack",
"Field": "memory"
},
{
"Type": "spread",
"Field": "host"
}
],
"PlacementConstraints": [
{
"Expression": "attribute:ecs.availability-zone != us-east-1d",
"Type": "memberOf"
},
{
"Type": "distinctInstance"
}
],
"Role": "Role",
"DeploymentConfiguration": {
"MaximumPercent": 200,
"MinimumHealthyPercent": 100
},
"DesiredCount": 0,
"TaskDefinition": "taskdefinition",
"ServiceName": "ServiceName",
"Cluster": "cluster",
"HealthCheckGracePeriodSeconds": "HealthCheckGracePeriodSeconds"
}
},
"elb": {
"DependsOn": "GatewayAttachment",
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
"LoadBalancerName": "LoadBalancerName",
"Listeners": [
{
"LoadBalancerPort": "80",
"Protocol": "HTTP",
"InstancePort": "AppHostPort"
}
],
"Subnets": [
"Subnet1"
]
}
},
"InternetGateway": {
"Type": "AWS::EC2::InternetGateway"
},
"GatewayAttachment": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": "VPC",
"InternetGatewayId": "InternetGateway"
}
},
"taskdefinition": {
"Type": "AWS::ECS::TaskDefinition",
"Properties": {
"ContainerDefinitions": [
{
"Essential": true,
"Name": "AppName",
"MountPoints": [
{
"SourceVolume": "my-vol",
"ContainerPath": "/var/www/my-vol"
}
],
"Image": "amazon/amazon-ecs-sample",
"Cpu": "10",
"PortMappings": [
{
"ContainerPort": "AppContainerPort",
"HostPort": "AppHostPort"
}
],
"EntryPoint": [
"/usr/sbin/apache2",
"-D",
"FOREGROUND"
],
"Memory": "500"
},
{
"Memory": "500",
"Command": [
"/bin/sh -c \"while true; do /bin/date \u003e /var/www/my-vol/date; sleep 1; done\""
],
"Essential": false,
"VolumesFrom": [
{
"SourceContainer": "AppName"
}
],
"Name": "busybox",
"Image": "busybox",
"Cpu": "10",
"EntryPoint": [
"sh",
"-c"
]
}
],
"Volumes": [
{
"Host": {
"SourcePath": "/var/lib/docker/vfs/dir/"
},
"Name": "my-vol",
"EFSVolumeConfiguration": {
"TransitEncryption": "DISABLED",
"TransitEncryptionPort": 8080
}
}
]
}
},
"VPC": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": "10.0.0.0/24"
}
},
"Subnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": "VPC",
"CidrBlock": "10.0.0.0/25"
}
},
"Role": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2008-10-17T00:00:00Z",
"Statement": [
{
"Principal": {
"Service": "ecs.amazonaws.com"
},
"Action": "sts:AssumeRole",
"Sid": "",
"Effect": "Allow"
}
]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole"
]
}
}
}
}
Positive test num. 4 - json file
{
"Resources": {
"InternetGateway": {
"Type": "AWS::EC2::InternetGateway"
},
"GatewayAttachment": {
"Properties": {
"InternetGatewayId": "InternetGateway",
"VpcId": "VPC"
},
"Type": "AWS::EC2::VPCGatewayAttachment"
},
"Role": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecs.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
],
"Version": "2008-10-17T00:00:00Z"
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole"
]
}
},
"cluster": {
"Type": "AWS::ECS::Cluster"
},
"service": {
"Type": "AWS::ECS::Service",
"Properties": {
"PlacementConstraints": [
{
"Type": "memberOf",
"Expression": "attribute:ecs.availability-zone != us-east-1d"
},
{
"Type": "distinctInstance"
}
],
"ServiceName": "ServiceName",
"Role": "Role",
"Cluster": "cluster",
"DesiredCount": 0,
"HealthCheckGracePeriodSeconds": "HealthCheckGracePeriodSeconds",
"TaskDefinition": "taskdefinition1",
"DeploymentConfiguration": {
"MaximumPercent": 200,
"MinimumHealthyPercent": 100
},
"LoadBalancers": [
{
"ContainerName": "AppName",
"ContainerPort": "AppContainerPort",
"LoadBalancerName": "elb"
}
],
"PlacementStrategies": [
{
"Type": "binpack",
"Field": "memory"
},
{
"Type": "spread",
"Field": "host"
}
]
}
},
"elb": {
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
"LoadBalancerName": "LoadBalancerName",
"Listeners": [
{
"LoadBalancerPort": "80",
"Protocol": "HTTP",
"InstancePort": "AppHostPort"
}
],
"Subnets": [
"Subnet1"
]
},
"DependsOn": "GatewayAttachment"
},
"VPC2": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": "10.0.0.0/24"
}
},
"Subnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": "VPC",
"CidrBlock": "10.0.0.0/25"
}
}
}
}
Code samples without security vulnerabilities¶
Negative test num. 1 - yaml file
AWSTemplateFormatVersion: 2010-09-09
Description: Creating ECS service
Parameters:
AppName:
Type: String
Description: Name of app requiring ELB exposure
Default: simple-app
AppContainerPort:
Type: Number
Description: Container port of app requiring ELB exposure
Default: '80'
AppHostPort:
Type: Number
Description: Host port of app requiring ELB exposure
Default: '80'
ServiceName:
Type: String
LoadBalancerName:
Type: String
HealthCheckGracePeriodSeconds:
Type: String
Resources:
cluster:
Type: AWS::ECS::Cluster
taskdefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Name: !Ref AppName
MountPoints:
- SourceVolume: my-vol
ContainerPath: /var/www/my-vol
Image: amazon/amazon-ecs-sample
Cpu: '10'
PortMappings:
- ContainerPort: !Ref AppContainerPort
HostPort: !Ref AppHostPort
EntryPoint:
- /usr/sbin/apache2
- '-D'
- FOREGROUND
Memory: '500'
Essential: true
- Name: busybox
Image: busybox
Cpu: '10'
EntryPoint:
- sh
- '-c'
Memory: '500'
Command:
- >-
/bin/sh -c "while true; do /bin/date > /var/www/my-vol/date; sleep
1; done"
Essential: false
VolumesFrom:
- SourceContainer: !Ref AppName
Volumes:
- Host:
SourcePath: /var/lib/docker/vfs/dir/
Name: my-vol
EFSVolumeConfiguration:
TransitEncryption: ENABLED
TransitEncryptionPort: 8080
service:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref cluster
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DesiredCount: 0
HealthCheckGracePeriodSeconds: !Ref HealthCheckGracePeriodSeconds
LoadBalancers:
- ContainerName: !Ref AppName
ContainerPort: !Ref AppContainerPort
LoadBalancerName: !Ref elb
PlacementStrategies:
- Type: binpack
Field: memory
- Type: spread
Field: host
PlacementConstraints:
- Type: memberOf
Expression: 'attribute:ecs.availability-zone != us-east-1d'
- Type: distinctInstance
TaskDefinition: !Ref taskdefinition
ServiceName: !Ref ServiceName
Role: !Ref Role
elb:
Type: AWS::ElasticLoadBalancing::LoadBalancer
Properties:
LoadBalancerName: !Ref LoadBalancerName
Listeners:
- InstancePort: !Ref AppHostPort
LoadBalancerPort: '80'
Protocol: HTTP
Subnets:
- !Ref Subnet1
DependsOn: GatewayAttachment
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/24
Subnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.0.0/25
InternetGateway:
Type: AWS::EC2::InternetGateway
GatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2008-10-17
Statement:
- Sid: ''
Effect: Allow
Principal:
Service: ecs.amazonaws.com
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole'
Outputs:
Cluster:
Value: !Ref cluster
Negative test num. 2 - json file
{
"AWSTemplateFormatVersion": "2010-09-09T00:00:00Z",
"Description": "Creating ECS service",
"Parameters": {
"HealthCheckGracePeriodSeconds": {
"Type": "String"
},
"AppName": {
"Type": "String",
"Description": "Name of app requiring ELB exposure",
"Default": "simple-app"
},
"AppContainerPort": {
"Type": "Number",
"Description": "Container port of app requiring ELB exposure",
"Default": "80"
},
"AppHostPort": {
"Type": "Number",
"Description": "Host port of app requiring ELB exposure",
"Default": "80"
},
"ServiceName": {
"Type": "String"
},
"LoadBalancerName": {
"Type": "String"
}
},
"Resources": {
"InternetGateway": {
"Type": "AWS::EC2::InternetGateway"
},
"GatewayAttachment": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"InternetGatewayId": "InternetGateway",
"VpcId": "VPC"
}
},
"Role": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2008-10-17T00:00:00Z",
"Statement": [
{
"Action": "sts:AssumeRole",
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecs.amazonaws.com"
}
}
]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole"
]
}
},
"cluster": {
"Type": "AWS::ECS::Cluster"
},
"service": {
"Type": "AWS::ECS::Service",
"Properties": {
"DeploymentConfiguration": {
"MaximumPercent": 200,
"MinimumHealthyPercent": 100
},
"TaskDefinition": "taskdefinition",
"Role": "Role",
"LoadBalancers": [
{
"ContainerName": "AppName",
"ContainerPort": "AppContainerPort",
"LoadBalancerName": "elb"
}
],
"PlacementStrategies": [
{
"Type": "binpack",
"Field": "memory"
},
{
"Type": "spread",
"Field": "host"
}
],
"PlacementConstraints": [
{
"Type": "memberOf",
"Expression": "attribute:ecs.availability-zone != us-east-1d"
},
{
"Type": "distinctInstance"
}
],
"ServiceName": "ServiceName",
"Cluster": "cluster",
"DesiredCount": 0,
"HealthCheckGracePeriodSeconds": "HealthCheckGracePeriodSeconds"
}
},
"elb": {
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
"Subnets": [
"Subnet1"
],
"LoadBalancerName": "LoadBalancerName",
"Listeners": [
{
"LoadBalancerPort": "80",
"Protocol": "HTTP",
"InstancePort": "AppHostPort"
}
]
},
"DependsOn": "GatewayAttachment"
},
"VPC": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": "10.0.0.0/24"
}
},
"Subnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.0.0/25",
"VpcId": "VPC"
}
},
"taskdefinition": {
"Type": "AWS::ECS::TaskDefinition",
"Properties": {
"ContainerDefinitions": [
{
"Image": "amazon/amazon-ecs-sample",
"Cpu": "10",
"PortMappings": [
{
"HostPort": "AppHostPort",
"ContainerPort": "AppContainerPort"
}
],
"EntryPoint": [
"/usr/sbin/apache2",
"-D",
"FOREGROUND"
],
"Memory": "500",
"Essential": true,
"Name": "AppName",
"MountPoints": [
{
"SourceVolume": "my-vol",
"ContainerPath": "/var/www/my-vol"
}
]
},
{
"Cpu": "10",
"EntryPoint": [
"sh",
"-c"
],
"Memory": "500",
"Command": [
"/bin/sh -c \"while true; do /bin/date \u003e /var/www/my-vol/date; sleep 1; done\""
],
"Essential": false,
"VolumesFrom": [
{
"SourceContainer": "AppName"
}
],
"Name": "busybox",
"Image": "busybox"
}
],
"Volumes": [
{
"Host": {
"SourcePath": "/var/lib/docker/vfs/dir/"
},
"Name": "my-vol",
"EFSVolumeConfiguration": {
"TransitEncryption": "ENABLED",
"TransitEncryptionPort": 8080
}
}
]
}
}
},
"Outputs": {
"Cluster": {
"Value": "cluster"
}
}
}