一,需求来源
1,因历史原因需要在同一个端口实现http和https的同时支持
2,因安全需求需要对部分接口URL添加白名单IP限制,需要将真实客户端IP转发到后端服务上
二,实现原由
1,同一端口实现兼容http和https主要使用的是nginx的stream->map $ssl_preread_protocol->server转发。
2,IP透传主要使用的是proxy_bind $remote_addr transparent;和iptables+ip route规则实现。
三,实现过程
1,后端真实服务监听端口在: 192.168.0.101:9000
2,前端NGINX代理运行在: 192.168.0.100:9000
3,在NGINX服务上建两个分别为HTTP和HTTPS协议的服务使用不同的端口指向后端服务
server {
listen 20036; # http
listen 20037 ssl; # https
ssl_certificate /etc/nginx/cert.pem; #证书。
ssl_certificate_key /etc/nginx/cert.key; #证书。
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #使用此加密套件。
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #使用该协议进行配置。
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_body_buffer_size 100M;
client_max_body_size 100M;
proxy_buffer_size 512k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 1m;
proxy_connect_timeout 300;
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding off;
proxy_pass http://192.168.0.101:9000;
}
}
4,在NGINX服务上建立stream通过ssl_preread_protocol自适应客户端请求类型进行转发。此时用http和https均能正常访问到后端服务。但是在后端服务的访问日志中可以看到所有的来源IP地址都是192.168.0.100。
stream {
upstream http_gateway {
server 127.0.0.1:20036;
}
upstream https_gateway {
server 127.0.0.1:20037;
}
map $ssl_preread_protocol $upstream{
default http_gateway;
"TLSv1.0" https_gateway;
"TLSv1.1" https_gateway;
"TLSv1.2" https_gateway;
"TLSv1.3" https_gateway;
}
server {
listen 9000;
ssl_preread on;
#proxy_bind $remote_addr transparent; #这行先注释
proxy_pass $upstream;
}
}
5,使用以下方法将客户端地址和连接透传到后端服务上。
在NGINX服务器上stream的server中配置启用以下:
proxy_bind $remote_addr transparent;
该行启用后客户端访问NGINX时会卡在连接状态无法连接成功,需要进后行续处理。
6,NGINX服务器上添加iptables规则和ip route路由
#1,添加路由到lo口,100
ip route add local 0.0.0.0/0 dev lo table 100
#2,mark标记为1的使用100路由规则
ip rule add fwmark 1 lookup 100
7,后端服务器上添加规则
#1,允许流量
iptables -I INPUT -i bond0 -j ACCEPT
#2,禁用101主机上的reverse path filter,避免无法回复非本地网段数据包
echo "net.ipv4.conf.all.rp_filter = 0" >> /etc/sysctl.conf
echo "net.ipv4.conf.bond0.rp_filter = 0" >> /etc/sysctl.conf
#3,对源地址和端口为本机服务的打mark为1
iptables -t mangle -A OUTPUT -p tcp --src 192.168.0.101 --sport 9000 -j MARK --set-xmark 0x1/0xffffffff
#4,添加路由到前端代理服务器,100
ip route add default via 192.168.0.100 table 100
#5,mark匹配的使用该100路由转发回前端代理主机
ip rule add fwmark 1 lookup 100
8,重启nginx(reload不生效)观察访问日志结果。
多次测试后成功。
四,参考资源和原理说明:
nginx的tcp透明代理设置 - 简书
IP Transparency and Direct Server Return with NGINX Plus
记玄妙莫测的透明代理_tproxy-CSDN博客
好文链接
发表评论