Aws-cdk: [aws-elasticloadbalancingv2] Defining ApplicationListener without referencing a defaultTargetGroup throws error

Created on 16 May 2019  路  4Comments  路  Source: aws/aws-cdk

Describe the bug
I want to create an ApplicationListener without setting a default group:

const listener = myElb.addListener('httpToHttpsRedirectionListener', {
    port: 80,
    protocol: elb.ApplicationProtocol.Http,
    // defaultTargetGroups: don't want one because this is just a redirection listener
});

new elb.CfnListenerRule(this, "httpToHttpsRedirectionListenerRule", {
    listenerArn: listener.listenerArn,
    priority: 1,
    conditions: [],  // might be another bug because we have no conditions - API says: "Each rule can include zero or one of the following conditions" -> see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html#rule-condition-types
    actions: [
        {
            type: "redirect", redirectConfig: {
                protocol: "HTTPS",
                port: "443",
                host: "#{host}",
                path: "/#{path}",
                query: "#{query}",
                statusCode: "HTTP_301"
            }
        }
    ]
});

This is giving me the following error:

Listener needs at least one default target group (call addTargetGroups)

To Reproduce
See code above

Expected behavior
Creation of an ApplicationListener with no defaultTargetGroup and a redirect config rule without condition renders a CF template.

Version:

  • OS: MacOS
  • Programming Language: TS
  • CDK Version: 0.31.0
@aws-cdaws-elasticloadbalancing bug p2

Most helpful comment

Thanks. I did something just a little differently that works for me. I added a "dummy" default action to the L2 Construct, then dug into the L1 CfnListener to overwrite defaultActions with a custom redirect rule:

const httpListener = loadBalancer.addListener("HttpListener", {
  protocol: elbv2.ApplicationProtocol.HTTP
});
httpListener.addFixedResponse("DummyResponse", {
  statusCode: "404"
});

const cfnHttpListener = httpListener.node.defaultChild as elbv2.CfnListener;
cfnHttpListener.defaultActions = [{
  type: "redirect",
  redirectConfig: {
    protocol: "HTTPS",
    host: "#{host}",
    path: "/#{path}",
    query: "#{query}",
    port: "443",
    statusCode: "HTTP_301"
  }
}];

That renders to CloudFormation like:

"LBHttpListenerA225B711": {
  "Type": "AWS::ElasticLoadBalancingV2::Listener",
  "Properties": {
    "DefaultActions": [
      {
        "RedirectConfig": {
          "Host": "#{host}",
          "Path": "/#{path}",
          "Port": "443",
          "Protocol": "HTTPS",
          "Query": "#{query}",
          "StatusCode": "HTTP_301"
        },
        "Type": "redirect"
      }
    ],
    "LoadBalancerArn": {
      "Ref": "LB8A12904C"
    },
    "Port": 80,
    "Protocol": "HTTP",
    "Certificates": []
  },
  "Metadata": {
    "aws:cdk:path": ".../LB/HttpListener/Resource"
  }
}

All 4 comments

I think you will want to use CloudFormation overrides to work around this one, or implement a redirect target.

I think the proper solution would be to implement the redirect rule directly within CDK. I'm interested in doing this as well. @mhuebner , did you find a viable workaround in the meantime?

My current implementation is:

        const listener = loadBalancer.addListener(Utils.createId('HttpListener', tenantId, app, env), {
            port: 80,
            protocol: elb.ApplicationProtocol.HTTP,
            defaultTargetGroups: [targetGroup],
        });

        new elb.CfnListenerRule(this, Utils.createId('HttpListenerRule', tenantId, app, env), {
            listenerArn: listener.listenerArn,
            priority: 1,
            conditions: [
                {
                    field: 'path-pattern',
                    values: ['*']
                }
            ],
            actions: [
                {
                    type: "redirect", redirectConfig: {
                        protocol: "HTTPS",
                        port: "443",
                        host: "#{host}",
                        path: "/#{path}",
                        query: "#{query}",
                        statusCode: "HTTP_301"
                    }
                }
            ]
        });

Thanks. I did something just a little differently that works for me. I added a "dummy" default action to the L2 Construct, then dug into the L1 CfnListener to overwrite defaultActions with a custom redirect rule:

const httpListener = loadBalancer.addListener("HttpListener", {
  protocol: elbv2.ApplicationProtocol.HTTP
});
httpListener.addFixedResponse("DummyResponse", {
  statusCode: "404"
});

const cfnHttpListener = httpListener.node.defaultChild as elbv2.CfnListener;
cfnHttpListener.defaultActions = [{
  type: "redirect",
  redirectConfig: {
    protocol: "HTTPS",
    host: "#{host}",
    path: "/#{path}",
    query: "#{query}",
    port: "443",
    statusCode: "HTTP_301"
  }
}];

That renders to CloudFormation like:

"LBHttpListenerA225B711": {
  "Type": "AWS::ElasticLoadBalancingV2::Listener",
  "Properties": {
    "DefaultActions": [
      {
        "RedirectConfig": {
          "Host": "#{host}",
          "Path": "/#{path}",
          "Port": "443",
          "Protocol": "HTTPS",
          "Query": "#{query}",
          "StatusCode": "HTTP_301"
        },
        "Type": "redirect"
      }
    ],
    "LoadBalancerArn": {
      "Ref": "LB8A12904C"
    },
    "Port": 80,
    "Protocol": "HTTP",
    "Certificates": []
  },
  "Metadata": {
    "aws:cdk:path": ".../LB/HttpListener/Resource"
  }
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

abelmokadem picture abelmokadem  路  3Comments

nzspambot picture nzspambot  路  3Comments

peterdeme picture peterdeme  路  3Comments

PaulMaddox picture PaulMaddox  路  3Comments

eladb picture eladb  路  3Comments