Kubernetes获取客户端IP

Posted by Zeusro on April 8, 2019
👈🏻 Select language

环境:

  1. kubernetes版本: 阿里云v1.11.5
  2. 节点系统 CentOS Linux 7 (Core)
  3. 节点容器版本 docker://17.6.2

概念介绍

X-Forwarded-For

1
X-Forwarded-For: <client>, <proxy1>, <proxy2>

remote_addr

remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的,当你的浏览器访问某个网站时,假设中间没有任何代理,那么网站的web服务器(Nginx,Apache等)就会把remote_addr设为你的机器IP,如果你用了某个代理,那么你的浏览器会先访问这个代理,然后再由这个代理转发到网站,这样web服务器就会把remote_addr设为这台代理机器的IP。

内部请求(Pod对Pod请求)

1
podA-->podB

这时只有getRemoteAddr能够获取IP,其余header全空.podB获得的clientIP为podA的podIP(虚拟IP)

The client_address is always the client pod’s IP address, whether the client pod and server pod are in the same node or in different nodes.

外部请求

Nodeport svc

1
client-->svc-->pod

externalTrafficPolicy: Cluster

svc.spec设置externalTrafficPolicy: Cluster,意思是所有节点都会启动kube-proxy,外部流量可能转发多1次.

1
2
3
4
5
6
7
8
9
          client
             \ ^
              \ \
               v \
   node 1 <--- node 2
    | ^   SNAT
    | |   --->
    v |
 endpoint

这时流量通过node2的转发,app 获得的clientIP不定,有可能是node 2 的IP,也有可能是客户端的IP

externalTrafficPolicy: Local

svc.spec设置externalTrafficPolicy: Local,在运行pod的节点上启动kube-proxy,外部流量直达节点.

1
2
3
4
5
6
7
8
9
        client
       ^ /   \
      / /     \
     / v       X
   node 1     node 2
    ^ |
    | |
    | v
 endpoint

这时,只有运行了pod的节点才会有对应的proxy,避免了中间商(node 2)挣差价

clientIPremote_addr

LoadBalancer svc

svc.spec设置externalTrafficPolicy: Local.

1
2
3
4
5
6
7
8
9
                      client
                        |
                      lb VIP
                     / ^
                    v /
health check --->   node 1   node 2 <--- health check
        200  <---   ^ |             ---> 500
                    | V
                 endpoint

image

SLB监听HTTP:取X-Forwarded-For即可(从SLB获得客户端IP).

SLB监听TCP,则取remote_addr

externalTrafficPolicy: Cluster的情况就不用说了,没有意义.

ingress

1
client-->slb-->ingress svc-->ingress pod-->app svc-->pod

首先需要设置ingress的svc类型为Nodeport/LoadBalancer,并且externalTrafficPolicy: Local

app svc type为ClusterIP/NodePort/LoadBalancer都无所谓.

这个时候,X-Forwarded-For的值即为clientIP

remote_addringress pod Virtual IP

参考链接:

  1. source-ip
  2. HTTP 请求头中的 X-Forwarded-For
  3. 如何获取客户端真实IP
  4. 源地址审计:追踪 kubernetes 服务的SNAT
  5. 谈谈kubernets的service组件的Virtual IP

Environment:

  1. kubernetes version: Alibaba Cloud v1.11.5
  2. Node system: CentOS Linux 7 (Core)
  3. Node container version: docker://17.6.2

Concept Introduction

X-Forwarded-For

1
X-Forwarded-For: <client>, <proxy1>, <proxy2>

remote_addr

remote_addr represents the client’s IP, but its value is not provided by the client. Instead, it’s specified by the server based on the client’s IP. When your browser accesses a website, assuming there are no proxies in between, the website’s web server (Nginx, Apache, etc.) will set remote_addr to your machine’s IP. If you use a proxy, your browser will first access the proxy, then the proxy forwards to the website. In this case, the web server will set remote_addr to that proxy machine’s IP.

Internal Requests (Pod to Pod Requests)

1
podA-->podB

At this time, only getRemoteAddr can get the IP, all other headers are empty. The clientIP obtained by podB is podA’s podIP (virtual IP).

The client_address is always the client pod’s IP address, whether the client pod and server pod are in the same node or in different nodes.

External Requests

Nodeport svc

1
client-->svc-->pod

externalTrafficPolicy: Cluster

Setting externalTrafficPolicy: Cluster in svc.spec means all nodes will start kube-proxy, and external traffic may be forwarded one more time.

1
2
3
4
5
6
7
8
9
          client
             \ ^
              \ \
               v \
   node 1 <--- node 2
    | ^   SNAT
    | |   --->
    v |
 endpoint

At this time, traffic goes through node2’s forwarding. The clientIP obtained by the app is uncertain. It could be node 2’s IP, or it could be the client’s IP.

externalTrafficPolicy: Local

Setting externalTrafficPolicy: Local in svc.spec starts kube-proxy on nodes running pods. External traffic goes directly to the node.

