Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(elasticloadbalancingv2): Update rules for alb listener to have two or more actions #12514

Closed
afsanehr opened this issue Jan 14, 2021 · 12 comments · Fixed by #19043
Closed

(elasticloadbalancingv2): Update rules for alb listener to have two or more actions #12514

afsanehr opened this issue Jan 14, 2021 · 12 comments · Fixed by #19043
Labels
@aws-cdk/aws-elasticloadbalancingv2 Related to Amazon Elastic Load Balancing V2 bug This issue is a bug. effort/small Small work item – less than a day of effort p1

Comments

@afsanehr
Copy link

afsanehr commented Jan 14, 2021

Hi,

We have an application load balancer that is targeting a lambda. We want to update its listener's rule to return fixed response 403 by default and forward actions to target group (of type lambda) if path is /test and method is post.
This is doable via management console.
With cdk and cloudformation template it throws error:
Protocol cannot be specified for target groups with target type 'lambda'

In management console we have this for listener:

Rule                condition                                              action
1                 IF: Http method is post                            THEN: Forward to target group
                      Path is /test
last              IF: Requests otherwise not routed                  THEN: Return fixed response 403

Reproduction Steps

    let target = new targets.LambdaTarget(this.lambda)
    let applicationLoadBalancerTargetGroup = new elb.ApplicationTargetGroup(this, 'GatewayTargetGroup', {
          port: 443,
          vpc: this.vpc,
          targets: [target]
     })
    let applicationLoadBalancerListener = this.applicationLoadBalancer.addListener('test', {
      port: 443,
      protocol: elb.Protocol.HTTPS,
      certificateArns: [this.cert], 
      defaultAction: elb.ListenerAction.fixedResponse(403, {
        contentType: elb.ContentType.APPLICATION_JSON,
        messageBody: 'Forbidden'
      })
    })
    let applicationLoadBalancerPathListenerRule = new elb.ApplicationListenerRule(this, 'PathListenerRule', {
      listener: applicationLoadBalancerListener,
      priority: 1,
      conditions:[
        elb.ListenerCondition.httpRequestMethods(['POST']),
        elb.ListenerCondition.pathPatterns(['/test'])
      ],
      action: elb.ListenerAction.forward([applicationLoadBalancerTargetGroup])
  })

What did you expect to happen?

To be able to update rules same as what is doable in management console

What actually happened?

cloudformation stack failed with: Protocol cannot be specified for target groups with target type 'lambda'

I understand according to this https://docs.aws.amazon.com/cdk/api/latest/docs/aws-elasticloadbalancingv2-readme.html#protocol-for-load-balancer-targets
seems like creating application target group is only limited to instance type or ip. If that is the case here, is there a workaround to be able to do this in cdk?

Environment

  • CDK CLI Version : 1.68.0
  • Node.js Version: v13.6.0
  • OS : macOS Mojave version 10.14.6
  • Language (Version): TypeScript

Other


This is 🐛 Bug Report

@afsanehr afsanehr added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Jan 14, 2021
@github-actions github-actions bot added the @aws-cdk/aws-elasticloadbalancingv2 Related to Amazon Elastic Load Balancing V2 label Jan 14, 2021
@amarflybot
Copy link

For me the error is different:
Message:
Invalid request provided: AWS::ElasticLoadBalancingV2::ListenerRule Validation exception new ApplicationListenerRule (~node_modules/@aws-cdk/aws-elasticloadbalancingv2/lib/alb/application-listener-rule.ts:231:22)

@NGL321 NGL321 self-assigned this Jan 14, 2021
@NGL321
Copy link
Contributor

NGL321 commented Jan 15, 2021

Hey @afsanehr,

Thanks for reporting this. Your error message and the way you structured makes me think this is one of two possible problems.

The first possibility I see is that you are passing the lambda function incorrectly to target:

let target = new targets.LambdaTarget(FUNCTION_GOES_HERE);

The error message Protocol cannot be specified for target groups with target type 'lambda' makes me think that you are passing a Lambda class object rather than a Function object. It would help to see where you declare your function this.lambda.

I attempted to reproduce, and I was unable to see your described behavior. What I did see is that in your code elb.Protocol.HTTPS should likely be elb.ApplicationProtocol.HTTPS, and assuming that certificateArns: [this.cert], references the cert and not the ARN, it should be certificates: [this.cert].

The other possibility is that there is a bug in our ELBv2 library.

To better understand this it would be helpful to know what line specifically is throwing your exception as well as seeing the variables referenced but not shown (this.cert, this.applicationLoadBalancer, this.lambda).

