目录

Istio 如何根据 Client IP 设置访问白名单(http协议)

1. Client IP 传递

要根据 Client IP 设置访问 gateway 的白名单,首先gateway 需要拿到 Client IP。

在 tcp 协议中,可以通过 source IP来获取 客户端的IP地址,然而如何中间经过代理后(四层、七层),通常情况下(可以通过其他手动达到传递source IP的方式,如DNAT),source IP 就会变为代理的IP地址,所以对于HTTP请求,只能在不经过代理的情况下Server端才能基于TCP协议拿到 Source IP。

在 http 协议中,可以通过 XFF(x-forwarded-for)Header 来传递 Client IP地址的。当客户端在访问Server时,Client 端会将本地IP地址放在request header中,格式为 x-forwarded-for: x.x.x.x

由于在请求过程中,可能会经过多转发代理(四层 或 七层)。如果是四层代理,http header是作为普通数据传递的,所以x-forwarded-for中的信息不会丢失。当通过七层代理时,业界流行的代理(Nginx,HAProxy,Envoy等)都会将自己的IP地址设置到 x-forwarded-for header中当前值的后面,并用逗号隔开,在转发都后端。因此,在http请求链路中的 Proxy和server端都可以拿到客户端的IP地址。

2. 基于Client IP设置白名单的方法

Istio 中提供了 AuthorizationPolicy 自定义对象,可以很方便的管理mesh中 workload 的访问控制。

下面以 istio-ingressgateway 来举例说明:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: ip-whitelist
  namespace: istio-system
spec:
  action: ALLOW       # 允许访问,还可以设置 DENY(禁止),AUDIT(审计),CUSTOM(自定义)
  rules:
  - from:
    - source:
#       ipBlocks:
#       - 2.2.2.2
#       - 3.3.3.0/24
#       notIpBlocks:
#       - 3.3.3.0/25
        remoteIpBlocks:
        - 1.1.1.1/24
        notRemoteIpBlocks:
        - 1.1.1.1/25
  selector:
    matchLabels:
      app: istio-ingressgateway
      istio: ingressgateway

以上配置解释:

  • 授权动作是 “允许”
  • 满足 from.source 中定义的条件(注:source中,各个字段是 AND关系,需要同时满足,每个字段内部列表是 OR关系)
  • 规则是对匹配 selector条件的 workload 生效,例子中为 istio-ingressgateway

例子中 ipBlocksnotIpBlocks 对应四层source IP;而 remoteIpBlocksnotRemoteIpBlocks 对应http协议中 x-forwarded-for header中的信息。

如果用 source IP 设置白名单,比较好理解,直接设置IP网段即可,但前提是 ingressgateway 必须能顺利拿到 source IP。对于HTTP协议,大部分情况下会用 XFF 中的IP来作为client IP的来源。

2.1 基于 XFF header中的IP列表设置白名单条件

上文提到,XFF header中,可能是一个IP列表,包含多个IP,如果用remoteIpBlocksnotRemoteIpBlocks设置条件的话,用列表中的那个IP呢?

第一反应可能是,将列表中的 IP 都设置上。但实际上不太现实,且不一定能实现预期的功能。 互联网的环境错综复杂,在访问链路中可能经过各种其次代理,其中代理可能分布在不同的位置。

./_images/client-proxy-server.png
http 请求访问示意图

如上图所示,client 中的内部环境中可能有多个正向代理,server 端的内部环境中也可能包括多个反向代理。假设外部网络中也有代理,XFF中就会有很多IP信息,所以很难通过remoteIpBlocksnotRemoteIpBlocks 两个字段精确指定。如果全部枚举,可能会有误伤,也可能会有漏网之鱼。

为了避免上述问题,istio提供了一个配置项 numTrustedProxies,用于指定 ingressgateway 接收到的 XFF header中,可信代理的数量。

假设 XFF的值为 1.1.1.1,2.2.2.2,3.3.3.3,4.4.4.4numTrustedProxies 的值为 1, 则表示从右边数第一个IP是可信proxy的IP (即 4.4.4.4),其他的都是不可信的。而 remoteIpBlocksnotRemoteIpBlocks 生效的IP为第一个 不可信 IP (即 3.3.3.3)。当 numTrustedProxies 的值无法在 XFF 列表中找到对应的IP,istio会认为列表中所有的IP都是不可信IP,例如 numTrustedProxies = 5

另外,在HTTP请求中,如果设置了numTrustedProxies 后,也在accesslog中的 downstream_remote_address 字段中体现。

下表为 x-forwarded-for (XFF) 取值 1.1.1.1,2.2.2.2,3.3.3.3,4.4.4.4numTrustedProxies取不同值时, 下面各字段的取值:

numTrustedProxies remoteIpBlocks 生效 IP downstream_remote_address 备注
0 4.4.4.4 4.4.4.4:[source_port] 4.4.4.4是直接
访问gateway的client IP
1 3.3.3.3 3.3.3.3:0
2 2.2.2.2 2.2.2.2:0
3
1.1.1.1 1.1.1.1:0
4 4.4.4.4 4.4.4.4:[source_port] 全部是信任IP,则取直接访问
gateway的Client IP

2.2 numTrustedProxies 的设置方法

有两个途径来设置 numTrustedProxies 的值。

全局设置:

1
2
3
4
5
6
7
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  meshConfig:
    defaultConfig:
      gatewayTopology:
        numTrustedProxies: 2  # 全局配置,将在网格中所有 Gateway中生效

workload设置:

在deployment中 template的annotation中添加如下字段:

1
2
3
4
  template:
    metadata:
      annotations:
        proxy.istio.io/config: '{"gatewayTopology": {"numTrustedProxies": 3}}'


参考连接:

https://istio.io/latest/docs/reference/config/security/authorization-policy/#Source https://istio.io/latest/docs/ops/configuration/traffic-management/network-topologies/#example-using-x-forwarded-for-capability-with-httpbin https://istio.io/latest/docs/reference/config/istio.mesh.v1alpha1/#Topology