Egress 网关

此例子对 Minikube 无效。

控制出口流量任务展示了如何配置 Istio 以允许网格内部的应用程序访问外部 HTTP 和 HTTPS 服务,但那个任务实际上是通过 Sidecar 直接调用的外部服务。而这个示例会展示如何配置 Istio 以通过专用的 Egress 网关服务间接调用外部服务。

Istio 使用 Ingress 和 Egress 网关 配置运行在服务网格边缘的负载均衡。Ingress 网关允许您定义网格所有入站流量的入口。 Egress 网关是一个与 Ingress 网关对称的概念,它定义了网格的出口。 Egress 网关允许您将 Istio 的功能(例如,监视和路由规则)应用于网格的出站流量。

使用场景

设想一个对安全有严格要求的组织,要求服务网格所有的出站流量必须经过一组专用节点。 专用节点运行在专门的机器上,与集群中运行应用程序的其他节点隔离。 这些专用节点用于实施出口流量的策略,并且受到比其余节点更严密地监控。

另一个使用场景是集群中的应用节点没有公有 IP,所以在该节点上运行的网格 Service 无法访问互联网。通过定义 Egress 网关,将公有 IP 分配给 Egress 网关节点,用它引导所有的出站流量,可以使应用节点以受控的方式访问外部服务。

Istio 支持 Kubernetes Gateway API, 并计划将其作为未来流量管理的默认 API。 以下说明指导您在网格中配置流量管理时如何选择使用 Gateway API 或 Istio 配置 API。 请按照您的首选项遵循 Gateway APIIstio APIs 页签中的指示说明。

本文档使用实验性的 Gateway API 功能配置 Istio,在使用 Gateway API 指令之前,请确保:

  1. 安装 实验版本 的 Gateway API CRD:

    1. $ kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd/experimental?ref=v1.1.0" | kubectl apply -f -
  2. 安装 Istio 时,通过将 PILOT_ENABLE_ALPHA_GATEWAY_API 环境变量设置为 true 使 Istio 读取 Alpha 版本的 Gateway API 资源:

    1. $ istioctl install --set values.pilot.env.PILOT_ENABLE_ALPHA_GATEWAY_API=true --set profile=minimal -y

开始之前

  • 参照安装指南中的说明搭建 Istio。

    如果您安装 demo 配置文件, 则会启用 Egress 网关和访问日志。

  • 部署 sleep 示例应用,用作发送请求的测试源。

    Zip

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

    您可以使用任何安装了 curl 的 Pod 作为测试源。

  • SOURCE_POD 环境变量设置为源 Pod 的名称:

    1. $ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})

    此任务中的指令在 default 命名空间中为 Egress 网关创建目标规则。 并假设客户端 SOURCE_POD 也在 default 命名空间中运行。如果没有, 目标规则将不会在目标规则查找路径上找到, 并且客户端请求将失败。

  • 如果尚未启用,则启用 Envoy 的访问日志。 例如,使用 istioctl

    1. $ istioctl install <flags-you-used-to-install-Istio> --set meshConfig.accessLogFile=/dev/stdout

部署 Istio Egress 网关

当使用 Gateway API 配置 Egress 网关时, 这些 Egress 网关会被自动部署。 如果您在下文中使用 Gateway API 指令,则可以跳过这部分。

  1. 检查 Istio Egress 网关是否已部署:

    1. $ kubectl get pod -l istio=egressgateway -n istio-system

    如果没有 Pod 返回,通过接下来的步骤来部署 Istio Egress 网关。

  2. 如果您使用 IstioOperator CR 安装 Istio,请在配置中添加以下字段:

    1. spec:
    2. components:
    3. egressGateways:
    4. - name: istio-egressgateway
    5. enabled: true

    否则,将等效设置添加到原始 istioctl install 命令中,例如:

    1. $ istioctl install <flags-you-used-to-install-Istio> \
    2. --set "components.egressGateways[0].name=istio-egressgateway" \
    3. --set "components.egressGateways[0].enabled=true"

定义 Egress 网关并引导 HTTP 流量

