Tap

  • v3 API reference

  • This filter should be configured with the name envoy.filters.http.tap.

Attention

The tap filter is experimental and is currently under active development. There is currently a very limited set of match conditions, output configuration, output sinks, etc. Capabilities will be expanded over time and the configuration structures are likely to change.

The HTTP tap filter is used to interpose on and record HTTP traffic. At a high level, the configuration is composed of two pieces:

  1. Match configuration: a list of conditions under which the filter will match an HTTP request and begin a tap session.

  2. Output configuration: a list of output sinks that the filter will write the matched and tapped data to.

Each of these concepts will be covered incrementally over the course of several example configurations in the following section.

Example configuration

Example filter configuration:

name: envoy.filters.http.tap
typed_config:
  "@type": type.googleapis.com/envoy.extensions.filters.http.tap.v3.Tap
  common_config:
    admin_config:
      config_id: test_config_id

The previous snippet configures the filter for control via the POST /tap admin handler. See the following section for more details.

Admin handler

When the HTTP filter specifies an admin_config, it is configured for admin control and the POST /tap admin handler will be installed. The admin handler can be used for live tapping and debugging of HTTP traffic. It works as follows:

  1. A POST request is used to provide a valid tap configuration. The POST request body can be either the JSON or YAML representation of the TapConfig message.

  2. If the POST request is accepted, Envoy will stream HttpBufferedTrace messages (serialized to JSON) until the admin request is terminated.

Attention

If using HTTP/1.1 to communicate with the admin endpoint, it is important to not use Unix Domain Sockets (UDS) as the underlying transport. This is because UDS do not support “early close detection” which means that when the client is disconnected it may take a substantial amount of time for Envoy to realize the connection has been terminated (typically when the next streamed message is written). During this time period it is currently impossible to connect a new tap. To work around this either use HTTP/2 or use TCP.

An example POST body:

config_id: test_config_id
tap_config:
  match_config:
    and_match:
      rules:
        - http_request_headers_match:
            headers:
              - name: foo
                string_match:
                  exact: bar
        - http_response_headers_match:
            headers:
              - name: bar
                string_match:
                  exact: baz
  output_config:
    sinks:
      - streaming_admin: {}

The preceding configuration instructs the tap filter to match any HTTP requests in which a request header foo: bar is present AND a response header bar: baz is present. If both of these conditions are met, the request will be tapped and streamed out the admin endpoint.

Another example POST body:

config_id: test_config_id
tap_config:
  match_config:
    or_match:
      rules:
        - http_request_headers_match:
            headers:
              - name: foo
                string_match:
                  exact: bar
        - http_response_headers_match:
            headers:
              - name: bar
                string_match:
                  exact: baz
  output_config:
    sinks:
      - streaming_admin: {}

The preceding configuration instructs the tap filter to match any HTTP requests in which a request header foo: bar is present OR a response header bar: baz is present. If either of these conditions are met, the request will be tapped and streamed out the admin endpoint.

Another example POST body:

config_id: test_config_id
tap_config:
  match_config:
    any_match: true
  output_config:
    sinks:
      - streaming_admin: {}

The preceding configuration instructs the tap filter to match any HTTP requests. All requests will be tapped and streamed out the admin endpoint.

Another example POST body:

config_id: test_config_id
tap_config:
  match_config:
    and_match:
      rules:
        - http_request_headers_match:
            headers:
              - name: foo
                string_match:
                  exact: bar
        - http_request_generic_body_match:
            patterns:
              - string_match: test
              - binary_match: 3q2+7w==
            bytes_limit: 128
        - http_response_generic_body_match:
            patterns:
              - binary_match: vu8=
            bytes_limit: 64
  output_config:
    sinks:
      - streaming_admin: {}

The preceding configuration instructs the tap filter to match any HTTP requests in which a request header foo: bar is present AND request body contains string test and hex bytes deadbeef (3q2+7w== in base64 format) in the first 128 bytes AND response body contains hex bytes beef (vu8= in base64 format) in the first 64 bytes. If all of these conditions are met, the request will be tapped and streamed out to the admin endpoint.

Attention

Searching for patterns in HTTP body is potentially cpu intensive. For each specified pattern, http body is scanned byte by byte to find a match. If multiple patterns are specified, the process is repeated for each pattern. If location of a pattern is known, bytes_limit should be specified to scan only part of the http body.

Output format

Each output sink has an associated format. The default format is JSON_BODY_AS_BYTES. This format is easy to read JSON, but has the downside that body data is base64 encoded. In the case that the tap is known to be on human readable data, the JSON_BODY_AS_STRING format may be more user friendly. See the reference documentation for more information on other available formats.

An example of a streaming admin tap configuration that uses the JSON_BODY_AS_STRING format:

config_id: test_config_id
tap_config:
  match_config:
    any_match: true
  output_config:
    sinks:
      - format: JSON_BODY_AS_STRING
        streaming_admin: {}

Buffered body limits

For buffered taps, Envoy will limit the amount of body data that is tapped to avoid OOM situations. The default limit is 1KiB for both received (request) and transmitted (response) data. This is configurable via the max_buffered_rx_bytes and max_buffered_tx_bytes settings.

Streaming matching

The tap filter supports “streaming matching.” This means that instead of waiting until the end of the request/response sequence, the filter will match incrementally as the request proceeds. I.e., first the request headers will be matched, then the request body if present, then the request trailers if present, then the response headers if present, etc.

The filter additionally supports optional streamed output which is governed by the streaming setting. If this setting is false (the default), Envoy will emit fully buffered traces. Users are likely to find this format easier to interact with for simple cases.

In cases where fully buffered traces are not practical (e.g., very large request and responses, long lived streaming APIs, etc.), the streaming setting can be set to true, and Envoy will emit multiple streamed trace segments for each tap. In this case, it is required that post-processing is performed to stitch all of the trace segments back together into a usable form. Also note that binary protobuf is not a self-delimiting format. If binary protobuf output is desired, the PROTO_BINARY_LENGTH_DELIMITED output format should be used.

An static filter configuration to enable streaming output looks like:

name: envoy.filters.http.tap
typed_config:
  "@type": type.googleapis.com/envoy.extensions.filters.http.tap.v3.Tap
  common_config:
    static_config:
      match_config:
        http_response_headers_match:
          headers:
            - name: bar
              string_match:
                exact: baz
      output_config:
        streaming: true
        sinks:
          - format: PROTO_BINARY_LENGTH_DELIMITED
            file_per_tap:
              path_prefix: /tmp/

The previous configuration will match response headers, and as such will buffer request headers, body, and trailers until a match can be determined (buffered data limits still apply as described in the previous section). If a match is determined, buffered data will be flushed in individual trace segments and then the rest of the tap will be streamed as data arrives. The messages output might look like this:

http_streamed_trace_segment:
  trace_id: 1
  request_headers:
    headers:
      - key: a
        value: b
http_streamed_trace_segment:
  trace_id: 1
  request_body_chunk:
    as_bytes: aGVsbG8=

Etc.

Statistics

The tap filter outputs statistics in the http.<stat_prefix>.tap. namespace. The stat prefix comes from the owning HTTP connection manager.

Name

Type

Description

rq_tapped

Counter

Total requests that matched and were tapped