|
| 1 | +--- |
| 2 | +title: "Istio Egress Gateway 简化指南" |
| 3 | +summary: "本文介绍在 Ambient 模式下,通过 waypoint 代理管理 egress 流量,包括部署应用、设代理、策略管理及启用 TLS 等操作。" |
| 4 | +authors: ["John Howard"] |
| 5 | +translators: ["云原生社区"] |
| 6 | +categories: ["Istio"] |
| 7 | +tags: ["Istio"] |
| 8 | +draft: false |
| 9 | +date: 2025-04-09T11:15:24+08:00 |
| 10 | +links: |
| 11 | + - icon: language |
| 12 | + icon_pack: fa |
| 13 | + name: 阅读英文版原文 |
| 14 | + url: https://www.solo.io/blog/egress-gateways-made-easy |
| 15 | +--- |
| 16 | + |
| 17 | +多年来,Istio 一直提供一种可选方案来部署 “[Egress Gateway](https://istio.io/latest/docs/tasks/traffic-management/egress/egress-gateway/)”,这是一种功能强大的机制,可将出站流量经由一个 Gateway 统一转发,以便对其实施各类策略,包括授权、审计、可观测性等等。 |
| 18 | + |
| 19 | +尽管功能强大,但长期以来,设置 egress gateway 一直相当复杂。即便只是最基本的场景:将来自特定域名的流量通过 egress gateway 转发,都需要先后配置 5 个不同的 Istio 对象(参见 [官方文档](https://istio.io/latest/docs/tasks/traffic-management/egress/egress-gateway/)),更不用说后续还要为流量添加各种高级策略了。 |
| 20 | + |
| 21 | +凭借 Istio 的 Ambient 模式与 Gloo Mesh,现在配置 egress gateway 的过程变得更加轻松,同时还能为网格中的流量提供更优的功能与管理。让我们在这篇博客中深入探讨一下。 |
| 22 | + |
| 23 | + |
| 24 | + |
| 25 | +## Istio Ambient 模式与 Gloo Mesh 带来的简化 |
| 26 | + |
| 27 | +借助 [Ambient 模式](https://www.solo.io/blog/istio-ambient-revolution/),管理 egress 流量变得非常轻松。在 Ambient 模式下,不再使用传统的 Sidecar 代理,而是使用独立部署的 “waypoint” 代理来代理服务的流量。整体示意如下所示: |
| 28 | + |
| 29 | + |
| 30 | + |
| 31 | +各个服务可以绑定到一个 waypoint 上,然后 Istio 会自动将访问这些服务的流量都通过该 waypoint。 |
| 32 | + |
| 33 | +有趣的是,我们也可以像对待内部服务一样,把 *外部域名*(通过 ServiceEntry 定义)绑定到某个 waypoint。只要像对待 Service 那样,将这些域名映射到 waypoint,访问这些域名的流量也能自动经由该 waypoint 代理转发。 |
| 34 | + |
| 35 | + |
| 36 | + |
| 37 | +通过这种方式,即使保持同样的丰富功能,配置 egress gateway 的过程也被极大简化。此后,流量可观测性还可以通过 Gloo Mesh 进行可视化。 |
| 38 | + |
| 39 | +## 实践体验 |
| 40 | + |
| 41 | +首先,在已安装 Istio Ambient 模式的集群上,我们部署一个测试应用并将其所在的 Namespace 加入 Ambient 网格: |
| 42 | + |
| 43 | +```bash |
| 44 | +$ kubectl apply -f shell.yaml |
| 45 | +$ kubectl label namespace default istio.io/dataplane-mode=ambient |
| 46 | +``` |
| 47 | + |
| 48 | +然后,我们可以验证测试应用依然可以正常发送出站流量: |
| 49 | + |
| 50 | +```bash |
| 51 | +$ curl httpbin.org/get |
| 52 | +{ |
| 53 | + "headers": { |
| 54 | + "Host": "httpbin.org", |
| 55 | + }, |
| 56 | + "url": "http://httpbin.org/get" |
| 57 | +} |
| 58 | +``` |
| 59 | + |
| 60 | +我们的目标是让这部分流量走过一个 egress gateway,从而统一对其进行策略和访问控制。在 Istio Ambient 模式中,这比在 Sidecar 模式要简单得多。 |
| 61 | + |
| 62 | +首先,我们需要部署一个 waypoint 代理来充当 egress gateway。只需部署一次即可,后续可以共享给要捕获流量的其他域名。 |
| 63 | + |
| 64 | +```bash |
| 65 | +$ kubectl create namespace istio-egress |
| 66 | +$ istioctl waypoint apply --enroll-namespace --namespace istio-egress |
| 67 | +``` |
| 68 | + |
| 69 | +接下来,为 **httpbin.org** 创建一个 **ServiceEntry**: |
| 70 | + |
| 71 | +```yaml |
| 72 | +apiVersion: networking.istio.io/v1 |
| 73 | +kind: ServiceEntry |
| 74 | +metadata: |
| 75 | + name: httpbin.org |
| 76 | + namespace: istio-egress |
| 77 | +spec: |
| 78 | + hosts: |
| 79 | + - httpbin.org |
| 80 | + ports: |
| 81 | + - number: 80 |
| 82 | + name: http |
| 83 | + protocol: HTTP |
| 84 | + resolution: DNS |
| 85 | +``` |
| 86 | +
|
| 87 | +这就是全部所需!因为部署 waypoint 时使用了 **--enroll-namespace** 参数,该命名空间(`istio-egress`)中的所有服务都会自动绑定到此 waypoint。如果我们只想在单个 Service/ServiceEntry 级别进行绑定,也可以在每个对象上显式添加标签 **istio.io/use-waypoint: waypoint**。 |
| 88 | + |
| 89 | +现在,这个 ServiceEntry 已经绑定到我们之前部署的 waypoint 代理上,原先的请求无需任何改动就会自动穿过该 waypoint,并由 Istio 自动进行 mTLS 加密: |
| 90 | + |
| 91 | +```bash |
| 92 | +$curl httpbin.org/get -v |
| 93 | +... |
| 94 | +* Request completely sent off |
| 95 | +< HTTP/1.1 200 OK |
| 96 | +< server: istio-envoy |
| 97 | +... |
| 98 | +
|
| 99 | +{ |
| 100 | + ... |
| 101 | +} |
| 102 | +``` |
| 103 | + |
| 104 | +之后,我们就可以从 waypoint 中收集日志、追踪信息以及指标来观察流量。例如,从 waypoint 的日志就能看到刚刚发出的请求: |
| 105 | + |
| 106 | +```bash |
| 107 | +$ kubectl logs waypoint-6c6b888f4f-wmnr2 --tail=1 |
| 108 | +[2024-07-18T16:13:58.198Z] "GET /get HTTP/1.1" 200 - via_upstream - "-" 0 252 260 259 "-" |
| 109 | +"curl/8.7.1" "8d80cec6-8fc1-40de-8bc7-19716f173bbd" "httpbin.org" "3.234.9.11:80" inbound-vip|80|http|httpbin.org; 10.244.0.24:41160 240.240.0.2:80 10.244.0.18:41548 - default |
| 110 | +``` |
| 111 | + |
| 112 | +## 策略管理 |
| 113 | + |
| 114 | +Egress gateway 最强大的特性之一就是能够对所有出站流量强制执行访问控制策略。策略范围可以很简单——比如基于域名的白名单,也可以非常复杂,比如 [数据丢失防护(DLP)](https://docs.solo.io/gloo-mesh-gateway/main/security/dlp/) 等。 |
| 115 | + |
| 116 | +举个例子,我们可以限制低权限应用只能访问 `/get` 接口,而高权限应用可以访问 httpbin.org 的所有接口。要实现这一点,只需在我们创建的 ServiceEntry 上附加一条 AuthorizationPolicy 即可: |
| 117 | + |
| 118 | +```yaml |
| 119 | +apiVersion: security.istio.io/v1 |
| 120 | +kind: AuthorizationPolicy |
| 121 | +metadata: |
| 122 | + name: httpbin |
| 123 | + namespace: istio-egress |
| 124 | +spec: |
| 125 | + targetRefs: |
| 126 | + - kind: ServiceEntry |
| 127 | + group: networking.istio.io |
| 128 | + name: httpbin.org |
| 129 | + action: ALLOW |
| 130 | + rules: |
| 131 | + # admin 应用可以访问任意接口 |
| 132 | + - from: |
| 133 | + - source: |
| 134 | + principals: ["cluster.local/ns/default/sa/admin"] |
| 135 | + # 其他应用只允许访问 /get |
| 136 | + - to: |
| 137 | + - operation: |
| 138 | + methods: ["GET"] |
| 139 | + paths: ["/get"] |
| 140 | +``` |
| 141 | + |
| 142 | +此时,从低权限应用发出的 POST 请求就会被拒绝: |
| 143 | + |
| 144 | +```bash |
| 145 | +$ curl httpbin.org/get |
| 146 | +{ |
| 147 | + "headers": { |
| 148 | + "Host": "httpbin.org", |
| 149 | + }, |
| 150 | + "url": "http://httpbin.org/get" |
| 151 | +} |
| 152 | +$ curl -X POST httpbin.org/post |
| 153 | +RBAC: access denied |
| 154 | +``` |
| 155 | + |
| 156 | +而在高权限应用(admin)中,POST 请求可以正常执行: |
| 157 | + |
| 158 | +```bash |
| 159 | +$ curl httpbin.org/post -X POST |
| 160 | +{ |
| 161 | + "headers": { |
| 162 | + "Host": "httpbin.org", |
| 163 | + }, |
| 164 | + "url": "http://httpbin.org/post" |
| 165 | +} |
| 166 | +``` |
| 167 | + |
| 168 | +## TLS Origination |
| 169 | + |
| 170 | +另一个在 egress gateway 上经常使用的策略是进行 TLS Origination。在上面的例子中,我们虽然在网格 *内部* 使用了 Istio 自动加密,但流量一旦离开集群,就会以明文形式通过公共网络传输——这显然存在严重的安全风险。 |
| 171 | + |
| 172 | +幸运的是,我们可以在 egress waypoint 中为请求启用 TLS,让请求在离开集群前就被加密。这个功能在对需要客户端身份认证的服务进行访问时尤为有用,可以集中地对访问进行控制;但在这里,我们仅演示最简单的 TLS。 |
| 173 | + |
| 174 | +对此,我们只需要在 ServiceEntry 中做一点小改动,并添加一个 DestinationRule: |
| 175 | + |
| 176 | +```yaml |
| 177 | +apiVersion: networking.istio.io/v1 |
| 178 | +kind: ServiceEntry |
| 179 | +metadata: |
| 180 | + name: httpbin.org |
| 181 | + namespace: istio-egress |
| 182 | +spec: |
| 183 | + hosts: |
| 184 | + - httpbin.org |
| 185 | + ports: |
| 186 | + - number: 80 |
| 187 | + name: http |
| 188 | + protocol: HTTP |
| 189 | + targetPort: 443 # 新增:把发往 80 端口的流量转发到 443 端口 |
| 190 | + resolution: DNS |
| 191 | +--- |
| 192 | +# 新增:为发往 `httpbin.org` 的请求启用 TLS |
| 193 | +apiVersion: networking.istio.io/v1 |
| 194 | +kind: DestinationRule |
| 195 | +metadata: |
| 196 | + name: httpbin.org-tls |
| 197 | + namespace: istio-egress |
| 198 | +spec: |
| 199 | + host: httpbin.org |
| 200 | + trafficPolicy: |
| 201 | + tls: |
| 202 | + mode: SIMPLE |
| 203 | +``` |
| 204 | +
|
| 205 | +这样一来,所有的请求都会被自动升级为 HTTPS,而应用自身无需做任何改动: |
| 206 | +
|
| 207 | +```bash |
| 208 | +$ curl httpbin.org/get |
| 209 | +{ |
| 210 | + "headers": { |
| 211 | + "Host": "httpbin.org", |
| 212 | + }, |
| 213 | + "url": "https://httpbin.org/get" |
| 214 | +} |
| 215 | +``` |
| 216 | + |
0 commit comments