Search code examples
envoyproxy

Configuring envoy to skip mTLS on a specific http route


I am using envoy has an edge proxy. Basically I want mTLS downstream on all http paths except for one. I have the following config: Notice how I set require_client_certificate: false in the first route

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

So, when I do a

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

I expect the request to go through and get a 200 response

Whereas, I if I hit /s1/request/post, then I expect mTLS to take place so I should be providing a certificate and a key.

However, when I start the envoy, I get the following error

[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

Is this the correct way to do the stuff I want?


Solution

  • I think I found the answer. Referring to https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route_components.proto#envoy-api-msg-route-routematch-tlscontextmatchoptions

    The only caveat is that this has to be repeat for each route, setting the values appropriately for each route.