My CloudFormation stack creation fails with a very generic error and I can't seem to figure out why.
I'm creating a single-container ECS service task with ALB.
Here's my stack template:
AWSTemplateFormatVersion: '2010-09-09'
Description: Services Containers
Parameters:
  VpcId:
    Type: String
    Default: vpc-4796bd23
  SubnetId:
    Type: String
    Default: subnet-f4701ff8
  ELBSecondarySubnetId:
    Type: String
    Default: subnet-8a453cef
  ECSCluster:
    Type: String
    Default: dev-ecs
  EcsSecurityGroup:
    Type: String
    Default: sg-74cb7b0c
  Color:
    Type: String
    AllowedValues: ['blue', 'green']
    Description: The deployment color
    Default: 'blue'
  BuildVersion:
    Type: String
    Description: The build version to deploy
  ComPublic:
    Type: String
    Description: Hosted Zone ID
    Default: Z00669325SSURKTK4ZPA
  MQPort:
    Type: Number
    Description: MQ Connectivity port
    Default: 5672
Resources:
  ApiLogsGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Join ['-', [ path-services-api, !Ref Color ]]
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ContainerDefinitions:
        - Essential: True
          Image: ***.dkr.ecr.us-east-1.amazonaws.com/path-services/path-services-api
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref ApiLogsGroup
              awslogs-region: us-east-1
              awslogs-stream-prefix: !Ref BuildVersion
          Name: path-services-api
          PortMappings:
            - ContainerPort: !Ref MQPort
              Protocol: tcp
      ExecutionRoleArn: arn:aws:iam::***:role/ecs-task-execution-role
      Family: path-services-api
      NetworkMode: awsvpc
      Cpu: 4096
      Memory: 8192 # max
      RequiresCompatibilities: 
        - FARGATE
      TaskRoleArn: !Ref ServiceTaskRole
  ServiceTaskRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: ['ecs-tasks.amazonaws.com', 'ecs.amazonaws.com']
            Action: ['sts:AssumeRole']
      Path: /
      Policies:
        - PolicyName: !Join ['-', [path-services, !Ref Color, read-secrets]]
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - 'secretsmanager:ListSecrets'
                  - 'secretsmanager:DescribeSecret'
                  - 'secretsmanager:GetRandomPassword'
                  - 'secretsmanager:GetResourcePolicy'
                  - 'secretsmanager:GetSecretValue'
                  - 'secretsmanager:ListSecretVersionIds'
                Resource: [ 'arn:aws:secretsmanager:us-east-1:***:secret:prod/path-services*' ]
  PathService:
    Type: AWS::ECS::Service
    DependsOn: LoadBalancerListener
    Properties:
      Cluster: !Ref ECSCluster
      DesiredCount: 1
      LaunchType: FARGATE
      LoadBalancers:
        - ContainerName: path-services-api
          ContainerPort: !Ref MQPort
          TargetGroupArn: !Ref TargetGroup
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - !Ref EcsSecurityGroup
          Subnets:
            - !Ref SubnetId
      PropagateTags: SERVICE
      ServiceName: !Join ['-', [ path-services-api, !Ref Color ] ]
      TaskDefinition: !Ref TaskDefinition
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckPort: !Ref MQPort
      HealthCheckProtocol: TCP
      Port: !Ref MQPort
      Protocol: TCP
      TargetType: ip
      VpcId: !Ref VpcId
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      IpAddressType: ipv4
      LoadBalancerAttributes:
        - Key: routing.http2.enabled
          Value: false
      Scheme: internet-facing
      SecurityGroups:
        - !Ref EcsSecurityGroup
      Subnets:
        - !Ref SubnetId
        - !Ref ELBSecondarySubnetId
      Type: application
  LoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref TargetGroup
      LoadBalancerArn: !Ref ApplicationLoadBalancer
      Port: !Ref MQPort
      Protocol: TCP
  ServiceScalingPolicy:
    Type: AWS::ApplicationAutoScaling::ScalingPolicy
    DependsOn: PathService
    Properties:
      PolicyName: !Join ['-', [ path-services-api, !Ref Color, scaling-policy ] ]
      PolicyType: TargetTrackingScaling
      ResourceId: !Join [ '/', [ service, !Ref ECSCluster, !Join ['-', [ path-services-api, !Ref Color ] ] ] ]
      ScalableDimension: ecs:service:DesiredCount
      ServiceNamespace: ecs
      TargetTrackingScalingPolicyConfiguration:
        PredefinedMetricSpecification:
          PredefinedMetricType: ECSServiceAverageCPUUtilization
        ScaleInCooldown: 30
        ScaleOutCooldown: 30
        TargetValue: 70.0
  # Route53Record:
  #   Type: AWS::Route53::RecordSet
  #   Properties:
  #     HostedZoneId: !Ref ComPublic
  #     Name: ***
  #     AliasTarget:
  #       DNSName: ApplicationLoadBalancer.DNSName
  #       HostedZoneId: !GetAtt ApplicationLoadBalancer.CanonicalHostedZoneI
  #     TTL: 600
  #     Type: A
  ServiceCpuAlarm:
    Type: AWS::CloudWatch::Alarm
    DependsOn: PathService
    Properties:
      AlarmActions:
        - !Ref ServiceAlarmTopic
      OKActions:
        - !Ref ServiceAlarmTopic
      ComparisonOperator: GreaterThanOrEqualToThreshold
      DatapointsToAlarm: 1
      Dimensions:
        - Name: Service
          Value: !GetAtt PathService.Name
      EvaluationPeriods: 1
      MetricName: CPUUtilization
      Namespace: AWS/ECS
      Period: 60
      Statistic: Maximum
      Threshold: 90
      TreatMissingData: notBreaching
  ServiceMemoryAlarm:
    Type: AWS::CloudWatch::Alarm
    DependsOn: PathService
    Properties:
      AlarmActions:
        - !Ref ServiceAlarmTopic
      OKActions:
        - !Ref ServiceAlarmTopic
      ComparisonOperator: GreaterThanOrEqualToThreshold
      DatapointsToAlarm: 1
      Dimensions:
        - Name: Service
          Value: !GetAtt PathService.Name
      EvaluationPeriods: 1
      MetricName: MemoryUtilization
      Namespace: AWS/ECS
      Period: 60
      Statistic: Maximum
      Threshold: 90
      TreatMissingData: notBreaching
  ServiceAlarmTopic:
    Type: AWS::SNS::Topic
    DependsOn: PathService
    Properties:
      TopicName: path-services-api-alarm-topic
      Subscription:
        - Endpoint: ***
          Protocol: email
        - Endpoint: ***
          Protocol: email