首先创建一个 ServiceEntry,允许流量直接访问一个外部服务。

  1. edition.cnn.com 定义一个 ServiceEntry

    必须在下面的服务条目中使用 DNS 解析。如果分辨率为 NONE, 则网关将将流量引导到一个无限循环中。这是因为网关收到原始请求目标 IP 地址,该地址等于网关的服务IP(因为请求是由 Sidecar 定向的网关的代理)。

    借助 DNS 解析,网关执行 DNS 查询以获取外部服务的 IP 地址并进行定向该 IP 地址的流量。

    1. $ kubectl apply -f - <<EOF
    2. apiVersion: networking.istio.io/v1
    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
  2. 发送 HTTPS 请求到 https://edition.cnn.com/politics, 验证 ServiceEntry 是否已正确应用。

    1. $ kubectl exec "$SOURCE_POD" -c sleep -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics
    2. ...
    3. HTTP/1.1 301 Moved Permanently
    4. ...
    5. location: https://edition.cnn.com/politics
    6. ...
    7. HTTP/2 200
    8. Content-Type: text/html; charset=utf-8
    9. ...

    输出结果应该与发起 TLS 的出口流量中示例中的输出结果相同, 都还没有发起 TLS。

  3. edition.cnn.com 端口 80 的出口流量创建一个 Gateway

要通过 Egress 网关引导多个主机,您可以在 Gateway 中包含主机列表, 或使用 * 匹配所有主机。应该将 DestinationRule 中的 subset 字段重用于其他主机。

  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1
  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/v1
  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
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: gateway.networking.k8s.io/v1
  3. kind: Gateway
  4. metadata:
  5. name: cnn-egress-gateway
  6. annotations:
  7. networking.istio.io/service-type: ClusterIP
  8. spec:
  9. gatewayClassName: istio
  10. listeners:
  11. - name: http
  12. hostname: edition.cnn.com
  13. port: 80
  14. protocol: HTTP
  15. allowedRoutes:
  16. namespaces:
  17. from: Same
  18. EOF
  1. 配置路由规则,将流量从边车导向到 Egress 网关,再从 Egress 网关导向到外部服务:
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1
  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 apply -f - <<EOF
  2. apiVersion: gateway.networking.k8s.io/v1
  3. kind: HTTPRoute
  4. metadata:
  5. name: direct-cnn-to-egress-gateway
  6. spec:
  7. parentRefs:
  8. - kind: ServiceEntry
  9. group: networking.istio.io
  10. name: cnn
  11. rules:
  12. - backendRefs:
  13. - name: cnn-egress-gateway-istio
  14. port: 80
  15. ---
  16. apiVersion: gateway.networking.k8s.io/v1
  17. kind: HTTPRoute
  18. metadata:
  19. name: forward-cnn-from-egress-gateway
  20. spec:
  21. parentRefs:
  22. - name: cnn-egress-gateway
  23. hostnames:
  24. - edition.cnn.com
  25. rules:
  26. - backendRefs:
  27. - kind: Hostname
  28. group: networking.istio.io
  29. name: edition.cnn.com
  30. port: 80
  31. EOF
  1. 重新发送 HTTP 请求到 http://edition.cnn.com/politics

    1. $ kubectl exec "$SOURCE_POD" -c sleep -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics
    2. ...
    3. HTTP/1.1 301 Moved Permanently
    4. ...
    5. location: https://edition.cnn.com/politics
    6. ...
    7. HTTP/2 200
    8. Content-Type: text/html; charset=utf-8
    9. ...

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

  2. 检查 Egress 网关 Pod 的日志,找到与请求对应的那一行。

如果 Istio 部署在 istio-system 命名空间中,则打印日志的命令是:

  1. $ kubectl logs -l istio=egressgateway -c istio-proxy -n istio-system | tail

您应该会看到一行类似于下面这样的内容:

  1. [2019-09-03T20:57:49.103Z] "GET /politics HTTP/2" 301 - "-" "-" 0 0 90 89 "10.244.2.10" "curl/7.64.0" "ea379962-9b5c-4431-ab66-f01994f5a5a5" "edition.cnn.com" "151.101.65.67:80" outbound|80||edition.cnn.com - 10.244.1.5:80 10.244.2.10:50482 edition.cnn.com -

如果启用了双向 TLS 身份验证, 并且当您在连接到 Egress 网关时遇到问题,请运行以下命令来验证证书是否正确:

  1. $ istioctl pc secret -n istio-system "$(kubectl get pod -l istio=egressgateway -n istio-system -o jsonpath='{.items[0].metadata.name}')" -ojson | jq '[.dynamicActiveSecrets[] | select(.name == "default")][0].secret.tlsCertificate.certificateChain.inlineBytes' -r | base64 -d | openssl x509 -text -noout | grep 'Subject Alternative Name' -A 1
  2. X509v3 Subject Alternative Name: critical
  3. URI:spiffe://cluster.local/ns/istio-system/sa/istio-egressgateway-service-account

