tap transport: refactor to use common tap framework (#5724)

This commit refactors the tap transport socket to use the common
tap extension configuration and tap matching infrastructure. More
match conditions will be added in a future PR as well as additional
cleanups that have been marked with TODOs.

One result of this PR is that the HTTP tap filter can now have a static
configuration as well as write to a file per tap sink.

All future tap PRs should be smaller and more targeted after this one.

Signed-off-by: Matt Klein <mklein@lyft.com>

Mirrored from https://github.com/envoyproxy/envoy @ f37ebdc14f4c0adf0e90aabddae833355c0cec1b
pull/620/head
data-plane-api(CircleCI) 6 years ago
parent 2a5be83a3e
commit 1df7f3ad16
  1. 1
      docs/BUILD
  2. 12
      envoy/config/common/tap/v2alpha/BUILD
  3. 32
      envoy/config/common/tap/v2alpha/common.proto
  4. 2
      envoy/config/filter/http/tap/v2alpha/BUILD
  5. 19
      envoy/config/filter/http/tap/v2alpha/tap.proto
  6. 1
      envoy/config/transport_socket/tap/v2alpha/BUILD
  7. 35
      envoy/config/transport_socket/tap/v2alpha/tap.proto
  8. 5
      envoy/data/tap/v2alpha/BUILD
  9. 8
      envoy/data/tap/v2alpha/transport.proto
  10. 4
      envoy/data/tap/v2alpha/wrapper.proto
  11. 20
      envoy/service/tap/v2alpha/common.proto
  12. 2
      tools/BUILD
  13. 2
      tools/data/tap2pcap_h2_ipv4.pb_text
  14. 9
      tools/tap2pcap.py

@ -33,6 +33,7 @@ proto_library(
"//envoy/config/accesslog/v2:als", "//envoy/config/accesslog/v2:als",
"//envoy/config/accesslog/v2:file", "//envoy/config/accesslog/v2:file",
"//envoy/config/bootstrap/v2:bootstrap", "//envoy/config/bootstrap/v2:bootstrap",
"//envoy/config/common/tap/v2alpha:common",
"//envoy/config/filter/accesslog/v2:accesslog", "//envoy/config/filter/accesslog/v2:accesslog",
"//envoy/config/filter/http/buffer/v2:buffer", "//envoy/config/filter/http/buffer/v2:buffer",
"//envoy/config/filter/http/ext_authz/v2:ext_authz", "//envoy/config/filter/http/ext_authz/v2:ext_authz",

@ -0,0 +1,12 @@
load("//bazel:api_build_system.bzl", "api_proto_library_internal")
licenses(["notice"]) # Apache 2
api_proto_library_internal(
name = "common",
srcs = ["common.proto"],
visibility = ["//visibility:public"],
deps = [
"//envoy/service/tap/v2alpha:common",
],
)

@ -0,0 +1,32 @@
syntax = "proto3";
import "envoy/service/tap/v2alpha/common.proto";
import "validate/validate.proto";
package envoy.config.common.tap.v2alpha;
option java_package = "io.envoyproxy.envoy.service.tap.v2alpha";
// [#protodoc-title: Common tap extension configuration]
// Common configuration for all tap extensions.
message CommonExtensionConfig {
oneof config_type {
option (validate.required) = true;
// If specified, the tap filter will be configured via an admin handler.
AdminConfig admin_config = 1;
// If specified, the tap filter will be configured via a static configuration that cannot be
// changed.
service.tap.v2alpha.TapConfig static_config = 2;
}
}
// Configuration for the admin handler. See :ref:`here <config_http_filters_tap_admin_handler>` for
// more information.
message AdminConfig {
// Opaque configuration ID. When requests are made to the admin handler, the passed opaque ID is
// matched to the configured filter opaque ID to determine which filter to configure.
string config_id = 1 [(validate.rules).string.min_bytes = 1];
}

@ -6,6 +6,6 @@ api_proto_library_internal(
name = "tap", name = "tap",
srcs = ["tap.proto"], srcs = ["tap.proto"],
deps = [ deps = [
"//envoy/service/tap/v2alpha:common", "//envoy/config/common/tap/v2alpha:common",
], ],
) )

@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
import "envoy/service/tap/v2alpha/common.proto"; import "envoy/config/common/tap/v2alpha/common.proto";
import "validate/validate.proto"; import "validate/validate.proto";
@ -12,18 +12,7 @@ option java_package = "io.envoyproxy.envoy.config.filter.http.tap.v2alpha";
// Top level configuration for the tap filter. // Top level configuration for the tap filter.
message Tap { message Tap {
oneof config_type { // Common configuration for the HTTP tap filter.
option (validate.required) = true; common.tap.v2alpha.CommonExtensionConfig common_config = 1
[(validate.rules).message.required = true];
// If specified, the tap filter will be configured via an admin handler.
AdminConfig admin_config = 1;
}
}
// Configuration for the admin handler. See :ref:`here <config_http_filters_tap_admin_handler>` for
// more information.
message AdminConfig {
// Opaque configuration ID. When requests are made to the admin handler, the passed opaque ID is
// matched to the configured filter opaque ID to determine which filter to configure.
string config_id = 1 [(validate.rules).string.min_bytes = 1];
} }

@ -7,5 +7,6 @@ api_proto_library_internal(
srcs = ["tap.proto"], srcs = ["tap.proto"],
deps = [ deps = [
"//envoy/api/v2/core:base", "//envoy/api/v2/core:base",
"//envoy/config/common/tap/v2alpha:common",
], ],
) )