CloudFormation stack creation fails on resource LoadBalancerListener with status reason:
Invalid request provided: AWS::ElasticLoadBalancingV2::Listener Validation exception
I've found no similar issue so far and don't know where to get more details about what's wrong. Thank you.
While the answer above is 100% correct, I just want to elaborate a bit more for those who are running into this same issue. @marcin states that the load balancer "type" is "application", but the "protocol" is TCP. He is referencing two separate CF template objects here.
When creating a load balancer, you actually need to define 3 different objects in the CF template. A "load balancer", a "load balancer listener" and a "target group" (the place the load balancer will be sending traffic).
So, if a load balancer's "type" is "application" the associated "TargetGroup" must have a protocol of either "HTTP", or "HTTPS". A type of "TCP" will give this error.
I had the same problem, but thanks to cloudformation, one error message can always mean multiple things.. In my case it was a permission error on the load balancer. Try to add this permission to your policy:
Statement:
- Effect: Allow
  Action: 
    - elasticloadbalancing:*
    - elasticloadbalancingv2:*
  Resource: *
If this fixes your problem, you know for sure it is a permission issue on elastic load balancing. Try to narrow it down by reducing permissions step by step. Hint: some loadbalancing permissions are NOT resource specific, for those you'll need the Resource: * to execute certain actions on it. From the AWS docs:
The Resource types column indicates whether each action supports resource-level permissions. If there is no value for this column, you must specify all resources ("*") in the Resource element of your policy statement. If the column includes a resource type, then you can specify an ARN of that type in a statement with that action.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With