1
2
3
4
5
6
7
8
9
        client
       ^ /   \
      / /     \
     / v       X
   node 1     node 2
    ^ |
    | |
    | v
 endpoint

At this time, only nodes running pods will have the corresponding proxy, avoiding the middleman (node 2) making a profit.

clientIP is remote_addr.

LoadBalancer svc

Set externalTrafficPolicy: Local in svc.spec.

1
2
3
4
5
6
7
8
9
                      client
                        |
                      lb VIP
                     / ^
                    v /
health check --->   node 1   node 2 <--- health check
        200  <---   ^ |             ---> 500
                    | V
                 endpoint

image

SLB listening on HTTP: Take X-Forwarded-For (get client IP from SLB).

SLB listening on TCP: Take remote_addr.

The case of externalTrafficPolicy: Cluster doesn’t need to be mentioned, it’s meaningless.

ingress

1
client-->slb-->ingress svc-->ingress pod-->app svc-->pod

First, you need to set the ingress svc type to Nodeport/LoadBalancer, and externalTrafficPolicy: Local.

The app svc type can be ClusterIP/NodePort/LoadBalancer, it doesn’t matter.

At this time, the value of X-Forwarded-For is the clientIP.

remote_addr is the ingress pod Virtual IP.

  1. source-ip
  2. X-Forwarded-For in HTTP Request Headers
  3. How to Get Client Real IP
  4. Source Address Auditing: Tracking SNAT of Kubernetes Services
  5. Talking About the Virtual IP of Kubernetes Service Components

Окружение:

  1. версия kubernetes: Alibaba Cloud v1.11.5
  2. Система узла: CentOS Linux 7 (Core)
  3. Версия контейнера узла: docker://17.6.2

Введение в концепции

X-Forwarded-For

1
X-Forwarded-For: <client>, <proxy1>, <proxy2>

remote_addr

remote_addr представляет IP клиента, но его значение не предоставляется клиентом. Вместо этого оно указывается сервером на основе IP клиента. Когда ваш браузер обращается к веб-сайту, предполагая, что между ними нет прокси, веб-сервер сайта (Nginx, Apache и т.д.) установит remote_addr в IP вашей машины. Если вы используете прокси, ваш браузер сначала обратится к прокси, а затем прокси перешлет на веб-сайт. В этом случае веб-сервер установит remote_addr в IP этой прокси-машины.

Внутренние запросы (Запросы Pod к Pod)

1
podA-->podB

В это время только getRemoteAddr может получить IP, все остальные заголовки пусты. clientIP, полученный podB, является podIP podA (виртуальный IP).

Адрес клиента всегда является IP-адресом клиентского пода, независимо от того, находятся ли клиентский под и серверный под на одном узле или на разных узлах.

Внешние запросы

Nodeport svc

1
client-->svc-->pod

externalTrafficPolicy: Cluster

Установка externalTrafficPolicy: Cluster в svc.spec означает, что все узлы запустят kube-proxy, и внешний трафик может быть передан еще раз.

1
2
3
4
5
6
7
8
9
          client
             \ ^
              \ \
               v \
   node 1 <--- node 2
    | ^   SNAT
    | |   --->
    v |
 endpoint

В это время трафик проходит через пересылку node2. clientIP, полученный приложением, неопределен. Это может быть IP node 2, или это может быть IP клиента.

externalTrafficPolicy: Local

Установка externalTrafficPolicy: Local в svc.spec запускает kube-proxy на узлах, запускающих поды. Внешний трафик идет напрямую к узлу.

1
2
3
4
5
6
7
8
9
        client
       ^ /   \
      / /     \
     / v       X
   node 1     node 2
    ^ |
    | |
    | v
 endpoint

В это время только узлы, запускающие поды, будут иметь соответствующий прокси, избегая посредника (node 2), получающего прибыль.

clientIP — это remote_addr.

LoadBalancer svc

Установите externalTrafficPolicy: Local в svc.spec.

1
2
3
4
5
6
7
8
9
                      client
                        |
                      lb VIP
                     / ^
                    v /
health check --->   node 1   node 2 <--- health check
        200  <---   ^ |             ---> 500
                    | V
                 endpoint

image

SLB прослушивает HTTP: Возьмите X-Forwarded-For (получите IP клиента от SLB).

SLB прослушивает TCP: Возьмите remote_addr.

Случай externalTrafficPolicy: Cluster не нужно упоминать, это бессмысленно.

ingress

1
client-->slb-->ingress svc-->ingress pod-->app svc-->pod

Сначала нужно установить тип svc ingress в Nodeport/LoadBalancer, и externalTrafficPolicy: Local.

Тип app svc может быть ClusterIP/NodePort/LoadBalancer, это не имеет значения.

В это время значение X-Forwarded-For является clientIP.

remote_addr — это виртуальный IP ingress pod.

Ссылки:

  1. source-ip
  2. X-Forwarded-For в заголовках HTTP-запросов
  3. Как получить реальный IP клиента
  4. Аудит исходного адреса: отслеживание SNAT служб Kubernetes
  5. Разговор о виртуальном IP компонентов службы kubernets