@ -6,41 +6,18 @@ option go_package = "v2";
// [#protodoc-title: Tap] // [#protodoc-title: Tap]
import "envoy/config/common/tap/v2alpha/common.proto";
import "envoy/api/v2/core/base.proto"; import "envoy/api/v2/core/base.proto";
// File sink. import "validate/validate.proto";
//
// .. warning::
//
// The current file sink implementation buffers the entire trace in memory
// prior to writing. This will OOM for long lived sockets and/or where there
// is a large amount of traffic on the socket.
message FileSink {
// Path prefix. The output file will be of the form <path_prefix>_<id>.pb, where <id> is an
// identifier distinguishing the recorded trace for individual socket instances (the Envoy
// connection ID).
string path_prefix = 1;
// File format.
enum Format {
// Binary proto format as per :ref:`Trace
// <envoy_api_msg_data.tap.v2alpha.Trace>`.
PROTO_BINARY = 0;
// Text proto format as per :ref:`Trace
// <envoy_api_msg_data.tap.v2alpha.Trace>`.
PROTO_TEXT = 1;
}
Format format = 2;
}
// Configuration for tap transport socket. This wraps another transport socket, providing the // Configuration for tap transport socket. This wraps another transport socket, providing the
// ability to interpose and record in plain text any traffic that is surfaced to Envoy. // ability to interpose and record in plain text any traffic that is surfaced to Envoy.
message Tap { message Tap {
oneof sink_selector { // Common configuration for the tap transport socket.
// Trace is to be written to a file sink. common.tap.v2alpha.CommonExtensionConfig common_config = 1
FileSink file_sink = 1; [(validate.rules).message.required = true];
}
// The underlying transport socket being wrapped. // The underlying transport socket being wrapped.
api.v2.core.TransportSocket transport_socket = 2; api.v2.core.TransportSocket transport_socket = 2 [(validate.rules).message.required = true];
} }

@ -17,5 +17,8 @@ api_proto_library_internal(
api_proto_library_internal( api_proto_library_internal(
name = "wrapper", name = "wrapper",
srcs = ["wrapper.proto"], srcs = ["wrapper.proto"],
deps = [":http"], deps = [
":http",
":transport",
],
) )

@ -23,8 +23,8 @@ message Connection {
envoy.api.v2.core.Address remote_address = 3; envoy.api.v2.core.Address remote_address = 3;
} }
// Event in a trace. // Event in a socket trace.
message Event { message SocketEvent {
// Timestamp for event. // Timestamp for event.
google.protobuf.Timestamp timestamp = 1; google.protobuf.Timestamp timestamp = 1;
// Data read by Envoy from the transport socket. // Data read by Envoy from the transport socket.
@ -50,9 +50,9 @@ message Event {
// Sequence of read/write events that constitute a trace on a socket. // Sequence of read/write events that constitute a trace on a socket.
// Multiple Trace messages might be emitted for a given connection ID, with the // Multiple Trace messages might be emitted for a given connection ID, with the
// sink (e.g. file set, network) responsible for later reassembly. // sink (e.g. file set, network) responsible for later reassembly.
message Trace { message SocketTrace {
// Connection properties. // Connection properties.
Connection connection = 1; Connection connection = 1;
// Sequence of observed events. // Sequence of observed events.
repeated Event events = 2; repeated SocketEvent events = 2;
} }

@ -1,6 +1,7 @@
syntax = "proto3"; syntax = "proto3";
import "envoy/data/tap/v2alpha/http.proto"; import "envoy/data/tap/v2alpha/http.proto";
import "envoy/data/tap/v2alpha/transport.proto";
import "validate/validate.proto"; import "validate/validate.proto";
@ -17,5 +18,8 @@ message BufferedTraceWrapper {
// An HTTP buffered tap trace. // An HTTP buffered tap trace.
HttpBufferedTrace http_buffered_trace = 1; HttpBufferedTrace http_buffered_trace = 1;
// A buffered socket tap trace.
SocketTrace socket_buffered_trace = 2;
} }
} }

