上一节学习了istio服务网格内部访问外部服务的三种方法,推荐使用ServiceEntry将一个外部服务注册到服务网格中的方式,这样服务网格内部的到外部服务的访问流量都是受到istio管理的,但这种方法下访问外部服务的流量都是从内部服务实例所在节点的sidecar代理发出的,这在某些场景下会有一些限制。 例如,一个对安全有严格要求的组织,要求服务网格所有的出站流量必须经过一组专用节点。专用节点运行在专门的机器上,与集群中运行应用程序的其他节点隔离,这些专用节点将专门实施针对出站流量的策略,并且受到比其余节点更严密地监控。另外一个场景是在集群中不是所有节点都可以访问公网(或某个外部IP的),如集群中只有一个节点可以访问公网,所以服务网格内其他节点上的服务实例也就无法访问公网上的外部服务了。在这两个场景中都是因为服务网格内的一部分节点在网络上无法访问外部服务,因此需要有一个在网络上可以访问外部服务的节点作为egress gateway节点,用来引导所有的出站流量,这样也能实现该节点以受控的方式访问外部服务。

前面第7节我们学习Istio Ingress Gateway用来将集群外部流量接入到服务网格内,与之对应的还有一个Istio Egress Gateway定义了服务网格的统一出口。 Ingress and Egress Gateways可以被理解为配置运行在服务网格边缘的负载均衡,Ingress gateway允许我们定义网格所有入站流量的入口,Egress gateway允许我们定义网格的出口。

下面来具体实际操作一下。以demo profile部署的isito已经随之安装了engress gateway,可以使用下面的命令查看一下:

1kubectl get all -n istio-system -l app=istio-egressgateway
2NAME                                      READY   STATUS    RESTARTS   AGE
3pod/istio-egressgateway-7d4f75956-mq6d9   1/1     Running   0          8d
4
5NAME                          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
6service/istio-egressgateway   ClusterIP   10.105.21.145   <none>        80/TCP,443/TCP   25d
7
8NAME                                  READY   UP-TO-DATE   AVAILABLE   AGE
9deployment.apps/istio-egressgateway   1/1     1            1           25d

在真实的使用场景中我们应该将istio-egressgateway调度到服务网格内专门用作egress gateway的节点上。

下面测试使用istio-egressgateway引导服务网格内访问外部服务httpbin.org的流量。

与上节内容一下,要访问外部服务,需要先创建一个ServiceEntry将外部服务注册到服务网格内:

 1kubectl apply -f - <<EOF
 2apiVersion: networking.istio.io/v1alpha3
 3kind: ServiceEntry
 4metadata:
 5  name: httpbin-ext
 6spec:
 7  hosts:
 8  - httpbin.org
 9  ports:
10  - number: 443
11    name: https
12    protocol: HTTPS
13  resolution: DNS
14EOF

因为default命名空间在前面部署bookinfo应用时已经开启了istio sidecar的自动注入功能,这里我们在default命令空间中手动启动一个radial/busyboxplus:curl pod用来测试,启动的这个pod将被自动注入istio sidecar代理:

1kubectl run curl --image=radial/busyboxplus:curl -it

在curl容器内部测试可以正常访问httpbin.org,说明ServiceEntry已经配置。

1curl -sSI https://httpbin.org/headers | grep "HTTP/"
2HTTP/1.1 200 OK

httpbin.org的443端口创建Egress Gateway。并为指向Egress Gateway的流量创建一个目标规则DestinationRule。

 1kubectl apply -f - <<EOF
 2apiVersion: networking.istio.io/v1alpha3
 3kind: Gateway
 4metadata:
 5  name: istio-egressgateway
 6spec:
 7  selector:
 8    istio: egressgateway
 9  servers:
10  - port:
11      number: 443
12      name: tls
13      protocol: TLS
14    hosts:
15    - httpbin.org
16    tls:
17      mode: PASSTHROUGH
18---
19apiVersion: networking.istio.io/v1alpha3
20kind: DestinationRule
21metadata:
22  name: egressgateway-for-httpbin-ext
23spec:
24  host: istio-egressgateway.istio-system.svc.cluster.local
25  subsets:
26  - name: httpbin-ext
27EOF

创建一个虚拟服务VirtualService,将流量从 sidecar 引导至 egress gateway,再从 egress gateway 引导至外部服务:

 1kubectl apply -f - <<EOF
 2apiVersion: networking.istio.io/v1alpha3
 3kind: VirtualService
 4metadata:
 5  name: direct-httpbin-ext-through-egress-gateway
 6spec:
 7  hosts:
 8  - httpbin.org
 9  gateways:
10  - mesh
11  - istio-egressgateway
12  tls:
13  - match:
14    - gateways:
15      - mesh
16      port: 443
17      sniHosts:
18      - httpbin.org
19    route:
20    - destination:
21        host: istio-egressgateway.istio-system.svc.cluster.local
22        subset: httpbin-ext
23        port:
24          number: 443
25  - match:
26    - gateways:
27      - istio-egressgateway
28      port: 443
29      sniHosts:
30      - httpbin.org
31    route:
32    - destination:
33        host: httpbin.org
34        port:
35          number: 443
36      weight: 100
37EOF

在curl容器内向https://httpbin.org/headers发送请求,确认正常可以访问:

1curl -sSI https://httpbin.org/headers | grep "HTTP/"
2HTTP/1.1 200 OK

检查istio-egressgateway代理的日志:

1kubectl logs -l istio=egressgateway -n istio-system
2
3[2021-07-29T12:13:02.120Z] "- - -" 0 - - - "-" 574 5590 1946 - "-" "-" "-" "-" "18.235.124.214:443" outbound|443||httpbin.org 10.244.166.182:42106 10.244.166.182:8443 10.244.104.48:41278 httpbin.org -

说明到httpbin.org的请求是由istio-egressgateway代理作为出口发出的。

需要注意,Istio中定义的egress Gateway本身并没有为其所在的节点提供任何特殊处理。集群管理员或云提供商可以在专用节点上部署egress gateway,并引入额外的安全措施,从而使这些节点比网格中的其他节点更安全。 另外要注意的是,Istio 无法强制让所有出站流量都经过egress gateway,Istio 只是通过sidecar代理实现了这种流向。攻击者只要绕过sidecar代理,就可以不经egress gateway直接与网格外的服务进行通信,从而避开了Istio的控制和监控。 出于安全考虑,集群管理员或云供应商必须确保网格所有的出站流量都要经过egress gateway。这需要通过Istio之外的机制来满足这一要求。例如,集群管理员可以配置防火墙,拒绝egress gateway以外的所有流量。Kubernetes网络策略也能禁止所有不是从egress gateway发起的出站流量。

参考