配置 Egress gateway

控制 Egress 流量任务演示了如何从网格内的应用程序访问外部(Kubernetes 集群外部)HTTP 和 HTTPS 服务。这里提醒一下:默认情况下,启用 Istio 的应用程序无法访问集群外的 URL。要启用此类访问,必须定义外部服务的 ServiceEntry,或者配置直接访问外部服务

Egress 流量的 TLS 任务演示了如何允许应用程序将 HTTP 请求发送到需要 HTTPS 的外部服务器。

此任务描述了通过名为 Egress Gateway 的专用服务如何配置 Istio 引导出口流量。我们实现了与 Egress 流量的 TLS 任务中描述的相同功能,唯一的区别就是,这里会使用 Egress gateway 来完成这一任务。

用例

设想一个具有严格安全要求的组织。根据这些要求,服务网格的所有外发流量必须流经一组专用节点。这些节点和运行其他应用分别在不同的节点上运行。这些专用的节点将用于 Egress 流量的策略实施,并且将比其余节点进行更详细地监控。

Istio 0.8 引入了 Ingress 和 Egress gateway 的概念。 Ingress 网关允许定义进入服务网格的入口点,所有入站流量都通过该入口点;Egress gateway 与之相对,它定义了网格的出口点。 Egress gateway 允许将 Istio 功能(例如,监控和路由规则)应用于 Egress 流量。

另一个用例是应用程序节点没有公共 IP 的集群,因此在其上运行的网格内服务无法访问 Internet。定义 Egress gateway ,通过它引导所有出口流量并将公共 IP 分配给 Egress gateway 节点,允许应用节点以受控方式访问外部服务。

开始之前

  • 按照安装指南中的说明设置 Istio 。

  • 启动 sleep 应用,它将被用作外部调用的测试源。

如果已经启用了 Sidecar 的自动注入,请执行此操作

Zip

  1. $ kubectl apply -f @samples/sleep/sleep.yaml@

否则,就要在部署 sleep 应用程序之前手工进行 Sidecar 的注入:

Zip

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

这样就可以在任意 pod 使用 execcurl 命令了。

  • 创建一个环境变量来保存源 Pod 名称,以便将请求发送到外部服务。例如在 sleep 示例中运行:
  1. $ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})

定义 Egress gateway 并引导 HTTP 流量通过这一网关

首先定向没有 TLS 的 HTTP 流量

  • edition.cnn.com 定义一个 ServiceEntry
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: ServiceEntry
  4. metadata:
  5. name: cnn
  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
  15. protocol: HTTPS
  16. resolution: DNS
  17. EOF
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
  2. HTTP/1.1 301 Moved Permanently
  3. ...
  4. location: https://edition.cnn.com/politics
  5. ...
  6. HTTP/1.1 200 OK
  7. Content-Type: text/html; charset=utf-8
  8. ...
  9. Content-Length: 151654
  10. ...

输出应与 Egress 流量的 TLS 任务中的输出相同,不带 TLS。

  • edition.cnn.com 端口 80 创建 Egress gateway。除此之外还要创建一个 DestinationRuleVirtualService 来引导流量通过 Egress gateway 与外部服务通信。

如果在 Istio 中启用了双向 TLS 认证,请使用以下命令。

  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: Gateway
  4. metadata:
  5. name: istio-egressgateway
  6. spec:
  7. selector:
  8. istio: egressgateway
  9. servers:
  10. - port:
  11. number: 80
  12. name: https
  13. protocol: HTTPS
  14. hosts:
  15. - edition.cnn.com
  16. tls:
  17. mode: MUTUAL
  18. serverCertificate: /etc/certs/cert-chain.pem
  19. privateKey: /etc/certs/key.pem
  20. caCertificates: /etc/certs/root-cert.pem
  21. ---
  22. apiVersion: networking.istio.io/v1alpha3
  23. kind: DestinationRule
  24. metadata:
  25. name: egressgateway-for-cnn
  26. spec:
  27. host: istio-egressgateway.istio-system.svc.cluster.local
  28. subsets:
  29. - name: cnn
  30. trafficPolicy:
  31. loadBalancer:
  32. simple: ROUND_ROBIN
  33. portLevelSettings:
  34. - port:
  35. number: 80
  36. tls:
  37. mode: ISTIO_MUTUAL
  38. sni: edition.cnn.com
  39. EOF

