ELB Health Checks Failing with running AWS ECS container - amazon-web-services

I'm currently trying to deploy an application onto AWS ECS via CloudFormation templates. A docker image is stored in AWS ECR and deployed into an ECS Service fronted by an Application Load Balancer.
My service starts, and my load balancer is created, but the tasks inside of the ECS service repeatedly fail with the error:
Task failed ELB health checks in (target-group arn:aws:elasticloadbalancing:us-east-1:...
I've checked my security groups - the ECS Service Security Group includes the Load Balancer Security Group, and the Load Balancer is successfully created.
I've manually tried pulling my image on ECR and running it - no issues there. What am I missing? My template is below.
Resources:
ECSRole:
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:
# Rules which allow ECS to attach network interfaces to instances
# on your behalf in order for awsvpc networking mode to work right
- 'ec2:AttachNetworkInterface'
- 'ec2:CreateNetworkInterface'
- 'ec2:CreateNetworkInterfacePermission'
- 'ec2:DeleteNetworkInterface'
- 'ec2:DeleteNetworkInterfacePermission'
- 'ec2:Describe*'
- 'ec2:DetachNetworkInterface'
# Rules which allow ECS to update load balancers on your behalf
# with the information sabout how to send traffic to your containers
- 'elasticloadbalancing:DeregisterInstancesFromLoadBalancer'
- 'elasticloadbalancing:DeregisterTargets'
- 'elasticloadbalancing:Describe*'
- 'elasticloadbalancing:RegisterInstancesWithLoadBalancer'
- 'elasticloadbalancing:RegisterTargets'
Resource: '*'
# This is a role which is used by the ECS tasks themselves.
ECSTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ecs-tasks.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: AmazonECSTaskExecutionRolePolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
# Allow the ECS Tasks to download images from ECR
- 'ecr:GetAuthorizationToken'
- 'ecr:BatchCheckLayerAvailability'
- 'ecr:GetDownloadUrlForLayer'
- 'ecr:BatchGetImage'
# Allow the ECS tasks to upload logs to CloudWatch
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: '*'
TaskDef:
Type: AWS::ECS::TaskDefinition
Properties:
Cpu: 4096
Memory: 30720
ContainerDefinitions:
- Image: !Ref ECRImageUrl
Name: !Sub "${ProjectName}-ecsContainer"
PortMappings:
- ContainerPort: 4000
HostPort: 4000
Protocol: tcp
Family: !Sub "${ProjectName}-taskDef"
ExecutionRoleArn: !Ref ECSTaskExecutionRole
RequiresCompatibilities:
- FARGATE
NetworkMode: awsvpc
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Sub "${ProjectName}-ECSCluster"
Service:
Type: AWS::ECS::Service
DependsOn:
- LoadBalancerListener
Properties:
Cluster: !Ref Cluster
DesiredCount: 2
LaunchType: FARGATE
ServiceName: !Sub "${ProjectName}-ECSService"
TaskDefinition: !Ref TaskDef
NetworkConfiguration:
AwsvpcConfiguration:
SecurityGroups:
- !Ref FargateContainerSecurityGroup
AssignPublicIp: ENABLED
Subnets: !Split [',', {'Fn::ImportValue': !Sub '${VPCStackName}-PublicSubnets'}]
LoadBalancers:
- ContainerName: !Sub "${ProjectName}-ecsContainer"
ContainerPort: 4000
TargetGroupArn: !Ref TargetGroup
FargateContainerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Access to the Fargate containers
VpcId:
Fn::ImportValue:
!Sub '${VPCStackName}-VPC'
EcsSecurityGroupIngressFromPublicALB:
Type: AWS::EC2::SecurityGroupIngress
Properties:
Description: Ingress from the public ALB
GroupId: !Ref 'FargateContainerSecurityGroup'
IpProtocol: -1
SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG'
EcsSecurityGroupIngressFromSelf:
Type: AWS::EC2::SecurityGroupIngress
Properties:
Description: Ingress from other containers in the same security group
GroupId: !Ref 'FargateContainerSecurityGroup'
IpProtocol: -1
SourceSecurityGroupId: !Ref 'FargateContainerSecurityGroup'
PublicLoadBalancerSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Access to the public facing load balancer
VpcId:
Fn::ImportValue:
!Sub '${VPCStackName}-VPC'
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
IpProtocol: -1
ACMCertificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Sub ${ProjectName}.${DomainName}
ValidationMethod: DNS
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
DependsOn:
- LoadBalancer
Properties:
TargetType: ip
Name: !Sub "${ProjectName}-ECSService"
Port: 4000
Protocol: HTTP
VpcId:
Fn::ImportValue:
!Sub '${VPCStackName}-VPC'
LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internet-facing
Subnets: !Split [',', {'Fn::ImportValue': !Sub '${VPCStackName}-PublicSubnets'}]
SecurityGroups:
- !Ref PublicLoadBalancerSG
LoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::Listener
DependsOn:
- LoadBalancer
Properties:
DefaultActions:
- TargetGroupArn: !Ref TargetGroup
Type: 'forward'
LoadBalancerArn: !Ref LoadBalancer
Port: 443
Protocol: HTTP

It turns out that my security groups were not permissive enough. Traffic coming in from a Network Load Balancer is seen as coming from its original source, so if your NLB is open to all traffic, so should your Fargate containers. This fixed my issue:
FargateContainerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Access to the Fargate containers
VpcId:
Fn::ImportValue:
!Sub '${VPCStackName}-VPC'
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: !Ref ApplicationPort
ToPort: !Ref ApplicationPort
CidrIp: 0.0.0.0/0

Health check feature automatically calls / at port 80 and expect 200 status code in response. Its available in EC2->target groups -> your ecs target group. You have to ensure you port is 4000 and in health check adjust default path and response status code.
Additionally you can always try connecting to your ec2 instance using public ip or DNS on port 4000 that you are using and see if that works.
If ec2 instance not working at port 4000 troubleshoot the docker deployment. There is something wrong with talks definition or parameters.
If it's working something wrong with target group trlargets or health check configuration.
Hope this helps.

After much pain and suffering, I found out that the ALB itself needs to associated with the security group (SG) that allows traffic on the ports that get dynamically allocated by ECS. You should have an SG defined automatically that defines those port ranges. Associate this SG with your ALB and your health checks will start passing (assuming everything else is hooked up correctly).
In addition, ensure that your task definition has network mode set to "bridge" & that the "hostPort" value is set to 0 -- this indicates to ECS to dynamically allocate a port on the underlying EC2 instance and map it to your container port.

Related

AWS Fargate: unable to pull secrets or registry auth

I am trying to launch a containerized grpc application on aws fargate. I've tested the image locally, and have pushed it to ecr. I've created a task with a role that has permission to reach ecr, yet I am still getting an error pulling the container (error message shown below). I even tried launching the container in a public subnet with internet gateway/route table association that auto assigns public ips and the security group allows all outbound traffic.
The full cloudformation template is given below:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
TicketingAppTaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Essential: true
Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/ticketing-app:latest"
Name: ticketing-app
PortMappings:
- ContainerPort: 8080
Cpu: "1 vCPU"
ExecutionRoleArn: !Ref ExecutionRole
Memory: "2 GB" #this is smallest for 1 vcpu .... could maybe decrease
NetworkMode: awsvpc
RuntimePlatform:
CpuArchitecture: X86_64
OperatingSystemFamily: LINUX
ExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: [ sts:AssumeRole ]
Effect: Allow
Principal:
Service: [ ecs-tasks.amazonaws.com ]
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
TicketingEcsService:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref TicketingEcsCluster
LaunchType: FARGATE
#TODO I think we eventually need to specify load balancers here
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED #TODO remove this when done, just seeing if this let's us grab image from ecr?
SecurityGroups: [ !GetAtt TicketingServiceSecurityGroup.GroupId ]
Subnets:
- !Ref TicketingServicePrivateSubnet01
- !Ref TicketingServicePrivateSubnet02
TaskDefinition: !Ref TicketingAppTaskDefinition
TicketingEcsCluster:
Type: AWS::ECS::Cluster
TicketingServiceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "A security group used for the ticketing app"
VpcId: !Ref TicketingServiceVpc
TicketingServiceVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
TicketingServicePrivateSubnet01:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Sub "${AWS::Region}a"
VpcId: !Ref TicketingServiceVpc
CidrBlock: 10.0.0.0/18
TicketingServicePrivateSubnet02:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Sub "${AWS::Region}b"
VpcId: !Ref TicketingServiceVpc
CidrBlock: 10.0.64.0/18
#TODO public subnets and NAT gateway?
TicketingSecurityGroupHttpIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
#TODO I would probably use load balancer security group name here once we make one instead of opening up to any ip
GroupId: !GetAtt TicketingServiceSecurityGroup.GroupId
CidrIpv6: "::/0"
FromPort: 8080
IpProtocol: tcp
ToPort: 8080
TicketingSecurityGroupAllTrafficEgress:
Type: AWS::EC2::SecurityGroupEgress
Properties:
GroupId: !GetAtt TicketingServiceSecurityGroup.GroupId
IpProtocol: "-1" #-1 indicates all -- like a wildcard
CidrIp: "0.0.0.0/0"
TicketingServiceInternetGateway:
Type: AWS::EC2::InternetGateway
DependsOn: TicketingServiceVpc
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref TicketingServiceVpc
InternetGatewayId: !Ref TicketingServiceInternetGateway
TicketingAppRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref TicketingServiceVpc
TicketingVPCRouteAllTrafficToInternetGateway:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref TicketingAppRouteTable
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref TicketingServiceInternetGateway
Would anyone be able to point out a simple way to get this working (even if it uses not best practices, such as public subnet instead of private subnet and nat gateway) -- it is just for a poc.
Thanks
I had pushed my image to ecr in a different region..... changed the region and it worked (face palm).
So check your region if anyone else is in the same spot as me.

AWS CloudFormation cannot create Stack using CodeDeploy blue/green deployments

I am trying to deploy a new stack using CloudFormation with an ECS service using the CodeDeploy launch type to enable blue/green deployments.
In the User Guide for performing blue/green deployments via CloudFormation, they state the following:
To enable CloudFormation to perform blue/green deployments on a Stack, include the following information in its stack template:
At least one of the ECS resources that will trigger a blue/green deployment if replaced during a stack update. Currently, those resources are AWS::ECS::TaskDefinition and AWS::ECS::TaskSet.
When I exclude a AWS::ECS::TaskSet, the Stack creation fails and I receive the following error:
Transform AWS::CodeDeployBlueGreen failed with: Failed to transform template.
ECSAttributes must include TaskSets in AWS::CodeDeploy::BlueGreen Hook
If I add a AWS::ECS::TaskSet, the stack fails to create with the following error instead:
Resource handler returned message:
"Invalid request provided: Amazon ECS does not support task set management on services where deployments
are controlled by AWS CodeDeploy.
(Service: AmazonECS; Status Code: 400; Error Code: InvalidParameterException;
Request ID: 61b8c146-3ae9-4bc2-ac5c-08a11e194f06; Proxy: null)"
(RequestToken: 86a8a3a5-fe89-9939-15c2-45b08b28c3f3, HandlerErrorCode: InvalidRequest)
These are the relevant parts of my stack template:
Transform:
- AWS::CodeDeployBlueGreen
Hooks:
CodeDeployBlueGreenHook:
Type: AWS::CodeDeploy::BlueGreen
Properties:
ServiceRole: BlueGreenDeploymentRole
Applications:
- Target:
Type: AWS::ECS::Service
LogicalID: EcsService
ECSAttributes:
TaskDefinitions:
- TaskDefinitionBlue
- TaskDefinitionGreen
TaskSets:
- TaskSetBlue
- TaskSetGreen
TrafficRouting:
ProdTrafficRoute:
Type: AWS::ElasticLoadBalancingV2::Listener
LogicalID: LoadBalancerListener
TargetGroups:
- TargetGroupBlue
- TargetGroupGreen
TrafficRoutingConfig:
Type: TimeBasedLinear
TimeBasedLinear:
StepPercentage: 20
BakeTimeMins: 10
AdditionalOptions:
TerminationWaitTimeInMinutes: 60
Resources:
# IAM Role for blue/green deployments
BlueGreenDeploymentRole:
Type: AWS::IAM::Role
Properties:
RoleName: blue-green-deployment-role
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: codedeploy.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: BlueGreenDeploymentPolicy
PolicyDocument:
Statement:
- Effect: Allow
Action:
- codedeploy:Get*
- codedeploy:CreateCloudFormationDeployment
Resource: '*'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSCodeDeployRoleForECS
#########################
# Load Balancer
#########################
# Application Load Balancer
LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
IpAddressType: ipv4
Name: service-alb
Scheme: internal
Subnets:
- !Ref SubnetOne
- !Ref SubnetTwo
SecurityGroups:
- !Ref SecurityGroup
# Load Balancer Listener
LoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
ForwardConfig:
TargetGroups:
- TargetGroupArn: !Ref TargetGroupBlue
Weight: 1
- TargetGroupArn: !Ref TargetGroupGreen
Weight: 1
LoadBalancerArn: !Ref LoadBalancer
Port: 8080
Protocol: HTTP
# Load Balancer Target Groups
TargetGroupBlue:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${ServiceName}-blue
TargetType: ip
VpcId: !Ref Vpc
Port: 8080
Protocol: HTTP
HealthCheckPort: 8080
HealthCheckPath: /actuator/health
TargetGroupGreen:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${ServiceName}-green
TargetType: ip
VpcId: !Ref Vpc
Port: 8080
Protocol: HTTP
HealthCheckPort: 8080
HealthCheckPath: /actuator/health
#########################
# ECS
#########################
# ECS Cluster
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Ref ServiceName
# ECS Service
EcsService:
Type: AWS::ECS::Service
DependsOn: LoadBalancerListener
Properties:
ServiceName: !Ref ServiceName
Cluster: !Ref Cluster
TaskDefinition: !Ref TaskDefinitionBlue
DeploymentController:
Type: CODE_DEPLOY
DesiredCount: 0
LaunchType: FARGATE
LoadBalancers:
- ContainerName: !Sub ${ServiceName}-container
ContainerPort: 8080
TargetGroupArn: !Ref TargetGroupBlue
- ContainerName: !Sub ${ServiceName}-container
ContainerPort: 8080
TargetGroupArn: !Ref TargetGroupGreen
NetworkConfiguration:
AwsvpcConfiguration:
Subnets:
- !Ref SubnetOne
- !Ref SubnetTwo
SecurityGroups:
- !Ref SecurityGroup
SchedulingStrategy: REPLICA
# Task Definitions
TaskDefinitionBlue:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Name: !Sub ${ServiceName}-container
Image: !Sub ${ImageRepository.RepositoryUri}:latest
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref LogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: payments
PortMappings:
- ContainerPort: 8080
Cpu: 256
Memory: 512
NetworkMode: awsvpc
Family: !Sub ${ServiceName}
ExecutionRoleArn: !Ref TaskExecutionRole
RequiresCompatibilities:
- FARGATE
TaskDefinitionGreen:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Name: !Sub ${ServiceName}-container
Image: !Sub ${ImageRepository.RepositoryUri}:latest
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref LogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: payments
PortMappings:
- ContainerPort: 8080
Cpu: 256
Memory: 512
NetworkMode: awsvpc
Family: !Sub ${ServiceName}
ExecutionRoleArn: !Ref TaskExecutionRole
RequiresCompatibilities:
- FARGATE
# Image Repository
ImageRepository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Sub ${ServiceName}
LifecyclePolicy:
LifecyclePolicyText: |
{
"rules": [
{
"rulePriority": 1,
"description": "Maintain at most 25 images",
"selection": {
"tagStatus": "untagged",
"countType": "imageCountMoreThan",
"countNumber": 25
},
"action": {
"type": "expire"
}
}
]
}
TaskSetBlue:
Type: AWS::ECS::TaskSet
Properties:
Cluster: !Ref Cluster
LaunchType: FARGATE
Service: !Ref EcsService
TaskDefinition: !Ref TaskDefinitionBlue
NetworkConfiguration:
AwsVpcConfiguration:
Subnets:
- !Ref SubnetOne
- !Ref SubnetTwo
SecurityGroups:
- !Ref SecurityGroup
LoadBalancers:
- ContainerName: !Sub ${ServiceName}-container
ContainerPort: 8080
TargetGroupArn: !Ref TargetGroupBlue
How can I update my template to allow for the blue/green deployment strategy via CodeDeploy?
G/B deployment using CFN is EXTERNAL, not CODE_DEPLOY. There could be many other issues with your template, but your current error relates to using wrong DeploymentController. Please study AWS docs and example:
Perform ECS blue/green deployments through CodeDeploy using AWS CloudFormation
Exactly, AWS doesn't support Blue Green deployment on EC2/ASG...!
The easiest way that I just figure out is to create the deployment group with In-Place method && Then change the deployment group configuration manually from In-place to Blue Green
Or you can use the lambda function, but is a litte bit hard to customize it
Wish this will help you

ECS Failed to create service due to assume role

I got the following error when attempting to create an ECS service (Fargate) using Cloud Formation.
Invalid request provided: CreateService error: Unable to assume role and validate the specified targetGroupArn. Please verify that the ECS service role being passed has the proper permissions. (Service: Ecs, Status Code: 400, Request ID: 32dc55bc-3b69-46dd-bf95-f3fff77c2508, Extended Request ID: null)
Things that tried/related:
Updating the role to include even AdministratorAccess (just for troubleshooting).
Allowing several services (ecs, elb, ec2, cloudformation) to assume role (was only ecs-tasks originally).
Create ECS service in web console successfully (same config). (But Cloud Formation doesn't work).
The ECS role has not been updated, the last successful ECS service creation was 21 Nov 2020 (/w Cloud Formation)
The following is the ECS role and Cloud Trail event of the above error. Has anyone faced similar issues or know what is happening?
Edit 1:
ECS template is included, IAM role and the ECS service belongs to different root stack such that it is not possible to use DependsOn attribute. We have CI/CD that ensures the IAM stack is updated before the ECS stack.
ECS Task role used:
EcsTaskRole:
Type: 'AWS::IAM::Role'
Properties:
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AdministratorAccess'
- 'arn:aws:iam::aws:policy/AmazonSQSFullAccess'
- 'arn:aws:iam::aws:policy/AmazonS3FullAccess'
- 'arn:aws:iam::aws:policy/AmazonSNSFullAccess'
- 'arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess'
- 'arn:aws:iam::aws:policy/AmazonRDSFullAccess'
- 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'
- 'arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess'
- 'arn:aws:iam::aws:policy/AWSXrayFullAccess'
- 'arn:aws:iam::aws:policy/AWSBatchFullAccess'
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
- ecs.amazonaws.com
- cloudformation.amazonaws.com
- elasticloadbalancing.amazonaws.com
- ec2.amazonaws.com
Action:
- 'sts:AssumeRole'
Outputs:
EcsTaskRoleArn:
Description: EcsTaskRoleArn
Value: !GetAtt EcsTaskRole.Arn
Export:
Name: !Sub "${AWS::StackName}-EcsTaskRoleArn"
Event from Cloud Trail: (Masked some info)
{
"eventVersion":"1.08",
"userIdentity":{
"type":"IAMUser",
"principalId":"********",
"arn":"arn:aws:iam::*****:user/****",
"accountId":"*********",
"accessKeyId":"********",
"userName":"********",
"sessionContext":{
"sessionIssuer":{
},
"webIdFederationData":{
},
"attributes":{
"mfaAuthenticated":"false",
"creationDate":"2021-01-01T20:48:02Z"
}
},
"invokedBy":"cloudformation.amazonaws.com"
},
"eventTime":"2021-01-01T20:48:14Z",
"eventSource":"ecs.amazonaws.com",
"eventName":"CreateService",
"awsRegion":"ap-east-1",
"sourceIPAddress":"cloudformation.amazonaws.com",
"userAgent":"cloudformation.amazonaws.com",
"errorCode":"InvalidParameterException",
"errorMessage":"Unable to assume role and validate the specified targetGroupArn. Please verify that the ECS service role being passed has the proper permissions.",
"requestParameters":{
"clientToken":"75e4c412-a82c-b01a-1909-cfdbe788f1f1",
"cluster":"********",
"desiredCount":1,
"enableECSManagedTags":true,
"enableExecuteCommand":false,
"healthCheckGracePeriodSeconds":300,
"launchType":"FARGATE",
"loadBalancers":[
{
"targetGroupArn":"arn:aws:elasticloadbalancing:ap-east-1:********:listener-rule/app/********/e6a62b4cc4d13aaa/098a6759b6062f3f/f374eba8a4fb66e5",
"containerName":"********",
"containerPort":8080
}
],
"networkConfiguration":{
"awsvpcConfiguration":{
"assignPublicIp":"ENABLED",
"securityGroups":[
"sg-025cd908f664b25fe"
],
"subnets":[
"subnet-067502309b0359486",
"subnet-018893d9e397ecac5",
"subnet-0bfb736aefb90f05a"
]
}
},
"propagateTags":"SERVICE",
"serviceName":"********",
"taskDefinition":"arn:aws:ecs:ap-east-1:********:task-definition/********"
},
"responseElements":null,
"requestID":"32dc55bc-3b69-46dd-bf95-f3fff77c2508",
"eventID":"3f872d94-72a7-4ced-96a6-028a6ceeacba",
"readOnly":false,
"eventType":"AwsApiCall",
"managementEvent":true,
"eventCategory":"Management",
"recipientAccountId":"904822583864"
}
Cloud formation template of ECS service
MyServiceLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: my-service-log
RetentionInDays: 365
MyServiceTargetGroup:
Type: 'AWS::ElasticLoadBalancingV2::TargetGroup'
Properties:
HealthCheckPath: /my-service/health
HealthCheckIntervalSeconds: 300
HealthCheckTimeoutSeconds: 10
Name: my-service-target-group
TargetType: ip
Port: 8080
Protocol: HTTP
VpcId: !Ref VpcId
MyServiceListenerRule:
Type: 'AWS::ElasticLoadBalancingV2::ListenerRule'
Properties:
Actions:
- Type: forward
TargetGroupArn: !Ref MyServiceTargetGroup
Conditions:
- Field: path-pattern
Values:
- /my-service/*
ListenerArn: !Ref AppAlbListenerArn
Priority: 164
MyServiceTaskDef:
Type: 'AWS::ECS::TaskDefinition'
Properties:
ContainerDefinitions:
- Name: my-service-container
Image: !Join
- ''
- - !Ref 'AWS::AccountId'
- .dkr.ecr.
- !Ref 'AWS::Region'
- .amazonaws.com/
- 'Fn::ImportValue': !Sub '${RepositoryStackName}-MyServiceECR'
- ':'
- !Ref MyServiceVersion
Essential: true
PortMappings:
- ContainerPort: 8080
Protocol: tcp
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref MyServiceLogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: my-service
RequiresCompatibilities:
- FARGATE
Cpu: 256
Memory: 512
Family: my-service-taskdef
NetworkMode: awsvpc
ExecutionRoleArn:
'Fn::ImportValue': !Sub '${IamStackName}-EcsTaskRoleArn'
TaskRoleArn:
'Fn::ImportValue': !Sub '${IamStackName}-EcsTaskRoleArn'
Volumes: []
MyServiceECS:
Type: 'AWS::ECS::Service'
Properties:
DesiredCount: 1
Cluster: !Ref EcsCluster
TaskDefinition: !Ref MyServiceTaskDef
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- !Ref SecurityGroupECS
Subnets:
- !Ref DmzSubnet1
- !Ref DmzSubnet2
- !Ref DmzSubnet3
LoadBalancers:
- ContainerName: my-service-container
ContainerPort: '8080'
TargetGroupArn: !Ref MyServiceListenerRule
EnableECSManagedTags: true
PropagateTags: SERVICE
HealthCheckGracePeriodSeconds: 300
DependsOn:
- MyServiceListenerRule
Use the DependsOn attribute to specify the dependency of the AWS::ECS::Service resource on AWS::IAM::Policy.
There are mistakes in your templates. The first apparent one is:
TargetGroupArn: !Ref MyServiceListenerRule
This should be:
TargetGroupArn: !Ref MyServiceTargetGroup
Large chunks of your templates are missing (ALB definition, listener), so can't comment on them.
p.s.
The IAM role is fine, in a sense that it is not the source of the issue. But giving full privileges to a number of services in one role is not a good practice.

Security group sg-0da667222da8a6eb2 does not appear to belong to the same VPC as the input subnets

As part of the CI/CD Jenkins pipeline, I am deploying a springboot application to AWS EC2/Fargate using cloudformation from an image available at dockerhub. I have my access key, the secret, region, and subnet defined as secrets that are passed at runtime. The cloudformation deployment is failing with status CREATE_FAILED and the following error:
Invalid request provided: CreateService error: Security group
sg-0da667222da8a6eb2 does not appear to belong to the same VPC as the
input subnets. (Service: Ecs, Status Code: 400, Request ID:
503ce486-c3db-4d35-bb92-5f4770662c05, Extended Request ID: null)
Here is my cloudformation yaml file content:
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
SubnetID:
Type: String
ServiceName:
Type: String
ServiceVersion:
Type: String
DockerHubUsername:
Type: String
Resources:
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: deployment-example-cluster
ServiceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: ServiceSecurityGroup
GroupDescription: Security group for service
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
CidrIp: 0.0.0.0/0
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub ${ServiceName}-task
Cpu: 256
Memory: 512
NetworkMode: awsvpc
ContainerDefinitions:
- Name: !Sub ${ServiceName}-container
Image: !Sub ${DockerHubUsername}/${ServiceName}:${ServiceVersion}
PortMappings:
- ContainerPort: 8080
RequiresCompatibilities:
- EC2
- FARGATE
Service:
Type: AWS::ECS::Service
Properties:
ServiceName: !Sub ${ServiceName}-service
Cluster: !Ref Cluster
TaskDefinition: !Ref TaskDefinition
DesiredCount: 1
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
Subnets:
- !Ref SubnetID
SecurityGroups:
- !GetAtt ServiceSecurityGroup.GroupId
Here is screenshot of cloudformation stack building process:
Surprisingly, sg-0da667222da8a6eb2 is not one of my security groups. Any help will be appreciated.
Your ServiceSecurityGroup, as it is defined, it is created in a default VPC. However, your SubnetID probably belongs to a custom VPC. Therefore, you have to provide VpcId for your ServiceSecurityGroup:
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
# others not shown
Resources:
# only relevant part shown
ServiceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: ServiceSecurityGroup
GroupDescription: Security group for service
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
CidrIp: 0.0.0.0/0
VpcId: !Ref VpcId
Service:
Type: AWS::ECS::Service
Properties:
ServiceName: !Sub ${ServiceName}-service
Cluster: !Ref Cluster
TaskDefinition: !Ref TaskDefinition
DesiredCount: 1
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
Subnets:
- !Ref SubnetID
SecurityGroups:
- !GetAtt ServiceSecurityGroup.GroupId
I am using a custom VPC and not the default VPC in my setup. When cloudformation kicks in, it looks to build the resources in the default VPC in the absence of the information provided. In my case when I pass the custom VPC from my Jenkins as an environment variable, the stack comes up as expected.

Fargate service not respecting security groups

I am unable to connect from a Fargate container to an RDS instance when its ingress is limited through security groups. I can connect with lambdas though.
The container has no issue hitting SQS, or the internet. Only has issues hitting the RDS endpoint.
Here is an excerpt from the template, where the database ingress is open. Fargate can connect without issue.
Service:
Type: AWS::ECS::Service
Properties:
ServiceName: !Ref ServiceName
Cluster: !Ref Cluster
TaskDefinition: !Ref TaskDefinition
PlatformVersion: 1.3.0
DeploymentConfiguration:
MinimumHealthyPercent: 100
MaximumPercent: 200
DesiredCount: 0
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: DISABLED
Subnets:
- !Ref PrivateSubnet1
SecurityGroups:
- !Ref DatabaseAccessSecurityGroup
DatabaseInstance:
Type: AWS::RDS::DBInstance
Properties:
Engine: mysql
EngineVersion: 8.0.16
AvailabilityZone: !GetAtt PrivateSubnet1.AvailabilityZone
PubliclyAccessible: false
...
VPCSecurityGroups:
- !Ref DatabaseSecurityGroup
DatabaseSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: Cloudformation managed Db subnet group
SubnetIds:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
DatabaseSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref VPC
GroupName: database-sg
GroupDescription: Database security group
SecurityGroupIngress:
- Description: Access to RDS
# allowing all works with Fargate
CidrIp: 0.0.0.0/0
FromPort: 3306
ToPort: 3306
IpProtocol: tcp
DatabaseAccessSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: database-access-sg
GroupDescription: Security group for accessing db
VpcId: !Ref VPC
But if I change the DatabaseSecurityGroup Group ingress to only allow ingress through DatabaseAccessSecurityGroup I get errors when trying to connect through Fargate. Lambdas using the same security group have no issue.
SecurityGroupIngress:
- Description: Access to RDS
CidrIp: 0.0.0.0/0
SourceSecurityGroupId: !GetAtt DatabaseAccessSecurityGroup.GroupId
FromPort: 3306
ToPort: 3306
IpProtocol: tcp
Is there any way to get the Fargate Service to respect security group rules?
This issue was occurring because I was using a Service in the Cloudformation template, but spinning up the tasks via ecs.runTask, which overrode the security groups in the Service.