赵钱孙
作者赵钱孙·2017-10-10 14:33
系统工程师·河南电信

Kubernetes的service mesh——第三部分:将一切加密

字数 3544阅读 1690评论 0赞 8

Kubernetes的service mesh

当linkerd在Kubernetes中作为service mesh部署后,我们使用DaemonSet在每个宿主机上部署一个linkerd实例。对于HTTP服务而言,pod可以通过使用http_proxy环境变量发送HTTP流量到它们本地的linkerd。(非HTTP流量情况下会稍微复杂些)

我们之前曾讲过在TLS中通过在连接的两端代理始发TLS和终止TLS,来使用linkerd“打包”HTTP请求的基本模式。然而,现在我们有了service mesh,问题显然变得简单了。将全部的跨宿主机通信加密是service mesh提供TLS证书的关键。

接下来举具体例子来说。接下来的例子的前两步与本系列PRAT 1相同,安装linkerd并安装简单的微服务“hello world”应用程序。如果你已经做过这些了,可以直接跳到第三步。

第一步:安装Linkerd

使用Kubernetes配置文件安装Linkerd。它会将Linkerd作为DaemonSet安装,且运行在Kubernetes的default命名空间:

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 # on OS X

如果集群不支持外部负载均衡,使用hostIP:

HOST_IP=$(kubectl get po -l app=l5d -o jsonpath="{.items[0].status.hostIP}")
open http://$HOST_IP:$(kubectl get svc l5d -o 'jsonpath={.spec.ports[2].nodePort}') # on OS X

第二步:安装样例应用程序

在default命名空间下安装两个Service,“hello”和“world”。这些应用程序依赖于Kubernetes downward API提供的nodeName来发现Linkerd。为了检测你的集群是否支持nodeName,你可以运行:

kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/node-name-test.yml

然后看它的日志:

kubectl logs node-name-test

如果你看到了一个IP就说明支持。接下来继续部署hello world应用程序如下:

kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world.yml

如果你看到报错“server can’t find…”,就部署旧版本hello-world,它依赖于hostIP而非nodeName:

kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world-legacy.yml

这两个Service——“hello”和“world”——功能在一起使得高度可扩展,“hello world”微服务(“hello”Service调用“world”Service完成这个请求)。

你可以通过给Linkerd的外部IP发送请求来查看此操作:

http_proxy=$INGRESS_LB:4140 curl -s http://hello

或者直接使用hostIP:

http_proxy=$HOST_IP:$(kubectl get svc l5d -o 'jsonpath={.spec.ports[0].nodePort}') curl -s http://hello

你应该可以看到字符串“Hello world”。

第三步:为使用TLS配置linkerd

现在linkerd已经安装好了,我们可以使用它来给流量加密了。我们在每一个宿主机上安装TLS证书,并为使用这些证书而配置linkerd。

我们将使用一个我们自己生成的全局证书。因为这个证书没有绑定公共DNS域名,我们就不需要使用Let’s Encrypt这样的服务了。我们可以生成自己的CA证书,并使用它来签署我们的mesh证书(“自签名”)。我们将为每个Kubernetes节点分配三样东西:CA证书,mesh密钥和mesh证书。

接下来的这个脚本使用我们自己生成的样本证书。请不要在生产环境中使用这些证书。

第四步:为Kubernetes部署证书并配置变更

我们已经做好准备为给流量加密而更新linkerd。我们将如Kubernetes secrets对象那样分配样例证书。

kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/certificates.yml

现在,我们将通过这个配置文件配置linkerd并重启它以使用这些证书:

kubectl delete ds/l5d configmap/l5d-config
kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd-tls.yml

第五步:成功

此时,linkerd应该透明地包裹TLS中的这些服务之间的所有通信。我们通过运行与之前相同的命令来验证这一点:

http_proxy=$INGRESS_LB:4140 curl -s http://hello

或者使用hostIP:

http_proxy=$HOST_IP:$(kubectl get svc l5d -o 'jsonpath={.spec.ports[0].nodePort}') curl -s http://hello

如果一切顺利进行,你应该仍然可以看到字符串“Hello world”。但是实际上,hello和world服务之间的通信正在被加密。我们可以通过直接向端口4141发送HTTPS请求来进行验证,其中,linkerd正在监听来自其他linkerd实例的请求:

curl -skH 'l5d-dtab: /svc=>/#/io.l5d.k8s/default/admin/l5d;' https://$INGRESS_LB:4141/admin/ping

或者使用hostIP:

curl -skH 'l5d-dtab: /svc=>/#/io.l5d.k8s/default/admin/l5d;'
https://$HOST_IP:$(kubectl get svc l5d -o 'jsonpath={.spec.ports[1].nodePort}')/admin/ping

这里,我们要求用curl进行HTTPS调用,并告诉它跳过TLS验证(因为curl期望一个站点,而不是linkerd)。我们还添加了一个dtab override来将请求路由到linkerd实例自己的管理界面。如果一切顺利,你应该再次看到一个成功的“pong”响应。恭喜! 你已加密了跨服务流量。

结束语

在这篇文章中,我们已经讲述了如何使用诸如linkerd的service mesh来透明地加密Kubernetes集群中的所有跨节点通信。我们还使用TLS来确保linkerd实例可以验证它们是否与其他linkerd实例进行通信,从而防止中间人攻击(和配置错误)。当然,这个应用程序仍然不知道任何这些变化。

TLS是一个复杂的主题,我们已经考虑了一些重要的安全注意事项以使演示变得简单些。在你于生产集群上尝试此过程之前,请确保你已经花时间充分了解了相关步骤。

本文转自微信公众号:容器时代

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

8

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广