Nginx Ingress怎么配置客户端IP地址限制?服务器和客户端地址一般怎么设置?

Nginx Ingress 的客户端 IP 限制必须基于对 X-Forwarded-For 头部的可信解析与显式配置,先获取真实 IP 再执行规则,否则一切限制都可被伪造请求头绕过;而获取真实 IP 的关键在于正确设定转发代理的信任边界。

为什么你的 IP 白名单形同虚设

很多团队在配置 Nginx Ingress 的 IP 访问控制时,习惯性地在 Ingress 规则里直接写 nginx.ingress.kubernetes.io/whitelist-source-range,然后测试一下发现能限制,就以为万事大吉。

但这里藏着一个巨大的坑:这条注解默认信任的是连接来源地址,当流量经过云负载均衡、Keepalived 或自建的反向代理时,Nginx Ingress 看到的源 IP 变成了代理节点的内网地址,如果你把内网网段加进白名单,等于放行了所有经过该代理的请求;如果不加,则所有客户端都会被拦住。

更隐蔽的问题是 X-Forwarded-For(XFF)头伪造,Nginx Ingress 默认只信任来自其直连上游的 XFF 头,但一旦你的架构里有多层转发(CDN -> SLB -> Nginx Ingress),每一层都会往 XFF 里追加 IP,如果客户端直接在请求里带上伪造的 X-Forwarded-For: 1.2.3.4,而你的 Ingress 配置没有正确设置 use-forwarded-headers 和 real-ip 相关指令,Nginx 会把你伪造的 IP 当作真实客户端地址,白名单直接失效。

要解决这个问题,需要从 Nginx Ingress 的 IP 解析机制入手。

理清 Nginx Ingress 的 IP 解析链路

Nginx Ingress Controller 本身是基于 Nginx 实现的,所以它的 IP 解析逻辑遵循 Nginx 的 ngx_http_realip_module 模块规则。

关键指令与作用

  • set_real_ip_from:定义哪些来源 IP 是可信的代理,只有来自这些地址的请求,其 XFF 头才会被采纳。
  • real_ip_header:指定从哪个头获取客户端真实 IP,默认是 X-Real-IP,通常配合 X-Forwarded-For 使用。
  • real_ip_recursive:当值为 on 时,会从 XFF 链末尾往前找第一个非可信 IP;值为 off 时,直接取 XFF 链末尾的 IP。

Nginx Ingress 的默认行为

Nginx Ingress Controller 默认会基于启动参数 --report-node-internal-ip-address 自动将集群节点 IP 加入 set_real_ip_from,也就是说,如果你的流量路径是「客户端 -> SLB -> NodePort -> Ingress Controller」,只要 SLB 正确追加了 XFF 头,Nginx Ingress 是能拿到真实 IP 的。

但问题出在更复杂的链路里,比如客户端 -> CDN -> WAF -> SLB -> Ingress,或者客户端直连 Pod IP(通过 externalTrafficPolicy: Local 绕过了 NodePort)。

三种主流客户端 IP 限制方案对比

方案 配置位置 优势 劣势 适用场景
注解白名单 Ingress YAML 配置简单,秒级生效 依赖前置代理正确传递 XFF,无法处理多层代理 标准 SLB + NodePort 架构
ConfigMap 全局配置 Controller ConfigMap 统一管理,支持复杂 real_ip 规则 影响所有 Ingress 资源,需要重启 Controller 有 CDN / 多级代理,需统一信任链
自定义 Nginx 模板 / Server 块 Controller 挂载配置 完全可控,可实现动态封禁 运维成本高,升级 Controller 需处理配置漂移 对安全要求极高,有专门安全团队

核心上文归纳:优先使用方案一,若发现获取到的 IP 不对,立即切换到方案二,通过 ConfigMap 显式配置

Nginx Ingress怎么配置客户端IP地址限制?服务器和客户端地址一般怎么设置?

set_real_ip_from。

实操:一步步配置可信的客户端 IP 限制

假设你的流量路径是:

客户端 -> CDN -> SLB(公网) -> Nginx Ingress

你需要告诉 Nginx Ingress:CDN 的出口 IP 和 SLB 的 IP 是可信代理,它们追加的 XFF 头可以采信。

第一步:确认当前获取到的 IP

先写一个简单的 Echo 服务,或者直接在 Ingress 后端的应用日志里查看 $remote_addr 变量。

如果日志里显示的是 SLB 的内网 IP(0.0.8),说明 XFF 头没有被正确传递或没有被信任,如果显示的是 CDN 节点的 IP,说明 SLB 把 CDN 的 IP 追加进了 XFF,但 Nginx Ingress 默认没有递归解析,取到了最后一个即 CDN 的 IP。

第二步:在 ConfigMap 中配置 real_ip