使用 Istio 生成的 Pod 标签访问与 Egress 网关对应的日志:

  1. $ kubectl logs -l gateway.networking.k8s.io/gateway-name=cnn-egress-gateway -c istio-proxy | tail

您应该会看到一行类似于下面这样的内容:

  1. [2024-01-09T15:35:47.283Z] "GET /politics HTTP/1.1" 301 - via_upstream - "-" 0 0 2 2 "172.30.239.55" "curl/7.87.0-DEV" "6c01d65f-a157-97cd-8782-320a40026901" "edition.cnn.com" "151.101.195.5:80" outbound|80||edition.cnn.com 172.30.239.16:55636 172.30.239.16:80 172.30.239.55:59224 - default.forward-cnn-from-egress-gateway.0

如果启用了双向 TLS 身份验证, 并且当您在连接到 Egress 网关时遇到问题,请运行以下命令来验证证书是否正确:

  1. $ istioctl pc secret "$(kubectl get pod -l gateway.networking.k8s.io/gateway-name=cnn-egress-gateway -o jsonpath='{.items[0].metadata.name}')" -ojson | jq '[.dynamicActiveSecrets[] | select(.name == "default")][0].secret.tlsCertificate.certificateChain.inlineBytes' -r | base64 -d | openssl x509 -text -noout | grep 'Subject Alternative Name' -A 1
  2. X509v3 Subject Alternative Name: critical
  3. URI:spiffe://cluster.local/ns/default/sa/cnn-egress-gateway-istio

请注意,您只是将流量从 80 端口重定向到 Egress 网关。到端口 443 的 HTTPS 流量直接进入 edition.cnn.com

清理 HTTP 网关

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

  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
  1. $ kubectl delete serviceentry cnn
  2. $ kubectl delete gtw cnn-egress-gateway
  3. $ kubectl delete httproute direct-cnn-to-egress-gateway
  4. $ kubectl delete httproute forward-cnn-from-egress-gateway

用 Egress 网关发起 HTTPS 请求

接下来尝试使用 Egress 网关发起 HTTPS 请求(TLS 由应用程序发起)。 您需要在相应的 ServiceEntry 和 Egress Gateway 中指定 TLS 协议的端口 443。

  1. edition.cnn.com 定义 ServiceEntry

    1. $ kubectl apply -f - <<EOF
    2. apiVersion: networking.istio.io/v1
    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
  2. 发送 HTTPS 请求到 https://edition.cnn.com/politics, 验证您的 ServiceEntry 是否已正确生效。

    1. $ kubectl exec "$SOURCE_POD" -c sleep -- curl -sSL -o /dev/null -D - https://edition.cnn.com/politics
    2. ...
    3. HTTP/2 200
    4. Content-Type: text/html; charset=utf-8
    5. ...
  3. edition.cnn.com 创建 Egress Gateway 以及路由规则, 用来引导流量通过 Egress 网关,并通过 Egress 网关与外部服务通信。

要通过 Egress 网关引导多个主机,您可以在 Gateway 中包含主机列表, 或使用 * 匹配所有主机。应该将 DestinationRule 中的 subset 字段用于其他主机。

  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1
  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/v1
  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/v1
  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. sniHosts:
  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. sniHosts:
  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 apply -f - <<EOF
  2. apiVersion: gateway.networking.k8s.io/v1
  3. kind: Gateway
  4. metadata:
  5. name: cnn-egress-gateway
  6. annotations:
  7. networking.istio.io/service-type: ClusterIP
  8. spec:
  9. gatewayClassName: istio
  10. listeners:
  11. - name: tls
  12. hostname: edition.cnn.com
  13. port: 443
  14. protocol: TLS
  15. tls:
  16. mode: Passthrough
  17. allowedRoutes:
  18. namespaces:
  19. from: Same
  20. ---
  21. apiVersion: gateway.networking.k8s.io/v1alpha2
  22. kind: TLSRoute
  23. metadata:
  24. name: direct-cnn-to-egress-gateway
  25. spec:
  26. parentRefs:
  27. - kind: ServiceEntry
  28. group: networking.istio.io
  29. name: cnn
  30. rules:
  31. - backendRefs:
  32. - name: cnn-egress-gateway-istio
  33. port: 443
  34. ---
  35. apiVersion: gateway.networking.k8s.io/v1alpha2
  36. kind: TLSRoute
  37. metadata:
  38. name: forward-cnn-from-egress-gateway
  39. spec:
  40. parentRefs:
  41. - name: cnn-egress-gateway
  42. hostnames:
  43. - edition.cnn.com
  44. rules:
  45. - backendRefs:
  46. - kind: Hostname
  47. group: networking.istio.io
  48. name: edition.cnn.com
  49. port: 443
  50. EOF
  1. 发送 HTTPS 请求到 https://edition.cnn.com/politics, 输出结果应该和之前一样。

    1. $ kubectl exec "$SOURCE_POD" -c sleep -- curl -sSL -o /dev/null -D - https://edition.cnn.com/politics
    2. ...
    3. HTTP/2 200
    4. Content-Type: text/html; charset=utf-8
    5. ...
  2. 检查 Egress 网关代理的日志。

