· cloud

Ingress获取真实IP

一般情况下,经过 ingress 的请求会携带 headerX-Real-IP,用户可根据 header 解析出真实访问 IP。

特殊情况,用户请求可能经过多个 nginx 才达到 ingress, 通过上述方法得到的并不是用户的真实 IP。

request -> nginx -> … -> ingress-nginx -> backend

方案 1 use-forwarded-headers

nginx-ingress 官方的建议是开启use-forwarded-headers, 配置如下:

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
data:
  compute-full-forwarded-for: 'true'
  use-forwarded-headers: 'true'

方案 2 real_ip_header

这种方式确实可以起作用,但是有用户反馈开启后访问 ingres 后端服务一直报308,检查了 ingress 的代码开启use-forwarded-headers后会同时开启ssl-redirect导致 308。

那么我们只需要开启 nginx 配置中的相关 real-ip 的配置,如下在http-snippet添加real_ip_header X-Forwarded-For;

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
data:
  http-snippet: |
    real_ip_header X-Forwarded-For;

golang 中获取真实 ip

func RemoteIP(r *http.Request) string {
  // ingress 行为,将真实ip放到header `X-Original-Forwarded-For`, 普通nginx可去掉此条
	ip := strings.TrimSpace(strings.Split(r.Header.Get("X-Original-Forwarded-For"), ",")[0])
	if ip != "" {
		return ip
	}

	ip = strings.TrimSpace(strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0])
	if ip != "" {
		return ip
	}

	ip = strings.TrimSpace(r.Header.Get("X-Real-Ip"))
	if ip != "" {
		return ip
	}

	if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil {
		return ip
	}

	return ""
}

注意

nginx-ingress configmap 中的配置会是全局生效的,上线前需要严格测试。