自动双向 TLS

本任务通过一个简化的工作流,展示如何使用双向 TLS。

借助 Istio 的自动双向 TLS 特性,您只需配置认证策略即可使用双向 TLS,而无需关注目标规则。

Istio 跟踪迁移到 sidecar 的服务端工作负载,并将客户端 sidecar 配置为自动向这些工作负载发送双向 TLS 流量,同时将明文流量发送到没有 sidecar 的工作负载。这使您可以通过最少的配置,逐步在网格中使用双向 TLS。

开始之前

  • 理解 Istio 认证策略和关于双向 TLS 认证章节的内容。

  • 安装 Istio 时,配置 global.mtls.enabled 选项为 false,global.mtls.auto 选项为 true。以安装 demo 配置文件为例:

  1. $ istioctl manifest apply --set profile=demo \
  2. --set values.global.mtls.auto=true \
  3. --set values.global.mtls.enabled=false

操作指南

安装

本例中,我们部署 httpbin 服务到 fullpartiallegacy 三个命名空间中,分别代表 Istio 迁移的不同阶段。

命名空间 full 包含已完成 Istio 迁移的所有服务器工作负载。每一个部署都有 Sidecar 注入。

ZipZip

  1. $ kubectl create ns full
  2. $ kubectl apply -f <(istioctl kube-inject -f @samples/httpbin/httpbin.yaml@) -n full
  3. $ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@) -n full

命名空间 partial 包含部分迁移到 Istio 的服务器工作负载。只有完成迁移的服务器工作负载(由于已注入 Sidecar)能够使用双向 TLS 流量。

Zip

  1. $ kubectl create ns partial
  2. $ kubectl apply -f <(istioctl kube-inject -f @samples/httpbin/httpbin.yaml@) -n partial
  3. $ cat <<EOF | kubectl apply -n partial -f -
  4. apiVersion: apps/v1
  5. kind: Deployment
  6. metadata:
  7. name: httpbin-nosidecar
  8. spec:
  9. replicas: 1
  10. selector:
  11. matchLabels:
  12. app: httpbin
  13. template:
  14. metadata:
  15. labels:
  16. app: httpbin
  17. version: nosidecar
  18. spec:
  19. containers:
  20. - image: docker.io/kennethreitz/httpbin
  21. imagePullPolicy: IfNotPresent
  22. name: httpbin
  23. ports:
  24. - containerPort: 80
  25. EOF

命名空间 legacy 中的工作负载,都没有注入 Sidecar。

ZipZip

  1. $ kubectl create ns legacy
  2. $ kubectl apply -f @samples/httpbin/httpbin.yaml@ -n legacy
  3. $ kubectl apply -f @samples/sleep/sleep.yaml@ -n legacy

接着,我们部署两个 sleep 工作负载,一个有 Sidecar,另一个没有。

ZipZip

  1. $ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@) -n full
  2. $ kubectl apply -f @samples/sleep/sleep.yaml@ -n legacy

您可以确认在所有命名空间部署完成。

  1. $ kubectl get pods -n full
  2. $ kubectl get pods -n partial
  3. $ kubectl get pods -n legacy
  4. NAME READY STATUS RESTARTS AGE
  5. httpbin-dcd949489-5cndk 2/2 Running 0 39s
  6. sleep-58d6644d44-gb55j 2/2 Running 0 38s
  7. NAME READY STATUS RESTARTS AGE
  8. httpbin-6f6fc94fb6-8d62h 1/1 Running 0 10s
  9. httpbin-dcd949489-5fsbs 2/2 Running 0 12s
  10. NAME READY STATUS RESTARTS AGE
  11. httpbin-54f5bb4957-lzxlg 1/1 Running 0 6s
  12. sleep-74564b477b-vb6h4 1/1 Running 0 4s

您还需验证系统中是否存在默认的网格验证策略,可以参考下面操作:

  1. $ kubectl get policies.authentication.istio.io --all-namespaces
  2. $ kubectl get meshpolicies -o yaml | grep ' mode'
  3. NAMESPACE NAME AGE
  4. istio-system grafana-ports-mtls-disabled 2h
  5. mode: PERMISSIVE

最后但并非最不重要的一点是,确认没有应用于示例服务的目标规则。您可以通过检查已有目标规则的 host: 字段,并确保它们没有匹配我们的示例服务。例如:

  1. $ kubectl get destinationrules.networking.istio.io --all-namespaces -o yaml | grep "host:"
  2. host: istio-policy.istio-system.svc.cluster.local
  3. host: istio-telemetry.istio-system.svc.cluster.local

您可通过使用 curl 从命名空间 fullpartiallegacy 中的任一 sleep Pod 发送 HTTP 请求到 httpbin.fullhttpbin.partialhttpbin.legacy 以验证安装。所有的请求都应成功返回 HTTP 200 状态码。

