Istio ServiceEntry 访问外部服务

代理出站流量策略模式

Istio有一个安装选项meshConfig.outboundTrafficPolicy.mode,用于配置对外部服务(即Istio内部服务注册表中未定义的那些服务)的处理方式。如果此选项设置为ALLOW_ANY,则Istio代理将允许对未知服务的调用。如果该选项设置为REGISTRY_ONLY,则Istio代理将阻止在网格中未定义HTTP服务或ServiceEntry的任何主机。

默认情况下,ALLOW_ANY为该配置项的默认值。

ServiceEntry

ServiceEntry是扩展Istio服务注册表的一种方式,以便现有的自动发现的服务可以访问其他服务,无论它们是未发现的内部服务还是完全在网格外部的服务(例如,Web API)。

通过配置ServiceEntry,您可以管理在网格外部运行的服务的流量,包括以下功能:

  • 重定向和转发用于外部目标的流量,例如从网络使用的API或到旧基础结构中服务的流量。
  • 为外部目标定义重试,超时和故障注入策略。
  • 通过将虚拟机添加到网格中,在虚拟机(VM)中运行网格服务。
  • 在逻辑上将来自其他集群的服务添加到网格,以在Kubernetes上配置多集群Istio网格。

访问一个外部的HTTP服务

1、部署之前先部署我们的sleep pod,作为网格内的工作负载。由于我们在之前的文章中已经部署完成,所以这里略过。

kubectl get pods -n foo
NAME                       READY   STATUS    RESTARTS   AGE
httpbin-779c54bf49-dqmgm   2/2     Running   0          27h
sleep-d6b58ff57-jl8pq      2/2     Running   0          27h

2、创建一个 ServiceEntry,以允许访问一个外部的 HTTP 服务:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: httpbin.org
  namespace: foo
spec:
  hosts:
  - httpbin.org
  - www.httpbin.org
  ports:
  - number: 80
    name: http
    protocol: HTTP
  exportTo:
  - "."
  resolution: DNS
  location: MESH_EXTERNAL

我们对该配置逐一字段解析:

  • hosts:DNS名称。可以具有通配符前缀。
  • ports:关联的端口。
  • ports.protocol: 以下之一:HTTP,HTTPS,HTTP2,GRPC,MONGO,TCP或TLS。
  • exportTo:默认情况下使用“*”,这意味着该ServiceEntry公开给每个命名空间。 “.”仅将其限制为当前命名空间。目前,exportTo值仅限于这两个。
  • resolution:主机的服务发现模式
  • location:从网格的角度来看,应将此服务视为内部或外部服务。

这里的字段并不是ServiceEntry支持的所有字段,更多请查看官方文档

DNS 解析在下面的服务条目中用作安全措。将解析设置为 NONE会开启了攻击的可能。恶意客户端在真正连接到其他IP时,可能会伪装设置 HOST 头信息为 httpbin.org(与 httpbin.org 不相关)。Istio sidecar 代理将信任 HOST 头信息,并错误地允许通信,甚至将其传递到其他主机的 IP 地址。 该主机可能是恶意的站点,或者网格安全策略禁止的站点。

使用 DNS 解析,Sidecar 代理将忽略原始目标 IP 地址并引导流量到 httpbin.org,并执行 DNS 查询以获取 httpbin.org 的IP地址。

3、从sleep的Pod内部,向外部服务的/delay端点发出curl请求:

$ kubectl exec sleep-d6b58ff57-jl8pq -c sleep -n foo -- time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5
200
real    0m 5.70s
user    0m 0.00s
sys    0m 0.00s

4、对外部服务httpbin.org增加超时设置,我们需要创建一个VirtualService如下:

$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin.org
  namespace: foo
spec:
  hosts:
    - httpbin.org
    - www.httpbin.org
  http:
  - timeout: 3s
    route:
      - destination:
          host: httpbin.org
        weight: 100
EOF

5、再次从sleep的Pod内部,向外部服务的/delay端点发出curl请求:

