通过 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 来运行如下命令:

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

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

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

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

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

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

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

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

获取 pods

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

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

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

调用 my-nginx

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

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

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

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

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

删除 HTTPS 服务。

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

与 sidecar 一起部署

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

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

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

运行

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

运行

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

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

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

$ kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c istio-proxy -- curl https://my-nginx -k
curl: (35) gnutls_handshake() failed: Handshake failed
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
$ kubectl delete -f @samples/sleep/sleep.yaml@
$ kubectl delete -f @samples/https/nginx-app.yaml@
$ kubectl delete configmap nginxconfigmap
$ kubectl delete secret nginxsecret
这些信息有用吗?
Do you have any suggestions for improvement?

Thanks for your feedback!