现有一套Java开发的应用,需要能获取到用户访问的真实IP地址,以此来过滤到一些不安全的因素。而实际部署的场景中Java服务提供给用户访问需要经过多次代理,默认情况下是无法获取到客户端真实IP地址的,因此要实现该需求,就得将客户端真实IP地址透传到后端。

- # haproxy.cfg
- defaults
- mode http
- log global
- option httplog
- option dontlognull
- option http-server-close
- log 127.0.0.1 local3
- option forwardfor except 127.0.0.0/8
- option redispatch
- retries 3
- timeout http-request 10s
- timeout queue 1m
- timeout connect 10s
- timeout client 5m
- timeout server 5m
- timeout http-keep-alive 10s
- timeout check 10s
- unique-id-format %{+X}o\ %ci%cp%fi%fp%Ts%rt%pid
-
- frontend https_link_ha
- bind *:443 ssl crt /usr/local/etc/haproxy/cert/crt/ ca-file /usr/local/etc/haproxy/cert/ca/ca.pem verify optional
- #log 127.0.0.1 local3
- mode http
- log-format "%ID %ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
- option accept-invalid-http-request
- # 配置请求头
- http-request set-header x-request-id %[unique-id]
- http-request set-header x-request-time %[date()]
- http-request set-header X-Real-IP %[src]
-
- default_backend pre
-
- backend pre
- server 1 192.168.100.100:8080 check inter 1500 rise 3 fall 3 weight 3
- server 2 192.168.100.101:9000 check inter 1500 rise 3 fall 3 weight 4
- server 3 192.168.100.102:8090 check inter 1500 rise 3 fall 3 weight 5
其中主要是两个配置:
option forwardfor except 127.0.0.0/8在由Haproxy发往后端的请求中加上XFF首部,其值是前个客户端的IP。
http-request set-header X-Real-IP %[src]在X-Real-IP中设置客户端IP。
- # nginx.conf 日志格式
-
- log_format main '$remote_addr - $remote_user [$time_local] "$request" "$http_x_forwarded_for" ';
-
- # location 反向代理的配置
-
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
更多参考资料:https://www.cnblogs.com/yanzi2020/p/17471481.html
默认情况下,Ingress没有开启XFF。
在
Ingress上要使用XFF,需要使用到以下三个参数:
use-forwarded-headers:是否开启XFF头传递,默认是false。
forwarded-for-header:XFF的真实header名,默认是X-Forwarded-For。
compute-full-forwarded-for:列出客户端访问所经过的代理IP,默认情况下,XFF是从remote_addr中获取的值。
- # 在Nginx Ingress的ConfigMap里增加以下两个配置
-
- use-forwarded-headers: 'true'
- compute-full-forwarded-for: 'true'
注意:不是所有的场景都能通过XFF获取到用户的真实IP,比如当SLB前面还有CDN的情况下,获取的可能就是CDN的来源IP
官方文档:Traefik EntryPoints Documentation - Traefik
命令行方式
--entryPoints.web.address=:80
--entryPoints.web.forwardedHeaders.insecure
- # k8s yaml文件示例,仅做参考
- ---
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- annotations:
- meta.helm.sh/release-name: traefik
- meta.helm.sh/release-namespace: default
- labels:
- app.kubernetes.io/instance: traefik
- app.kubernetes.io/managed-by: Helm
- app.kubernetes.io/name: traefik
- helm.sh/chart: traefik-9.11.0
- name: traefik
- namespace: default
- resourceVersion: '505763774'
- spec:
- progressDeadlineSeconds: 600
- replicas: 6
- revisionHistoryLimit: 10
- selector:
- matchLabels:
- app.kubernetes.io/instance: traefik
- app.kubernetes.io/name: traefik
- strategy:
- rollingUpdate:
- maxSurge: 1
- maxUnavailable: 1
- type: RollingUpdate
- template:
- metadata:
- creationTimestamp: null
- labels:
- app.kubernetes.io/instance: traefik
- app.kubernetes.io/managed-by: Helm
- app.kubernetes.io/name: traefik
- helm.sh/chart: traefik-9.11.0
- spec:
- containers:
- - args:
- - '--global.checknewversion'
- - '--global.sendanonymoususage'
- - '--entryPoints.traefik.address=:9000/tcp'
- - '--entryPoints.web.address=:8000/tcp'
- - '--entryPoints.websecure.address=:8443/tcp'
- - '--api.dashboard=true'
- - '--ping=true'
- - '--providers.kubernetescrd'
- - '--providers.kubernetesingress'
- - '--entrypoints.web.forwardedHeaders.insecure'
- - '--entrypoints.websecure.forwardedHeaders.insecure'
- image: 'traefik:2.3.3'
- imagePullPolicy: IfNotPresent
- livenessProbe:
- failureThreshold: 3
- httpGet:
- path: /ping
- port: 9000
- scheme: HTTP
- initialDelaySeconds: 10
- periodSeconds: 10
- successThreshold: 1
- timeoutSeconds: 2
- name: traefik
- ports:
- - containerPort: 9000
- name: traefik
- protocol: TCP
- - containerPort: 8000
- name: web
- protocol: TCP
- - containerPort: 8443
- name: websecure
- protocol: TCP
- readinessProbe:
- failureThreshold: 1
- httpGet:
- path: /ping
- port: 9000
- scheme: HTTP
- initialDelaySeconds: 10
- periodSeconds: 10
- successThreshold: 1
- timeoutSeconds: 2
- resources: {}
- securityContext:
- capabilities:
- drop:
- - ALL
- readOnlyRootFilesystem: true
- runAsGroup: 65532
- runAsNonRoot: true
- runAsUser: 65532
- terminationMessagePath: /dev/termination-log
- terminationMessagePolicy: File
- volumeMounts:
- - mountPath: /data
- name: data
- - mountPath: /tmp
- name: tmp
- dnsPolicy: ClusterFirst
- restartPolicy: Always
- schedulerName: default-scheduler
- securityContext:
- fsGroup: 65532
- serviceAccount: traefik
- serviceAccountName: traefik
- terminationGracePeriodSeconds: 60
- volumes:
- - emptyDir: {}
- name: data
- - emptyDir: {}
- name: tmp
- status:
- availableReplicas: 6
- conditions:
- - lastTransitionTime: '2022-10-10T07:58:50Z'
- lastUpdateTime: '2022-10-10T07:58:50Z'
- message: Deployment has minimum availability.
- reason: MinimumReplicasAvailable
- status: 'True'
- type: Available
- - lastTransitionTime: '2020-11-25T22:53:59Z'
- lastUpdateTime: '2022-11-17T10:44:40Z'
- message: ReplicaSet "traefik-54bf67c74d" has successfully progressed.
- reason: NewReplicaSetAvailable
- status: 'True'
- type: Progressing
- observedGeneration: 13
- readyReplicas: 6
- replicas: 6
- updatedReplicas: 6
-
- ---
- apiVersion: v1
- kind: Service
- metadata:
- annotations:
- meta.helm.sh/release-name: traefik
- meta.helm.sh/release-namespace: default
- labels:
- app.kubernetes.io/instance: traefik
- app.kubernetes.io/managed-by: Helm
- app.kubernetes.io/name: traefik
- helm.sh/chart: traefik-9.11.0
- name: traefik
- namespace: default
- resourceVersion: '505762379'
- spec:
- clusterIP: 10.96.252.109
- externalTrafficPolicy: Cluster
- ports:
- - name: web
- nodePort: 30079
- port: 80
- protocol: TCP
- targetPort: web
- selector:
- app.kubernetes.io/instance: traefik
- app.kubernetes.io/name: traefik
- sessionAffinity: None
- type: NodePort
- status:
- loadBalancer: {}
在deployment部署中的traefik启动参数中添加
- '--entrypoints.web.forwardedHeaders.insecure'
和
- '--entrypoints.websecure.forwardedHeaders.insecure'
启动参数
本文仅做记录和参考,在实际使用中需要充分测试。