如果 Istio 部署在 istio-system 命名空间中,则打印日志的命令是:

  1. $ kubectl logs -l istio=egressgateway -n istio-system

您应该会看到类似于下面的内容:

  1. [2019-01-02T11:46:46.981Z] "- - -" 0 - 627 1879689 44 - "-" "-" "-" "-" "151.101.129.67:443" outbound|443||edition.cnn.com 172.30.109.80:41122 172.30.109.80:443 172.30.109.112:59970 edition.cnn.com

使用 Istio 生成的 Pod 标签访问与 Egress 网关对应的日志:

  1. $ kubectl logs -l gateway.networking.k8s.io/gateway-name=cnn-egress-gateway -c istio-proxy | tail

您应该会看到类似于下面的内容:

  1. [2024-01-11T21:09:42.835Z] "- - -" 0 - - - "-" 839 2504306 231 - "-" "-" "-" "-" "151.101.195.5:443" outbound|443||edition.cnn.com 172.30.239.8:34470 172.30.239.8:443 172.30.239.15:43956 edition.cnn.com -

清理 HTTPS 网关

  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
  1. $ kubectl delete serviceentry cnn
  2. $ kubectl delete gtw cnn-egress-gateway
  3. $ kubectl delete tlsroute direct-cnn-to-egress-gateway
  4. $ kubectl delete tlsroute forward-cnn-from-egress-gateway

其他安全注意事项

注意,Istio 中定义的 Egress Gateway 本身并没有为其所在的节点提供任何特殊处理。 集群管理员或云提供商可以在专用节点上部署 Egress 网关,并引入额外的安全措施, 从而使这些节点比网格中的其他节点更安全。

另外要注意的是,Istio 无法强制让所有出站流量都经过 Egress 网关, Istio 只是通过 Sidecar 代理实现了这种流向。攻击者只要绕过 Sidecar 代理, 就可以不经 Egress 网关直接与网格外的服务进行通信,从而避开了 Istio 的控制和监控。 出于安全考虑,集群管理员和云供应商必须确保网格所有的出站流量都要经过 Egress 网关。 这需要通过 Istio 之外的机制来满足这一要求。例如,集群管理员可以配置防火墙, 拒绝 Egress 网关以外的所有流量。 Kubernetes 网络策略也能禁止所有不是从 Egress 网关发起的出站流量(下一节有一个这样的例子)。 此外,集群管理员和云供应商还可以对网络进行限制,让运行应用的节点只能通过 gateway 来访问外部网络。 要实现这一限制,可以只给网关 Pod 分配公网 IP,并且可以配置 NAT 设备, 丢弃来自 Egress 网关 Pod 之外的所有流量。

应用 Kubernetes 网络策略