如果没有启用双向 TLS 认证:

  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: Gateway
  4. metadata:
  5. name: istio-egressgateway
  6. spec:
  7. selector:
  8. istio: egressgateway
  9. servers:
  10. - port:
  11. number: 80
  12. name: http
  13. protocol: HTTP
  14. hosts:
  15. - edition.cnn.com
  16. ---
  17. apiVersion: networking.istio.io/v1alpha3
  18. kind: DestinationRule
  19. metadata:
  20. name: egressgateway-for-cnn
  21. spec:
  22. host: istio-egressgateway.istio-system.svc.cluster.local
  23. subsets:
  24. - name: cnn
  25. EOF
  • 定义 VirtualService 来引导流量通过 Egress gateway :
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: VirtualService
  4. metadata:
  5. name: direct-cnn-through-egress-gateway
  6. spec:
  7. hosts:
  8. - edition.cnn.com
  9. gateways:
  10. - istio-egressgateway
  11. - mesh
  12. http:
  13. - match:
  14. - gateways:
  15. - mesh
  16. port: 80
  17. route:
  18. - destination:
  19. host: istio-egressgateway.istio-system.svc.cluster.local
  20. subset: cnn
  21. port:
  22. number: 80
  23. weight: 100
  24. - match:
  25. - gateways:
  26. - istio-egressgateway
  27. port: 80
  28. route:
  29. - destination:
  30. host: edition.cnn.com
  31. port:
  32. number: 80
  33. weight: 100
  34. EOF
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
  2. HTTP/1.1 301 Moved Permanently
  3. ...
  4. location: https://edition.cnn.com/politics
  5. ...
  6. HTTP/1.1 200 OK
  7. Content-Type: text/html; charset=utf-8
  8. ...
  9. Content-Length: 151654
  10. ...

输出应与步骤2中的输出相同。

  • 检查 istio-egressgateway pod 的日志,并查看与我们的请求对应的行。如果 Istio 部署在 istio-system 命名空间中,则打印日志的命令是:
  1. $ kubectl logs -l istio=egressgateway -c istio-proxy -n istio-system | tail

我们看到与请求相关的行,类似于以下内容:

  1. [2018-06-14T11:46:23.596Z] "GET /politics HTTP/1.1" 301 - 0 0 3 1 "172.30.146.87" "curl/7.35.0" "ab7be694-e367-94c5-83d1-086eca996dae" "edition.cnn.com" "151.101.193.67:80"

请注意,我们只将流量从 80 端口重定向到 Egress gateway ,到 443 端口的 HTTPS 流量直接转到 edition.cnn.com

清除 HTTP 流量的 Egress gateway

在继续下一步之前删除先前的定义:

  1. $ kubectl delete gateway istio-egressgateway
  2. $ kubectl delete serviceentry cnn
  3. $ kubectl delete virtualservice direct-cnn-through-egress-gateway
  4. $ kubectl delete destinationrule egressgateway-for-cnn

用 Egress gateway 发起 TLS 连接

接下来尝试使用 Egress Gateway 发起 TLS 连接,效果类似于 出口流量的 TLS 任务,具体区别是,在这种情况下,TLS 功能是由 Egress gateway 服务器完成的,而不是前一任务中的 Sidecar。

  • edition.cnn.com 定义 ServiceEntry
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: ServiceEntry
  4. metadata:
  5. name: cnn
  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: http-port-for-tls-origination
  15. protocol: HTTP
  16. resolution: DNS
  17. EOF
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
  2. HTTP/1.1 301 Moved Permanently
  3. ...
  4. location: https://edition.cnn.com/politics
  5. ...
  6. command terminated with exit code 35

