title: ELB Health Checks Failing with running AWS ECS container
body: <p>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. </p>
  
  <p>My service starts, and my load balancer is created, but the tasks inside of the ECS service repeatedly fail with the error: </p>
  
  <p><code>Task failed ELB health checks in (target-group arn:aws:elasticloadbalancing:us-east-1:...</code></p>
  
  <p>I've checked my security groups - the ECS Service Security Group includes the Load Balancer Security Group, and the Load Balancer is successfully created. </p>
  
  <p>I've manually tried pulling my image on ECR and running it - no issues there. What am I missing? My template is below. </p>
  
  <pre><code>
  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
  </code></pre>