Envoy 到 Envoy TLS 代理

Envoy 到 Envoy TLS 代理

假设这个架构

                             ................................................
                             .                                              .
                             .                                              .
                             .                                              .
                             .                                              .
                   ┌───────────────────┐                            ┌─────────────────┐
┌──────────────────┤ Customer Firewall ├─┐     ┌────────────────────┤Provider Firewall├─┐
│                  └──────────┬────────┘ │     │Provider Network    └──┬──────────────┘ │
│   Customer Network          │          │     │             ┌─────────┴─┐              │
│                             │          │     │       ┌─────┤ Envoy - B ├───────┐      │
│                             │          │     │       │     └─────┬─────┘       │      │
│                      ┌──────┴─────┐    │     │       │           │             │      │
│       ┌─────────┐    │            │    │     │       │           │             │      │
│       │ Client  ├────┤  Envoy - A │    │     │  ┌────┴────┐  ┌───┴─────┐  ┌────┴────┐ │
│       └─────────┘    │            │    │     │  │ Service │  │ Service │  │ Service │ │
│                      └────────────┘    │     │  └─────────┘  └─────────┘  └─────────┘ │
│                                        │     │                                        │
└────────────────────────────────────────┘     └────────────────────────────────────────┘

客户端想要连接到提供商网络上的服务,但客户防火墙有严格的政策HTTP 过滤SNI 过滤

它将丢弃任何未经授权的流量,因此任何不允许的域/SNI 都将被丢弃。

SNI/域名特使Benvoy-b.example.com) 是允许在防火墙中,但他们不允许任何其他域名

所有服务均采用 HTTP/HTTPS

以下是 Envoy 服务器的配置:

特使-A:

  • 它监听端口80,对于每个 HTTP 流量,它将使用以下方式将流量转发到 Envoy - B:HTTP2 + TLSv1.3
  • 它监听端口443,以及每个传输控制协议流量,它将转发流量到 Envoy - B无需任何进一步加密
static_resources:
  listeners:
    # HTTP
    - name: http_forwarder
      address:
        socket_address:
          protocol: TCP
          address: 0.0.0.0
          port_value: 80
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                route_config:
                  name: http_route
                  virtual_hosts:
                    - name: http_forwarder
                      domains: [ "*" ]
                      routes:
                        - match:
                            prefix: "/"
                          route:
                            cluster: forwarder_to_envoy_b_http
                http_filters:
                  - name: envoy.filters.http.router
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

    # HTTPS/TLS
    - name: https_forwarder
      address:
        socket_address:
          protocol: TCP
          address: 0.0.0.0
          port_value: 443
      filter_chains:
        - filters:
            - name: envoy.filters.network.tcp_proxy
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
                cluster: forwarder_to_envoy_b_tls
                stat_prefix: https_passthrough
                access_log:
                  - name: envoy.access_loggers.stdout
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog

  clusters:
    - name: forwarder_to_envoy_b_http
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: forwarder_to_envoy_b_http
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: envoy-b.example.com
                      port_value: 8888

      dns_resolution_config:
        resolvers:
          - socket_address:
              address: "1.1.1.1"
              port_value: 53
        dns_resolver_options:
          no_default_search_domain: true
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
          common_tls_context:
            tls_params:
              tls_minimum_protocol_version: TLSv1_3
              tls_maximum_protocol_version: TLSv1_3

    - name: forwarder_to_envoy_b_tls
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: forwarder_to_envoy_b_tls
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: envoy-b.example.com
                      port_value: 8889
      dns_resolution_config:
        resolvers:
          - socket_address:
              address: "1.1.1.1"
              port_value: 53
        dns_resolver_options:
          no_default_search_domain: true

特使-B:

  • 它监听端口8888,并且每当有HTTP2 + TLSv1.3流量时,它都会解密流量并转发普通 HTTP 请求前往服务
  • 它监听端口8889,以及每个传输控制协议流量,它将转发流量到 Envoy - B无需进一步加密/解密
static_resources:
  listeners:
    - name: http_listener_0
        address:
          socket_address:
            protocol: TCP
            address: 0.0.0.0
            port_value: 8888
        filter_chains:
          - filters:
              - name: envoy.filters.network.http_connection_manager
                typed_config:
                  "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                  stat_prefix: ingress_http
                  route_config:
                    name: local_route
                    virtual_hosts:
                      - name: local_service
                        domains: [ "*" ]
                        routes:
                          - match:
                              prefix: "/"
                            route:
                              cluster: http_cluster
                  http_filters:
                    - name: envoy.filters.http.router
                      typed_config:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
            
            transport_socket:
              name: envoy.transport_sockets.tls
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
                common_tls_context:
                  tls_params:
                    tls_minimum_protocol_version: TLSv1_3
                    tls_maximum_protocol_version: TLSv1_3
                  tls_certificates:
                    certificate_chain:
                      filename: /certs/proxy-crt.pem
                    private_key:
                      filename: /certs/proxy-key.pem
                  alpn_protocols: HTTP2


    - name: tls_listener_0
      address:
        socket_address:
          protocol: TCP
          address: 0.0.0.0
          port_value: 8889
      filter_chains:
        - filters:
            - name: envoy.filters.network.tcp_proxy
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
                cluster: tls_cluster
                stat_prefix: https_passthrough
                access_log:
                  - name: envoy.access_loggers.stdout
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog

  clusters:
    - name: http_cluster
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: http_cluster
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: private.service.example.com
                      port_value: 80

      dns_resolution_config:
        resolvers:
          - socket_address:
              address: "1.1.1.1"
              port_value: 53
        dns_resolver_options:
          no_default_search_domain: true


    - name: tls_cluster
      type: STRICT_DNS
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: tls_cluster
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: private.service.example.com
                      port_value: 443
      dns_resolution_config:
        resolvers:
          - socket_address:
              address: "1.1.1.1"
              port_value: 53
        dns_resolver_options:
          no_default_search_domain: true

问题

当客户端发送 HTTP 请求时,特使-A将对其进行加密,并且 SNI 将是envoy-b.example.com客户端防火墙允许的(而不是原始请求的 HOST 标头private.service.example.com

但当客户端发送 HTTPS/TLS 流量时,特使-A只是转发TCP 流,因此 SNI 不会改变并保持不变private.service.example.com-> 因为防火墙不允许此主机名它将被丢弃

我希望 TCP 代理的流量再次加密,以便 SNI 发生变化envoy-b.example.com并且防火墙不会丢弃请求。

我尝试transport_socket在两个 Envoy 主机上添加 TLS 流量,但没有成功:

Envoy A > clusters > forwarder_to_envoy_b_tls


      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
          common_tls_context:
            tls_params:
              tls_minimum_protocol_version: TLSv1_3
              tls_maximum_protocol_version: TLSv1_3

Envoy B > listener > tls_listener_0


            transport_socket:
              name: envoy.transport_sockets.tls
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
                common_tls_context:
                  tls_params:
                    tls_minimum_protocol_version: TLSv1_3
                    tls_maximum_protocol_version: TLSv1_3
                  tls_certificates:
                    certificate_chain:
                      filename: /certs/proxy-crt.pem
                    private_key:
                      filename: /certs/proxy-key.pem
                  alpn_protocols: HTTP2

笔记

  1. 客户端不接受 Envoy B 将 HTTPS 流量转换为 HTTP,然后传输(使用 HTTPS),然后在 Envoy A 再次进行 HTTPS 加密
  2. 我们无权访问服务私钥,因此如果我们按照注释 1 中的说明进行操作,证书将会更改
  3. 特使B需要 SNI确定流量应该转发到哪些服务

相关内容