如果看到输出结果中包含 301 Moved Permanently,说明 ServiceEntry 配置正确。退出代码 35 是由于 Istio 没有执行 TLS。 为了让 Egress gateway 执行 TLS,还要继续执行以下步骤进行配置。

  • edition.cnn.com 创建 Egress Gateway,端口 443。除此之外还创建了一个 DestinationRuleVirtualService,这两个对象用来引导流量通过 Egress gateway 与外部服务通信。

如果在 Istio 中启用了 双向 TLS 认证,请使用以下命令。

  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: Gateway
  4. metadata:
  5. name: istio-egressgateway
  6. spec:
  7. selector:
  8. istio: egressgateway
  9. servers:
  10. - port:
  11. number: 443
  12. name: https
  13. protocol: HTTPS
  14. hosts:
  15. - edition.cnn.com
  16. tls:
  17. mode: MUTUAL
  18. serverCertificate: /etc/certs/cert-chain.pem
  19. privateKey: /etc/certs/key.pem
  20. caCertificates: /etc/certs/root-cert.pem
  21. ---
  22. apiVersion: networking.istio.io/v1alpha3
  23. kind: DestinationRule
  24. metadata:
  25. name: egressgateway-for-cnn
  26. spec:
  27. host: istio-egressgateway.istio-system.svc.cluster.local
  28. subsets:
  29. - name: cnn
  30. trafficPolicy:
  31. loadBalancer:
  32. simple: ROUND_ROBIN
  33. portLevelSettings:
  34. - port:
  35. number: 443
  36. tls:
  37. mode: ISTIO_MUTUAL
  38. sni: edition.cnn.com
  39. EOF

如果没有启用双向 TLS 认证:

  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: Gateway
  4. metadata:
  5. name: istio-egressgateway
  6. spec:
  7. selector:
  8. istio: egressgateway
  9. servers:
  10. - port:
  11. number: 443
  12. name: http-port-for-tls-origination
  13. protocol: HTTP
  14. hosts:
  15. - edition.cnn.com
  16. ---
  17. apiVersion: networking.istio.io/v1alpha3
  18. kind: DestinationRule
  19. metadata:
  20. name: egressgateway-for-cnn
  21. spec:
  22. host: istio-egressgateway.istio-system.svc.cluster.local
  23. subsets:
  24. - name: cnn
  25. EOF
  • 定义 VirtualService 来引导流量通过 Egress gateway,并定义 DestinationRule 以执行 TLS:
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: VirtualService
  4. metadata:
  5. name: direct-cnn-through-egress-gateway
  6. spec:
  7. hosts:
  8. - edition.cnn.com
  9. gateways:
  10. - istio-egressgateway
  11. - mesh
  12. http:
  13. - match:
  14. - gateways:
  15. - mesh
  16. port: 80
  17. route:
  18. - destination:
  19. host: istio-egressgateway.istio-system.svc.cluster.local
  20. subset: cnn
  21. port:
  22. number: 443
  23. weight: 100
  24. - match:
  25. - gateways:
  26. - istio-egressgateway
  27. port: 443
  28. route:
  29. - destination:
  30. host: edition.cnn.com
  31. port:
  32. number: 443
  33. weight: 100
  34. ---
  35. apiVersion: networking.istio.io/v1alpha3
  36. kind: DestinationRule
  37. metadata:
  38. name: originate-tls-for-edition-cnn-com
  39. spec:
  40. host: edition.cnn.com
  41. trafficPolicy:
  42. loadBalancer:
  43. simple: ROUND_ROBIN
  44. portLevelSettings:
  45. - port:
  46. number: 443
  47. tls:
  48. mode: SIMPLE # initiates HTTPS for connections to edition.cnn.com
  49. EOF
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
  2. HTTP/1.1 200 OK
  3. ...
  4. content-length: 150793
  5. ...

输出应与 出口流量的 TLS 任务中的输出相同:没有 301 Moved Permanently 信息。

  • 检查 istio-egressgateway pod 的日志,并查看与我们的请求相对应的行。如果 Istio 部署在 istio-system 命名空间中,则打印日志的命令是:
  1. $ kubectl logs -l istio=egressgateway -c istio-proxy -n istio-system | tail