@ -91,9 +91,29 @@ message OutputSink {
// been configured to receive tap configuration from some other source (e.g., static // been configured to receive tap configuration from some other source (e.g., static
// file, XDS, etc.) configuring the streaming admin output type will fail. // file, XDS, etc.) configuring the streaming admin output type will fail.
StreamingAdminSink streaming_admin = 1; StreamingAdminSink streaming_admin = 1;
// Tap output will be written to a file per tap sink.
FilePerTapSink file_per_tap = 2;
} }
} }
// Streaming admin sink configuration. // Streaming admin sink configuration.
message StreamingAdminSink { message StreamingAdminSink {
} }
// The file per tap sink outputs a discrete file for every tapped stream.
message FilePerTapSink {
// Path prefix. The output file will be of the form <path_prefix>_<id>.pb, where <id> is an
// identifier distinguishing the recorded trace for stream instances (the Envoy
// connection ID, HTTP stream ID, etc.).
string path_prefix = 1 [(validate.rules).string.min_bytes = 1];
// File format.
enum Format {
// Binary proto format.
PROTO_BINARY = 0;
// Text proto format.
PROTO_TEXT = 1;
}
Format format = 2 [(validate.rules).enum.defined_only = true];
}

@ -6,7 +6,7 @@ py_binary(
licenses = ["notice"], # Apache 2 licenses = ["notice"], # Apache 2
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//envoy/data/tap/v2alpha:transport_py", "//envoy/data/tap/v2alpha:wrapper_py",
], ],
) )

