上一节学习了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,可以使用下面的命令查看一下:

1
2
3
4
5
6
7
8
9
kubectl get all -n istio-system -l app=istio-egressgateway
NAME                                      READY   STATUS    RESTARTS   AGE
pod/istio-egressgateway-7d4f75956-mq6d9   1/1     Running   0          8d

NAME                          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/istio-egressgateway   ClusterIP   10.105.21.145   <none>        80/TCP,443/TCP   25d

NAME                                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/istio-egressgateway   1/1     1            1           25d

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

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

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

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

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

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

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

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

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

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

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

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

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

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

检查istio-egressgateway代理的日志:

1
2
3
kubectl logs -l istio=egressgateway -n istio-system

[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发起的出站流量。

参考