istio.io/content_zh/docs/tasks/security/mtls-migration/index.md

6.4 KiB
Raw Blame History

title description weight keywords
双向 TLS 的迁移 如何渐进式的为现有 Istio 服务添加双向 TLS 支持。 80
security
authentication
migration

本文任务展示了如何在不中断通信的情况下,把现存 Istio 服务的流量从明文升级为双向 TLS

在实际情况中,集群中可能包含 Istio 服务(注入了 Envoy sidecar以及非 Istio 服务(没有注入 Envoy sidecar 的服务,下文简称为存量服务)。存量服务无法使用 Istio 签发的密钥/证书来进行双向 TLS 通信。我们希望安全的、渐进的启用双向 TLS。

开始之前

  • 理解 Istio 认证策略以及相关的双向 TLS 认证概念。

  • 已成功在 Kubernetes 集群中部署 Istio并且没有启用双向 TLS 支持(也就是使用安装步骤中所说的 install/kubernetes/istio-demo.yaml 进行部署,或者在 Helm 安装时设置 global.mtls.enabled 的值为 false

  • 为了演示目的,创建三个命名空间,分别是 foobar 以及 legacy,然后在 foobar 中分别部署注入 Istio sidecar 的 [httpbin]({{< github_tree >}}/samples/httpbin) 以及 [sleep]({{< github_tree >}}/samples/sleep) 应用,最后在 legacy 命名空间中运行未经注入的 sleep 应用。

    {{< text bash >}} $ kubectl create ns foo $ kubectl apply -f <(istioctl kube-inject -f @samples/httpbin/httpbin.yaml@) -n foo $ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@) -n foo $ kubectl create ns bar $ kubectl apply -f <(istioctl kube-inject -f @samples/httpbin/httpbin.yaml@) -n bar $ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@) -n bar $ kubectl create ns legacy $ kubectl apply -f @samples/sleep/sleep.yaml@ -n legacy {{< /text >}}

  • 检查部署情况:从任意一个命名空间选一个 sleep pod发送 http 请求到 httpbin.foo。所有的请求都应该能返回 HTTP 200。

    {{< text bash >}} for from in "foo" "bar" "legacy"; do kubectl exec(kubectl get pod -l app=sleep -n {from} -o jsonpath={.items..metadata.name}) -c sleep -n {from} -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.foo: %{http_code}\n"; done sleep.foo to httpbin.foo: 200 sleep.bar to httpbin.foo: 200 sleep.legacy to httpbin.foo: 200 {{< /text >}}

  • 确认系统中不存在认证策略和目标规则:

    {{< text bash >}} $ kubectl get policies.authentication.istio.io --all-namespaces No resources found. $ kubectl get destinationrule --all-namespaces No resources found. {{< /text >}}

配置服务器使其同时能接收双向 TLS 以及明文流量

在认证策略中有一个 PERMISSIVE 模式,这种模式让服务器能够同时接收明文和双向 TLS 流量。下面就把服务器设置为这种模式:

{{< text bash >}} $ cat <<EOF | istioctl create -n foo -f - apiVersion: "authentication.istio.io/v1alpha1" kind: "Policy" metadata: name: "example-httpbin-permissive" namespace: foo spec: targets:

  • name: httpbin peers:
  • mtls: mode: PERMISSIVE EOF {{< /text >}}

接下来再次发送流量到 httpbin.foo,确认所有请求依旧成功。

{{< text bash >}} for from in "foo" "bar" "legacy"; do kubectl exec(kubectl get pod -l app=sleep -n {from} -o jsonpath={.items..metadata.name}) -c sleep -n {from} -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.foo: %{http_code}\n"; done 200 200 200 {{< /text >}}

配置客户端进行双向 TLS 通信

利用设置 DestinationRule 的方式,让 Istio 服务进行双向 TLS 通信。

{{< text bash >}} $ cat <<EOF | istioctl create -n foo -f - apiVersion: "networking.istio.io/v1alpha3" kind: "DestinationRule" metadata: name: "example-httpbin-istio-client-mtls" spec: host: httpbin.foo.svc.cluster.local trafficPolicy: tls: mode: ISTIO_MUTUAL EOF {{< /text >}}

这样一来,sleep.foosleep.bar 就会开始使用双向 TLS 和 httpbin.foo 进行通信了。而 sleep.legacy 因为没有进行 sidecar 注入,因此不受 DestinationRule 配置影响,还是会使用明文和 httpbin.foo 通信。

现在复查一下,所有到 httpbin.foo 的通信是否依旧成功:

{{< text bash >}} for from in "foo" "bar" "legacy"; do kubectl exec(kubectl get pod -l app=sleep -n {from} -o jsonpath={.items..metadata.name}) -c sleep -n {from} -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.foo: %{http_code}\n"; done 200 200 200 {{< /text >}}

还可以在 DestinationRule 中指定一个客户端的子集所发出的请求来是用双向 TLS 通信,然后使用 Grafana 验证配置执行情况,确认通过之后,将策略的应用范围扩大到该服务的所有子集。

锁定使用双向 TLS (可选)

把所有进行过 sidecar 注入的客户端到服务器流量都迁移到双向 TLS 之后,就可以设置 httpbin.foo 只支持双向 TLS 流量了。

{{< text bash >}} $ cat <<EOF | istioctl create -n foo -f - apiVersion: "authentication.istio.io/v1alpha1" kind: "Policy" metadata: name: "example-httpbin-permissive" namespace: foo spec: targets:

  • name: httpbin peers:
  • mtls: mode: STRICT EOF {{< /text >}}

这样设置之后,sleep.legacy 的请求就会失败。

{{< text bash >}} for from in "foo" "bar" "legacy"; do kubectl exec(kubectl get pod -l app=sleep -n {from} -o jsonpath={.items..metadata.name}) -c sleep -n {from} -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.foo: %{http_code}\n"; done 200 200 503 {{< /text >}}

也就是说,如果不能把所有服务都迁移到 Istio (进行 Sidecar 注入)的话,就只能使用 PERMISSIVE 模式了。然而在配置为 PERMISSIVE 的时候,是不会对明文流量进行授权和鉴权方面的检查的。我们推荐使用 RBAC 来给不同的路径配置不同的授权策略。

清理

移除所有资源

{{< text bash >}} $ kubectl delete ns foo bar legacy Namespaces foo bar legacy deleted. {{< /text >}}