第十三节 Mixer 适配器的应用(简介/Denier访问控制/Listchecker访问控制)
Istio 除了提供了丰富的流量控制功能,还通过Mixer:提供了可扩展的外接功能。
Mixer“知晓”每一次服务间的调用过程,这些调用过程会为Mixer:提供丰富的相关信息,Mixer通过接人的适配器对这些信息进行处理,能够在调用的预检(执行前)和报告(执行后)阶段执行多种任务
并且Mixer的适配器模型是可以扩充的,这也赋予了Mixer更大的扩展能力。 
1、Mixer适配器简介
Mixer:中现有的适配器大致可以分为以下两类。
- 一类是
Istio内部实现的适配器,用于完成网格的内部功能,例如Fluentd、Stdio、RedisQuota等。 - 另一类是第三方服务的适配器,用于和外部系统进行对接,例如
DataDog、StackDriver等。 
本章同样从应用场景出发,介绍在Istio中使用Mixer:能够完成的各种任务,只涉及网格内部功能相关的适配器,如下所述。 
Denier:根据自定义条件判断是否拒绝服务。Fluentd: 向Fluentd服务提交日志。List:用于执行白名单或者黑名单检查。MemQuota:以内存为存储后端,提供简易的配额控制功能。Prometheus:为Prometheus提供Istio的监控指标。RedisQuota:基于Redis存储后端,提供配额管理功能。StatsD:向StatsD发送监控指标。Stdio:用于在本地输出日志和指标。
Mixer:的配置通常由以下三部分组成。 
Handler: 声明一个适配器的配置Instance: 声明一个模板,用模板将传给Mixer的数据转换为特定适配器的输出格式Rule: 将Instance和Hanlder连接起来, 确认处理关系
2、 基于Denier适配器的访问控制
本节会利用Denier适配器为httpbin服务创建一个Rule对象,该对象会阻止来自sleep 服务的v1版本的请求。
要使用Denier适配器, 则首先要定义它的个Handler,每个适配器都会自己的配置格式,可前往官方网站(https://istio.io/docs/reference/config/policy-and-telemetry/adapters/)进行查询。
本节为Denier:适配器定义的Handler结构很简单,仅包含一个错误码和消息: 
apiVersion: "config.istio.io/v1alpha2" 
kind: denier 
metadata: 
  name: code-7 
spec: 
  status: 
    code: 7 
    message: Not allowed 
这段代码意味着:如果有流量的预检请求通过Rule对象传递给了这个Handler就会调用失败,返回错误码7及错误信急Not allowed。
将其保存为denier.yaml 然后使用kubectl apply命令提交到Kubernetes集群 
$ kubectl apply -f denier.yaml 
denier.config.istio.io/code-7 created
我们现在只想禁止一个sleep服务的v1版本.仅通过Rule对象的match字段匹配即可因此可以使用一个checknonting的校板来定义输入.就是说无须对进入的数据进行检查 
apiVersion: "config.istio.io/v1alpha2" 
kind: checknothing 
metadata: 
  name: place-holder 
spec: 
checknothing的模板因为没做任何处理.所以也是相当简单的将其深存为checknothing.yaml并使用kubectl apply命令提交到Kubernetes集群 
$ kubectl apply -f checknonthing.yaml --validate=false
checknothing.config.istio.io/place-holder created
接下来就可以创建一个Rule对象把二者连接起来编辑denier.rule.yaml
apiVersion: "config.istio.io/v1alpha2" 
kind: rule 
metadata: 
  name: deny-sleep-v1-to-httpbin 
spec: 
  match: destination.labels["app"] == "httpbin" && source.labels["app"] == "sleep" && source.labels["version"] == "v1"
  actions: 
  - handler: code-7.denier 
    instances: place-holder.checknothing
注意,在instance和handler两个宇段中引用对象的方式为一名称.类型
handler: code-7.denier 
instances: [place-holder.checknothing]
在match字段中使用源和目标的标签时服进行鉴别、整个表达式实现了对来自Sleep服务的v1版本向httpbin服务发起调用的流量的识别
$ kubectl apply -f denier.rule.yaml 
rule.config.istio.io/deny-sleep-v1-to-httpbin created
$ kubectl exec -it sleep-v1-548d87cc5c-92lqk -c sleep bash
bash-4.4# http --body http://httpbin:8000/ip
PERMISSION DENIED:code一7.denier.defau1t:Not allowed
$ kubectl exec -it sleep-v2-7c6b874968-dx6ll -c sleep bash
bash-4.4# http --body http://httpbin:8000/ip
{
    "origin": "127.0.0.1"
}
测试结果表明,从sleep服务的v1版本向httpbin服务发起i请求,会失败且返回"PERMISSION DENIED:code一7.denier.defau1t:Not allowed" ,
从sleep服务的v2版本向httpbin服务发起请求,就会正常返回结果。 
为了后续内容的继续进行,删除刚刚创建的三个对象:
$ kubectl delete -f denier.rule.yaml -f checknonthing.yaml -f denier.yaml 
rule.config.istio.io "deny-sleep-v1-to-httpbin" deleted
checknothing.config.istio.io "place-holder" deleted
denier.config.istio.io "code-7" deleted
3、 基于Listchecker适配器的访问控制
上面提供的Denier适配器的访问控制是比较死板的,表达式修改也稍显烦琐,如果想使用更灵活的控制方式,则可以使用Listchecker适配器。 
在Listechecker适配器中会保存一个列表,并可以声明这一列表是黑名单还是白名单,在有数据输入后,首先判断该数据是否属于列表成员,然后根据列表的黑名单或白名单属性来返回是否许可此次调用。

然后就可以创建一系列对象来验证这一列表是否正确了。为Listchecker适配器创建一个Handler对象,其中的数据定义来自表的第1行: 
apiVersion: config.istio.io/v1alpha2 
kind: listchecker 
metadata:
  name: chaos 
spec: 
  overrides: ["v1", "v3"] 
  blacklist: true
$ kubectl apply -f chaos-listchcker.yaml 
listchecker.config.istio.io/chaos created
在上面的代码中使用了overrides字段保存一个列表用于检查并在blacklist字段声明这一列表为黑名单。
Listchecker适配器还可以使用providerUrl字段引用一个远程列表并定时更新,以获得更大的灵话性
接下来使用listentry模板从输入数据中提取内容并输出给Listchecker适配器。将下面代码保存为version.listentry.yaml
apiVersion: config.istio.io/v1alpha2 
kind: listentry 
metadata:
  name: version 
spec: 
  value: source.labels["version"]
listentry只有value一个字段在其中用表达式从输入数据中提取内容进行后续输出
$ kubectl apply -f version.listentry.yaml 
listentry.config.istio.io/version created
最后创建Rule对象将Instance和 Handler 连接在一起这为httpbin的流址进行测试: 
apiVersion: config.istio.io/v1alpha2 
kind: rule 
metadata:
  name: checkversion 
spec: 
  match: destination.labels["app"] == "httpbin" 
  actions: 
  - handler: chaos.listchecker 
    instances: 
      - version.listentry
listentry.rule.yaml
$ kubectl apply -f listentry.rule.yaml 
rule.config.istio.io/checkversion created
现在Handler、 Instance, 及Rule三个对象都已经创建完毕了.我们可以进行测试了: 
$ kubectl exec -it sleep-v1-548d87cc5c-92lqk -c sleep bash
bash-4.4# http --body http://httpbin:8000/ip
PERMISSION DENIED:chaos.Iistchecker.default:v1 is blacklisted
$ kubectl exec -it sleep-v2-7c6b874968-dx6ll -c sleep bash
bash-4.4# http --body http://httpbin:8000/ip
{
    "origin": "127.0.0.1"
}
可以看到,在使用sleep Pod的v1版本访间httpbin服务时,访问被拒绝,出现错误信息"PERMISSION DENIED:chaos.Iistchecker.default:v1 is blacklisted;
而从sleep服务的v2版本进行访问时就可以成功返回向应的内容要验证白名单也很简单、只要把chaos.listchecker.yaml中的blacklist: true改成 blacklist: false.然后重新提交即可。
再次执行测试:
apiVersion: config.istio.io/v1alpha2 
kind: listchecker 
metadata:
  name: chaos 
spec: 
  overrides: ["v1", "v3"] 
  blacklist: false
$ kubectl apply -f chaos-listchcker.yaml 
listchecker.config.istio.io/chaos configured
$ kubectl exec -it sleep-v1-548d87cc5c-92lqk -c sleep bash
bash-4.4# http --body http://httpbin:8000/ip
{
    "origin": "127.0.0.1"
}
$ kubectl exec -it sleep-v2-7c6b874968-dx6ll -c sleep bash
bash-4.4# http --body http://httpbin:8000/ip
NOT FOUND:chaoslistchecker.default:v2 is not whitelisted
在Listchecker适配器更新之后进行新一轮测试,可以看到测试结果发生了变化, 与中的3:4行一致
sleep服务的v2版本向httpbin发出的访问被拒绝,返回信息为
NOT FOUND:chaoslistchecker.default:v2 is not whitelisted