这里会看到与之前请求相关的行,类似于以下内容:

  1. "[2018-06-14T13:49:36.340Z] "GET /politics HTTP/1.1" 200 - 0 148528 5096 90 "172.30.146.87" "curl/7.35.0" "c6bfdfc3-07ec-9c30-8957-6904230fd037" "edition.cnn.com" "151.101.65.67:443"

清除发起 TLS 的 Egress gateway

删除我们创建的 Istio 配置项:

  1. $ kubectl delete gateway istio-egressgateway
  2. $ kubectl delete serviceentry cnn
  3. $ kubectl delete virtualservice direct-cnn-through-egress-gateway
  4. $ kubectl delete destinationrule originate-tls-for-edition-cnn-com
  5. $ kubectl delete destinationrule egressgateway-for-cnn

通过 Egress gateway 进行 HTTPS 流量透传

在本节中,将通过 Egress gateway 进行 HTTPS 流量透传(由应用程序发起的 TLS)。在相应的 ServiceEntryEgress gateway 以及 VirtualService 中指定端口 443,协议 TLS

  • edition.cnn.com 定义 ServiceEntry
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: ServiceEntry
  4. metadata:
  5. name: cnn
  6. spec:
  7. hosts:
  8. - edition.cnn.com
  9. ports:
  10. - number: 443
  11. name: tls
  12. protocol: TLS
  13. resolution: DNS
  14. EOF
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - https://edition.cnn.com/politics
  2. HTTP/1.1 200 OK
  3. Content-Type: text/html; charset=utf-8
  4. ...
  5. Content-Length: 151654
  6. ...
  • edition.cnn.com 创建 Egress gateway,端口 443,TLS 协议。除此之外还创建了一个 DestinationRuleVirtualService 来引导流量通过 Egress gateway 与外部服务通信。

如果在 Istio 中启用了双向 TLS 认证,请使用以下命令。

  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: Gateway
  4. metadata:
  5. name: istio-egressgateway
  6. spec:
  7. selector:
  8. istio: egressgateway
  9. servers:
  10. - port:
  11. number: 443
  12. name: tls-cnn
  13. protocol: TLS
  14. hosts:
  15. - edition.cnn.com
  16. tls:
  17. mode: MUTUAL
  18. serverCertificate: /etc/certs/cert-chain.pem
  19. privateKey: /etc/certs/key.pem
  20. caCertificates: /etc/certs/root-cert.pem
  21. ---
  22. apiVersion: networking.istio.io/v1alpha3
  23. kind: DestinationRule
  24. metadata:
  25. name: egressgateway-for-cnn
  26. spec:
  27. host: istio-egressgateway.istio-system.svc.cluster.local
  28. subsets:
  29. - name: cnn
  30. trafficPolicy:
  31. loadBalancer:
  32. simple: ROUND_ROBIN
  33. portLevelSettings:
  34. - port:
  35. number: 443
  36. tls:
  37. mode: ISTIO_MUTUAL
  38. sni: edition.cnn.com
  39. ---
  40. apiVersion: networking.istio.io/v1alpha3
  41. kind: VirtualService
  42. metadata:
  43. name: direct-cnn-through-egress-gateway
  44. spec:
  45. hosts:
  46. - edition.cnn.com
  47. gateways:
  48. - mesh
  49. - istio-egressgateway
  50. tls:
  51. - match:
  52. - gateways:
  53. - mesh
  54. port: 443
  55. sni_hosts:
  56. - edition.cnn.com
  57. route:
  58. - destination:
  59. host: istio-egressgateway.istio-system.svc.cluster.local
  60. subset: cnn
  61. port:
  62. number: 443
  63. tcp:
  64. - match:
  65. - gateways:
  66. - istio-egressgateway
  67. port: 443
  68. route:
  69. - destination:
  70. host: edition.cnn.com
  71. port:
  72. number: 443
  73. weight: 100
  74. EOF

