配置特使以跳过特定 http 路由上的 mTLS

Configuring envoy to skip mTLS on a specific http route

我正在使用 envoy 有一个边缘代理。 基本上我希望 mTLS 在除一个之外的所有 http 路径上下游。 我有以下配置: 请注意我如何在第一条路线

中设置 require_client_certificate: false
admin:
  access_log_path: /dev/stdout
  address:
    socket_address:
      address: 127.0.0.1
      port_value: 9901
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 443
    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
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/s1/request/get"
                  headers:
                  - name: ":method"
                    exact_match: "GET"
                route:
                  host_rewrite_literal: service1
                  cluster: internal_service1
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          require_client_certificate: false
          common_tls_context:
            tls_certificates:
              certificate_chain: 
                filename: /etc/ssl/listener/cert.pem
              private_key: 
                filename: /etc/ssl/listener/key.pem
            validation_context:
              trusted_ca:
                filename: /etc/ssl/cluster/cabundle.pem
    - 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
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/s1/request/post"
                  headers:
                  - name: ":method"
                    exact_match: "POST"
                route:
                  host_rewrite_literal: service1
                  cluster: internal_service1
                 
          http_filters:
          - name: envoy.filters.http.router
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          require_client_certificate: true
          common_tls_context:
            tls_certificates:
              certificate_chain: 
                filename: /etc/ssl/listener/cert.pem
              private_key: 
                filename: /etc/ssl/listener/key.pem
            validation_context:
              trusted_ca:
                filename: /etc/ssl/cluster/cabundle.pem

  clusters:
  - name: internal_service1
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: internal_service1
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: service1
                port_value: 443
    tls_context:
      allow_renegotiation: true
      common_tls_context:
        tls_certificates:
          certificate_chain: 
            filename: /etc/ssl/listener/cert.pem
          private_key: 
            filename: /etc/ssl/listener/key.pem
        validation_context:
          trusted_ca:
            filename: /etc/ssl/cluster/cabundle.pem
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        sni: service1

所以,当我做一个

curl -k  --location  --cacert cabundle.pem --request GET 'http://localhost:443/s1/request/get'

我希望请求通过并获得 200 响应

然而,如果我点击 /s1/request/post,那么我希望 mTLS 发生,所以我应该提供证书和密钥。

但是,当我启动 envoy 时,出现以下错误

[2020-10-28 05:42:40.674][1][debug][init] [source/common/init/watcher_impl.cc:27] init manager Server destroyed
error adding listener '0.0.0.0:443': multiple filter chains with the same matching rules are defined
make: *** [run-local] Error 1

这是完成我想要的事情的正确方法吗?

@kosta 您需要在 TLS 侦听器上指定一个新字段 filter_chain_match。基本上,现在您的两个侦听器应该匹配所有传入连接,因此特使不知道对任何给定连接使用哪个。

如果您将下面的字段添加到您的第二个侦听器,它将仅匹配 TLS 连接,这将允许 Envoy 启动。

filter_chain_match:
  transport_protocol: tls

我修改了您的第二个侦听器,如下所示,Envoy 启动正常。

    - 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
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/s1/request/post"
                  headers:
                  - name: ":method"
                    exact_match: "POST"
                route:
                  host_rewrite_literal: service1
                  cluster: internal_service1
          http_filters:
          - name: envoy.filters.http.router
      filter_chain_match:
        transport_protocol: "tls"
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          require_client_certificate: true
          common_tls_context:
            tls_certificates:
              certificate_chain: 
                filename: /etc/ssl/listener/cert.pem
              private_key: 
                filename: /etc/ssl/listener/key.pem
            validation_context:
              trusted_ca:
                filename: /etc/ssl/cluster/cabundle.pem

我想我找到了答案。 参考https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#envoy-api-msg-route-routematch-tlscontextmatchoptions

唯一需要注意的是,必须为每条路线重复此操作,为每条路线设置适当的值。