AWS Pass traffic from NLB to an ALB?

2020-03-26 07:50发布

问题:

I am trying to pass incoming traffic from amazon's Network Load Balancer to Application Load Balancer, I am using NLB since it has an Elastic IP attachment and I want it to serve as a proxy for the ALB. is that even possible?

回答1:

It is possible, but it's slightly messy.

The problem is that Application Load Balancers can scale up, out, in, and/or down, and in each case the internal IP addresses of the balancers can change... but NLB requires static addresses for its targets.

So, at a low level, this means the NLB target group must be modified every time the IPs of the ALB change.

AWS has published an official solution for accomplishing this, using a Lambda function on a schedule to capture the addresses of the ALB and update the NLB configuration whenever the results change.

https://aws.amazon.com/blogs/networking-and-content-delivery/using-static-ip-addresses-for-application-load-balancers/

One notable limitation, here, is that this solution does not allow you to identify the client IP address. It is lost when the traffic goes through the NLB, because NLBs only preserve the source IP when the target is an instance (not an IP address) or when the target understands the Proxy protocol on the client side and the feature is enabled on the NLB, but ALB doesn't support such a configuration. With the setup shown at the link, above, the rightmost address in X-Forwarded-For will be set by the ALB to the internal address of the NLB.



回答2:

This is correct. Your app server behind the ALB (or the ALB itself) will always see the source IP as that of the NLB.

As a workaround that works for some use cases you can enforce HTTPS and configure access logs on the NLB. Then the access logs will have the original source IP.

In case this was not clear, what I mean is:

  • make sure to enable access logs on your NLB
  • make sure to configure your NLB listener to use TLS

There are some additional complications if you want to accept plain HTTP and issue redirects to HTTPS. In that case you would have 2 listeners and 2 target groups, so you need to either spin up 2 copies of the Lambda to monitor (and eventually update) both target groups or you need to modify the Lambda code (which is what I did).

In addition IMO the code in that example is far from production ready (especially for scale - if you have many instances of this setup), so I had to practically rewrite it.

Relevant excerpts from CloudFormation template are below:

  NLB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      IpAddressType: ipv4
      Scheme: internet-facing
      Type: network
      LoadBalancerAttributes:
        - Key: load_balancing.cross_zone.enabled
          Value: 'true'
        - Key: access_logs.s3.enabled
          Value: 'true'
        # make sure the bucket policy grants access -  https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-access-logs.html
        - Key: access_logs.s3.bucket
          Value: !Ref S3BucketForNLBAccessLogs
        - Key: access_logs.s3.prefix
          Value: !Sub 'raw/${AppInstance}'

  nlbHTTPSListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      Certificates:
        - CertificateArn: !Ref FrontEndSSLCertificateArn
      LoadBalancerArn: !Ref NLB
      Port: 443
      Protocol: TLS
      DefaultActions:
        - Type: 'forward'
          TargetGroupArn: !Ref nlbHTTPSTargetGroup