如果没有启用双向 TLS 认证:

  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: Gateway
  4. metadata:
  5. name: istio-egressgateway
  6. spec:
  7. selector:
  8. istio: egressgateway
  9. servers:
  10. - port:
  11. number: 443
  12. name: tls
  13. protocol: TLS
  14. hosts:
  15. - edition.cnn.com
  16. tls:
  17. mode: PASSTHROUGH
  18. ---
  19. apiVersion: networking.istio.io/v1alpha3
  20. kind: DestinationRule
  21. metadata:
  22. name: egressgateway-for-cnn
  23. spec:
  24. host: istio-egressgateway.istio-system.svc.cluster.local
  25. subsets:
  26. - name: cnn
  27. ---
  28. apiVersion: networking.istio.io/v1alpha3
  29. kind: VirtualService
  30. metadata:
  31. name: direct-cnn-through-egress-gateway
  32. spec:
  33. hosts:
  34. - edition.cnn.com
  35. gateways:
  36. - mesh
  37. - istio-egressgateway
  38. tls:
  39. - match:
  40. - gateways:
  41. - mesh
  42. port: 443
  43. sni_hosts:
  44. - edition.cnn.com
  45. route:
  46. - destination:
  47. host: istio-egressgateway.istio-system.svc.cluster.local
  48. subset: cnn
  49. port:
  50. number: 443
  51. - match:
  52. - gateways:
  53. - istio-egressgateway
  54. port: 443
  55. sni_hosts:
  56. - edition.cnn.com
  57. route:
  58. - destination:
  59. host: edition.cnn.com
  60. port:
  61. number: 443
  62. weight: 100
  63. EOF
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - https://edition.cnn.com/politics
  2. HTTP/1.1 200 OK
  3. Content-Type: text/html; charset=utf-8
  4. ...
  5. Content-Length: 151654
  6. ...
  • 检查 Egress gateway 代理的统计信息,并查看与我们对 edition.cnn.com 的请求相对应的计数器。如果 Istio 部署在 istio-system 命名空间中,则打印计数器的命令是:
  1. $ kubectl exec -it $(kubectl get pod -l istio=egressgateway -n istio-system -o jsonpath='{.items[0].metadata.name}') -c istio-proxy -n istio-system -- curl -s localhost:15000/stats | grep edition.cnn.com.upstream_cx_total
  2. cluster.outbound|443||edition.cnn.com.upstream_cx_total: 1

如果再执行几个额外的请求,应该会看到每次请求之后上面的计数器都会加 1。

清除 HTTPS 流量的 Egress gateway

  1. $ kubectl delete serviceentry cnn
  2. $ kubectl delete gateway istio-egressgateway
  3. $ kubectl delete virtualservice direct-cnn-through-egress-gateway
  4. $ kubectl delete destinationrule egressgateway-for-cnn

额外的安全考量

在 Istio 中定义的 Egress gateway,本身并不会对运行 Egress gateway 服务的节点进行任何特殊处理。集群管理员或云提供商可以在专用节点上部署 Egress gateway ,并引入额外的安全措施,使这些节点比网格的其余部分更安全。