例如,这是一个检查 sleep.fullhttpbin.full 可达性的命令:

  1. $ kubectl exec $(kubectl get pod -l app=sleep -n full -o jsonpath={.items..metadata.name}) -c sleep -n full -- curl http://httpbin.full:8000/headers -s -w "response %{http_code}\n" | egrep -o 'URI\=spiffe.*sa/[a-z]*|response.*$'
  2. URI=spiffe://cluster.local/ns/full/sa/sleep
  3. response 200

SPIFFE URI 显示来自 X509 证书的客户端标识,它表明流量是在双向 TLS 中发送的。如果流量为明文,将不会显示客户端证书。

从 PERMISSIVE 模式开始

这里,我们从开启网格服务双向 TLS 的 PERMISSIVE 模式开始。

  • 所有的 httpbin.full 工作负载以及在 httpbin.partial 中使用了 Sidecar 的工作负载都能够使用双向 TLS 和明文流量。

  • 命名空间 httpbin.partial 中没有 Sidecar 的服务和 httpbin.legacy 中的服务都只能使用明文流量。

自动双向 TLS 将客户端和 sleep.full 配置为可将双向 TLS 流量发送到具有 Sidecar 的工作负载,明文流量发送到没有 Sidecar 的工作负载。

您可以通过以下方式验证可达性:

  1. $ for from in "full" "legacy"; do for to in "full" "partial" "legacy"; do echo "sleep.${from} to httpbin.${to}";kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl http://httpbin.${to}:8000/headers -s -w "response code: %{http_code}\n" | egrep -o 'URI\=spiffe.*sa/[a-z]*|response.*$'; echo -n "\n"; done; done
  2. sleep.full to httpbin.full
  3. URI=spiffe://cluster.local/ns/full/sa/sleep
  4. response code: 200
  5. sleep.full to httpbin.partial
  6. URI=spiffe://cluster.local/ns/full/sa/sleep
  7. response code: 200
  8. sleep.full to httpbin.legacy
  9. response code: 200
  10. sleep.legacy to httpbin.full
  11. response code: 200
  12. sleep.legacy to httpbin.partial
  13. response code: 200
  14. sleep.legacy to httpbin.legacy
  15. response code: 200

使用 Sidecar 迁移

无论工作负载是否带有 Sidecar,对 httpbin.partial 的请求都可以到达。Istio 自动将 sleep.full 客户端配置为使用双向 TLS 连接带有 Sidecar 的工作负载。

  1. $ for i in `seq 1 10`; do kubectl exec $(kubectl get pod -l app=sleep -n full -o jsonpath={.items..metadata.name}) -c sleep -nfull -- curl http://httpbin.partial:8000/headers -s -w "response code: %{http_code}\n" | egrep -o 'URI\=spiffe.*sa/[a-z]*|response.*$'; echo -n "\n"; done
  2. URI=spiffe://cluster.local/ns/full/sa/sleep
  3. response code: 200
  4. response code: 200
  5. URI=spiffe://cluster.local/ns/full/sa/sleep
  6. response code: 200
  7. response code: 200
  8. URI=spiffe://cluster.local/ns/full/sa/sleep
  9. response code: 200
  10. URI=spiffe://cluster.local/ns/full/sa/sleep
  11. response code: 200
  12. response code: 200
  13. URI=spiffe://cluster.local/ns/full/sa/sleep
  14. response code: 200
  15. response code: 200
  16. response code: 200

如果不使用自动双向 TLS,您必须跟踪 Sidecar 迁移完成情况,然后显式的配置目标规则,使客户端发送双向 TLS 流量到 httpbin.full

锁定双向 TLS 为 STRICT 模式

您可配置认证策略为 STRICT,以锁定 httpbin.full 服务仅接收双向 TLS 流量。

  1. $ cat <<EOF | kubectl apply -n full -f -
  2. apiVersion: "authentication.istio.io/v1alpha1"
  3. kind: "Policy"
  4. metadata:
  5. name: "httpbin"
  6. spec:
  7. targets:
  8. - name: httpbin
  9. peers:
  10. - mtls: {}
  11. EOF

All httpbin.full workloads and the workload with sidecar for httpbin.partial can only servemutual TLS traffic.

所有 httpbin.full 工作负载和带有 Sidecar 的 httpbin.partial 都只可使用双向 TLS 流量。

现在来自 sleep.legacy 的请求将开始失败,因为其不支持发送双向 TLS 流量。但是客户端 sleep.full 的请求将仍可成功返回 200 状态码,因为它已配置为自动双向 TLS,并且发送双向 TLS 请求。

  1. $ for from in "full" "legacy"; do for to in "full" "partial" "legacy"; do echo "sleep.${from} to httpbin.${to}";kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl http://httpbin.${to}:8000/headers -s -w "response code: %{http_code}\n" | egrep -o 'URI\=spiffe.*sa/[a-z]*|response.*$'; echo -n "\n"; done; done
  2. sleep.full to httpbin.full
  3. URI=spiffe://cluster.local/ns/full/sa/sleep
  4. response code: 200
  5. sleep.full to httpbin.partial
  6. URI=spiffe://cluster.local/ns/full/sa/sleep
  7. response code: 200
  8. sleep.full to httpbin.legacy
  9. response code: 200
  10. sleep.legacy to httpbin.full
  11. response code: 000
  12. command terminated with exit code 56
  13. sleep.legacy to httpbin.partial
  14. response code: 200
  15. sleep.legacy to httpbin.legacy
  16. response code: 200

