通过 HTTPS 进行 TLS

这个任务展示了双向 TLS 是如何与 HTTPS 服务一起工作的。它包括:

  • 在没有 Istio sidecar 的情况下部署 HTTPS 服务

  • 关闭 Istio 双向 TLS 情况下部署 HTTPS 服务

  • 部署一个启用双向 TLS 的 HTTPS 服务。对于每个部署,连接到此服务并验证其是否有效。

当 Istio sidecar 与 HTTPS 服务一起部署时,代理将自动从 L7 降至 L4(无论是否启用了双向 TLS),这就意味着它不会终止原来的 HTTPS 通信。这就是为什么 Istio 可以对 HTTPS 服务产生作用。

开始之前

按照快速开始中的说明设置 Istio。 请注意,当使用 demo 配置文件安装 Istio 时,应该禁用默认的双向 TLS 认证。

该演示还假定在一个禁用了自动 sidecar 注入的命名空间中运行,并且使用 istioctl 手动注入 Istio sidecars。

生成证书和 configmap

下面的例子考虑实现一个可以使用 HTTPS 加密流量的 NGINX 服务 pod。 在开始之前,先生成该服务后面会用到的 TLS 证书和密钥。

您需要安装 openssl 来运行如下命令:

  1. $ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/nginx.key -out /tmp/nginx.crt -subj "/CN=my-nginx/O=my-nginx"
  2. $ kubectl create secret tls nginxsecret --key /tmp/nginx.key --cert /tmp/nginx.crt
  3. secret "nginxsecret" created

创建一个该 HTTPS 服务所要用的 configmap

  1. $ kubectl create configmap nginxconfigmap --from-file=samples/https/default.conf
  2. configmap "nginxconfigmap" created

部署一个没有 Istio sidecar 的 HTTPS 服务

本节创建一个基于 NGINX 的 HTTPS 服务。

Zip

  1. $ kubectl apply -f @samples/https/nginx-app.yaml@
  2. service "my-nginx" created
  3. replicationcontroller "my-nginx" created

然后,创建另一个 pod 来调用该服务。

Zip

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

获取 pods

  1. $ kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. my-nginx-jwwck 1/1 Running 0 1h
  4. sleep-847544bbfc-d27jg 2/2 Running 0 18h

通过 ssh 进入 sleep pod 的 istio-proxy 容器。

  1. $ kubectl exec -it $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c istio-proxy /bin/bash

调用 my-nginx

  1. $ curl https://my-nginx -k
  2. ...
  3. <h1>Welcome to nginx!</h1>
  4. ...

其实,您可以将上述三个命令合并为一个:

  1. $ kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c istio-proxy -- curl https://my-nginx -k
  2. ...
  3. <h1>Welcome to nginx!</h1>
  4. ...

创建一个有 Istio sidecar 但禁用双向 TLS 的 HTTPS 服务

在“开始之前”小节中,部署了一个禁用了双向 TLS 的 Istio 控制平面。 因此您只需带着 sidecar 重新部署 NGINX HTTPS 服务。

删除 HTTPS 服务。

Zip

  1. $ kubectl delete -f @samples/https/nginx-app.yaml@

与 sidecar 一起部署

Zip

  1. $ kubectl apply -f <(istioctl kube-inject -f @samples/https/nginx-app.yaml@)

确保该 pod 已经启动且正在运行

  1. $ kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. my-nginx-6svcc 2/2 Running 0 1h
  4. sleep-847544bbfc-d27jg 2/2 Running 0 18h

运行

  1. $ kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c sleep -- curl https://my-nginx -k
  2. ...
  3. <h1>Welcome to nginx!</h1>
  4. ...

如果您从 istio-proxy 容器运行,它应该也会正常运行:

  1. $ kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c istio-proxy -- curl https://my-nginx -k
  2. ...
  3. <h1>Welcome to nginx!</h1>
  4. ...

该例子来自 Kubernetes 示例

创建一个有 Istio sidecar 并启用双向 TLS 的 HTTPS 服务

