AWS elbv2支持websocket获取用户真实IP和禁止国家地区访问

一. 问题和需求

需求分析

1. 使用ELB要支持http,https访问,同时要支持websocket , 这个需求好办,直接开通http/https模式ELB用于支持普通http协议访问,开通TCP模式ELB用于支持websocket。

2. 通过ELB的访问要禁止部分国家访问, 这个需求如果使用http/https 的ELB,很好实现,直接创建web acl并应用上ELB即可,但由于有websocket需求,这部分访问就不能走http/https模式的ELB,需要走TCP模式的ELB,而TCP模式的ELB是基于4层实现的,不能使用web acl策略,因此只能在nginx层面使用geoip模块做限制 ,但nginx层面要求能获取用户真实IP,TCP模式的ELB给出的IP $remote_addr 为ELB本身的IP,而 $http_x_forwarded_for是空的,完全不符合要求,这就是本次操作的难点。

为了让ELB支持给出用户真实IP,我搜遍了全网,都只找到如下教程,但这些教程都是elb老版本的,而且操作难度高,而目前AWS上的elb都已经升到了v2版本,原来的老版本已经不支持了,目前最新的elbv2无法使用下面这些方法来实现效果:

http://www.ttlsa.com/nginx/aws-elb-nginx-enable-proxy-protocol/

https://www.jb51.net/article/76750.htm

https://blog.csdn.net/fgf00/article/details/80164200

经过两天的研究和搜索,终于找到了如下方法,大体思路如下:

1. nginx启用http_realip_module 模块,用于支持 real_ip_header     proxy_protocol  和 set_real_ip_from

2. 由于要支持websocket, 创建TCP模式的elb  ,也就是 network Load Balancer, 此ELB不支持web acl,无法从ELB层面限制源IP国家地区访问

3. 对于要支持http/https访问的,创建http/https模式的elb ,也就是 application Load Balancer,此ELB可直接使用web acl 限制国家访问,很好实现,如下图

二. 安装相关组件

cd /root

##先上传openresty-1.17.8.2.tar.gz 包到/root下

tar zxvf openresty-1.17.8.2.tar.gz

cd openresty-1.17.8.2

/usr/local/openresty/nginx/sbin/nginx -V

./configure --prefix=/usr/local/openresty --with-http_stub_status_module --with-http_geoip_module  --with-http_realip_module  # 注意要加上realip_module模块,用于获取ELB用户IP,geoip用于nginx层面限制国家地区访问

make

mv /usr/local/openresty/nginx/sbin/nginx /usr/local/openresty/nginx/sbin/nginx.old

cp -pf /root/openresty-1.17.8.2/build/nginx-1.17.8/objs/nginx /usr/local/openresty/nginx/sbin/

systemctl restart openresty  

/usr/local/openresty/nginx/sbin/nginx -V

 

三. 踩坑过程

1. 创建ELB

分别创建两个ELB,一个http模式,一个TCP模式,前者直接用上web acl,后者无法使用web acl,此时难题出现了,访问tcp模式的ELB, access日志里显示的IP不对

2. 使用网上教程过程中碰到的坑

网上说在awscli使用如下命令来启用相关代理协议,就可以获取到真实IP了,实际操作不可行,因为现在ELB默认已经升级到了elbv2, 原来的命令和方法全部作废, aws官方也没有详细说明

# aws elb create-load-balancer-policy --load-balancer-name YOU_ELB_NAME --policy-name EnableProxyProtocol --policy-type-name ProxyProtocolPolicyType --policy-attributes AttributeName=ProxyProtocol,AttributeValue=True

3. 解决方法

 (1) nginx上加配置

nginx.conf里http块加上如下内容,注意 set_real_ip_from一定要设置ELB所在的IP段,用于排除掉ELB的IP,取出用户真实IP

#此功能是设置拒绝CN(china)区访问,无此需求的不用加,geoip相关安装配置不在此展开
geoip_country /usr/share/GeoIP/GeoIP.dat;

    map $geoip_country_code $is_cn_country {
        default yes;
        CN no;
    }

# 开启websocket
map $http_upgrade $connection_upgrade {
             default upgrade;
            '' close;
         }

#启用proxy_protocol,用于读取ELB后端目标组的代理协议v2的头数据,抓取用户真实IP
set_real_ip_from   127.0.0.1;
set_real_ip_from   172.31.0.0/16;
# 表示把来在172.31.0.0/16 段(TCP负载均衡器的IP段)的所有请求的来源地址,都改成 $proxy_protocol_addr,并且记录在 $remote_addr 变量里。
real_ip_header     proxy_protocol;
real_ip_recursive  on;

在要用户websocket的网站conf文件里配置:

server {
    listen       80 proxy_protocol;   #注意这里一定要加上 proxy_protocol
    server_name  api-ws.domain.com;

    access_log logs/api-ws.domain.com-access.log access;
    error_log logs/api-ws.domain.com-error.log;

    location / {
            #限制CN区访问
            if ($is_cn_country = no) {
              return 403;
            }
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # 启用支持websocket连接
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_pass http://apiws7777/;
    }
}

(2)AWS后台的负载均衡配置里的目标群组里,启用代理协议v2, 注意,这一步最为关键!必须启用。

 

(3)重启nginx,开始测试,经测试,用户IP抓取到了,大功告成!

 

(4)测试不同国家访问,CN区访问返回403,符合预期,国外能正常打开,功能已实现。

四. 经验总结

1. 用百度搜索aws相关的问题资料特别少,可能是国人用AWS用得相对少一些,最近几年才开始用得多,问题总结用百度在网上很难搜到,很多问题只能自己摸索,或者搜索国外英文网站。

2. aws 的elb老版本现在已经没有了,现在都是elbv2, 相关技术文档没有跟上,只能借鉴前人的技术文档,不能直接套用。

3. 碰到问题一定要多动脑筋,多尝试。

4. 此问题是站在前人的肩膀上解决的,再次感谢如下链接的作者

http://www.ttlsa.com/nginx/aws-elb-nginx-enable-proxy-protocol/

https://www.jb51.net/article/76750.htm

https://blog.csdn.net/fgf00/article/details/80164200

5. 中间遇到的报错

" while reading PROXY protocol, client: 127.0.0.1, server: 0.0.0.0:80
2021/01/28 17:56:47 [error] 3206#0: *24714 broken header: "GET / HTTP/1.1^M
Host: 172.31.101.19
Connection: close
User-Agent: ELB-HealthChecker/2.0
Accept-Encoding: gzip, compressed

报错的原因是因为有部分网站server conf文件里的 linsten 80这里加上了 proxy_protocol, 一旦nginx下某一个网站启用proxy_protocol, 其他站点都会自动启用 proxy_protocol头,如果同一个nginx下其他网站不是TCP ELB模式代理进来,就会报错,导致其他网站都打不开,显示 502 Bad Gateway, 解决办法是其他网站也要使用TCP模式ELB,后端服务组开启代理模式v2, 此问题参考说明 https://trac.nginx.org/nginx/ticket/1048

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值