Istio 的高级边缘流量控制(二)


通过 Egress gateway 发起 TLS 连接

Istio 的高级边缘流量控制(二)

通过 Egress gateway 发起 TLS 连接

Wed Nov 28, 2018

1400 Words|Read in about 3 Min|本文总阅读量
Tags: istio   service mesh   kubernetes  

上一节我演示了如何通过 Egress Gateway 引导 Istio 的出口 HTTP 流量,但到 443 端口的 HTTPS 流量没有通过 Egress Gateway,而是直接转到 edition.cnn.comIstio 出口流量的 TLS 演示了如何在网格内部直接通过 HTTP 协议访问外部加密服务。本文尝试将这两者结合起来,先将 HTTP 流量路由到 Egress Gateway,然后直接使用 Egress Gateway 发起 TLS 连接。

前提条件与上一篇文章相同。

1. ServiceEntry


首先需要为 edition.cnn.com 定义一个 ServiceEntry 以允许网格内服务访问外部服务。

$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: cnn
spec:
  hosts:
  - edition.cnn.com
  ports:
  - number: 80
    name: http-port
    protocol: HTTP
  - number: 443
    name: http-port-for-tls-origination
    protocol: HTTP
  resolution: DNS
EOF

该 ServiceEntry 会在服务网格内的所有应用的所有 Pod上创建相应的路由规则和与之对应的 Cluster。具体可以参考:控制 Egress 流量

验证 ServiceEntry 是否生效。发送 HTTPS 请求到 http://edition.cnn.com/politics

$ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics

HTTP/1.1 301 Moved Permanently
...
location: https://edition.cnn.com/politics
...

command terminated with exit code 35

如果看到输出结果中包含 301 Moved Permanently,说明 ServiceEntry 配置正确。退出码 35 是由于 Istio 没有执行 TLS。 为了让 Egress gateway 执行 TLS,还要继续执行以下步骤进行配置。

2. Gateway


edition.cnn.com443 端口创建一个 Egress Gateway(假设没有启用双向 TLS 认证)。

$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: istio-egressgateway
spec:
  selector:
    istio: egressgateway
  servers:
  - port:
      number: 443
      name: http-port-for-tls-origination
      protocol: HTTP
    hosts:
    - edition.cnn.com
EOF

此处 Istio 会将 Gateway 翻译成 Egress Gateway 所在的 Pod 的 Listener。具体配置如下:

$ istioctl -n istio-system pc listener istio-egressgateway-f8b6469db-fj6zr -o json
[
    {
        "name": "0.0.0.0_443",
        "address": {
            "socketAddress": {
                "address": "0.0.0.0",
                "portValue": 443
            }
        },
        "filterChains": [
            {
                "filters": [
                    {
                        "name": "envoy.http_connection_manager",
                        "config": {
                            ...
                            "rds": {
                                "config_source": {
                                    "ads": {}
                                },
                                "route_config_name": "http.443"
                            },
                            ...

可以看到经过该 Listener 的流量被转交给 RDS http.443,由于此时我们还没有创建 VirtualService,所以 RDS http.443 中不会包含任何有意义的路由,它会直接返回 404 状态码。

$ istioctl -n istio-system pc route istio-egressgateway-f8b6469db-fj6zr -o json
[
    {
        "name": "http.443",
        "virtualHosts": [
            {
                "name": "blackhole:443",
                "domains": [
                    "*"
                ],
                "routes": [
                    {
                        "match": {
                            "prefix": "/"
                        },
                        "directResponse": {
                            "status": 404
                        },
                        "perFilterConfig": {
                            "mixer": {}
                        }
                    }
                ]
            }
        ],
        "validateClusters": false
    }
]

3. VirtualService 和 DestinationRule


创建一个 DestinationRuleVirtualService 来引导流量通过 Egress Gateway 与外部服务通信。

$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: egressgateway-for-cnn
spec:
  host: istio-egressgateway.istio-system.svc.cluster.local
  subsets:
  - name: cnn
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: direct-cnn-through-egress-gateway
spec:
  hosts:
  - edition.cnn.com
  gateways:
  - istio-egressgateway
  - mesh
  http:
  - match:
    - gateways:
      - mesh
      port: 80
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
        subset: cnn
        port:
          number: 443
      weight: 100
  - match:
    - gateways:
      - istio-egressgateway
      port: 443
    route:
    - destination:
        host: edition.cnn.com
        port:
          number: 443
      weight: 100
EOF

这里 VirtualService 会分别为网格内的应用和 Egress Gateway 各创建一条路由,以实现通过 Egress Gateway 访问目的地址 edition.cnn.com:443。具体的 Envoy 配置解析与上一篇文章类似。

但此时我们仍然不能访问外部服务,因为 Egress Gateway 通过 443 端口发起连接的时候,使用的仍然是 HTTP 协议。所以我们需要让 Egress Gateway 在出口流量上执行 TLS 发起,使用 HTTPS 协议来访问外部服务。

$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: originate-tls-for-edition-cnn-com
spec:
  host: edition.cnn.com
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
    portLevelSettings:
    - port:
        number: 443
      tls:
        mode: SIMPLE # initiates HTTPS for connections to edition.cnn.com
EOF

现在所有的配置都已经完成,只要是访问 edition.cnn.com:80 的流量都会被 Egress Gateway 路由到 Cluster outbound|443||edition.cnn.com,最后将流量转发到服务 https://edition.cnn.com:443

完整的流量转发流程如下图所示:

网格内服务访问 http://edition.cnn.com

重新发送 HTTP 请求到 http://edition.cnn.com/politics

$ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics

HTTP/1.1 200 OK
...
content-length: 150793
...

输出应该与 Istio 出口流量的 TLS 中的输出相同:没有 301 Moved Permanently 信息。

Note


注意,这里我们只将到 80 端口的 HTTP 流量重定向到 Egress Gateway,并通过 Egress Gateway 发起 TLS 连接;到 443 端口的 HTTP 流量仍然直接通过应用的 sidecar 代理发起 TLS 连接。

4. 清理


删除之前创建的 Istio 配置项:

$ kubectl delete gateway istio-egressgateway
$ kubectl delete serviceentry cnn
$ kubectl delete virtualservice direct-cnn-through-egress-gateway
$ kubectl delete destinationrule originate-tls-for-edition-cnn-com
$ kubectl delete destinationrule egressgateway-for-cnn

5. 参考



-----------他日江湖相逢 再当杯酒言欢-----------

「真诚赞赏,手留余香」

杨传胜

真诚赞赏,手留余香

使用微信扫描二维码完成支付

See Also

隐藏