禁用双向 TLS 以启用明文传输

如果出于某种原因,您希望服务显式地处于明文模式,则可以将身份验证策略配置为明文。

  1. $ cat <<EOF | kubectl apply -n full -f -
  2. apiVersion: "authentication.istio.io/v1alpha1"
  3. kind: "Policy"
  4. metadata:
  5. name: "httpbin"
  6. spec:
  7. targets:
  8. - name: httpbin
  9. EOF

在这种情况下,由于服务处于纯文本模式。Istio 自动配置客户端 Sidecar 发送明文流量以避免错误。

  1. $ for from in "full" "legacy"; do for to in "full" "partial" "legacy"; do echo "sleep.${from} to httpbin.${to}";kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl http://httpbin.${to}:8000/headers -s -w "response code: %{http_code}\n" | egrep -o 'URI\=spiffe.*sa/[a-z]*|response.*$'; echo -n "\n"; done; done
  2. sleep.full to httpbin.full
  3. response code: 200
  4. sleep.full to httpbin.partial
  5. response code: 200
  6. sleep.full to httpbin.legacy
  7. response code: 200
  8. sleep.legacy to httpbin.full
  9. response code: 200
  10. sleep.legacy to httpbin.partial
  11. response code: 200
  12. sleep.legacy to httpbin.legacy
  13. response code: 200

现在,所有流量都可以明文传输。

重写目标规则

为了向后兼容,您仍然可以像以前一样使用目标规则来覆盖 TLS 配置。当目标规则具有显式 TLS 配置时,它将覆盖 Sidecar 客户端的 TLS 配置。

例如,您可以显式的为 httpbin.full 配置目标规则,以显式启用或禁用双向 TLS。

  1. $ cat <<EOF | kubectl apply -n full -f -
  2. apiVersion: "networking.istio.io/v1alpha3"
  3. kind: "DestinationRule"
  4. metadata:
  5. name: "httpbin-full-mtls"
  6. spec:
  7. host: httpbin.full.svc.cluster.local
  8. trafficPolicy:
  9. tls:
  10. mode: ISTIO_MUTUAL
  11. EOF

由于在前面的步骤中,我们已经禁用了 httpbin.full 的身份验证策略,以禁用双向 TLS,现在应该看到来自 sleep.full 的流量开始失败。

  1. $ for from in "full" "legacy"; do for to in "full" "partial" "legacy"; do echo "sleep.${from} to httpbin.${to}";kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl http://httpbin.${to}:8000/headers -s -w "response code: %{http_code}\n" | egrep -o 'URI\=spiffe.*sa/[a-z]*|response.*$'; echo -n "\n"; done; done
  2. sleep.full to httpbin.full
  3. response code: 503
  4. sleep.full to httpbin.partial
  5. URI=spiffe://cluster.local/ns/full/sa/sleep
  6. response code: 200
  7. sleep.full to httpbin.legacy
  8. response code: 200
  9. sleep.legacy to httpbin.full
  10. response code: 200
  11. sleep.legacy to httpbin.partial
  12. response code: 200
  13. sleep.legacy to httpbin.legacy
  14. response code: 200

清理

  1. $ kubectl delete ns full partial legacy

摘要

自动双向 TLS 配置 Sidecar 客户端默认情况下在 Sidecar 之间发送 TLS 流量。您只需要配置身份验证策略。

如前所述,自动双向 TLS 是网格 Helm 安装选项。您必须重新安装 Istio 才能启用或禁用该功能。当此功能被禁用,如果您已经依靠它来自动加密流量,则流量可以回退到纯明文模式,这可能会影响您的安全状态或中断流量(如果该服务已配置为 STRICT 模式以仅接收双向 TLS 流量)。

当前,自动双向 TLS 还处于 Alpha 阶段,请注意其风险以及 TLS 加密的额外 CPU 成本。

我们正在考虑将此功能设置为默认启用。当您使用自动双向 TLS 时,请考虑通过 GitHub 发送您的反馈或遇到的问题。

相关内容

Istio 2020——为了商用

Istio 在 2020 年的愿景声明及路线图。

移除跨 pod Unix domain socket

一种更安全的秘密管理方式。

DNS 证书管理

在 Istio 中配置和管理 DNS 证书。

Istio v1beta1 授权策略概述

Istio v1beta1 授权策略的设计原则、基本概述及迁移操作。

安全管理 Webhook

一种更安全管理 Istio webhook 的方法。

用于隔离和边界保护的多网格部署

将需要隔离的环境部署到单独的网格中,并通过网格联邦启用网格间通信。