zh:sync example-egress-gateway (#2648)

This commit is contained in:
Vincent 2018-09-19 21:17:25 +08:00 committed by istio-bot
parent ee2f55a5ad
commit 41dd7e9f18
1 changed files with 229 additions and 66 deletions

View File

@ -1,60 +1,58 @@
---
title: 配置 Egress 网关
title: 配置 Egress gateway
description: 描述如何通过专用网关服务将流量定向到外部服务来配置 Istio。
weight: 43
keywords: [traffic-management,egress]
---
> 此任务使用新的 [v1alpha3 流量管理 API](/zh/blog/2018/v1alpha3-routing/) 。旧的 API 已被弃用并将在下一个 Istio 版本中删除。如果您需要使用旧版本,请按照[此处](https://archive.istio.io/v0.7/docs/tasks/traffic-management/)的文档操作。请注意,此任务引入了一个新概念,即 Egress 网关,这在以前的 Istio 版本中是不存在的。
[控制 Egress 流量](/zh/docs/tasks/traffic-management/egress/)任务演示了如何从网格内的应用程序访问外部Kubernetes 集群外部HTTP 和 HTTPS 服务。快速提醒:默认情况下,启用 Istio 的应用程序无法访问集群外的 URL。要启用此类访问必须定义外部服务的[服务条目](/docs/reference/config/istio.networking.v1alpha3/#ServiceEntry),或者[直接访问外部服务](/docs/tasks/traffic-management/egress/#calling-external-services-directly)。
[控制 Egress 流量](/zh/docs/tasks/traffic-management/egress/)任务演示了如何从网格内的应用程序访问外部Kubernetes 集群外部HTTP 和 HTTPS 服务。这里提醒一下:默认情况下,启用 Istio 的应用程序无法访问集群外的 URL。要启用此类访问必须定义外部服务的 [`ServiceEntry`](/docs/reference/config/istio.networking.v1alpha3/#ServiceEntry),或者配置[直接访问外部服务](/docs/tasks/traffic-management/egress/#calling-external-services-directly)。
[Egress 流量的 TLS](/zh/docs/examples/advanced-gateways/egress-tls-origination/) 任务演示了如何允许应用程序将 HTTP 请求发送到需要 HTTPS 的外部服务器。
此任务描述了通过名为 _Egress Gateway_ 的专用服务如何配置 Istio 引导出口流量。我们实现了与 [Egress 流量的 TLS](/zh/docs/examples/advanced-gateways/egress-tls-origination/) 任务中描述的相同功能,这次我们通过添加 egress 网关来完成它
此任务描述了通过名为 `Egress Gateway` 的专用服务如何配置 Istio 引导出口流量。我们实现了与 [Egress 流量的 TLS](/zh/docs/examples/advanced-gateways/egress-tls-origination/) 任务中描述的相同功能,唯一的区别就是,这里会使用 Egress gateway 来完成这一任务
## 用例
考虑一个具有严格安全要求的组织。根据这些要求,离​​开服务网格的所有流量必须流经一组专用节点。这些节点将在专用计算机上运行,​​与用于在集群中运行应用程序的其余节点分开运行。特殊节点将用于 egress 流量的策略实施,并且将比其余节点进行更详细地监控。
设想一个具有严格安全要求的组织。根据这些要求,服务网格的所有外发流量必须流经一组专用节点。这些节点和运行其他应用分别在不同的节点上运行。这些专用的节点将用于 Egress 流量的策略实施,并且将比其余节点进行更详细地监控。
Istio 0.8 引入了 [ingress 和 egress 网关](/docs/reference/config/istio.networking.v1alpha3/#Gateway)的概念。 Ingress 网关允许定义进入服务网格的入口点,所有入站流量都通过该入口点_Egress gateway_ 是一个对称的概念,它定义了网格的出口点。 Egress 网关允许将 Istio 功能(例如,监控和路由规则)应用于离开网格的流量。
Istio 0.8 引入了 [Ingress 和 Egress gateway](/zh/docs/reference/config/istio.networking.v1alpha3/#gateway) 的概念。 Ingress 网关允许定义进入服务网格的入口点,所有入站流量都通过该入口点`Egress gateway` 与之相对,它定义了网格的出口点。 Egress gateway 允许将 Istio 功能(例如,监控和路由规则)应用于 Egress 流量。
另一个用例是应用程序节点没有公共 IP 的集群,因此在其上运行的网格内服务无法访问 Internet。定义 egress 网关,通过它引导所有出口流量并将公共 IP 分配给 egress 网关节点,允许应用节点以受控方式访问外部服务。
另一个用例是应用程序节点没有公共 IP 的集群,因此在其上运行的网格内服务无法访问 Internet。定义 Egress gateway ,通过它引导所有出口流量并将公共 IP 分配给 Egress gateway 节点,允许应用节点以受控方式访问外部服务。
## 开始之前
* 按照[安装指南](/zh/docs/setup/)中的说明设置 Istio 。
* 启动 [sleep]({{<github_tree>}}/samples/sleep),它将被用作外部调用的测试源。
* 启动 [sleep]({{<github_tree>}}/samples/sleep) 应用,它将被用作外部调用的测试源。
如果您已经启用了 [automatic sidecar injection](/docs/setup/kubernetes/sidecar-injection/#automatic-sidecar-injection),请执行此操作
如果已经启用了 [Sidecar 的自动注入](/zh/docs/setup/kubernetes/sidecar-injection/#sidecar-的自动注入),请执行此操作
{{< text bash >}}
$ kubectl apply -f @samples/sleep/sleep.yaml@
{{< /text >}}
否则,您必须在部署 `sleep` 应用程序之前手动注入 sidecar
否则,就要在部署 `sleep` 应用程序之前手工进行 Sidecar 的注入
{{< text bash >}}
$ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@)
{{< /text >}}
请注意,您可以在任意 pod 使用 `exec``curl`
这样就可以在任意 pod 使用 `exec``curl` 命令了
* 创建一个 shell 变量来保存源 pod 的名称,以便将请求发送到外部服务。如果我们使用 [sleep]({{<github_tree>}}/samples/sleep) 示例,我们运行:
* 创建一个环境变量来保存源 Pod 名称,以便将请求发送到外部服务。例如在 [sleep]({{<github_tree>}}/samples/sleep) 示例中运行:
{{< text bash >}}
$ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
{{< /text >}}
## 定义 egress `Gateway` 并通过它定向 HTTP 流量
## 定义 Egress gateway 并引导 HTTP 流量通过这一网关
首先定向没有 TLS 的 HTTP 流量
1. `edition.cnn.com` 定义一个 `ServiceEntry`
1. 为 `edition.cnn.com` 定义一个 `ServiceEntry`
{{< text bash >}}
$ cat <<EOF | istioctl create -f -
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
@ -69,11 +67,11 @@ Istio 0.8 引入了 [ingress 和 egress 网关](/docs/reference/config/istio.net
- number: 443
name: https
protocol: HTTPS
resolution: DNS
resolution: DNS
EOF
{{< /text >}}
1. 验证您的 `ServiceEntry` 是否已正确应用。发送 HTTPS 请求到 [http://edition.cnn.com/politics](http://edition.cnn.com/politics)。
1. 验证 `ServiceEntry` 是否已正确应用。发送 HTTPS 请求到 [http://edition.cnn.com/politics](http://edition.cnn.com/politics)。
{{< text bash >}}
$ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
@ -91,12 +89,12 @@ Istio 0.8 引入了 [ingress 和 egress 网关](/docs/reference/config/istio.net
输出应与 [Egress 流量的 TLS](/zh/docs/examples/advanced-gateways/egress-tls-origination/) 任务中的输出相同,不带 TLS。
1. 创建 egress `Gateway`_edition.cnn.com_ ,端口 80。除此之外还创建了一个 `DestinationRule``VirtualService` 来引导流量通过 egress 网关与外部服务通信。
1. `edition.cnn.com` 端口 80 创建 Egress gateway。除此之外还要创建一个 `DestinationRule``VirtualService` 来引导流量通过 Egress gateway 与外部服务通信。
如果在 Istio 中启用了[双向 TLS 认证](/zh/docs/tasks/security/mutual-tls/),请使用以下命令。
{{< text bash >}}
$ cat <<EOF | istioctl create -f -
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
@ -140,7 +138,7 @@ Istio 0.8 引入了 [ingress 和 egress 网关](/docs/reference/config/istio.net
如果没有启用双向 TLS 认证:
{{< text bash >}}
$ cat <<EOF | istioctl create -f -
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
@ -167,10 +165,10 @@ Istio 0.8 引入了 [ingress 和 egress 网关](/docs/reference/config/istio.net
EOF
{{< /text >}}
1. 定义 `VirtualService` 来引导流量通过 egress 网关
1. 定义 `VirtualService` 来引导流量通过 Egress gateway
{{< text bash >}}
$ cat <<EOF | istioctl create -f -
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
@ -206,7 +204,7 @@ Istio 0.8 引入了 [ingress 和 egress 网关](/docs/reference/config/istio.net
EOF
{{< /text >}}
1. 将 HTTP 请求重新发送到 [http://edition.cnn.com/politics](https://edition.cnn.com/politics)。
1. 将 HTTP 请求重新发送到 [http://edition.cnn.com/politics](https://edition.cnn.com/politics)。
{{< text bash >}}
$ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
@ -224,7 +222,7 @@ Istio 0.8 引入了 [ingress 和 egress 网关](/docs/reference/config/istio.net
输出应与步骤2中的输出相同。
1. 检查 `istio-egressgateway` pod 的日志,并查看与我们的请求对应的行。如果 Istio 部署在 `istio-system` 命名空间中,则打印日志的命令是:
1. 检查 `istio-egressgateway` pod 的日志,并查看与我们的请求对应的行。如果 Istio 部署在 `istio-system` 命名空间中,则打印日志的命令是:
{{< text bash >}}
$ kubectl logs $(kubectl get pod -l istio=egressgateway -n istio-system -o jsonpath='{.items[0].metadata.name}') egressgateway -n istio-system | tail
@ -236,9 +234,9 @@ Istio 0.8 引入了 [ingress 和 egress 网关](/docs/reference/config/istio.net
[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"
{{< /text >}}
请注意,我们只将流量从 80 端口重定向到 egress 网关,到 443 端口的 HTTPS 流量直接转到 _edition.cnn.com_
请注意,我们只将流量从 80 端口重定向到 Egress gateway ,到 443 端口的 HTTPS 流量直接转到 `edition.cnn.com`
### 清除 HTTP 流量的 egress 网关
### 清除 HTTP 流量的 Egress gateway
在继续下一步之前删除先前的定义:
@ -249,14 +247,14 @@ $ kubectl delete virtualservice direct-cnn-through-egress-gateway
$ kubectl delete destinationrule egressgateway-for-cnn
{{< /text >}}
## Egress `Gateway` 执行 TLS
## 用 Egress gateway 发起 TLS 连接
让我们用 egress `Gateway` 执行 TLS类似于 [TLS Origination for Egress Traffic](/zh/docs/examples/advanced-gateways/egress-tls-origination/) 任务。请注意在这种情况下TLS 将由 egress 网关服务器完成,而不是前一任务中的 sidecar。
接下来尝试使用 Egress Gateway 发起 TLS 连接,效果类似于 [出口流量的 TLS](/zh/docs/examples/advanced-gateways/egress-tls-origination/) 任务具体区别是在这种情况下TLS 功能是由 Egress gateway 服务器完成的,而不是前一任务中的 Sidecar。
1. `edition.cnn.com` 定义 `ServiceEntry`
1. 为 `edition.cnn.com` 定义 `ServiceEntry`
{{< text bash >}}
$ cat <<EOF | istioctl create -f -
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
@ -264,18 +262,18 @@ $ kubectl delete destinationrule egressgateway-for-cnn
spec:
hosts:
- edition.cnn.com
ports:
ports:
- number: 80
name: http-port
protocol: HTTP
- number: 443
name: http-port-for-tls-origination
protocol: HTTP
resolution: DNS
resolution: DNS
EOF
{{< /text >}}
1. 验证您的 `ServiceEntry` 是否已正确应用。发送 HTTPS 请求到 [http://edition.cnn.com/politics](https://edition.cnn.com/politics)。
1. 验证您的 `ServiceEntry` 是否已正确生效。发送 HTTPS 请求到 [http://edition.cnn.com/politics](https://edition.cnn.com/politics)。
{{< text bash >}}
$ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
@ -287,14 +285,14 @@ $ kubectl delete destinationrule egressgateway-for-cnn
command terminated with exit code 35
{{< /text >}}
如果你看到输出结果中包含 _301 Moved Permanently_ ,说明 `ServiceEntry` 配置正确。退出代码 _35_ 是由于 Istio 没有执行 TLS。 为了让 Egress 网关执行 TLS继续执行以下步骤进行配置。
如果看到输出结果中包含 `301 Moved Permanently`,说明 `ServiceEntry` 配置正确。退出代码 `35` 是由于 Istio 没有执行 TLS。 为了让 Egress gateway 执行 TLS还要继续执行以下步骤进行配置。
1. _edition.cnn.com_ 创建 egress `Gateway`,端口 443。除此之外还创建了一个 `DestinationRule``VirtualService` 来引导流量通过 egress 网关与外部服务通信。
1. `edition.cnn.com` 创建 Egress Gateway,端口 443。除此之外还创建了一个 `DestinationRule``VirtualService`,这两个对象用来引导流量通过 Egress gateway 与外部服务通信。
如果在 Istio 中启用了 [双向 TLS 认证](/zh/docs/tasks/security/mutual-tls/) ,请使用以下命令。
如果在 Istio 中启用了 [双向 TLS 认证](/zh/docs/tasks/security/mutual-tls/),请使用以下命令。
{{< text bash >}}
$ cat <<EOF | istioctl create -f -
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
@ -338,7 +336,7 @@ $ kubectl delete destinationrule egressgateway-for-cnn
如果没有启用双向 TLS 认证:
{{< text bash >}}
$ cat <<EOF | istioctl create -f -
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
@ -365,10 +363,10 @@ $ kubectl delete destinationrule egressgateway-for-cnn
EOF
{{< /text >}}
1. 定义 `VirtualService` 来引导流量通过 egress 网关,并定义 `DestinationRule` 以执行 TLS
1. 定义 `VirtualService` 来引导流量通过 Egress gateway,并定义 `DestinationRule` 以执行 TLS
{{< text bash >}}
$ cat <<EOF | istioctl create -f -
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
@ -419,7 +417,7 @@ $ kubectl delete destinationrule egressgateway-for-cnn
EOF
{{< /text >}}
1. 发送 HTTP 请求到 [http://edition.cnn.com/politics](https://edition.cnn.com/politics).
1. 发送 HTTP 请求到 [http://edition.cnn.com/politics](https://edition.cnn.com/politics).
{{< text bash >}}
$ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics
@ -429,21 +427,21 @@ $ kubectl delete destinationrule egressgateway-for-cnn
...
{{< /text >}}
输出应与 [TLS Origination for Egress Traffic](/zh/docs/examples/advanced-gateways/egress-tls-origination/) 任务中的输出相同TLS 来源:没有 _301 Moved Permanently_ 信息。
输出应与 [出口流量的 TLS](/zh/docs/examples/advanced-gateways/egress-tls-origination/) 任务中的输出相同:没有 `301 Moved Permanently` 信息。
1. 检查 `istio-egressgateway` pod 的日志,并查看与我们的请求相对应的行。如果 Istio 部署在 `istio-system` 命名空间中,则打印日志的命令是:
1. 检查 `istio-egressgateway` pod 的日志,并查看与我们的请求相对应的行。如果 Istio 部署在 `istio-system` 命名空间中,则打印日志的命令是:
{{< text bash >}}
$ kubectl logs $(kubectl get pod -l istio=egressgateway -n istio-system -o jsonpath='{.items[0].metadata.name}') egressgateway -n istio-system | tail
{{< /text >}}
我们看到与我们的请求相关的行,类似于以下内容:
这里会看到与之前请求相关的行,类似于以下内容:
{{< text plain>}}
"[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"
{{< /text >}}
### 清除 TLS 发起的 egress 网关
### 清除发起 TLS 的 Egress gateway
删除我们创建的 Istio 配置项:
@ -455,14 +453,14 @@ $ kubectl delete destinationrule originate-tls-for-edition-cnn-com
$ kubectl delete destinationrule egressgateway-for-cnn
{{< /text >}}
## 通过 egress 网关定向 HTTPS 流量
## 通过 Egress gateway 进行 HTTPS 流量透传
在本节中,您将通过 egress 网关引导HTTPS流量由应用程序发起的 TLS。在相应的 `ServiceEntry` 中指定端口 443协议 `TLS`egress `Gateway``VirtualService`。
在本节中,将通过 Egress gateway 进行 HTTPS 流量透传(由应用程序发起的 TLS。在相应的 `ServiceEntry`、`Egress gateway` 以及 `VirtualService` 中指定端口 443协议 `TLS`。
1. `edition.cnn.com` 定义 `ServiceEntry`
1. 为 `edition.cnn.com` 定义 `ServiceEntry`
{{< text bash >}}
$ cat <<EOF | istioctl create -f -
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
@ -470,15 +468,15 @@ $ kubectl delete destinationrule egressgateway-for-cnn
spec:
hosts:
- edition.cnn.com
ports:
ports:
- number: 443
name: tls
protocol: TLS
resolution: DNS
resolution: DNS
EOF
{{< /text >}}
1. 验证您的 `ServiceEntry` 是否已正确应用。发送 HTTPS 请求到 [http://edition.cnn.com/politics](https://edition.cnn.com/politics)。输出应与上一节中的输出相同。
1. 验证 `ServiceEntry` 是否已正确生效。发送 HTTPS 请求到 [http://edition.cnn.com/politics](https://edition.cnn.com/politics)。输出应与上一节中的输出相同。
{{< text bash >}}
$ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - https://edition.cnn.com/politics
@ -489,12 +487,12 @@ $ kubectl delete destinationrule egressgateway-for-cnn
...
{{< /text >}}
1. _edition.cnn.com_ 创建 egress `Gateway` ,端口 443TLS 协议。除此之外还创建了一个 `DestinationRule``VirtualService` 来引导流量通过 egress 网关与外部服务通信。
1. `edition.cnn.com` 创建 Egress gateway,端口 443TLS 协议。除此之外还创建了一个 `DestinationRule``VirtualService` 来引导流量通过 Egress gateway 与外部服务通信。
如果在 Istio 中启用了[双向 TLS 认证](/zh/docs/tasks/security/mutual-tls/) ,请使用以下命令。
如果在 Istio 中启用了[双向 TLS 认证](/zh/docs/tasks/security/mutual-tls/),请使用以下命令。
{{< text bash >}}
$ cat <<EOF | istioctl create -f -
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
@ -573,7 +571,7 @@ $ kubectl delete destinationrule egressgateway-for-cnn
如果没有启用双向 TLS 认证:
{{< text bash >}}
$ cat <<EOF | istioctl create -f -
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
@ -638,7 +636,7 @@ $ kubectl delete destinationrule egressgateway-for-cnn
EOF
{{< /text >}}
1. 发送 HTTPS 请求到 [http://edition.cnn.com/politics](https://edition.cnn.com/politics)。输出应与之前相同。
1. 发送 HTTPS 请求到 [http://edition.cnn.com/politics](https://edition.cnn.com/politics)。输出应与之前相同。
{{< text bash >}}
$ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - https://edition.cnn.com/politics
@ -649,16 +647,16 @@ $ kubectl delete destinationrule egressgateway-for-cnn
...
{{< /text >}}
1. 检查 egress 网关代理的统计信息,并查看与我们对 _edition.cnn.com_ 的请求相对应的计数器。如果 Istio 部署在 `istio-system` 命名空间中,则打印计数器的命令是:
1. 检查 Egress gateway 代理的统计信息,并查看与我们对 `edition.cnn.com` 的请求相对应的计数器。如果 Istio 部署在 `istio-system` 命名空间中,则打印计数器的命令是:
{{< text bash >}}
$ 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
cluster.outbound|443||edition.cnn.com.upstream_cx_total: 1
{{< /text >}}
您可能需要执行几个额外的请求,并验证每个请求上面的计数器增加1。
如果再执行几个额外的请求,应该会看到每次请求之后上面的计数器都会加 1。
### 清除 HTTPS 流量的 egress 网关
### 清除 HTTPS 流量的 Egress gateway
{{< text bash >}}
$ kubectl delete serviceentry cnn
@ -667,17 +665,158 @@ $ kubectl delete virtualservice direct-cnn-through-egress-gateway
$ kubectl delete destinationrule egressgateway-for-cnn
{{< /text >}}
## 其他安全因素
## 额外的安全考量
请注意,在 Istio 中定义 egress `Gateway` 本身并不为运行 egress 网关服务的节点提供任何特殊处理。集群管理员或云提供商可以在专用节点上部署 egress 网关,并引入额外的安全措施,使这些节点比网格的其余部分更安全。
在 Istio 中定义的 Egress gateway本身并不会对运行 Egress gateway 服务的节点进行任何特殊处理。集群管理员或云提供商可以在专用节点上部署 Egress gateway ,并引入额外的安全措施,使这些节点比网格的其余部分更安全。
另请注意,实际上 Istio 本身无法安全地强制将所有 egress 流量流经 egress 网关Istio 仅通过其 sidecar 代理启用此类流量。如果恶意应用程序攻击连接到应用程序 pod 的 sidecar 代理,它可能会绕过 sidecar 代理。绕过 sidecar 代理后,恶意应用程序可能会尝试绕过 egress 网关直接与网格外面的服务通信,以逃避 Istio 的控制和监控。由集群管理员或云服务商通过 Istio 以外的机制来确保没有流量绕过 egress 网关直接与网格外面的服务通信。例如,防火墙可以拒绝其源不是 egress 网关的所有流量。 [Kubernetes 网络策略](https://kubernetes.io/docs/concepts/services-networking/network-policies/)也可以禁止所有不经过 egress 网关出口的 egress 流量。另一种可能的安全措施涉及以这样的方式配置网络:由于应用节点不能直接访问因特网,必须将 egress 流量引导到 egress 网关才能访问因特网。这种网络配置的一个例子是只给 egress 网关分配外网 IP。
另外要注意的是,实际上 Istio 本身无法安全地强制将所有 Egress 流量流经 Egress gateway Istio 仅通过其 Sidecar 代理启用此类流量。攻击者只要绕过 Sidecar 代理,就可以不经 Egress gateway 直接与网格外面的服务进行通信,从而避免了 Istio 的控制和监控。集群管理员或云供应商必须确保所有外发流量都从 Egress gateway 途径发起。需要用 Istio 之外的机制来满足这一需求,例如以下几种做法:
* 使用防火墙拒绝所有来自 Egress gateway 以外的流量。
* [Kubernetes 网络策略](https://kubernetes.io/docs/concepts/services-networking/network-policies/)也能禁止所有不是从 Egress gateway 发起的 Egress 流量([#下一节](#应用-Kubernetes-网络策略) 中举出了这样的例子)。
* 管理员或者云供应商还可以对网络进行限制,让运行应用的节点只能通过 Gateway 来访问外部网络。要完成这一限制,可以只给 Gateway Pod 分配公网 IP或者可以配置 NAT 设备,丢弃来自 Egress gateway 以外 Pod 的流量。
## 应用 Kubernetes 网络策略
本节中会创建 [Kubernetes 网络策略](https://kubernetes.io/docs/concepts/services-networking/network-policies/),阻止绕过 Egress gateway 的外发流量。要完成这一示例,首先创建一个 `test-egress` 命名空间,并在其中部署 [sleep]({{< github_tree >}}/samples/sleep) 示例应用。
1. 重复执行[“通过 Egress gateway 进行 HTTPS 流量透传”](#通过-Egress-gateway-进行-HTTPS-流量透传)一节的内容。
1. 创建 `test-egress` 命名空间:
{{< text bash >}}
$ kubectl create namespace test-egress
{{< /text >}}
1. 在 `test-egress` 命名空间中部署 [sleep]({{< github_tree >}}/samples/sleep) 示例应用:
{{< text bash >}}
$ kubectl apply -n test-egress -f @samples/sleep/sleep.yaml@
{{< /text >}}
1. 检查生成的 Pod其中应该只有一个容器也就是说没有注入 Istio sidecar
{{< text bash >}}
$ kubectl get pod $(kubectl get pod -n test-egress -l app=sleep -o jsonpath={.items..metadata.name}) -n test-egress
NAME READY STATUS RESTARTS AGE
sleep-776b7bcdcd-z7mc4 1/1 Running 0 18m
{{< /text >}}
1. 从 `test-egress` 命名空间的 `sleep` Pod 中向 [http://edition.cnn.com/politics](https://edition.cnn.com/politics) 发送 HTTPS 请求。因为没有任何限制,所以这一请求应该会成功:
{{< text bash >}}
$ 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
200
{{< /text >}}
1. 给 Istio 组件(控制平面和 Gateway所在的命名空间打上标签例如 `istio-system`
{{< text bash >}}
$ kubectl label namespace istio-system istio=system
{{< /text >}}
1. 给 `kube-system` 命名空间打标签:
{{< text bash >}}
$ kubectl label ns kube-system kube-system=true
{{< /text >}}
1. 创建一个 `NetworkPolicy`,来自 `test-egress` 命名空间的流量,只允许目标为 `kube-system` 的 DNS端口 53请求以及目标为 `istio-system` 命名空间的所有请求:
{{< text bash >}}
$ cat <<EOF | kubectl apply -n test-egress -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-to-istio-system-and-kube-dns
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kube-system: "true"
ports:
- protocol: UDP
port: 53
- to:
- namespaceSelector:
matchLabels:
istio: system
EOF
{{< /text >}}
1. 重新发送前面的 HTTPS 请求到 [http://edition.cnn.com/politics](https://edition.cnn.com/politics)。这次请求就不会成功了,这是因为流量被网络策略拦截了。测试 Pod 无法越过 `istio-egressgateway`。要访问 `edition.cnn.com`,只能通过 Istio sidecar 将流量转给 `istio-egressgateway` 才能完成。这一设置演示了即使绕过了 Sidecar也会被网络策略拦截而无法访问到外部站点。
{{< text bash >}}
$ 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
Hostname was NOT found in DNS cache
Trying 151.101.65.67...
Trying 2a04:4e42:200::323...
Immediate connect fail for 2a04:4e42:200::323: Cannot assign requested address
Trying 2a04:4e42:400::323...
Immediate connect fail for 2a04:4e42:400::323: Cannot assign requested address
Trying 2a04:4e42:600::323...
Immediate connect fail for 2a04:4e42:600::323: Cannot assign requested address
Trying 2a04:4e42::323...
Immediate connect fail for 2a04:4e42::323: Cannot assign requested address
connect to 151.101.65.67 port 443 failed: Connection timed out
{{< /text >}}
1. 接下来在 `test-egress` 命名空间的 `sleep` Pod 上注入 Sidecar启用 `test-egress` 命名空间的自动注入:
{{< text bash >}}
$ kubectl label namespace test-egress istio-injection=enabled
{{< /text >}}
1. 重新部署 `sleep`
{{< text bash >}}
$ kubectl delete deployment sleep -n test-egress
$ kubectl apply -f @samples/sleep/sleep.yaml@ -n test-egress
{{< /text >}}
1. 检查生成的 Pod其中应该有了两个容器其中包含了注入的 Sidecar`istio-proxy`
{{< text bash >}}
$ 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}
sleep istio-proxy
{{< /text >}}
1. 向 [http://edition.cnn.com/politics](https://edition.cnn.com/politics) 发送 HTTP 请求,这次会成功,原因是网络策略允许流量流向 `istio-system` 中的 `istio-egressgateway``istio-egressgateway` 最终把流量转发到 `edition.cnn.com`
{{< text bash >}}
$ 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
200
{{< /text >}}
1. 检查 Egress gateway 中的代理统计数据,查看对 `edition.cnn.com` 的请求计数。如果 Istio 部署在 `istio-system` 命名空间,那么打印计数器的命令就是:
{{< text bash >}}
$ 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
cluster.outbound|443||edition.cnn.com.upstream_cx_total: 2
{{< /text >}}
### 清理网络策略
1. 删除本节中建立的资源:
{{< text bash >}}
$ kubectl delete -f @samples/sleep/sleep.yaml@ -n test-egress
$ kubectl delete networkpolicy allow-egress-to-istio-system-and-kube-dns -n test-egress
$ kubectl label namespace kube-system kube-system-
$ kubectl label namespace istio-system istio-
$ kubectl delete namespace test-egress
{{< /text >}}
1. 执行[“通过 Egress gateway 进行 HTTPS 流量透传”](#通过-Egress-gateway-进行-HTTPS-流量透传)一节中的[清理工作](#清除-HTTPS-流量的-Egress-gateway)。
## 故障排除
1. 检查您是否在 Istio 中启用了[双向 TLS 认证](/zh/docs/tasks/security/mutual-tls/),然后执行以下步骤:[验证 Istio 的双向 TLS 认证设置](/docs/tasks/security/mutual-tls/#verify-mutual-tls-configuration)。如果启用了双向 TLS请确保创建相应的项目配置请注意备注 _如果您在 Istio 中启用了双向 TLS 认证,则必须创建..._ )。
1. 检查是否在 Istio 中启用了[双向 TLS 认证](/zh/docs/tasks/security/mutual-tls/),然后执行以下步骤:[验证 Istio 的双向 TLS 认证设置](/zh/docs/tasks/security/mutual-tls/#检查-istio-双向-tls-认证的配置)。如果启用了双向 TLS请确保创建相应的项目配置请注意备注**如果您在 Istio 中启用了双向 TLS 认证,则必须创建...**)。
1. 如果[双向 TLS 认证](/zh/docs/tasks/security/mutual-tls/)启用后, 验证 egress 网关的证书:
1. 如果[双向 TLS 认证](/zh/docs/tasks/security/mutual-tls/)启用后, 验证 Egress gateway 的证书:
{{< text bash >}}
$ 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
@ -685,6 +824,30 @@ $ kubectl delete destinationrule egressgateway-for-cnn
URI:spiffe://cluster.local/ns/istio-system/sa/istio-egressgateway-service-account
{{< /text >}}
1. HTTPS 透传流量情况,需要使用 `openssl` 命令测试流量。`openssl` 的 `-servername` 选项可以用来设置 SNI
{{< text bash >}}
$ kubectl exec -it $SOURCE_POD -c sleep -- openssl s_client -connect edition.cnn.com:443 -servername edition.cnn.com
CONNECTED(00000003)
...
Certificate chain
0 s:/C=US/ST=California/L=San Francisco/O=Fastly, Inc./CN=turner-tls.map.fastly.net
i:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign CloudSSL CA - SHA256 - G3
1 s:/C=BE/O=GlobalSign nv-sa/CN=GlobalSign CloudSSL CA - SHA256 - G3
i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
...
{{< /text >}}
如果在上面命令的输出中看到了类似的证书信息,就表明路由是正确的。接下来检查 Egress gateway 代理,查找对应请求的计数器(由 `openssl``curl` 发送,目标是 `edition.cnn.com`
{{< text bash >}}
$ 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
cluster.outbound|443||edition.cnn.com.upstream_cx_total: 2
{{< /text >}}
## 清理
关闭 [sleep]({{<github_tree>}}/samples/sleep) 服务: