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 来举例说明:
|
|
以上配置解释:
- 授权动作是 “允许”
- 满足
from.source
中定义的条件(注:source中,各个字段是AND
关系,需要同时满足,每个字段内部列表是OR
关系) - 规则是对匹配
selector
条件的 workload 生效,例子中为istio-ingressgateway
。
例子中 ipBlocks
和 notIpBlocks
对应四层source IP
;而 remoteIpBlocks
和 notRemoteIpBlocks
对应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,如果用remoteIpBlocks
和 notRemoteIpBlocks
设置条件的话,用列表中的那个IP呢?
第一反应可能是,将列表中的 IP 都设置上。但实际上不太现实,且不一定能实现预期的功能。 互联网的环境错综复杂,在访问链路中可能经过各种其次代理,其中代理可能分布在不同的位置。
如上图所示,client 中的内部环境中可能有多个正向代理,server 端的内部环境中也可能包括多个反向代理。假设外部网络中也有代理,XFF中就会有很多IP信息,所以很难通过remoteIpBlocks
和 notRemoteIpBlocks
两个字段精确指定。如果全部枚举,可能会有误伤,也可能会有漏网之鱼。
为了避免上述问题,istio提供了一个配置项 numTrustedProxies
,用于指定 ingressgateway
接收到的 XFF
header中,可信代理的数量。
假设 XFF
的值为 1.1.1.1,2.2.2.2,3.3.3.3,4.4.4.4
,numTrustedProxies
的值为 1
, 则表示从右边数第一个IP是可信proxy的IP (即 4.4.4.4
),其他的都是不可信的。而 remoteIpBlocks
和 notRemoteIpBlocks
生效的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.4
,numTrustedProxies
取不同值时, 下面各字段的取值:
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
的值。
全局设置:
|
|
workload设置:
在deployment中 template的annotation中添加如下字段:
|
|
参考连接:
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