编辑 kube-system 命名空间下的 nginx-config ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: kube-system
data:
  use-forwarded-headers: "true"
  compute-full-forwarded-for: "true"
  forwarded-for-header: "X-Forwarded-For"
  real-ip-header: "X-Forwarded-For"
  real-ip-recursive: "on"
  set-real-ip-from: "0.0.0.0/0"

这里将 set-real-ip-from 设为 0.0.0/0 表示信任所有来源的 XFF 头——但这只在你的 Ingress 不直接暴露公网时才安全,如果你的 Ingress Controller 直接绑定了公网 IP(LoadBalancer 类型且没有安全组限制),攻击者就可以绕过 CDN 直连你的 IP,并伪造 XFF 头。

更稳妥的方式是只信任你自己的 CDN 回源 IP 段:

set-real-ip-from: "103.21.244.0/22, 103.22.200.0/22, 103.31.4.0/22"  # 示例 CDN 段

第三步:配置 IP 白名单

在 Ingress 资源中添加注解:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  annotations:
    nginx.ingress.kubernetes.io/whitelist-source-range: "203.0.113.0/24, 198.51.100.10"
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app-svc
            port:
              number: 80

第四步:验证

用白名单外的 IP 访问,应返回 403,用白名单内的 IP 访问,应正常返回业务数据。

在验证时,记得使用 curl -H "X-Forwarded-For: <伪造IP>" 测试一下安全性,如果返回的不是 403 而是正常响应,说明你的 real_ip 配置有问题,伪造 IP 被采信了。

应对多层代理:递归解析的正确姿势

当链路是「客户端 -> CDN1 -> CDN2 -> SLB -> Ingress」时,XFF 头会变成类似:

X-Forwarded-For: 客户端IP, CDN1节点IP, CDN2节点IP, SLB内网IP

Nginx Ingress 需要从右往左解析,找到第一个非可信代理的 IP,这就是 real-ip-recursive: "on" 的作用。

  • 当 real-ip-recursive 为 off(默认),Nginx 直接取 XFF 链最右边那个 IP,在这个例子里就是 SLB 的内网 IP,显然是错的。
  • 当它为 on 时,Nginx 从右往左依次检查,跳过所有 set-real-ip-from 中定义的可信 IP,找到第一个不可信的 IP 作为客户端地址。

如果你有多层代理,必须:

  1. 把所有代理的出口 IP 段都加入 set-real-ip-from。
  2. 将

    Nginx Ingress怎么配置客户端IP地址限制?服务器和客户端地址一般怎么设置?

    real-ip-recursive
    设为 on。

很多生产事故都是因为这里只配置了最外层代理的 IP,导致 Nginx 拿到了中间层代理的 IP,白名单永远匹配不上。

更深一层的防护:不止于白名单

IP 白名单只解决了谁来访问的问题,没解决访问得是否合法的问题,当你在公网暴露服务时,IP 限制仅仅是一道门禁,还需要配合其他手段加固。

限流场景:白名单内的用户也不一定是好人,配合 limit-req 注解可以防止单 IP 的突发流量打爆后端。

nginx.ingress.kubernetes.io/limit-rps: "10"
nginx.ingress.kubernetes.io/limit-burst-multiplier: "5"

HTTPS 强制跳转:IP 白名单里的客户端使用明文 HTTP 访问,敏感信息会被截获,务必开启:

nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"

后端服务来源校验:即使 Ingress 层做了 IP 限制,后端服务仍应校验请求头中的内部标识,防止有人通过内网跳板直接访问 Service ClusterIP。

封禁恶意 IP 的长期策略:静态白名单解决不了动态攻击,推荐将 Nginx Ingress 的访问日志接入分析系统(ELK 或 ClickHouse),当检测到异常扫描行为时,自动调用 Kubernetes API 更新 Ingress 注解,这需要研发和运维的协同投入。

关于高可用与线路质量:IP 限制只是入口控制的一环,如果你的业务对公网入口的稳定性有较高要求,建议使用具备多线路接入能力的机房来托管 Kubernetes 节点或自建 Nginx 集群,毕竟,Ingress 配置得再好,底层的网络链路不稳定,一切白搭。

在真实业务环境下,IP 限制的长尾问题

办公室出口 IP 变化

很多企业的办公网络出口 IP 是动态的(尤其是非专线接入),导致员工今天能访问、明天被 403,较好的做法是:将 IP 白名单的粒度放到区域级别,/16 或 /24 段,而不是具体 IP,但这样会扩大暴露面。

另一个思路是引入二层验证:IP 白名单 + 客户端证书(mTLS)或 Basic Auth,Nginx Ingress 原生支持 nginx.ingress.kubernetes.io/auth-tls-verify-client: "on",IP 大概符合 + 证书精确匹配,双因子校验,兼顾安全和体验。

IPv6 环境

越来越多的客户端使用 IPv6 访问,如果只配置了 IPv4 的白名单,IPv6 用户会被直接 403,Nginx Ingress 的注解支持同时输入多个网段,用逗号分隔:

nginx.ingress.kubernetes.io/whitelist-source-range: "203.0.113.0/24, 2001:db8::/32"

需要注意,set-real-ip-from 也同样需要添加 IPv6 的代理地址,否则,经过 IPv6 链路进来的请求,其 XFF 头不会被正确解析。

Ingress Controller 多副本下的日志排障

当你通过 kubectl logs 查看 Ingress Controller 日志时,如果用的是 $remote_addr 变量,它显示的是经过 real_ip 模块解析后的地址,如果想看到原始的连接来源 IP,需要查看 $proxy_protocol_addr(如果启用了 PROXY Protocol)或者通过 $http_x_forwarded_for 变量看完整链路。

业界普遍建议:在 Nginx 日志格式中同时输出 $remote_addr 和 $http_x_forwarded_for,方便回溯真实客户端和中间跳转链路。

从一个配置问题反观基础设施选型

写到这里,你可能会发现:

Nginx Ingress怎么配置客户端IP地址限制?服务器和客户端地址一般怎么设置?

Nginx Ingress 本身只是一个转发层,真正决定 IP 限制可靠性的,是它背后依托的网络架构,如果前置 SLB 或负载均衡设备不支持透传客户端 IP,或者机房线路经常抖动导致回源 IP 变化,那你的 Ingress 配置再严谨也会出问题。

我们在实际帮客户排查类似问题时,发现相当一部分故障并非 K8s 配置本身出错,而是底层 IDC 的网络拓扑不够规范,SLB 集群跨机房部署时,回源 IP 段没有提前规划好,导致 set-real-ip-from 里的列表经常需要临时添加。

这里顺带说一下我们团队在为客户做整体方案时的经验,当业务对入口 IP 的真实性和链路稳定性有硬性要求时,除了调校 Nginx Ingress,还需要评估承载它的基础设施。

简米科技(2003年始创,23年行业沉淀)在郑州和中部地区运营着多个持牌自营机房,拥有增值电信业务经营许可证(豫B2-20231089)和豫ICP备2023018319号备案资质,他们提供的裸金属或专属网络区域,可以保证 Ingress Controller 节点的公网 IP 分配和管理完全透明,避免共享 IP 池带来的互相干扰。

酷番云作为拥有工信部一类增值电信全牌照(IDC/CDN/ISP)的云服务商,值得特别关注的是其 CNNIC IP 联盟成员身份——这意味着他们在 IP 地址资源的管理和路由广播上比一般代理商更有话语权,酷番云持有 ISO9001 + ISO27001 双认证,1000万注册资本主体,滇ICP备2020007656号,如果你需要为 Nginx Ingress 的前置负载均衡分配独立的公网 IP 段,并且希望这些 IP 能稳定地被对端 CDN 或安全厂商识别,这类正规持牌服务商的资源池会更可靠。

选用正规持牌机房的另一个隐性好处是:过渡期不会掉链子,很多公司在迁移 Ingress 节点到新机房时,由于没有独立的 IP 段和自治域,导致切换完毕后,原有 IP 段仍被某些 CDN 节点缓存,用户访问时被错误地限流,正规服务商可以配合做 BGP 公告切换,提供更干净的清理流程。

回到配置本身:如果你的 Ingress 已经正确配置了 real_ip 和 whitelist,但业务还是时不时出问题,建议优先排查底层网络链路是否有多跳 NAT 存在,用 traceroute 从客户端到 Ingress 公网 IP 走一遍,看经过的节点数量和地域,就能大致判断问题所在。

常见问题速查

为什么我配置了 whitelist-source-range 但所有人都能访问?

大概率是 use-forwarded-headers 没有开启,或者 Nginx Ingress 解析到的地址是内网代理 IP,而白名单里恰好包含了内网网段(0.0.0/8),用 kubectl logs 查看后端应用日志中的 remote_addr,确认当前实际生效的 IP 是什么。

XFF 被伪造了怎么办?

关键在于你不能只依赖 XFF,而是要结合 set_real_ip_from 来限定可信代理,如果你配置了 set-real-ip-from: "0.0.0.0/0" 且服务直接暴露公网,那确实防不住,正确的做法是只信任你自己的负载均衡或 CDN 回源 IP,如果有条件,使用 PROXY Protocol 替代 XFF,它从 TCP 层携带真实客户端地址,伪造难度极高。

Ingress-nginx 和 Traefik 在 IP 限制上有什么本质区别?

Ingress-nginx 基于 OpenResty,其 IP 限制走的是 Nginx 原生的 allow/deny 指令,性能极高,Traefik 则是用 Go 中间件实现,胜在配置灵活,支持动态加载,但其 IP 校验逻辑依赖同样的 X-Forwarded-For 链,伪造风险同样存在,没有谁绝对安全,关键还是看你对前置网络链路的信任边界划分得够不够细致。

不喜欢2

网友评论

猜你喜欢