另外要注意的是,实际上 Istio 本身无法安全地强制将所有 Egress 流量流经 Egress gateway ,Istio 仅通过其 Sidecar 代理启用此类流量。攻击者只要绕过 Sidecar 代理,就可以不经 Egress gateway 直接与网格外面的服务进行通信,从而避免了 Istio 的控制和监控。集群管理员或云供应商必须确保所有外发流量都从 Egress gateway 途径发起。需要用 Istio 之外的机制来满足这一需求,例如以下几种做法:

  • 使用防火墙拒绝所有来自 Egress gateway 以外的流量。
  • Kubernetes 网络策略也能禁止所有不是从 Egress gateway 发起的 Egress 流量(#下一节中举出了这样的例子)。
  • 管理员或者云供应商还可以对网络进行限制,让运行应用的节点只能通过 Gateway 来访问外部网络。要完成这一限制,可以只给 Gateway Pod 分配公网 IP,或者可以配置 NAT 设备,丢弃来自 Egress gateway 以外 Pod 的流量。

应用 Kubernetes 网络策略

本节中会创建 Kubernetes 网络策略,阻止绕过 Egress gateway 的外发流量。要完成这一示例,首先创建一个 test-egress 命名空间,并在其中部署 sleep 示例应用。

  1. $ kubectl create namespace test-egress
  • test-egress 命名空间中部署 sleep 示例应用:

Zip

  1. $ kubectl apply -n test-egress -f @samples/sleep/sleep.yaml@
  • 检查生成的 Pod,其中应该只有一个容器,也就是说没有注入 Istio sidecar:
  1. $ kubectl get pod $(kubectl get pod -n test-egress -l app=sleep -o jsonpath={.items..metadata.name}) -n test-egress
  2. NAME READY STATUS RESTARTS AGE
  3. sleep-776b7bcdcd-z7mc4 1/1 Running 0 18m
  • test-egress 命名空间的 sleep Pod 中向 http://edition.cnn.com/politics 发送 HTTPS 请求。因为没有任何限制,所以这一请求应该会成功:
  1. $ kubectl exec -it $(kubectl get pod -n test-egress -l app=sleep -o jsonpath={.items..metadata.name}) -n test-egress -c sleep -- curl -s -o /dev/null -w "%{http_code}\n" https://edition.cnn.com/politics
  2. 200
  • 给 Istio 组件(控制平面和 Gateway)所在的命名空间打上标签,例如 istio-system
  1. $ kubectl label namespace istio-system istio=system
  • kube-system 命名空间打标签:
  1. $ kubectl label ns kube-system kube-system=true
  • 创建一个 NetworkPolicy,来自 test-egress 命名空间的流量,只允许目标为 kube-system 的 DNS(端口 53)请求,以及目标为 istio-system 命名空间的所有请求:
  1. $ cat <<EOF | kubectl apply -n test-egress -f -
  2. apiVersion: networking.k8s.io/v1
  3. kind: NetworkPolicy
  4. metadata:
  5. name: allow-egress-to-istio-system-and-kube-dns
  6. spec:
  7. podSelector: {}
  8. policyTypes:
  9. - Egress
  10. egress:
  11. - to:
  12. - namespaceSelector:
  13. matchLabels:
  14. kube-system: "true"
  15. ports:
  16. - protocol: UDP
  17. port: 53
  18. - to:
  19. - namespaceSelector:
  20. matchLabels:
  21. istio: system
  22. EOF
  • 重新发送前面的 HTTPS 请求到 http://edition.cnn.com/politics。这次请求就不会成功了,这是因为流量被网络策略拦截了。测试 Pod 无法越过 istio-egressgateway。要访问 edition.cnn.com,只能通过 Istio sidecar 将流量转给 istio-egressgateway 才能完成。这一设置演示了即使绕过了 Sidecar,也会被网络策略拦截,而无法访问到外部站点。
  1. $ kubectl exec -it $(kubectl get pod -n test-egress -l app=sleep -o jsonpath={.items..metadata.name}) -n test-egress -c sleep -- curl -v https://edition.cnn.com/politics
  2. Hostname was NOT found in DNS cache
  3. Trying 151.101.65.67...
  4. Trying 2a04:4e42:200::323...
  5. Immediate connect fail for 2a04:4e42:200::323: Cannot assign requested address
  6. Trying 2a04:4e42:400::323...
  7. Immediate connect fail for 2a04:4e42:400::323: Cannot assign requested address
  8. Trying 2a04:4e42:600::323...
  9. Immediate connect fail for 2a04:4e42:600::323: Cannot assign requested address
  10. Trying 2a04:4e42::323...
  11. Immediate connect fail for 2a04:4e42::323: Cannot assign requested address
  12. connect to 151.101.65.67 port 443 failed: Connection timed out
  • 接下来在 test-egress 命名空间的 sleep Pod 上注入 Sidecar,启用 test-egress 命名空间的自动注入:
  1. $ kubectl label namespace test-egress istio-injection=enabled
  • 重新部署 sleep

Zip

  1. $ kubectl delete deployment sleep -n test-egress
  2. $ kubectl apply -f @samples/sleep/sleep.yaml@ -n test-egress
  • 检查生成的 Pod,其中应该有了两个容器,其中包含了注入的 Sidecar(istio-proxy):
  1. $ kubectl get pod $(kubectl get pod -n test-egress -l app=sleep -o jsonpath={.items..metadata.name}) -n test-egress -o jsonpath={.spec.containers[*].name}
  2. sleep istio-proxy
  • http://edition.cnn.com/politics 发送 HTTP 请求,这次会成功,原因是网络策略允许流量流向 istio-system 中的 istio-egressgatewayistio-egressgateway 最终把流量转发到 edition.cnn.com
  1. $ kubectl exec -it $(kubectl get pod -n test-egress -l app=sleep -o jsonpath={.items..metadata.name}) -n test-egress -c sleep -- curl -s -o /dev/null -w "%{http_code}\n" https://edition.cnn.com/politics
  2. 200
  • 检查 Egress gateway 中的代理统计数据,查看对 edition.cnn.com 的请求计数。如果 Istio 部署在 istio-system 命名空间,那么打印计数器的命令就是:
  1. $ kubectl exec -it $(kubectl get pod -l istio=egressgateway -n istio-system -o jsonpath='{.items[0].metadata.name}') -c istio-proxy -n istio-system -- curl -s localhost:15000/stats | grep edition.cnn.com.upstream_cx_total
  2. cluster.outbound|443||edition.cnn.com.upstream_cx_total: 2

清理网络策略

  • 删除本节中建立的资源:

Zip

  1. $ kubectl delete -f @samples/sleep/sleep.yaml@ -n test-egress
  2. $ kubectl delete networkpolicy allow-egress-to-istio-system-and-kube-dns -n test-egress
  3. $ kubectl label namespace kube-system kube-system-
  4. $ kubectl label namespace istio-system istio-
  5. $ kubectl delete namespace test-egress

故障排除

  1. $ kubectl exec -i -n istio-system $(kubectl get pod -l istio=egressgateway -n istio-system -o jsonpath='{.items[0].metadata.name}') -- cat /etc/certs/cert-chain.pem | openssl x509 -text -noout | grep 'Subject Alternative Name' -A 1
  2. X509v3 Subject Alternative Name:
  3. URI:spiffe://cluster.local/ns/istio-system/sa/istio-egressgateway-service-account
  • HTTPS 透传流量情况,需要使用 openssl 命令测试流量。openssl-servername 选项可以用来设置 SNI:
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- openssl s_client -connect edition.cnn.com:443 -servername edition.cnn.com
  2. CONNECTED(00000003)
  3. ...
  4. Certificate chain
  5. 0 s:/C=US/ST=California/L=San Francisco/O=Fastly, Inc./CN=turner-tls.map.fastly.net
  6. i:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign CloudSSL CA - SHA256 - G3
  7. 1 s:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign CloudSSL CA - SHA256 - G3
  8. i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
  9. ---
  10. Server certificate
  11. -----BEGIN CERTIFICATE-----
  12. ...

如果在上面命令的输出中看到了类似的证书信息,就表明路由是正确的。接下来检查 Egress gateway 代理,查找对应请求的计数器(由 opensslcurl 发送,目标是 edition.cnn.com):

  1. $ kubectl exec -it $(kubectl get pod -l istio=egressgateway -n istio-system -o jsonpath='{.items[0].metadata.name}') -c istio-proxy -n istio-system -- curl -s localhost:15000/stats | grep edition.cnn.com.upstream_cx_total
  2. cluster.outbound|443||edition.cnn.com.upstream_cx_total: 2

清理

关闭 sleep 服务:

Zip

  1. $ kubectl delete -f @samples/sleep/sleep.yaml@