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内部,向http://httpbin.org外部服务的/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内部,向http://httpbin.org外部服务的/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(网关超时)。尽管http://httpbin.org等待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配置
Field | Type | Description | Required |
---|---|---|---|
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
Name | Description |
---|---|
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