😸 😷

@NGL321 NGL321 added response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. and removed needs-triage This issue or PR still needs to be triaged. labels Jan 15, 2021
@afsanehr
Copy link
Author

afsanehr commented Jan 15, 2021

Hi @NGL321, thanks for the quick turnaround :)

I am passing the following to the lambdaTargets

this.lambda = new lambda.Function(this, 'lambda', {
      runtime: lambda.Runtime.PYTHON_2_7,
      code: lambda.Code.fromBucket(s3Bucket, this.artifactoryKey),
      handler: 'testLambda.lambda_handler',
      timeout: cdk.Duration.seconds(300)
    })

I also updated the elb.Protocol.HTTPS to elb.ApplicationProtocol.HTTPS same result
One more thing is that since I have the certificateArn I am using the certificateArns rather than certificates, I assume that should be doable?
so this.cert actually holds the certficiateArn value and is coming from a customresource lambda creating the arns, we are passing this in other projects using that Arn value and it works fine.
may be I should rewrite the snippet such as this that:

     this.lambda = new lambda.Function(this, 'lambda', {
      runtime: lambda.Runtime.PYTHON_2_7,
      code: lambda.Code.fromBucket(s3Bucket, this.artifactoryKey),
      handler: 'testLambda.lambda_handler',
      timeout: cdk.Duration.seconds(300)
    })
    let target = new targets.LambdaTarget(this.lambda)
    let applicationLoadBalancerTargetGroup = new elb.ApplicationTargetGroup(this, 'GatewayTargetGroup', {
          port: 443,
          vpc: this.vpc,
          targets: [target]
     })
    this.applicationLoadBalancer = new elb.ApplicationLoadBalancer(this, 'GatewayALB', {
      vpc: this.vpc,
      internetFacing: false,
      vpcSubnets: this.vpc.isolatedSubnets,
      securityGroup: this.securityGroup
    })
    let applicationLoadBalancerListener = this.applicationLoadBalancer.addListener('test', {
      port: 443,
      protocol: elb.ApplicationProtocol.HTTPS,
      certificateArns: [this.certArn], 
      defaultAction: elb.ListenerAction.fixedResponse(403, {
        contentType: elb.ContentType.APPLICATION_JSON,
        messageBody: 'Forbidden'
      })
    })
    let applicationLoadBalancerPathListenerRule = new elb.ApplicationListenerRule(this, 'PathListenerRule', {
      listener: applicationLoadBalancerListener,
      priority: 1,
      conditions:[
        elb.ListenerCondition.httpRequestMethods(['POST']),
        elb.ListenerCondition.pathPatterns(['/test'])
      ],
      action: elb.ListenerAction.forward([applicationLoadBalancerTargetGroup])
  })

Another note is that the stack with the generated cloud formation template fails at GatewayTargetGroup creation with the error mentioned. When you say you couldn't replicate the issue, did the stack generation pass for you? I tried commenting everything after the ApplicationTargetGroup and the stack still fails.
Thank you again.

@NGL321 NGL321 added investigating This issue is being investigated and/or work is in progress to resolve the issue. and removed response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. labels Jan 16, 2021
@afsanehr
Copy link
Author

Hi @NGL321 was wondering if there is any update on this issue? Thanks!

@NGL321
Copy link
Contributor

NGL321 commented Feb 16, 2021

Hey @afsanehr,

Sorry for the delay. I have, as of yet, still been unable to reproduce your described behavior, despite using an identical stack. Unsure of what is causing this. I have one more thing to try, and will report if that fails to reproduce the failure.

From what I can tell at the moment, this is not an issue with generating the template as cdk synth works 100% of the time with code provided. There is a chance this is a cloudformation bug with the elb handling.

@NGL321
Copy link
Contributor

NGL321 commented Feb 19, 2021

Okay, I was finally able to reproduce.

My initial assessment was very wrong 🤦. The problem here is that the prop protocol in ApplicationListener cannot presently be specified for Lambda function targets. The exception is being generated by the Elastic Load Balancer API rather than the CDK.

The biggest problem here is that the parameter is forced into the template. If left blank, it is automatically assigned based on port:

const [protocol, port] = determineProtocolAndPort(props.protocol, props.port);

if (protocol === undefined) { protocol = defaultProtocolForPort(port!); }

There are two possibilities here: either it is intended behavior of ELBv2 and we need to stop forcing protocol, OR it is a bug in the API.

I have cut an internal ticket to the team to determine this. Unfortunately I am not aware of a workaround atm, but I will update this ticket as soon as I hear from the team.

