Egress TLS 流量中的 SNI 监控及策略

使用通配符主机配置 Egress 流量示例中描述了为 *.wikipedia.org 这样的域名启用 Egress 流量 TLS 支持的方法。本示例中将演示的是如何为 Egress TLS 流量配置 SNI 监控并应用策略。

开始之前

  • 按照安装指南中的说明安装 Istio。

  • 部署 sleep 示例,以获取发送请求的测试源。 如果您启用了 自动 sidecar 注入,请执行

    Zip
    $ kubectl apply -f @samples/sleep/sleep.yaml@
    

    否则,在部署 sleep 应用程序前,您必须手动注入 sidecar:

    Zip
    $ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@)
    
  • 为了发送请求,您需要创建 SOURCE_POD 环境变量来存储源 pod 的名称:

    $ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
    

SNI 监控和访问策略

通过配置,让 Egress 流量流入 Egress 网关之后,就可以对其实施安全的监控和策略管理了。在本节中,会为 *.wikipedia.org 定义一个 LogEntry 以及访问策略。

  1. 创建日志配置:

    Zip
    $ kubectl apply -f @samples/sleep/telemetry/sni-logging.yaml@
    
  2. https://en.wikipedia.orghttps://de.wikipedia.org 发起 HTTPS 访问:

    $ kubectl exec -it $SOURCE_POD -c sleep -- sh -c 'curl -s https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"; curl -s https://de.wikipedia.org/wiki/Wikipedia:Hauptseite | grep -o "<title>.*</title>"'
    <title>Wikipedia, the free encyclopedia</title>
    <title>Wikipedia – Die freie Enzyklopädie</title>
    
  3. 检查 Mixer 日志。如果 Istio 部署在 istio-system 命名空间,可以用如下命令:

    $ kubectl -n istio-system logs -l istio-mixer-type=telemetry -c mixer | grep 'egress-access'
    
  4. 定义一条策略,允许访问主机名符合 *.wikipedia.org 规则的主机,但是排除英文版:

    Zip
    $ kubectl apply -f @samples/sleep/policy/sni-wikipedia.yaml@
    
  5. 向黑名单中的英文版 Wikipedia

    $ kubectl exec -it $SOURCE_POD -c sleep -- sh -c 'curl -v https://en.wikipedia.org/wiki/Main_Page'
    ...
    curl: (35) Unknown SSL protocol error in connection to en.wikipedia.org:443
    command terminated with exit code 35
    

    对英文版 Wikipedia 的访问会被策略拒绝。

  6. 向其它 Wikipedia 站点发送 HTTPS 请求,例如 https://es.wikipedia.orghttps://de.wikipedia.org

    $ kubectl exec -it $SOURCE_POD -c sleep -- sh -c 'curl -s https://es.wikipedia.org/wiki/Wikipedia:Portada | grep -o "<title>.*</title>"; curl -s https://de.wikipedia.org/wiki/Wikipedia:Hauptseite | grep -o "<title>.*</title>"'
    <title>Wikipedia, la enciclopedia libre</title>
    <title>Wikipedia – Die freie Enzyklopädie</title>
    

    和我们计划的一样,其它语言的 Wikipedia 站点是可以访问的。

清理监控和策略定义

ZipZip
$ kubectl delete -f @samples/sleep/telemetry/sni-logging.yaml@
$ kubectl delete -f @samples/sleep/policy/sni-wikipedia.yaml@

监控 SNI 和源身份,并据此作出访问控制

