AWS CLB / ELB + HTTP / 2支持

时间:2017-03-20 12:30:15

标签: amazon-web-services amazon-ec2 amazon-elb http2

目标是在简单堆栈中包含HTTP / 2支持:部署在多个EC2实例中的Web应用程序+启用了PROXY协议策略的传输级CLB( SSL:443 ➝TCP:80 )以卸载SSL / TLS并平衡传入的HTTPS流量。

PROXY协议的几个原因 :( 1)执行地理定位逻辑; (2)执行简单的访问控制规则; (3)伐木。所有这些功能都需要访问可靠的(即非简单的可伪造的)客户端IP地址。 AWS中PROXY协议的唯一替代方法是切换到应用程序级平衡,并使用XFF标头提取客户端的远程IP地址。然而,这是不可接受的:任何人都可以简单地改变其IP地址,只需在传入的HTTPS请求中注入假的XFF头。 AFAIK,AWS CLB / ELB不会注入包含客户端远程IP的标头(例如the True-Client-IP header in Akamai)。

因此,如何在堆栈中添加H2支持?经过一些研究后,所有可能的选项看起来都不尽如人意:

  • 当前架构无效,因为SSL / TLS在CLB中终止,但CLB不向announce H2 support through ALPN提供任何选项。

  • 使用CLB的另一种方法是停止使用SSL / TLS卸载功能并将其移至EC2实例(即 TCP:443➝TCP:443 )。这样就可以在SSL / TLS握手期间宣布H2支持,但是此选项需要升级EC2实例以支持额外的SSL / TSL工作负载。类似的替代方案:

    • TCP:443➝SSL:443 :类似于TCP:443➝TCP:443但允许使用可靠的公钥证书列表进行后端身份验证。
    • SSL:443➝SSL:443 :类似于TCP的端到端加密:443➝SSL:443。不是一个选项:(1)PROXY协议是not supported for this combination(并且使用XFF也不是一个选项,因为这是传输级平衡); (2)客户端SSL / TLS握手在CLB中执行,因此H2不会被公布。
  • 其他选项是用ELB替换CLB(HTTPS➝HTTP)。 ELB支持H2。然而(1)我们需要依靠XFF来提取客户端IP地址(已经解释了为什么这是一个问题); (2)ELB和EC2实例之间的流量为H1(我们希望让未加密的H2流量到达EC2实例)。换句话说,这不是一种选择。

总而言之,所有选项都存在问题。恕我直言,理想的解决方案是保留原始CLB(SSL:443➝TCP:80;平衡+ SSL / TLS卸载+ PROXY协议),并允许CLB中的策略通过ALPN宣布H2支持。但是我担心这在AWS中是不可能的。 CLB TCP的任何替代方案:443➝TCP:443方法?

1 个答案:

答案 0 :(得分:2)

这个答案没有提供出色的解决方案,因为可能没有,但我相信您对AWS Application Load Balancer(ALB,也称为ELB / 2.0)的理解存在差距。

  

任何人都可以简单地更改其IP地址,只需在传入的HTTPS请求中注入假的XFF标头。 AFAIK,AWS CLB / ELB不会注入包含客户端远程IP的标头

这两种情况都不正确。

客户端的远程IP是X-Forwarded-For中最右边的IP地址,由平衡器发送给实例。这不能欺骗。如果客户端在XFF中包含一个或多个地址,则根据处理HTTP标头的规则(从左到右,从头到尾),它们由平衡器标准化为单个标头,并且它们显示在实际的左侧客户IP。

示例请求:我在请求中注入了两个欺骗性X-Forwarded-For标头,一个包含2个值,一个包含1个...这里是curl发送的内容:

$ curl -v http://cx-xxxxxxxx-xxxx-xxxxxxxxxx.us-east-1.elb.amazonaws.com/test/dump/headers \
       -H 'X-Forwarded-For: 192.168.254.252, 10.10.10.10' \
       -H 'X-Forwarded-For: 172.16.16.16'
* Hostname was NOT found in DNS cache
*   Trying 52.x.x.x...
* Connected to cx-xxxxxxxx-xxxx-xxxxxxxxxx.us-east-1.elb.amazonaws.com (52.x.x.x) port 80 (#0)
> GET /test/dump/headers HTTP/1.1
> User-Agent: curl/7.35.0
> Host: cx-xxxxxxxx-xxxx-xxxxxxxxxx.us-east-1.elb.amazonaws.com
> Accept: */*
> X-Forwarded-For: 192.168.254.252, 10.10.10.10
> X-Forwarded-For: 172.16.16.16
>
< HTTP/1.1 200 OK

但这是我的实例所看到的:

GET /test/dump/headers HTTP/1.1
X-Forwarded-For: 192.168.254.252, 10.10.10.10, 172.16.16.16, 203.0.113.1
X-Forwarded-Proto: http
X-Forwarded-Port: 80
Host: cx-xxxxxxxx-xxxx-xxxxxxxxxx.us-east-1.elb.amazonaws.com
X-Amzn-Trace-Id: Root=1-58d0704b-557517de784f5exxxxxxxxxx
User-Agent: curl/7.35.0
Accept: */*

我发送的标题已经由平衡器标准化,平衡器添加了X-Forwarded-For中最右边的值 - 它是我正在运行curl的机器的IP地址,建立了传入连接.¹

这就是它如何与ALB一起使用。如果客户端提供了任何XFF,那么这些XFF当然是不可信的(尽管您仍然应该记录或保存它们,因为如果客户端使用的代理正确识别了客户端,它们可能很有用),但是最后一个在右侧始终是外部机器的地址,从外部建立与ALB的连接。

这是你总是解释X-Forwarded-For:的方式 - 从标题的底部,向上,然后从右到左,因为这是任何正确行为的代理(在这种情况下,ALB是这样)的方式处理它们 - 通过将其客户端的IP地址(从其网络堆栈报告)附加到右侧(或通过在任何其他之后添加额外的X-Forwarded-For标头 - 任一方式在语义上有效,但ALB不使用后一种方法)。在解析时,当您遇到不属于您自己的第一个地址时,您就会停止 - 这是您可以信任的唯一地址。

此外,如果客户端在使用http进行连接时注入X-Forwarded-Proto: https - 尝试欺骗与平衡器建立安全连接,而实际上并不是这样做 - ALB会丢弃它。该实例只看到了真相:X-Forwarded-Proto: http

此外,您可能会忽略这样一个事实,即在使用HTTP / 1.1连接到实例时,平衡器会执行其他非常有用的操作:

  

您可以将HTTP / 2与HTTPS侦听器一起使用。您可以使用一个HTTP / 2连接并行发送多达128个请求。负载均衡器将这些请求转换为单独的HTTP / 1.1请求,并使用循环路由算法将它们分布到目标组中的健康目标上。

     

http://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html

据我估计,该功能将负载均衡的概念提升到一个全新的水平。

¹我正在运行curl的机器的IP地址。精明的观察者会注意到这实际上是来自RFC-5737的IP地址,但它被报告给实例作为我家里的IP地址。除了用于清理目的之外,我没有以其他方式更改实例看到的请求标头。否则,这里精确保留原始顺序和内容。