kubectl exec sleep-d6b58ff57-jl8pq -c sleep -n foo -- time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5
504
real    0m 3.01s
user    0m 0.00s
sys    0m 0.00s

这次3秒后出现504(网关超时)。尽管等待5秒,但Istio却在3秒时截断了请求。

访问外部 HTTPS 服务

1、创建一个 ServiceEntry,允许对外部服务的访问。

kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: google
spec:
  hosts:
  - www.google.com
  ports:
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS
  location: MESH_EXTERNAL
EOF

2、从 SOURCE_POD 往外部 HTTPS 服务发送请求:

kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://www.google.com | grep  "HTTP/"
HTTP/2 200

3、检查 SOURCE_POD 的 sidecar 代理的日志:

kubectl logs $SOURCE_POD -c istio-proxy | tail
[2019-01-24T12:48:54.977Z] "- - -" 0 - 601 17766 1289 - "-" "-" "-" "-" "172.217.161.36:443" outbound|443||www.google.com 172.30.109.82:59480 172.217.161.36:443 172.30.109.82:59478 www.google.com

ServiceEntry配置

FieldTypeDescriptionRequired
hosts string[] 绑定到 ServiceEntry 上的主机名。可以是一个带有通配符前缀的 DNS 名称。如果服务不是 HTTP 协议的,例如 mongo、TCP 以及 HTTPS 中,hosts 中的 DNS 名称会被忽略,这种情况下会使用 endpoints 中的 address 以及 port 来甄别调用目标。 Yes
addresses string[] 服务相关的虚拟 IP。可以是 CIDR 前缀。对 HTTP 服务来说,这一字段会被忽略,而会使用 HTTP 的 HOST/Authority Header。而对于非 HTTP 服务,例如 mongo、TCP 以及 HTTPS 中,这些主机会被忽略。如果指定了一个或者多个 IP 地址,对于在列表范围内的 IP 的访问会被判定为属于这一服务。如果地址字段为空,服务的鉴别就只能靠目标端口了。在这种情况下,被访问服务的端口一定不能和其他网格内的服务进行共享。换句话说,这里的 Sidecar 会简单的做为 TCP 代理,将特定端口的访问转发到指定目标端点的 IP、主机上去。就无法支持 Unix socket 了。 No
ports Port[] 和外部服务关联的端口。如果 endpoints 是 Unix socket 地址,这里必须只有一个端口。 Yes
location Location 用于指定该服务的位置,属于网格内部还是外部。 No
resolution Resolution 主机的服务发现模式。在没有附带 IP 地址的情况下,为 TCP 端口设置解析模式为 NONE 时必须小心。在这种情况下,对任何 IP 的指定端口的流量都是允许的(例如 0.0.0.0:)。 Yes
endpoints Endpoint[] 一个或者多个关联到这一服务的 endpoint No
exportTo string[] 此服务导出到的名称空间列表。导出服务允许它被其他名称空间中定义的边车,网关和虚拟服务使用。此功能为服务所有者和网格管理员提供了一种机制,可以控制跨名称空间边界的服务的可见性。 如果未指定名称空间,则默认情况下会将服务导出到所有名称空间 No
subjectAltNames string[] 实施此服务的工作负载实例允许使用的使用者备用名称列表。此信息用于强制执行安全命名。如果指定,则代理将验证服务器证书的使用者备用名称是否与指定值之一匹配。 No

ServiceEntry.Location

NameDescription
MESH_EXTERNAL 表示服务在网格外部。通常用于指示通过API使用的外部服务。
MESH_INTERNAL 表示服务是网格的一部分。通常用于指示在扩展服务网格以包括不受管理的基础架构时显式添加的服务

具体细节的参数明细可查阅: https://preliminary.istio.io/zh/docs/reference/config/networking/service-entry

 

参考:

https://preliminary.istio.io/latest/zh/docs/tasks/traffic-management/egress/egress-control/

https://skyao.io/learning-istio/crd/network/serviceentry.html

posted @ 2021-09-06 16:26  fat_girl_spring  阅读(781)  评论(0编辑  收藏  举报