@ -1,3 +1,4 @@
socket_buffered_trace {
connection { connection {
local_address { local_address {
socket_address { socket_address {
@ -66,3 +67,4 @@ events {
data: "\000\014\010\000\000\000\000\000\001\"ds\"><span class=\"lsbb\"><input class=\"lsb\" value=\"I\'m Feeling Lucky\" name=\"btnI\" onclick=\"if(this.form.q.value)this.checked=1; else top.location=\'/doodles/\'\" type=\"submit\"></span></span></td><td class=\"fl sblc\" align=\"left\" nowrap=\"\" width=\"25%\"><a href=\"/advanced_search?hl=en&amp;authuser=0\">Advanced search</a><a href=\"/language_tools?hl=en&amp;authuser=0\">Language tools</a></td></tr></table><input id=\"gbv\" name=\"gbv\" type=\"hidden\" value=\"1\"></form><div id=\"gac_scont\"></div><div style=\"font-size:83%;min-height:3.5em\"><br></div><span id=\"footer\"><div style=\"font-size:10pt\"><div style=\"margin:19px auto;text-align:center\" id=\"fll\"><a href=\"/intl/en/ads/\">Advertising\240Programs</a><a href=\"/services/\">Business Solutions</a><a href=\"https://plus.google.com/116899029375914044550\" rel=\"publisher\">+Google</a><a href=\"/intl/en/about.html\">About Google</a></div></div><p style=\"color:#767676;font-size:8pt\">&copy; 2018 - <a href=\"/intl/en/policies/privacy/\">Privacy</a> - <a href=\"/intl/en/policies/terms/\">Terms</a></p></span></center><script nonce=\"rLBCtD6iWuWYX1UPQlCXOA==\">(function(){window.google.cdo={height:0,width:0};(function(){var a=window.innerWidth,b=window.innerHeight;if(!a||!b){var c=window.document,d=\"CSS1Compat\"==c.compatMode?c.documentElement:c.body;a=d.clientWidth;b=d.clientHeight}a&&b&&(a!=google.cdo.width||b!=google.cdo.height)&&google.log(\"\",\"\",\"/client_204?&atyp=i&biw=\"+a+\"&bih=\"+b+\"&ei=\"+google.kEI);}).call(this);})();</script><div id=\"xjsd\"></div><div id=\"xjsi\"><script nonce=\"rLBCtD6iWuWYX1UPQlCXOA==\">(function(){function c(b){window.setTimeout(function(){var a=document.createElement(\"script\");a.src=b;google.timers&&google.timers.load.t&&google.tick(\"load\",{gen204:\"xjsls\",clearcut:31});document.getElementById(\"xjsd\").appendChild(a)},0)}google.dljp=function(b,a){google.xjsu=b;c(a)};google.dlj=c;}).call(this);if(!google.xjs){window._=window._||{};window._DumpException=window._._DumpException=function(e){throw e};window._F_installCss=window._._F_installCss=function(c){};google.dljp(\'/xjs/_/js/k\\x3dxjs.hp.en_US.hJpRN-HQS74.O/m\\x3dsb_he,d/am\\x3dVDA2/rt\\x3dj/d\\x3d1/rs\\x3dACT90oGoOpEv-zlKjP7tm3pX-9wBDPuVdQ\',\'/xjs/_/js/k\\x3dxjs.hp.en_US.hJpRN-HQS74.O/m\\x3dsb_he,d/am\\x3dVDA2/rt\\x3dj/d\\x3d1/rs\\x3dACT90oGoOpEv-zlKjP7tm3pX-9wBDPuVdQ\');google.xjs=1;}google.pmc={\"sb_he\":{\"agen\":true,\"cgen\":true,\"client\":\"heirloom-hp\",\"dh\":true,\"dhqt\":true,\"ds\":\"\",\"ffql\":\"en\",\"fl\":true,\"host\":\"google.com\",\"isbh\":28,\"jsonp\":true,\"msgs\":{\"cibl\":\"Clear Search\",\"dym\":\"Did you mean:\",\"lcky\":\"I\\u0026#39;m Feeling Lucky\",\"lml\":\"Learn more\",\"oskt\":\"Input tools\",\"psrc\":\"This search was removed from your \\u003Ca href=\\\"/history\\\"\\u003EWeb History\\u003C/a\\u003E\",\"psrl\":\"Remove\",\"sbit\":\"Search by image\",\"srch\":\"Google Search\"},\"nds\":true,\"ovr\":{},\"pq\":\"\",\"refpd\":true,\"rfs\":[],\"sbpl\":24,\"sbpr\":24,\"scd\":10,\"sce\":5,\"stok\":\"3mJuW88WexlwJgN3WXmg_mhSAvs\"},\"d\":{},\"ZI/YVQ\":{},\"U5B21g\":{},\"DPBNMg\":{},\"YFCs/g\":{}};google.x(null,function(){});(function(){var r=[];google.plm(r);})();(function(){var ctx=[]\n;google.jsc && google.jsc.x(ctx);})();</script></div></body></html>\000\000\000\000\001\000\000\000\001" data: "\000\014\010\000\000\000\000\000\001\"ds\"><span class=\"lsbb\"><input class=\"lsb\" value=\"I\'m Feeling Lucky\" name=\"btnI\" onclick=\"if(this.form.q.value)this.checked=1; else top.location=\'/doodles/\'\" type=\"submit\"></span></span></td><td class=\"fl sblc\" align=\"left\" nowrap=\"\" width=\"25%\"><a href=\"/advanced_search?hl=en&amp;authuser=0\">Advanced search</a><a href=\"/language_tools?hl=en&amp;authuser=0\">Language tools</a></td></tr></table><input id=\"gbv\" name=\"gbv\" type=\"hidden\" value=\"1\"></form><div id=\"gac_scont\"></div><div style=\"font-size:83%;min-height:3.5em\"><br></div><span id=\"footer\"><div style=\"font-size:10pt\"><div style=\"margin:19px auto;text-align:center\" id=\"fll\"><a href=\"/intl/en/ads/\">Advertising\240Programs</a><a href=\"/services/\">Business Solutions</a><a href=\"https://plus.google.com/116899029375914044550\" rel=\"publisher\">+Google</a><a href=\"/intl/en/about.html\">About Google</a></div></div><p style=\"color:#767676;font-size:8pt\">&copy; 2018 - <a href=\"/intl/en/policies/privacy/\">Privacy</a> - <a href=\"/intl/en/policies/terms/\">Terms</a></p></span></center><script nonce=\"rLBCtD6iWuWYX1UPQlCXOA==\">(function(){window.google.cdo={height:0,width:0};(function(){var a=window.innerWidth,b=window.innerHeight;if(!a||!b){var c=window.document,d=\"CSS1Compat\"==c.compatMode?c.documentElement:c.body;a=d.clientWidth;b=d.clientHeight}a&&b&&(a!=google.cdo.width||b!=google.cdo.height)&&google.log(\"\",\"\",\"/client_204?&atyp=i&biw=\"+a+\"&bih=\"+b+\"&ei=\"+google.kEI);}).call(this);})();</script><div id=\"xjsd\"></div><div id=\"xjsi\"><script nonce=\"rLBCtD6iWuWYX1UPQlCXOA==\">(function(){function c(b){window.setTimeout(function(){var a=document.createElement(\"script\");a.src=b;google.timers&&google.timers.load.t&&google.tick(\"load\",{gen204:\"xjsls\",clearcut:31});document.getElementById(\"xjsd\").appendChild(a)},0)}google.dljp=function(b,a){google.xjsu=b;c(a)};google.dlj=c;}).call(this);if(!google.xjs){window._=window._||{};window._DumpException=window._._DumpException=function(e){throw e};window._F_installCss=window._._F_installCss=function(c){};google.dljp(\'/xjs/_/js/k\\x3dxjs.hp.en_US.hJpRN-HQS74.O/m\\x3dsb_he,d/am\\x3dVDA2/rt\\x3dj/d\\x3d1/rs\\x3dACT90oGoOpEv-zlKjP7tm3pX-9wBDPuVdQ\',\'/xjs/_/js/k\\x3dxjs.hp.en_US.hJpRN-HQS74.O/m\\x3dsb_he,d/am\\x3dVDA2/rt\\x3dj/d\\x3d1/rs\\x3dACT90oGoOpEv-zlKjP7tm3pX-9wBDPuVdQ\');google.xjs=1;}google.pmc={\"sb_he\":{\"agen\":true,\"cgen\":true,\"client\":\"heirloom-hp\",\"dh\":true,\"dhqt\":true,\"ds\":\"\",\"ffql\":\"en\",\"fl\":true,\"host\":\"google.com\",\"isbh\":28,\"jsonp\":true,\"msgs\":{\"cibl\":\"Clear Search\",\"dym\":\"Did you mean:\",\"lcky\":\"I\\u0026#39;m Feeling Lucky\",\"lml\":\"Learn more\",\"oskt\":\"Input tools\",\"psrc\":\"This search was removed from your \\u003Ca href=\\\"/history\\\"\\u003EWeb History\\u003C/a\\u003E\",\"psrl\":\"Remove\",\"sbit\":\"Search by image\",\"srch\":\"Google Search\"},\"nds\":true,\"ovr\":{},\"pq\":\"\",\"refpd\":true,\"rfs\":[],\"sbpl\":24,\"sbpr\":24,\"scd\":10,\"sce\":5,\"stok\":\"3mJuW88WexlwJgN3WXmg_mhSAvs\"},\"d\":{},\"ZI/YVQ\":{},\"U5B21g\":{},\"DPBNMg\":{},\"YFCs/g\":{}};google.x(null,function(){});(function(){var r=[];google.plm(r);})();(function(){var ctx=[]\n;google.jsc && google.jsc.x(ctx);})();</script></div></body></html>\000\000\000\000\001\000\000\000\001"
} }
} }
}

@ -28,7 +28,7 @@ import time
from google.protobuf import text_format from google.protobuf import text_format
from envoy.data.tap.v2alpha import transport_pb2 from envoy.data.tap.v2alpha import wrapper_pb2
def DumpEvent(direction, timestamp, data): def DumpEvent(direction, timestamp, data):
@ -44,14 +44,15 @@ def DumpEvent(direction, timestamp, data):
def Tap2Pcap(tap_path, pcap_path): def Tap2Pcap(tap_path, pcap_path):
trace = transport_pb2.Trace() wrapper = wrapper_pb2.BufferedTraceWrapper()
if tap_path.endswith('.pb_text'): if tap_path.endswith('.pb_text'):
with open(tap_path, 'r') as f: with open(tap_path, 'r') as f:
text_format.Merge(f.read(), trace) text_format.Merge(f.read(), wrapper)
else: else:
with open(tap_path, 'r') as f: with open(tap_path, 'r') as f:
trace.ParseFromString(f.read()) wrapper.ParseFromString(f.read())
trace = wrapper.socket_buffered_trace
local_address = trace.connection.local_address.socket_address.address local_address = trace.connection.local_address.socket_address.address
local_port = trace.connection.local_address.socket_address.port_value local_port = trace.connection.local_address.socket_address.port_value
remote_address = trace.connection.remote_address.socket_address.address remote_address = trace.connection.remote_address.socket_address.address

Loading…
Cancel
Save