hopscotch
hopscotch

Reputation: 203

AWS ELB Listener creation fails with Validation exception

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.

Upvotes: 4

Views: 5862

Answers (3)

Robbert van den Bogerd
Robbert van den Bogerd

Reputation: 1034

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.

Upvotes: 1

Avery Pfeiffer
Avery Pfeiffer

Reputation: 61

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.

Upvotes: 6

Marcin
Marcin

Reputation: 238051

This happens probably because you are using application load balancer:

Type: application

However, you specify that your connection protocol is TCP. This is obviously incorrect, as ALB only supports HTTP and HTTPS protocols. For TCP you need network load balancer (NLB).

Upvotes: 0

Related Questions