😸 😷

@NGL321 NGL321 added effort/small Small work item – less than a day of effort p1 labels Feb 19, 2021
@afsanehr
Copy link
Author

Thanks for the update @NGL321, appreciate it 😄

@NGL321 NGL321 removed the investigating This issue is being investigated and/or work is in progress to resolve the issue. label Feb 20, 2021
@NGL321
Copy link
Contributor

NGL321 commented Feb 20, 2021

@afsanehr
Looks like this is the intended behavior of ELB. Feel free to put in a PR if you would like to resolve this yourself, otherwise someone from the team will take a look when the opportunity arises.

@lodi-g
Copy link

lodi-g commented Mar 10, 2021

Hi @NGL321, is there a possible workaround (in CDK) for this issue?
If not, what would you expect from a PR?

My problem is in a NetworkTargetGroup:


Protocol is either specified or default to TCP.

Edit: a workaround is using

        cfn_target_group = target_group.node.default_child
        cfn_target_group.add_property_deletion_override("Protocol")
        cfn_target_group.add_property_deletion_override("Port")

@corymhall
Copy link
Contributor

@afsanehr this should work as long as you don't provide port when creating your target group. I have a PR open to add some validation around this behavior.

let applicationLoadBalancerTargetGroup = new elb.ApplicationTargetGroup(this, 'GatewayTargetGroup', {
          vpc: this.vpc,
          targets: [target]
     })

@mergify mergify bot closed this as completed in #19043 Feb 21, 2022
mergify bot pushed a commit that referenced this issue Feb 21, 2022
…for lambda targets (#19043)

When creating a target group with the targetType = `LAMBDA` you should
not provide the port or protocol. If protocol is provided then
CloudFormation will throw an error message. If you provide the port to
CDK, CDK will figure out and provide the protocol as well.

This PR adds validation and throws an error if either port or protocol
is provided when the target type is Lambda.

fixes #12514


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

TikiTDO pushed a commit to TikiTDO/aws-cdk that referenced this issue Feb 21, 2022
…for lambda targets (aws#19043)

When creating a target group with the targetType = `LAMBDA` you should
not provide the port or protocol. If protocol is provided then
CloudFormation will throw an error message. If you provide the port to
CDK, CDK will figure out and provide the protocol as well.

This PR adds validation and throws an error if either port or protocol
is provided when the target type is Lambda.

fixes aws#12514


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
@yokharian
Copy link

Hi @NGL321, is there a possible workaround (in CDK) for this issue? If not, what would you expect from a PR?

My problem is in a NetworkTargetGroup:

Protocol is either specified or default to TCP.

Edit: a workaround is using

        cfn_target_group = target_group.node.default_child
        cfn_target_group.add_property_deletion_override("Protocol")
        cfn_target_group.add_property_deletion_override("Port")

hello

you must define somewhere both protocol and port when using non-lambda targets or you'll get this error

A protocol must be specified (Service: AmazonElasticLoadBalancing; Status Code: 400; Error Code: ValidationError; Request ID: ... ; Proxy: null)
and
A port must be specified (Service: AmazonElasticLoadBalancing; Status Code: 400; Error Code: ValidationError; Request ID: ...; Proxy: null)

in my case i am using alb, more info on docs

they tell you that:

port: The port on which the listener listens for requests. Default: - Determined from protocol if known, optional for Lambda targets.

protocol: The protocol to use. Default: - Determined from port if known, optional for Lambda targets.


if someone got this error with ALB

Resource handler returned message: "Invalid request provided: AWS::ElasticLoadBalancingV2::ListenerRule Validation exception" (RequestToken: ... HandlerErrorCode: InvalidRequest)

Got this error with alb listeners "80" & "443" forwarding to "ecs service" inside of an Application Target Group, then if you add redirects from 80 to 443 fine, but for elb redirect from www to non-www in 443 listener, got that error.

a simple workaround is to double check the elbv2.ListenerAction.redirect parameters, try first using only host redirect then add 1 by 1 until you validate it.

SNIPPET

main_listener.add_action(  # REDIRECT EVERYTHING WWW. TO NON-WWW
            "redirectWwwToNonWwwAction",
            conditions=[
                elbv2.ListenerCondition.host_headers(
                    values=[f"www.{airflows_host}"]
                )
            ],
            action=elbv2.ListenerAction.redirect(host=airflows_host),
            priority=1,
        )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-elasticloadbalancingv2 Related to Amazon Elastic Load Balancing V2 bug This issue is a bug. effort/small Small work item – less than a day of effort p1
Projects
None yet
7 participants