AWS Classic Load Balancer配置Proxy Protocol
阿里云SLB不支持在TCP上挂SSL证书,拿HAProxy作为服务前置挂载证书会吃掉2个TCP连接数,单机只能撑近32K(65K的一半)的外部连接数。可以通过一些方法(比如增加Virtual Network Interface)突破这个限制,但服务因需挂SSL证书而额外绑定HAProxy,增加了一层中间件,架构图画出来后总觉得不好看。周一跑去服务器上动手脚,挂好SSL证书,可以拿掉HAProxy,连接数也突破了这个限制。
检查连接的时候发现服务能认TCP Source IP,阿里云SLB默认就开了Proxy Protocol,挺厉害的,不需要Client那边额外设置就能拿到Source IP。于是去AWS控制台找了一圈ELB的选项,没有开启Proxy Protocol的设置,倒是文档上写了可以通过awscli
开启,折腾了一下把这个配置打开了,这里记录一下。
Proxy Protocol是什么
Proxy Protocol是HAProxy的作者Willy Tarreau在2010年实现的一个Internet协议,在三次握手之后,由Proxy往TCP上插一个很小的数据包来传递客户端信息,如源IP、目标IP等,在负载均衡和后端服务通信或更复杂的网络环境时非常有用,有点类似HTTP请求上的X-Forwarded-For头。
Proxy Protocol有两个版本,V1和V2。
Human-readable header format (version 1)
V1很简单,1行US-ASCII文本表示,严格遵循下面格式:
PROXY INET_PROTOCOL CLIENT_IP PROXY_IP CLIENT_PORT PROXY_PORT\r\n
假如无法识别PROXY,格式则为:
PROXY UNKNOWN\r\n
IPv4示例:
PROXY TCP4 198.51.100.22 203.0.113.7 35646 80\r\n
IPv6示例:
PROXY TCP6 2001:DB8::21f:5bff:febf:ce22:8a2e 2001:DB8::12f:8baa:eafc:ce29:6b2e 35646 80\r\n
Binary header format (version 2)
V1格式便于人类可读,但解析V1比较麻烦,长度不定,需要找到尾部的CRLF(即\r\n)才停止,遇到UNKNOWN处理起来也比较麻烦,V2使用了新的二进制格式,为了处理效率定制了一套新协议,该协议为:
0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A <13th byte> <14th byte> <15-16th byte> <17th byte onwards>
0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A
——协议签名13th byte
——协议版本(v2)与指令(LOCAL or PROXY)14th byte
——地址族(0 - AF_UNSPEC, 1 - AF_INET, 2 - AF_INET6, 3 - AF_UNIX)和协议族(0 - UNSPEC, 1 - STREAM, 2 - DGRAM)15-16th byte
——网络顺序的地址长度17th byte onwards
——网络顺序的地址信息:源IP,目标IP,源Port,目标Port
AWS ELB开启Proxy Protocol
AWS ELB使用的是V1。
前置
AWS ELB开启Proxy Protocol的选项并没有配置在控制台里,只能通过awscli
启用,所以需要安装awscli并且通过aws configure
配置好access key、access secret和region,切区时需要用aws configure
来切。
此外还需要检查当前区域ELB是否支持Proxy Protocol Policy,通过aws elb describe-load-balancers
命令,在输出中找到这段则表明可以开启:
{
"PolicyTypeDescriptions": [
...
{
"PolicyAttributeTypeDescriptions": [
{
"Cardinality": "ONE",
"AttributeName": "ProxyProtocol",
"AttributeType": "Boolean"
}
],
"PolicyTypeName": "ProxyProtocolPolicyType",
"Description": "Policy that controls whether to include the IP address and port of the originating
request for TCP messages. This policy operates on TCP/SSL listeners only"
},
...
]
}
创建Policy
满足前置条件的话,键入命令创建ELB Policy:
aws elb create-load-balancer-policy --load-balancer-name my-loadbalancer --policy-name my-ProxyProtocol-policy --policy-type-name ProxyProtocolPolicyType --policy-attributes AttributeName=ProxyProtocol,AttributeValue=true
需要注意的是,里面my-loadbalancer
与my-ProxyProtocol-policy
应修改为能更好分辨与记住的名字。
应用Policy
若之前ELB后端服务器已经应用Policy,需要找到之前的Policy,将Proxy Protocol追加到旧有的Policy里;若没有,则需要新增Policy。两个命令是不一样的。
通过命令aws elb describe-load-balancers --load-balancer-name my-loadbalancer
找到BackendServerDescriptions
,如显示如下:
{
"LoadBalancerDescriptions": [
...
{
"LoadBalancerName": "mqtt-slb",
...
"BackendServerDescriptions": [],
...
}
...
}
表明没有任何Policy应用在该ELB的后端服务器上,此时命令为:
aws elb set-load-balancer-policies-for-backend-server --load-balancer-name my-loadbalancer --instance-port 80 --policy-names my-ProxyProtocol-policy
其中80为后端服务器使用的端口。
如显示如下:
{
"LoadBalancerDescriptions": [
...
{
"LoadBalancerName": "mqtt-slb",
...
"BackendServerDescriptions": [
{
"InstancePort": 80,
"PolicyNames": [
"my-existing-policy"
]
}
],
...
}
...
}
则表明已经有名为my-existing-policy
在发挥作用,此时命令为:
aws elb set-load-balancer-policies-for-backend-server --load-balancer-name my-loadbalancer --instance-port 80 --policy-names my-ProxyProtocol-policy my-existing-policy
如果有多项Policy,那么请在--policy-names
后面依次追加。
移除Policy
当然有可能往后不需要这个Policy,那么可以通过如下命令重新设置Policy:
aws elb set-load-balancer-policies-for-backend-server --load-balancer-name my-loadbalancer --instance-port 80 --policy-names my-existing-policy
该命令仅保留my-existing-policy
。
如需完全移除所有Policy,那么命令为:
aws elb set-load-balancer-policies-for-backend-server --load-balancer-name my-loadbalancer --instance-port 80 --policy-names "[]"
此时如果通过命令aws elb describe-load-balancers --load-balancer-name my-loadbalancer
检查状态,则BackendServerDescriptions
应该显示为空数组:
{
"LoadBalancerDescriptions": [
...
{
"LoadBalancerName": "mqtt-slb",
...
"BackendServerDescriptions": [],
...
}
...
}
结语
之前需要在HAProxy里面开启proxy-pass的配置,现在通过awscli
可以帮忙打开,只是同样都属于Load Balancer的设置,只有这个选项不可以通过AWS Management Console改变,不知道是为啥。