在本文中,我们将展示如何在不修改当前应用代码的前提下来为所有的服务到服务的(service-to-service) HTTP 调用提供 TLS 支持。
提示:本文只是我们介绍 linkerd,Kubernetes和服务网格的系列文章的一篇,包括本篇在内的文章列表如下:
在本系列的第一部分中,展示了linkerd作为服务网格进行安装时,如何轻松监控关键服务指标(成功率,延迟和请求率)。在本文中,我们将展示服务网格带来的另一个好处:它允许你将应用的协议与传输时使用的协议解耦。换句话说,应用程序使用的协议与传输协议可以不同。
一个常见的场景就是,linkerd利用解耦无需数据转换就可以完成协议的自动升级。 (常见的有 HTTP / 1.x 到HTTP / 2,thrift 到支持多路复用的thrift(thrift-mux),以及本文将演示的HTTP到HTTPS)
当linkerd在Kubernetes上作为服务网格部署时,我们使用DaemonSets在每个主机上放置一个链接实例。对于HTTP服务,pod可以通过设置 http_proxy
环境变量将HTTP流量指向其本地主机的linkerd。 (对于非HTTP流量会稍微复杂一些。)
在原作者之前的文章中展示了使用linkerd在HTTP调用外“包装”TLS协议的基本方法,就是在连接的两端设置代理,分别发起和终止TLS。现在我们已经完成了服务网格部署,这个任务做起来就简单多了,加密所有跨主机通信的任务变成了为服务网格提供TLS证书。
我们来通过一个例子理解一下。前两个步骤与我们在本系列第一篇文章中所做的相同 - 我们将安装linkerd作为服务网格,并安装一个简单的微服务——“hello world”应用。如果你已经做过了,可以直接跳到步骤3。
使用这个Kubernetes配置来安装linkerd 。这会linkerd作为DaemonSet安装(即每个主机对应一个实例)并运行在Kubernetes默认的命名空间:
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd.yml
您可以通过查看linkerd的管理页面来确认安装是否成功:
INGRESS_LB = $(kubectl get svc l5d -o jsonpath ="{.status.loadBalancer.ingress [0].*}")
open http://$INGRESS_LB:9990 #在OS X上
使用hello-world config安装两个服务“hello”和“world” 。这两个服务将被安装到默认的命名空间中:
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world.yml
这两个服务将共同组成一个高度可扩展的“hello world”微服务(hello
服务通过调用world
服务来完成一次请求流程)。
可以设定通过linkerd的外部IP发送流量来观察请求的动作:
http_proxy = $INGRESS_LB:4140 curl -s http://hello
如果一切顺利,你会看到字符串“Hello world”。
linkerd已经安装成功,现在我们用它来加密流量。我们将在每台主机上放置TLS证书,并配置linkerd来使用它们。
我们将使用我们生成的全局证书(网格证书)。由于此证书没有绑定在公共DNS上,因此我们不需要使用“Let’s Encrypt”等服务。我们可以直接生成我们自己的CA证书并使用它来生成我们的网格证书(“自签名”)。我们将分配三个东西到每个Kubernetes主机:CA证书,网格秘钥和网格证书。
以下脚本使用我们生成的示例证书。请不要在生产中使用这种证书。有关如何生成自己的自签名证书的说明,请参阅作者以前的帖子)。
下面,我们只需要更新linkerd实现配置的变更就可以完成流量的加密。首先分发示例证书作为Kubernetes的secrets
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/certificates.yml
变更配置来使用这些证书,然后重启一下服务
kubectl delete ds/l5d configmap/l5d-config
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd-tls.yml
现在,所有服务间的通信应该都已经进行了TLS协议的加密,让我们通过下面的命令验证一下:
http_proxy=$INGRESS_LB:4140 curl -s http://hello
如果一切顺利,你会看到字符串“Hello world”。——虽然看起来还是一样的,但是在hello和world服务间的通信已经完成了加密。我们可以直接发送一个HTTPS请求到linkerd用于监听其他linkerd实例请求的端口4141来验证一下
curl -skH 'l5d-dtab: /svc=>/#/io.l5d.k8s/default/admin/l5d;' https://$INGRESS_LB:4141/admin/ping
这里我们通过curl发送了一个HTTPS请求并且要求它跳过TLS验证(因为curl一般用来请求的是网页而不是一个linkerd)。我们还添加了dtab override来讲请求路由到管理员界面所在的linkerd实例。如果你看到一个成功的"pong"响应,说明你已经成功加密了跨服务请求。
在这篇文章中,我们演示了如何linkerd这样的服务网格来实现Kubernetes集群中所有跨节点通信的加密。我们还使用了TLS来确保linkerd实例可以在避免第三方攻击的情况下完成与另一个目标linkerd实例的通信(也验证了我们的配置是正确的)。同样的,这样的实现方式也不会影响到应用的正常运行。
TLS实际上是一个很复杂的话题,但是为了保证demo的快速上手,很多重要的安全性考虑我们都省略或者一笔带过了,如果你要在产品集群上使用,一定要花时间深入的理解文中这几步背后的细节。
使用TLS对通信进行加密只是服务网格可以完成的诸多任务中的一个,如果你还想了解更多,请关注该系列文章的其他部分。
对于有对本文或其他于linkerd相关的问题,欢迎到我们非常活跃的linkerd Slack社区提问, 在linkerd discourse下发表话题讨论或者直接联系我们。