【问题标题】:Nginx ingress sends private IP for X-Real-IP to servicesNginx 入口将 X-Real-IP 的私有 IP 发送到服务
【发布时间】:2021-09-21 13:20:31
【问题描述】:

我使用以下代码创建了一个 Nginx 入口和服务:

apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  type: ClusterIP
  selector:
    name: my-app
  ports:
    - port: 8000
      targetPort: 8000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myingress
  annotations:
    kubernetes.io/ingress.class: nginx
  labels:
    name: myingress
spec:
  rules:
  - host: mydomain.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: my-service
            port: 
              number: 8000

安装了 Nginx 入口: helm install ingress-nginx ingress-nginx/ingress-nginx.

我还为 ELB 启用了代理协议。但是在 nginx 日志中,我看不到 X-Forwarded-For 和 X-Real-IP 标头的真实客户端 IP。这是我在应用日志中看到的最后一个标题:

X-Forwarded-For:[192.168.21.145] X-Forwarded-Port:[80] X-Forwarded-Proto:[http] X-Forwarded-Scheme:[http] X-Real-Ip:[192.168.21.145] X-Request-Id:[1bc14871ebc2bfbd9b2b6f31] X-Scheme:[http]

如何获取真正的客户端 IP 而不是入口 pod IP?还有一种方法可以知道 ELB 将哪些标头发送到入口?

【问题讨论】:

  • 你确定192.168.21.145 是 ELB IP 而不是 nginx 入口控制器 pod IP?
  • @whites11 你是对的。那是吊舱IP。已编辑。

标签: kubernetes kubernetes-ingress amazon-eks amazon-elb ingress-nginx


【解决方案1】:

一种解决方案是使用externalTrafficPolicyLocal(参见documentation)。

其实根据kubernetes documentation

由于这个特性的实现,在目标容器中看到的源 IP 不是客户端的原始源 IP。 ... service.spec.externalTrafficPolicy - 表示此服务是否希望将外部流量路由到节点本地或集群范围的端点。有两个可用选项:集群(默认)和本地。集群掩盖了客户端源 IP,可能会导致第二次跳转到另一个节点,但应该具有良好的整体负载分布。 Local 保留客户端源 IP 并避免 LoadBalancer 和 NodePort 类型服务的第二个跃点,但可能存在流量传播不平衡的风险。

如果您想遵循这条路线,请更新您的 nginx ingress controller Service 并添加 externalTrafficPolicy 字段:

apiVersion: v1
kind: Service
metadata:
  name: nginx-ingress-controller
spec:
  ...
  externalTrafficPolicy: Local

一种可能的替代方法是使用Proxy protocol(参见documentation

【讨论】:

  • 谢谢,但似乎 externalTrafficPolicy 不适用于 ClusterIP。我将 ClusterIP 更改为 NodePort 并添加了 externalTrafficPolicy,但仍然得到相同的结果。
  • 我的错误。您必须在 nginx 入口控制器服务中执行此操作,而不是您的后端服务
【解决方案2】:

应在 ConfigMap 中为入口控制器和 ELB 启用代理协议。

L4 使用proxy-protocol

对于 L7,请使用 use-forwarded-headers

# configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
data:
  use-forwarded-headers: "true"
  use-proxy-protocol: "true"

https://kubernetes.github.io/ingress-nginx/user-guide/miscellaneous/#proxy-protocol

【讨论】:

    【解决方案3】:

    只是扩展@strongjz 的答案。

    默认情况下,将在 AWS 中为 LoadBalancer 类型的服务创建的负载均衡器将是传统负载均衡器,在第 4 层上运行,即在 TCP 协议级别进行代理。

    对于这种情况,保留真实 ip 的最佳方法是使用代理协议,因为它能够在 TCP 级别执行此操作。

    为此,您应该在负载均衡器和 Nginx-ingress 上启用代理协议。

    这些值应该适用于 nginx-ingress 的 Helm 安装:

      controller:
        service:
          annotations:
            service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
        config:
          use-proxy-protocol: "true"
          real-ip-header: "proxy_protocol"
    

    service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*" 注释将告诉aws-load-balancer-controller 创建启用代理协议的 LoadBalancer。我不确定如果将它添加到预先存在的 Ingress-nginx 会发生什么,但它也应该可以工作。

    use-proxy-protocolreal-ip-header 是传递给 Nginx 的选项,用于在那里启用代理协议。

    参考:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-07
      • 2012-04-29
      • 1970-01-01
      • 2021-06-11
      • 2017-01-09
      • 2020-07-13
      • 2014-03-30
      • 2012-05-27
      相关资源
      最近更新 更多