diff --git a/CODEOWNERS b/CODEOWNERS index 32cf634d3f16a..c8c3fa0e50a02 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,6 +6,7 @@ /api/ @envoyproxy/api-shepherds # access loggers /*/extensions/access_loggers/common @auni53 @zuercher +/*/extensions/access_loggers/filters/cel @dio @douglas-reid /*/extensions/access_loggers/open_telemetry @itamarkam @yanavlasov /*/extensions/access_loggers/stream @mattklein123 @davinci26 # compression extensions diff --git a/api/BUILD b/api/BUILD index ddd1f98b36cb7..b6438a01d7357 100644 --- a/api/BUILD +++ b/api/BUILD @@ -112,6 +112,7 @@ proto_library( "//envoy/data/dns/v3:pkg", "//envoy/data/tap/v3:pkg", "//envoy/extensions/access_loggers/file/v3:pkg", + "//envoy/extensions/access_loggers/filters/cel/v3:pkg", "//envoy/extensions/access_loggers/grpc/v3:pkg", "//envoy/extensions/access_loggers/open_telemetry/v3:pkg", "//envoy/extensions/access_loggers/stream/v3:pkg", diff --git a/api/envoy/config/accesslog/v3/accesslog.proto b/api/envoy/config/accesslog/v3/accesslog.proto index bb53286380c98..a89a4a709be1c 100644 --- a/api/envoy/config/accesslog/v3/accesslog.proto +++ b/api/envoy/config/accesslog/v3/accesslog.proto @@ -83,6 +83,7 @@ message AccessLogFilter { GrpcStatusFilter grpc_status_filter = 10; // Extension filter. + // [#extension-category: envoy.access_loggers.extension_filters] ExtensionFilter extension_filter = 11; // Metadata Filter diff --git a/api/envoy/extensions/access_loggers/filters/cel/v3/BUILD b/api/envoy/extensions/access_loggers/filters/cel/v3/BUILD new file mode 100644 index 0000000000000..ee92fb652582e --- /dev/null +++ b/api/envoy/extensions/access_loggers/filters/cel/v3/BUILD @@ -0,0 +1,9 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"], +) diff --git a/api/envoy/extensions/access_loggers/filters/cel/v3/cel.proto b/api/envoy/extensions/access_loggers/filters/cel/v3/cel.proto new file mode 100644 index 0000000000000..8cb4d8b779259 --- /dev/null +++ b/api/envoy/extensions/access_loggers/filters/cel/v3/cel.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package envoy.extensions.access_loggers.filters.cel.v3; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.access_loggers.filters.cel.v3"; +option java_outer_classname = "CelProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: ExpressionFilter] +// [#extension: envoy.access_loggers.extension_filters.cel] + +// ExpressionFilter is an access logging filter that evaluates configured +// symbolic Common Expression Language expressions to inform the decision +// to generate an access log. +message ExpressionFilter { + // Expression that, when evaluated, will be used to filter access logs. + // Expressions are based on the set of Envoy :ref:`attributes `. + // The provided expression must evaluate to true for logging (expression errors are considered false). + // Examples: + // - `response.code >= 400` + // - `(connection.mtls && request.headers['x-log-mtls'] == 'true') || request.url_path.contains('v1beta3')` + string expression = 1; +} diff --git a/api/versioning/BUILD b/api/versioning/BUILD index 24195d8d680dd..8be3045e4b9c6 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -49,6 +49,7 @@ proto_library( "//envoy/data/dns/v3:pkg", "//envoy/data/tap/v3:pkg", "//envoy/extensions/access_loggers/file/v3:pkg", + "//envoy/extensions/access_loggers/filters/cel/v3:pkg", "//envoy/extensions/access_loggers/grpc/v3:pkg", "//envoy/extensions/access_loggers/open_telemetry/v3:pkg", "//envoy/extensions/access_loggers/stream/v3:pkg", diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 55e87d55300e2..ea3658f978710 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -859,6 +859,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( urls = ["https://github.com/google/cel-cpp/archive/{version}.tar.gz"], use_category = ["dataplane_ext"], extensions = [ + "envoy.access_loggers.extension_filters.cel", "envoy.access_loggers.wasm", "envoy.bootstrap.wasm", "envoy.rate_limit_descriptors.expr", @@ -882,6 +883,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( urls = ["https://github.com/google/flatbuffers/archive/v{version}.tar.gz"], use_category = ["dataplane_ext"], extensions = [ + "envoy.access_loggers.extension_filters.cel", "envoy.access_loggers.wasm", "envoy.bootstrap.wasm", "envoy.rate_limit_descriptors.expr", @@ -1078,6 +1080,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( # ANTLR has a runtime component, so is not purely build. use_category = ["dataplane_ext"], extensions = [ + "envoy.access_loggers.extension_filters.cel", "envoy.access_loggers.wasm", "envoy.bootstrap.wasm", "envoy.rate_limit_descriptors.expr", @@ -1098,6 +1101,7 @@ REPOSITORY_LOCATIONS_SPEC = dict( urls = ["https://github.com/antlr/antlr4/archive/{version}.tar.gz"], use_category = ["dataplane_ext"], extensions = [ + "envoy.access_loggers.extension_filters.cel", "envoy.access_loggers.wasm", "envoy.bootstrap.wasm", "envoy.rate_limit_descriptors.expr", diff --git a/docs/root/api-v3/config/accesslog/accesslog.rst b/docs/root/api-v3/config/accesslog/accesslog.rst index dae49773f7881..6f265939d7eee 100644 --- a/docs/root/api-v3/config/accesslog/accesslog.rst +++ b/docs/root/api-v3/config/accesslog/accesslog.rst @@ -9,3 +9,4 @@ Access loggers v3/* ../../extensions/access_loggers/*/v3/* + ../../extensions/access_loggers/filters/*/v3/* diff --git a/docs/root/api-v3/config/accesslog/filters.rst b/docs/root/api-v3/config/accesslog/filters.rst new file mode 100644 index 0000000000000..692d0a18586b3 --- /dev/null +++ b/docs/root/api-v3/config/accesslog/filters.rst @@ -0,0 +1,8 @@ +Extension Filters +================= + +.. toctree:: + :glob: + :maxdepth: 2 + + filters/filters diff --git a/docs/root/api-v3/config/accesslog/filters/filters.rst b/docs/root/api-v3/config/accesslog/filters/filters.rst new file mode 100644 index 0000000000000..a27e04e376921 --- /dev/null +++ b/docs/root/api-v3/config/accesslog/filters/filters.rst @@ -0,0 +1,8 @@ +Extension Filters +================= + +.. toctree:: + :glob: + :maxdepth: 2 + + ../../../extensions/access_loggers/filters/*/v3/* diff --git a/docs/root/api-v3/config/config.rst b/docs/root/api-v3/config/config.rst index 6d4034ff5b8d8..605afc346a32d 100644 --- a/docs/root/api-v3/config/config.rst +++ b/docs/root/api-v3/config/config.rst @@ -9,6 +9,7 @@ Extensions filter/filter accesslog/accesslog + accesslog/filters rbac/rbac health_checker/health_checker transport_socket/transport_socket diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 3caf3e6be8ebe..8a6bd863c3ef8 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -54,6 +54,8 @@ Removed Config or Runtime New Features ------------ * access log: added :ref:`grpc_stream_retry_policy ` to the gRPC logger to reconnect when a connection fails to be established. +* access_log: added :ref:`METADATA` token to handle all types of metadata (DYNAMIC, CLUSTER, ROUTE). +* access_log: added a CEL extension filter to enable filtering of access logs based on Envoy attribute expressions. * access_log: added new access_log command operator ``%UPSTREAM_REQUEST_ATTEMPT_COUNT%`` to retrieve the number of times given request got attempted upstream. * access_log: added new access_log command operator ``%VIRTUAL_CLUSTER_NAME%`` to retrieve the matched Virtual Cluster name. * api: added support for *xds.type.v3.TypedStruct* in addition to the now-deprecated *udpa.type.v1.TypedStruct* proto message, which is a wrapper proto used to encode typed JSON data in a *google.protobuf.Any* field. diff --git a/source/extensions/access_loggers/filters/cel/BUILD b/source/extensions/access_loggers/filters/cel/BUILD new file mode 100644 index 0000000000000..4e53f30780d7a --- /dev/null +++ b/source/extensions/access_loggers/filters/cel/BUILD @@ -0,0 +1,63 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_extension( + name = "cel_lib", + srcs = ["cel.cc"], + hdrs = ["cel.h"], + extra_visibility = [ + "//test:__subpackages__", + ], + deps = [ + "//envoy/access_log:access_log_interface", + "//envoy/http:header_map_interface", + "//envoy/stream_info:stream_info_interface", + "//source/common/access_log:access_log_lib", + "//source/common/config:utility_lib", + "//source/common/protobuf", + "//source/common/protobuf:utility_lib", + "//source/extensions/filters/common/expr:evaluator_lib", + ], +) + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + hdrs = ["config.h"], + copts = select({ + "//bazel:windows_x86_64": [], # TODO: fix the windows ANTLR build + "//conditions:default": [ + "-DUSE_CEL_PARSER", + ], + }), + extra_visibility = [ + "//test:__subpackages__", + ], + deps = [ + ":cel_lib", + "//envoy/access_log:access_log_interface", + "//envoy/http:header_map_interface", + "//envoy/registry", + "//envoy/stream_info:stream_info_interface", + "//source/common/access_log:access_log_lib", + "//source/common/config:utility_lib", + "//source/common/protobuf", + "//source/common/protobuf:utility_lib", + "//source/extensions/filters/common/expr:evaluator_lib", + "@envoy_api//envoy/extensions/access_loggers/filters/cel/v3:pkg_cc_proto", + ] + select( + { + "//bazel:windows_x86_64": [], + "//conditions:default": [ + "@com_google_cel_cpp//parser", + ], + }, + ), +) diff --git a/source/extensions/access_loggers/filters/cel/cel.cc b/source/extensions/access_loggers/filters/cel/cel.cc new file mode 100644 index 0000000000000..a9c87da2e1a01 --- /dev/null +++ b/source/extensions/access_loggers/filters/cel/cel.cc @@ -0,0 +1,35 @@ +#include "source/extensions/access_loggers/filters/cel/cel.h" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Filters { +namespace CEL { + +namespace Expr = Envoy::Extensions::Filters::Common::Expr; + +CELAccessLogExtensionFilter::CELAccessLogExtensionFilter( + Expr::Builder& builder, const google::api::expr::v1alpha1::Expr& input_expr) + : parsed_expr_(input_expr) { + compiled_expr_ = Expr::createExpression(builder, parsed_expr_); +} + +bool CELAccessLogExtensionFilter::evaluate( + const StreamInfo::StreamInfo& stream_info, const Http::RequestHeaderMap& request_headers, + const Http::ResponseHeaderMap& response_headers, + const Http::ResponseTrailerMap& response_trailers) const { + Protobuf::Arena arena; + auto eval_status = Expr::evaluate(*compiled_expr_, arena, stream_info, &request_headers, + &response_headers, &response_trailers); + if (!eval_status.has_value() || eval_status.value().IsError()) { + return false; + } + auto result = eval_status.value(); + return result.IsBool() ? result.BoolOrDie() : false; +} + +} // namespace CEL +} // namespace Filters +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/access_loggers/filters/cel/cel.h b/source/extensions/access_loggers/filters/cel/cel.h new file mode 100644 index 0000000000000..911f04106b60f --- /dev/null +++ b/source/extensions/access_loggers/filters/cel/cel.h @@ -0,0 +1,36 @@ +#include "envoy/access_log/access_log.h" +#include "envoy/http/header_map.h" +#include "envoy/stream_info/stream_info.h" + +#include "source/common/access_log/access_log_impl.h" +#include "source/common/config/utility.h" +#include "source/common/protobuf/message_validator_impl.h" +#include "source/common/protobuf/protobuf.h" +#include "source/common/protobuf/utility.h" +#include "source/extensions/filters/common/expr/evaluator.h" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Filters { +namespace CEL { + +class CELAccessLogExtensionFilter : public AccessLog::Filter { +public: + CELAccessLogExtensionFilter(Extensions::Filters::Common::Expr::Builder&, + const google::api::expr::v1alpha1::Expr&); + + bool evaluate(const StreamInfo::StreamInfo& info, const Http::RequestHeaderMap& request_headers, + const Http::ResponseHeaderMap& response_headers, + const Http::ResponseTrailerMap& response_trailers) const override; + +private: + const google::api::expr::v1alpha1::Expr parsed_expr_; + Extensions::Filters::Common::Expr::ExpressionPtr compiled_expr_; +}; + +} // namespace CEL +} // namespace Filters +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/access_loggers/filters/cel/config.cc b/source/extensions/access_loggers/filters/cel/config.cc new file mode 100644 index 0000000000000..0df41fc19c525 --- /dev/null +++ b/source/extensions/access_loggers/filters/cel/config.cc @@ -0,0 +1,65 @@ +#include "source/extensions/access_loggers/filters/cel/config.h" + +#include "envoy/extensions/access_loggers/filters/cel/v3/cel.pb.h" + +#include "source/extensions/access_loggers/filters/cel/cel.h" + +#if defined(USE_CEL_PARSER) +#include "parser/parser.h" +#endif + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Filters { +namespace CEL { + +Envoy::AccessLog::FilterPtr CELAccessLogExtensionFilterFactory::createFilter( + const envoy::config::accesslog::v3::ExtensionFilter& config, Runtime::Loader&, + Random::RandomGenerator&) { + + // TODO(douglas-reid): use factory_context validation. likely needs update to + // createFilter signature to pass in validation visitor. + auto factory_config = Config::Utility::translateToFactoryConfig( + config, Envoy::ProtobufMessage::getNullValidationVisitor(), *this); + +#if defined(USE_CEL_PARSER) + envoy::extensions::access_loggers::filters::cel::v3::ExpressionFilter cel_config = + *dynamic_cast( + factory_config.get()); + + auto parse_status = google::api::expr::parser::Parse(cel_config.expression()); + if (!parse_status.ok()) { + throw EnvoyException("Not able to parse filter expression: " + + parse_status.status().ToString()); + } + + return std::make_unique(getOrCreateBuilder(), + parse_status.value().expr()); +#else + throw EnvoyException("CEL is not available for use in this environment."); +#endif +} + +ProtobufTypes::MessagePtr CELAccessLogExtensionFilterFactory::createEmptyConfigProto() { + return std::make_unique(); +} + +Extensions::Filters::Common::Expr::Builder& +CELAccessLogExtensionFilterFactory::getOrCreateBuilder() { + if (expr_builder_ == nullptr) { + expr_builder_ = Extensions::Filters::Common::Expr::createBuilder(nullptr); + } + return *expr_builder_; +} + +/** + * Static registration for the CELAccessLogExtensionFilter. @see RegisterFactory. + */ +REGISTER_FACTORY(CELAccessLogExtensionFilterFactory, Envoy::AccessLog::ExtensionFilterFactory); + +} // namespace CEL +} // namespace Filters +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/access_loggers/filters/cel/config.h b/source/extensions/access_loggers/filters/cel/config.h new file mode 100644 index 0000000000000..0266af6fbb0ab --- /dev/null +++ b/source/extensions/access_loggers/filters/cel/config.h @@ -0,0 +1,36 @@ +#include "envoy/access_log/access_log.h" +#include "envoy/http/header_map.h" +#include "envoy/registry/registry.h" +#include "envoy/stream_info/stream_info.h" + +#include "source/common/access_log/access_log_impl.h" +#include "source/common/config/utility.h" +#include "source/common/protobuf/message_validator_impl.h" +#include "source/common/protobuf/protobuf.h" +#include "source/common/protobuf/utility.h" +#include "source/extensions/filters/common/expr/evaluator.h" + +namespace Envoy { +namespace Extensions { +namespace AccessLoggers { +namespace Filters { +namespace CEL { + +class CELAccessLogExtensionFilterFactory : public Envoy::AccessLog::ExtensionFilterFactory { +public: + Envoy::AccessLog::FilterPtr + createFilter(const envoy::config::accesslog::v3::ExtensionFilter& config, Runtime::Loader&, + Random::RandomGenerator&) override; + ProtobufTypes::MessagePtr createEmptyConfigProto() override; + std::string name() const override { return "envoy.access_loggers.extension_filters.cel"; } + +private: + Extensions::Filters::Common::Expr::Builder& getOrCreateBuilder(); + Extensions::Filters::Common::Expr::BuilderPtr expr_builder_; +}; + +} // namespace CEL +} // namespace Filters +} // namespace AccessLoggers +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index cd6a62d3d5c42..af6c536084391 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -5,6 +5,7 @@ EXTENSIONS = { # "envoy.access_loggers.file": "//source/extensions/access_loggers/file:config", + "envoy.access_loggers.extension_filters.cel": "//source/extensions/access_loggers/filters/cel:config", "envoy.access_loggers.http_grpc": "//source/extensions/access_loggers/grpc:http_config", "envoy.access_loggers.tcp_grpc": "//source/extensions/access_loggers/grpc:tcp_config", "envoy.access_loggers.open_telemetry": "//source/extensions/access_loggers/open_telemetry:config", diff --git a/source/extensions/extensions_metadata.yaml b/source/extensions/extensions_metadata.yaml index 6a4a403220fdb..3cf47195acf25 100644 --- a/source/extensions/extensions_metadata.yaml +++ b/source/extensions/extensions_metadata.yaml @@ -3,6 +3,11 @@ envoy.access_loggers.file: - envoy.access_loggers security_posture: robust_to_untrusted_downstream status: stable +envoy.access_loggers.extension_filters.cel: + categories: + - envoy.access_loggers.extension_filters + security_posture: unknown + status: alpha envoy.access_loggers.http_grpc: categories: - envoy.access_loggers diff --git a/test/common/access_log/BUILD b/test/common/access_log/BUILD index 5a1908dfb08ad..bc8eb168dccd8 100644 --- a/test/common/access_log/BUILD +++ b/test/common/access_log/BUILD @@ -11,10 +11,17 @@ envoy_package() envoy_cc_test( name = "access_log_impl_test", srcs = ["access_log_impl_test.cc"], + copts = select({ + "//bazel:windows_x86_64": [], # TODO: fix the windows ANTLR build + "//conditions:default": [ + "-DUSE_CEL_PARSER", + ], + }), deps = [ "//source/common/access_log:access_log_lib", "//source/common/stream_info:utility_lib", "//source/extensions/access_loggers/file:config", + "//source/extensions/access_loggers/filters/cel:config", "//source/extensions/access_loggers/grpc:http_config", "//source/extensions/access_loggers/grpc:tcp_config", "//source/extensions/access_loggers/stream:config", diff --git a/test/common/access_log/access_log_impl_test.cc b/test/common/access_log/access_log_impl_test.cc index d2d4c291f110d..c5b24903996df 100644 --- a/test/common/access_log/access_log_impl_test.cc +++ b/test/common/access_log/access_log_impl_test.cc @@ -1598,6 +1598,72 @@ name: accesslog } } +#if defined(USE_CEL_PARSER) +TEST_F(AccessLogImplTest, CelExtensionFilter) { + const std::string yaml = R"EOF( +name: accesslog +filter: + extension_filter: + name: cel_extension_filter + typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.filters.cel.v3.ExpressionFilter + expression: "(request.headers['log'] == 'true') && (response.code >= 400)" +typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + path: /dev/null + )EOF"; + + InstanceSharedPtr logger = AccessLogFactory::fromProto(parseAccessLogFromV3Yaml(yaml), context_); + + request_headers_.addCopy("log", "true"); + stream_info_.response_code_ = 404; + EXPECT_CALL(*file_, write(_)); + logger->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); + + request_headers_.remove("log"); + EXPECT_CALL(*file_, write(_)).Times(0); + logger->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); +} + +TEST_F(AccessLogImplTest, CelExtensionFilterExpressionError) { + const std::string yaml = R"EOF( +name: accesslog +filter: + extension_filter: + name: cel_extension_filter + typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.filters.cel.v3.ExpressionFilter + expression: "foo['test']" +typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + path: /dev/null + )EOF"; + + InstanceSharedPtr logger = AccessLogFactory::fromProto(parseAccessLogFromV3Yaml(yaml), context_); + + EXPECT_CALL(*file_, write(_)).Times(0); + logger->log(&request_headers_, &response_headers_, &response_trailers_, stream_info_); +} + +TEST_F(AccessLogImplTest, CelExtensionFilterExpressionUnparsable) { + const std::string yaml = R"EOF( +name: accesslog +filter: + extension_filter: + name: cel_extension_filter + typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.filters.cel.v3.ExpressionFilter + expression: "(+++" +typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + path: /dev/null + )EOF"; + + EXPECT_THROW_WITH_REGEX(AccessLogFactory::fromProto(parseAccessLogFromV3Yaml(yaml), context_), + EnvoyException, "Not able to parse filter expression: .*"); +} +#endif // USE_CEL_PARSER + // Test that the deprecated extension names are disabled by default. // TODO(zuercher): remove when envoy.deprecated_features.allow_deprecated_extension_names is removed TEST_F(AccessLogImplTest, DEPRECATED_FEATURE_TEST(DeprecatedExtensionFilterName)) { diff --git a/tools/extensions/extensions_check.py b/tools/extensions/extensions_check.py index c9c204050f38d..313206572d122 100644 --- a/tools/extensions/extensions_check.py +++ b/tools/extensions/extensions_check.py @@ -55,7 +55,7 @@ "envoy.stats_sinks", "envoy.thrift_proxy.filters", "envoy.tracers", "envoy.sip_proxy.filters", "envoy.transport_sockets.downstream", "envoy.transport_sockets.upstream", "envoy.tls.cert_validator", "envoy.upstreams", "envoy.wasm.runtime", "envoy.common.key_value", - "envoy.network.dns_resolver", "envoy.rbac.matchers") + "envoy.network.dns_resolver", "envoy.rbac.matchers", "envoy.access_loggers.extension_filters") EXTENSION_STATUS_VALUES = ( # This extension is stable and is expected to be production usable.