因为已经在 Sidecar 之间、Sidecar 和 Egress 网关之间启用了双向 TLS,所以就有办法对访问外部的应用的服务身份进行监控和策略控制了。在 Kubernetes 上运行的 Istio,其身份是建立在 Service Accounts 基础之上的。这一节中将会部署两个 sleep 容器,sleep-ussleep-canada,各自用不同的 Service account 运行。然后定义一个策略,允许 sleep-us 的身份访问英文和西班牙文版本的维基百科,而 sleep-canada 身份的应用可以访问英文和法文版。

  1. 部署两个 sleep 容器,sleep-ussleep-canada,各自使用各自的同名 Service account 运行:

    ZipZip
    $ sed 's/: sleep/: sleep-us/g' @samples/sleep/sleep.yaml@ | kubectl apply -f -
    $ sed 's/: sleep/: sleep-canada/g' @samples/sleep/sleep.yaml@ | kubectl apply -f -
    serviceaccount "sleep-us" created
    service "sleep-us" created
    deployment "sleep-us" created
    serviceaccount "sleep-canada" created
    service "sleep-canada" created
    deployment "sleep-canada" created
    
  2. 创建日志配置:

    Zip
    $ kubectl apply -f @samples/sleep/telemetry/sni-logging.yaml@
    
  3. sleep-us 向英文、德文、西班牙文和法文版本的维基百科分别发送 HTTPS 请求:

    $ kubectl exec -it $(kubectl get pod -l app=sleep-us -o jsonpath='{.items[0].metadata.name}') -c sleep-us -- sh -c 'curl -s https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"; curl -s https://de.wikipedia.org/wiki/Wikipedia:Hauptseite | grep -o "<title>.*</title>"; curl -s https://es.wikipedia.org/wiki/Wikipedia:Portada | grep -o "<title>.*</title>"; curl -s https://fr.wikipedia.org/wiki/Wikip%C3%A9dia:Accueil_principal | grep -o "<title>.*</title>"'
    <title>Wikipedia, the free encyclopedia</title>
    <title>Wikipedia – Die freie Enzyklopädie</title>
    <title>Wikipedia, la enciclopedia libre</title>
    <title>Wikipédia, l'encyclopédie libre</title>
    
  4. 查看 Mixer 日志。如果 Istio 部署在 istio-system 命名空间,可以使用如下命令:

    $ kubectl -n istio-system logs -l istio-mixer-type=telemetry -c mixer | grep 'egress-access'
    {"level":"info","time":"2019-01-10T17:33:55.559093Z","instance":"egress-access.instance.istio-system","connectionEvent":"open","destinationApp":"","requestedServerName":"en.wikipedia.org","source":"istio-egressgateway-with-sni-proxy","sourceNamespace":"default","sourcePrincipal":"cluster.local/ns/default/sa/sleep-us","sourceWorkload":"istio-egressgateway-with-sni-proxy"}
    {"level":"info","time":"2019-01-10T17:33:56.166227Z","instance":"egress-access.instance.istio-system","connectionEvent":"open","destinationApp":"","requestedServerName":"de.wikipedia.org","source":"istio-egressgateway-with-sni-proxy","sourceNamespace":"default","sourcePrincipal":"cluster.local/ns/default/sa/sleep-us","sourceWorkload":"istio-egressgateway-with-sni-proxy"}
    {"level":"info","time":"2019-01-10T17:33:56.779842Z","instance":"egress-access.instance.istio-system","connectionEvent":"open","destinationApp":"","requestedServerName":"es.wikipedia.org","source":"istio-egressgateway-with-sni-proxy","sourceNamespace":"default","sourcePrincipal":"cluster.local/ns/default/sa/sleep-us","sourceWorkload":"istio-egressgateway-with-sni-proxy"}
    {"level":"info","time":"2019-01-10T17:33:57.413908Z","instance":"egress-access.instance.istio-system","connectionEvent":"open","destinationApp":"","requestedServerName":"fr.wikipedia.org","source":"istio-egressgateway-with-sni-proxy","sourceNamespace":"default","sourcePrincipal":"cluster.local/ns/default/sa/sleep-us","sourceWorkload":"istio-egressgateway-with-sni-proxy"}
    

    注意 requestedServerName 属性,以及 sourcePrincipal,应取值为 cluster.local/ns/default/sa/sleep-us

  5. 定义一条策略,允许 sleep-us Service account 访问英文和西班牙版本的维基百科;而 sleep-canada 则可以访问英文和法文版本的维基百科。对其它语言的访问会被拦截。

    Zip
    $ kubectl apply -f @samples/sleep/policy/sni-serviceaccount.yaml@
    
  6. sleep-us 发送 HTTPS 流量到英文、德文、西班牙文和法文版本的维基百科:

    $ kubectl exec -it $(kubectl get pod -l app=sleep-us -o jsonpath='{.items[0].metadata.name}') -c sleep-us -- sh -c 'curl -s https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"; curl -s https://de.wikipedia.org/wiki/Wikipedia:Hauptseite | grep -o "<title>.*</title>"; curl -s https://es.wikipedia.org/wiki/Wikipedia:Portada | grep -o "<title>.*</title>"; curl -s https://fr.wikipedia.org/wiki/Wikip%C3%A9dia:Accueil_principal | grep -o "<title>.*</title>";:'
    <title>Wikipedia, the free encyclopedia</title>
    <title>Wikipedia, la enciclopedia libre</title>
    

    会看到 sleep-us 身份允许访问英文和西班牙版本。

    $ kubectl delete pod -n istio-system -l istio-mixer-type=policy
    
  7. sleep-canada 发送 HTTPS 流量到英文、德文、西班牙文和法文版本的维基百科:

    $ kubectl exec -it $(kubectl get pod -l app=sleep-canada -o jsonpath='{.items[0].metadata.name}') -c sleep-canada -- sh -c 'curl -s https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"; curl -s https://de.wikipedia.org/wiki/Wikipedia:Hauptseite | grep -o "<title>.*</title>"; curl -s https://es.wikipedia.org/wiki/Wikipedia:Portada | grep -o "<title>.*</title>"; curl -s https://fr.wikipedia.org/wiki/Wikip%C3%A9dia:Accueil_principal | grep -o "<title>.*</title>";:'
    <title>Wikipedia, the free encyclopedia</title>
    <title>Wikipédia, l'encyclopédie libre</title>
    

    会看到 sleep-us 身份允许访问英文和法文版本。

清理基于 SNI 和源身份的监控和访问策略对象

ZipZip
$ kubectl delete service sleep-us sleep-canada
$ kubectl delete deployment sleep-us sleep-canada
$ kubectl delete serviceaccount sleep-us sleep-canada
$ kubectl delete -f @samples/sleep/telemetry/sni-logging.yaml@
$ kubectl delete -f @samples/sleep/policy/sni-serviceaccount.yaml@

清理

  1. 执行 使用通配符主机配置 Egress 流量例子中的清理任意域名的通配符配置步骤。

  2. 停止 sleep 服务:

    Zip
    $ kubectl delete -f @samples/sleep/sleep.yaml@