本节中展示了如何创建 Kubernetes 网络策略来阻止绕过 Egress 网关的出站流量。为了测试网络策略,首先创建一个 test-egress 命名空间, 并在其中部署 sleep 示例应用, 然后尝试发送一个会通过安全网关的外部服务请求。

  1. 参考用 Egress Gateway 发起 HTTPS 请求一节中的步骤。

  2. 创建 test-egress 命名空间:

    1. $ kubectl create namespace test-egress
  3. sleep 样例部署到 test-egress 命名空间。

    Zip

    1. $ kubectl apply -n test-egress -f @samples/sleep/sleep.yaml@
  4. 检查生成的 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
  5. test-egress 命名空间的 sleep Pod 中向 https://edition.cnn.com/politics 发送 HTTPS 请求。因为没有任何限制,所以这一请求应该会成功:

    1. $ kubectl exec "$(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
  6. 给 Istio 组件(控制平面和 Gateway)所在的命名空间打上标签。 如果您将 Istio 部署在 istio-system 命名空间中,则命令是:

  1. $ kubectl label namespace istio-system istio=system
  1. $ kubectl label namespace istio-system istio=system
  2. $ kubectl label namespace default gateway=true
  1. kube-system 命名空间打标签:

    1. $ kubectl label ns kube-system kube-system=true
  2. 创建一个 NetworkPolicy,来限制 test-egress 命名空间的出站流量, 只允许目标为控制平面、网关和 kube-system DNS 服务(端口 53)的所有请求。

    网络政策由 Kubernetes 集群中的网络插件实现。根据您的测试集群,以下步骤中的流量可能不会被阻止。

  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
  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. - to:
  23. - namespaceSelector:
  24. matchLabels:
  25. gateway: "true"
  26. EOF
  1. 重新发送前面的 HTTPS 请求到 https://edition.cnn.com/politics。 这次请求就不会成功了,这是因为流量被网络策略拦截了。sleep Pod 无法绕过 istio-egressgateway。 要访问 edition.cnn.com,只能通过 Istio Sidecar 代理,让流量经过 istio-egressgateway 才能完成。这种配置表明,即使一些恶意的 Pod 绕过了 Sidecar,也会被网络策略拦截,而无法访问到外部站点。

    1. $ kubectl exec "$(kubectl get pod -n test-egress -l app=sleep -o jsonpath={.items..metadata.name})" -n test-egress -c sleep -- curl -v -sS 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
  2. 接下来在 test-egress 命名空间的 sleep Pod 上注入 Sidecar,启用 test-egress 命名空间的自动注入:

    1. $ kubectl label namespace test-egress istio-injection=enabled
  3. 重新部署 sleep

    Zip

    1. $ kubectl delete deployment sleep -n test-egress
    2. $ kubectl apply -f @samples/sleep/sleep.yaml@ -n test-egress
  4. 检查生成的 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

default 命名空间中创建一个与 sleep Pod 类似的目标规则,用来引导 test-egress 命名空间内的流量经过 Egress 网关:

  1. $ kubectl apply -n test-egress -f - <<EOF
  2. apiVersion: networking.istio.io/v1
  3. kind: DestinationRule
  4. metadata:
  5. name: egressgateway-for-cnn
  6. spec:
  7. host: istio-egressgateway.istio-system.svc.cluster.local
  8. subsets:
  9. - name: cnn
  10. EOF
  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
  1. https://edition.cnn.com/politics 发送 HTTP 请求,这次会成功,原因是网络策略允许流量流向 Egress 网关。 Gateway 最终把流量转发到 edition.cnn.com

    1. $ kubectl exec "$(kubectl get pod -n test-egress -l app=sleep -o jsonpath={.items..metadata.name})" -n test-egress -c sleep -- curl -sS -o /dev/null -w "%{http_code}\n" https://edition.cnn.com/politics
    2. 200
  2. 检查 Egress 网关代理的日志。

如果 Istio 部署在 istio-system 命名空间,那么打印日志的命令就是:

  1. $ kubectl logs -l istio=egressgateway -n istio-system

您应该会看到一行类似于下面这样的内容:

  1. [2020-03-06T18:12:33.101Z] "- - -" 0 - "-" "-" 906 1352475 35 - "-" "-" "-" "-" "151.101.193.67:443" outbound|443||edition.cnn.com 172.30.223.53:39460 172.30.223.53:443 172.30.223.58:38138 edition.cnn.com -

使用 Istio 生成的 Pod 标签访问与 Egress 网关对应的日志:

  1. $ kubectl logs -l gateway.networking.k8s.io/gateway-name=cnn-egress-gateway -c istio-proxy | tail

您应该会看到一行类似于下面这样的内容:

  1. [2024-01-12T19:54:01.821Z] "- - -" 0 - - - "-" 839 2504837 46 - "-" "-" "-" "-" "151.101.67.5:443" outbound|443||edition.cnn.com 172.30.239.60:49850 172.30.239.60:443 172.30.239.21:36512 edition.cnn.com -

清理网络策略

  1. 删除本节中建立的资源:

Zip

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

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 label namespace default gateway-
  6. $ kubectl delete namespace test-egress
  1. 请参考清理 HTTPS 网关 一节的内容。

清理

关闭 sleep 服务:

Zip

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