需求说明
现有一套Java开发的应用,需要能获取到用户访问的真实IP地址,以此来过滤到一些不安全的因素。而实际部署的场景中Java服务提供给用户访问需要经过多次代理,默认情况下是无法获取到客户端真实IP地址的,因此要实现该需求,就得将客户端真实IP地址透传到后端。
访问路径
如何实现
haproxy上配置
# haproxy.cfg
defaultsmode httplog globaloption httplogoption dontlognulloption http-server-closelog 127.0.0.1 local3option forwardfor except 127.0.0.0/8option redispatchretries 3timeout http-request 10stimeout queue 1mtimeout connect 10stimeout client 5mtimeout server 5mtimeout http-keep-alive 10stimeout check 10sunique-id-format %{+X}o\ %ci%cp%fi%fp%Ts%rt%pidfrontend https_link_habind *: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 local3mode httplog-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 prebackend pre server 1 192.168.100.100:8080 check inter 1500 rise 3 fall 3 weight 3server 2 192.168.100.101:9000 check inter 1500 rise 3 fall 3 weight 4server 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上配置
# 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上配置
默认情况下,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上配置
官方文档: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: traefikmeta.helm.sh/release-namespace: defaultlabels:app.kubernetes.io/instance: traefikapp.kubernetes.io/managed-by: Helmapp.kubernetes.io/name: traefikhelm.sh/chart: traefik-9.11.0name: traefiknamespace: defaultresourceVersion: '505763774'
spec:progressDeadlineSeconds: 600replicas: 6revisionHistoryLimit: 10selector:matchLabels:app.kubernetes.io/instance: traefikapp.kubernetes.io/name: traefikstrategy:rollingUpdate:maxSurge: 1maxUnavailable: 1type: RollingUpdatetemplate:metadata:creationTimestamp: nulllabels:app.kubernetes.io/instance: traefikapp.kubernetes.io/managed-by: Helmapp.kubernetes.io/name: traefikhelm.sh/chart: traefik-9.11.0spec: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: IfNotPresentlivenessProbe:failureThreshold: 3httpGet:path: /pingport: 9000scheme: HTTPinitialDelaySeconds: 10periodSeconds: 10successThreshold: 1timeoutSeconds: 2name: traefikports:- containerPort: 9000name: traefikprotocol: TCP- containerPort: 8000name: webprotocol: TCP- containerPort: 8443name: websecureprotocol: TCPreadinessProbe:failureThreshold: 1httpGet:path: /pingport: 9000scheme: HTTPinitialDelaySeconds: 10periodSeconds: 10successThreshold: 1timeoutSeconds: 2resources: {}securityContext:capabilities:drop:- ALLreadOnlyRootFilesystem: truerunAsGroup: 65532runAsNonRoot: truerunAsUser: 65532terminationMessagePath: /dev/termination-logterminationMessagePolicy: FilevolumeMounts:- mountPath: /dataname: data- mountPath: /tmpname: tmpdnsPolicy: ClusterFirstrestartPolicy: AlwaysschedulerName: default-schedulersecurityContext:fsGroup: 65532serviceAccount: traefikserviceAccountName: traefikterminationGracePeriodSeconds: 60volumes:- emptyDir: {}name: data- emptyDir: {}name: tmp
status:availableReplicas: 6conditions:- lastTransitionTime: '2022-10-10T07:58:50Z'lastUpdateTime: '2022-10-10T07:58:50Z'message: Deployment has minimum availability.reason: MinimumReplicasAvailablestatus: 'True'type: Available- lastTransitionTime: '2020-11-25T22:53:59Z'lastUpdateTime: '2022-11-17T10:44:40Z'message: ReplicaSet "traefik-54bf67c74d" has successfully progressed.reason: NewReplicaSetAvailablestatus: 'True'type: ProgressingobservedGeneration: 13readyReplicas: 6replicas: 6updatedReplicas: 6---
apiVersion: v1
kind: Service
metadata:annotations:meta.helm.sh/release-name: traefikmeta.helm.sh/release-namespace: defaultlabels:app.kubernetes.io/instance: traefikapp.kubernetes.io/managed-by: Helmapp.kubernetes.io/name: traefikhelm.sh/chart: traefik-9.11.0name: traefiknamespace: defaultresourceVersion: '505762379'
spec:clusterIP: 10.96.252.109externalTrafficPolicy: Clusterports:- name: webnodePort: 30079port: 80protocol: TCPtargetPort: webselector:app.kubernetes.io/instance: traefikapp.kubernetes.io/name: traefiksessionAffinity: Nonetype: NodePort
status:loadBalancer: {}
在deployment部署中的traefik启动参数中添加
- '--entrypoints.web.forwardedHeaders.insecure'
和
- '--entrypoints.websecure.forwardedHeaders.insecure'
启动参数
本文仅做记录和参考,在实际使用中需要充分测试。