istio 的访问策略
istio 提供了限速、按 header 路由等访问控制策略。
istio 黑白名单
istio 基于 mixer 获取的属性设置黑白名单,黑白名单也是通过 instance、handler 和 rule 设置。
按标签设置黑白名单
下面三条规则禁止 productpage 访问 http-record v2:
apiVersion: "config.istio.io/v1alpha2"
kind: handler
metadata:
name: denyproductpagehandler
spec:
compiledAdapter: denier
params:
status:
code: 7
message: Not allowed
---
apiVersion: "config.istio.io/v1alpha2"
kind: instance
metadata:
name: denyproductpagerequest
spec:
compiledTemplate: checknothing
---
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
name: denyproductpage
spec:
match: destination.labels["app"] == "http-record" && destination.labels["version"] == "v2" && source.labels["app"]=="productpage"
actions:
- handler: denyproductpagehandler
instances: [ denyproductpagerequest ]
按标签禁止访问
http-record v1 和 http-record v2 的 ip 地址如下:
$ kubectl get pod --show-labels |grep http-record
http-record-v1-5f9c95b7cf-t9tzx 2/2 Running 0 5d23h 172.17.0.16 app=http-record,pod-template-hash=5f9c95b7cf,security.istio.io/tlsMode=istio,version=v1
http-record-v2-d697c886-lqpsw 2/2 Running 0 5d23h 172.17.0.4 app=http-record,pod-template-hash=d697c886,security.istio.io/tlsMode=istio,version=v2
在 productpage 中访问 http-record v1:
$ curl 172.17.0.16:8080
{
"RemoteAddr": "127.0.0.1:52814",
"Method": "GET",
"Host": "172.17.0.16:8080",
"RequestURI": "/",
"Header": {
...省略...
在 productpage 中访问 http-record v2:
$ curl -v 172.17.0.4:8080
* Rebuilt URL to: 172.17.0.4:8080/
* Trying 172.17.0.4...
* TCP_NODELAY set
* Connected to 172.17.0.4 (172.17.0.4) port 8080 (#0)
> GET / HTTP/1.1
> Host: 172.17.0.4:8080
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< content-length: 60
< content-type: text/plain
< date: Thu, 28 Nov 2019 06:27:39 GMT
< server: envoy
< x-envoy-upstream-service-time: 4
<
* Curl_http_done: called premature == 0
* Connection #0 to host 172.17.0.4 left intact
PERMISSION_DENIED:denyproductpagehandler.default:Not allowed
通过这个例子我们同时得知,istio 的黑白名单是基于 pod 的,禁止的是 pod 到 pod 的访问。
不过网络层依旧是可达的,网络层不在 istio 的管控范围内:
$ ping 172.17.0.4
PING 172.17.0.4 (172.17.0.4) 56(84) bytes of data.
64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.367 ms
64 bytes from 172.17.0.4: icmp_seq=2 ttl=64 time=0.046 ms
按 IP 设置黑白名单
这是一个 ip 白名单的例子,只允许特定网段的 client 通过 ingressgateway 访问:
$ kubectl apply -f samples/bookinfo/policy/mixer-rule-deny-ip.yaml
通过下面三项配置,只允许 10.57.0.0/16 网段内的 ingressgateway 的访问:
apiVersion: config.istio.io/v1alpha2
kind: handler
metadata:
name: whitelistip
spec:
compiledAdapter: listchecker
params:
# providerUrl: ordinarily black and white lists are maintained
# externally and fetched asynchronously using the providerUrl.
overrides: ["10.57.0.0/16"] # overrides provide a static list
blacklist: false
entryType: IP_ADDRESSES
---
apiVersion: config.istio.io/v1alpha2
kind: instance
metadata:
name: sourceip
spec:
compiledTemplate: listentry
params:
value: source.ip | ip("0.0.0.0")
---
apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
name: checkip
spec:
match: source.labels["istio"] == "ingressgateway"
actions:
- handler: whitelistip
instances: [ sourceip ]
这个规则需要说明一下,rule 限定只作用于 ingressgateway,会检查 ingressgateway 的源 IP 是否在白名单内,如果不在就拒绝访问。
我这里的 ingressgateway 的 IP 是 172.17.0.19,不在白名单内:
$ kubectl -n istio-system get pod -o wide |grep ingressgateway
istio-ingressgateway-75d6d5fd99-m2jnf 1/1 Running 1 6d2h 172.17.0.19
通过该 ingressgateway 访问服务会被禁止:
编辑 handler whitelistip,将 172.17 网段加入白名单后,就可以访问了:
$ kubectl edit handler whitelistip
...省略...
spec:
compiledAdapter: listchecker
params:
blacklist: false
entryType: IP_ADDRESSES
overrides:
- 10.57.0.0/16
- 172.17.0.0/16
...
istio 限速策略
istio 的 限速功能 用起来相当繁琐,用到 handler、instance、QuotaSpec、QuotaSpecBinding 和 rule 总共 5 个 CRD。(这么繁琐,想吐槽... 2019-11-27 18:36:29)
$ kubectl apply -f samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml
instance 定义了度量的维度,后面的 handler 会使用这些维度属性:
apiVersion: config.istio.io/v1alpha2
kind: instance
metadata:
name: requestcountquota
namespace: istio-system
spec:
compiledTemplate: quota
params:
dimensions:
source: request.headers["x-forwarded-for"] | "unknown"
destination: destination.labels["app"] | destination.service.name | "unknown"
destinationVersion: destination.labels["version"] | "unknown"
handler 定义了基于内存的请求配额管理策略(memquota,众多配额管理器中的一种),设置了限速规则:
apiVersion: config.istio.io/v1alpha2
kind: handler
metadata:
name: quotahandler
namespace: istio-system
spec:
compiledAdapter: memquota
params:
quotas:
- name: requestcountquota.instance.istio-system
maxAmount: 500
validDuration: 1s
# The first matching override is applied.
# A requestcount instance is checked against override dimensions.
overrides:
# The following override applies to 'reviews' regardless
# of the source.
- dimensions:
destination: reviews
maxAmount: 1
validDuration: 5s
# The following override applies to 'productpage' when
# the source is a specific ip address.
- dimensions:
destination: productpage
source: "10.28.11.20"
maxAmount: 500
validDuration: 1s
# The following override applies to 'productpage' regardless
# of the source.
- dimensions:
destination: productpage
maxAmount: 2
validDuration: 5s
rule 设置了限速的范围,对符合条件的请求启用限速:
apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
name: quota
namespace: istio-system
spec:
# quota only applies if you are not logged in.
# match: match(request.headers["cookie"], "user=*") == false
actions:
- handler: quotahandler
instances:
- requestcountquota
QuotaSpec 是分配的限速配额,它将被绑定到要被限速的服务:
apiVersion: config.istio.io/v1alpha2
kind: QuotaSpec
metadata:
name: request-count
namespace: istio-system
spec:
rules:
- quotas:
- charge: 1
quota: requestcountquota
QuotaSpecBinding 将限速配额与目标服务绑定:
apiVersion: config.istio.io/v1alpha2
kind: QuotaSpecBinding
metadata:
name: request-count
namespace: istio-system
spec:
quotaSpecs:
- name: request-count
namespace: istio-system
services:
- name: productpage
namespace: default
# - service: '*' # Uncomment this to bind *all* services to request-count
这些配置的最终效果是:
productpage 的访问频率限制为 5 秒 2 次,如源头 IP 是 10.28.11.20,访问限速为 500次/s。
reviews 的访问频率限制为 5 秒 1 次。
其它服务的访问频率限制为 500 次/s