.本案例演示了如何去配置执行TLS origination到外部的服务流量 。当起源的流量是HTTP的时候istio将会打开HTTPS的流量到外部服务。

1. 使用案例

考虑一个对外部站点执行HTTP调用的遗留应用程序。假设操作应用程序的组织收到一个新的要求,要求所有的外部通信必须加密。使用Istio,只需通过配置就可以实现这一需求,而无需更改应用程序中的任何代码。应用程序可以发送未加密的HTTP请求,然后Istio将为应用程序加密这些请求。

从源发送未加密的HTTP请求并让Istio执行TLS升级的另一个好处是,Istio可以产生更好的遥测,并为未加密的请求提供更多的路由控制。

2. 准备工作

  • 启动一个sleep的案例应用。如果开启了自动注入sidecar执行如下命令:
  1. $ kubectl apply -f samples/sleep/sleep.yaml
  • 如果需要手工注入sidecar,执行如下命令
  1. $ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml
  • 使用一个变量去获取sleep案例应用的名称
  1. $ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})

3. 配置去访问外部的应用

此次,使用单一的服务条目去开启HTTP和HTTPS,访问服务。

  1. 创建一个服务条目和虚拟服务去开启到edition.cnn.com的访问。
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: ServiceEntry
  4. metadata:
  5. name: edition-cnn-com
  6. spec:
  7. hosts:
  8. - edition.cnn.com
  9. ports:
  10. - number: 80
  11. name: http-port
  12. protocol: HTTP
  13. - number: 443
  14. name: https-port
  15. protocol: HTTPS
  16. resolution: DNS
  17. ---
  18. apiVersion: networking.istio.io/v1alpha3
  19. kind: VirtualService
  20. metadata:
  21. name: edition-cnn-com
  22. spec:
  23. hosts:
  24. - edition.cnn.com
  25. tls:
  26. - match:
  27. - port: 443
  28. sniHosts:
  29. - edition.cnn.com
  30. route:
  31. - destination:
  32. host: edition.cnn.com
  33. port:
  34. number: 443
  35. weight: 100
  36. EOF
  1. 发送一个请求到HTTP服务
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics

[info] 请注意,这个-L选项告诉curl去遵循重定向。在本案例中,这个服务器个到HTTP请求的http://edition.cnn.com/politics,返回一个301的永久重定向。这个重定向告诉客户端去发送一个额外的请求,这次使用的是https,到https://edition.cnn.com/politics. 针对第二次请求,这个服务器返回的是200的状态码。

[info]尽管这个curl命令处理这个重定向是透明的,但是在这里有两个问题。第一个问题就是冗余的请求,抓取http://edition.cnn.com/politics有双倍的延迟。第二个问题是URL的路径(在本例中为politics)是明文发送的。如果有一个攻击者嗅探您的应用程序和edition.cnn.com之间的通信,那么攻击者就会知道应用程序获取了edition.cnn.com的哪些特定主题。出于隐私方面的考虑,你可能会想要避免这样的泄露。

这两个问题都可以通过配置TLS origination来解决。

4. 针对egress traffic的TLS 源

  1. 重新定义你的ServiceEntry和VirtualService,去重写HTTP的请求端口和添加一个DestionationRule来执行TLS源。
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: ServiceEntry
  4. metadata:
  5. name: edition-cnn-com
  6. spec:
  7. hosts:
  8. - edition.cnn.com
  9. ports:
  10. - number: 80
  11. name: http-port
  12. protocol: HTTP
  13. - number: 443
  14. name: https-port-for-tls-origination
  15. protocol: HTTPS
  16. resolution: DNS
  17. ---
  18. apiVersion: networking.istio.io/v1alpha3
  19. kind: VirtualService
  20. metadata:
  21. name: edition-cnn-com
  22. spec:
  23. hosts:
  24. - edition.cnn.com
  25. http:
  26. - match:
  27. - port: 80
  28. route:
  29. - destination:
  30. host: edition.cnn.com
  31. subset: tls-origination
  32. port:
  33. number: 443
  34. ---
  35. apiVersion: networking.istio.io/v1alpha3
  36. kind: DestinationRule
  37. metadata:
  38. name: edition-cnn-com
  39. spec:
  40. host: edition.cnn.com
  41. subsets:
  42. - name: tls-origination
  43. trafficPolicy:
  44. loadBalancer:
  45. simple: ROUND_ROBIN
  46. portLevelSettings:
  47. - port:
  48. number: 443
  49. tls:
  50. mode: SIMPLE # initiates HTTPS when accessing edition.cnn.com
  51. EOF

就像前面定义的那样,虚拟服务重定向HTTP请求到端口443上,而它又根据DestinationRule执行TLS origination. 注意,与前一节中的ServiceEntry不同,这一次端口443上的协议是HTTP,而不是HTTPS。这是因为客户端只会发送HTTP请求,而Istio会将连接升级到HTTPS。

  1. 发送HTTP的请求到http://edition.cnn.com/politics
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics

[info]这一次,您将收到200 OK作为第一个和惟一的响应。Istio为curl执行了TLS发起,因此原始的HTTP请求被作为HTTPS转发到edition.cnn.com。服务器直接返回内容,不需要重定向。您消除了客户端和服务器之间的双重往返,请求留下了加密的网格,而没有披露您的应用程序获取了edition.cnn.com的politics部分。
注意,您使用的命令与前一节中的命令相同。对于以编程方式访问外部服务的应用程序,不需要更改代码。您可以通过配置Istio来获得TLS初始化的好处,而无需更改一行代码。

  1. 请注意,使用HTTPS访问外部服务的应用程序仍像以前一样工作
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - https://edition.cnn.com/politics

5. 其它的安全考量

因为应用程序pod和本地主机上的sidecar代理之间的通信仍然是未加密的,所以能够穿透应用程序节点的攻击者仍然能够看到该节点的本地网络上未加密的通信。在某些环境中,严格的安全需求可能要求所有的通信必须加密,即使在节点的本地网络上也是如此。有了这样一个严格的要求,应用程序应该只使用HTTPS (TLS)。本例中描述的TLS起源是不够的。

还要注意,即使是应用程序发起的HTTPS,攻击者也可以通过检查服务器名指示(SNI)来知道对edition.cnn.com的请求是被发送的。SNI字段在TLS握手期间未加密发送。使用HTTPS可以防止攻击者知道特定的主题和文章,但是不能防止攻击者知道edition.cnn.com被访问。

6. 清除本节实验

  1. 移除istio的配置
  1. $ kubectl delete serviceentry edition-cnn-com
  2. $ kubectl delete virtualservice edition-cnn-com
  3. $ kubectl delete destinationrule edition-cnn-com
  1. 删除sleep的服务
  1. $ kubectl delete -f samples/sleep/sleep.yaml