您需要部署 Istio 控制平面并启用双向 TLS。 如果您已经安装了一个禁用双向 TLS 的 Istio 控制平面,请删除它。 例如,如果您按照入门中的指引:

  1. $ istioctl manifest generate --set profile=demo | kubectl delete -f -

并且等所有内容都被删除,也就是说,在控制平面命名空间(istio-system)中已经没有 pod 了:

  1. $ kubectl get pod -n istio-system
  2. No resources found.

安装 Istio 并启用严格双向 TLS 模式

  1. $ istioctl manifest apply --set profile=demo,values.global.controlPlaneSecurityEnabled=true,values.global.mtls.enabled=true

确保所有内容都启动且正在运行:

  1. $ kubectl get po -n istio-system
  2. NAME READY STATUS RESTARTS AGE
  3. grafana-6f6dff9986-r6xnq 1/1 Running 0 23h
  4. istio-citadel-599f7cbd46-85mtq 1/1 Running 0 1h
  5. istio-cleanup-old-ca-mcq94 0/1 Completed 0 23h
  6. istio-egressgateway-78dd788b6d-jfcq5 1/1 Running 0 23h
  7. istio-ingressgateway-7dd84b68d6-dxf28 1/1 Running 0 23h
  8. istio-mixer-post-install-g8n9d 0/1 Completed 0 23h
  9. istio-pilot-d5bbc5c59-6lws4 2/2 Running 0 23h
  10. istio-policy-64595c6fff-svs6v 2/2 Running 0 23h
  11. istio-sidecar-injector-645c89bc64-h2dnx 1/1 Running 0 23h
  12. istio-statsd-prom-bridge-949999c4c-mv8qt 1/1 Running 0 23h
  13. istio-telemetry-cfb674b6c-rgdhb 2/2 Running 0 23h
  14. istio-tracing-754cdfd695-wqwr4 1/1 Running 0 23h
  15. prometheus-86cb6dd77c-ntw88 1/1 Running 0 23h

然后重新部署 HTTPS 服务和 sleep 服务

ZipZipZipZip

  1. $ kubectl delete -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@)
  2. $ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@)
  3. $ kubectl delete -f <(istioctl kube-inject -f @samples/https/nginx-app.yaml@)
  4. $ kubectl apply -f <(istioctl kube-inject -f @samples/https/nginx-app.yaml@)

确保该 pod 已经启动且正在运行

  1. $ kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. my-nginx-9dvet 2/2 Running 0 1h
  4. sleep-77f457bfdd-hdknx 2/2 Running 0 18h

运行

  1. $ kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c sleep -- curl https://my-nginx -k
  2. ...
  3. <h1>Welcome to nginx!</h1>
  4. ...

原因在于,对于工作流 “sleep -> sleep-proxy -> nginx-proxy -> nginx”,整个流程是 L7 流,而在 sleep-proxynginx-proxy 之间存在一个 L4 的双向 TLS 加密。 在这种情况下,一切都运行正常。

但是,如果您在 istio-proxy 容器中运行整个命令,它将不起作用:

  1. $ kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c istio-proxy -- curl https://my-nginx -k
  2. curl: (35) gnutls_handshake() failed: Handshake failed
  3. command terminated with exit code 35

这个是因为对于工作流 “sleep-proxy -> nginx-proxy -> nginx”,nginx-proxy 期望的是来自 sleep-proxy 的双向 TLS 流量。 在上面的命令中,sleep-proxy 并未提供客户端证书。因此,它无法正常运行。 而且,就算 sleep-proxy 提供了客户端证书,它也无法正常运行,因为从 nginx-proxy 到 nginx 时,流量会降为 http。

清理

ZipZip

  1. $ kubectl delete -f @samples/sleep/sleep.yaml@
  2. $ kubectl delete -f @samples/https/nginx-app.yaml@
  3. $ kubectl delete configmap nginxconfigmap
  4. $ kubectl delete secret nginxsecret

相关内容

Istio 2020——为了商用

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

移除跨 pod Unix domain socket

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

DNS 证书管理

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

Istio v1beta1 授权策略概述

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

安全管理 Webhook

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

把 Istio 作为外部服务的代理

把 Istio 入口网关配置为外部服务的代理。