Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add extension point for custom StringMatcher, and lua implementation #32586

Merged
merged 33 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
58e9631
add field
ggreenway Feb 13, 2024
603fe94
start work on extension
ggreenway Feb 13, 2024
e4c9248
includes
ggreenway Feb 13, 2024
2c19a62
wip
ggreenway Feb 14, 2024
50a7bc1
starting to create filter - needs message validation visitor
ggreenway Feb 15, 2024
2f9d983
fix circular dependency between matchers and stats, grpc
ggreenway Feb 15, 2024
9e49958
wip
ggreenway Feb 15, 2024
5ba4161
working tests and integration test
ggreenway Feb 16, 2024
fd26479
Merge remote-tracking branch 'upstream/main' into stringmatcher-exten…
ggreenway Feb 28, 2024
2988a31
switch to DataSource for code
ggreenway Feb 28, 2024
24cf4b1
remove comment that isn't needed
ggreenway Feb 28, 2024
c5406b0
rename proto filed from `extension` to `custom`
ggreenway Feb 28, 2024
55ef7e6
change namespace
ggreenway Feb 28, 2024
5f75d3c
prefix function name with `envoy_`; hold a reference to function in lua
ggreenway Feb 28, 2024
43e53fd
document lua
ggreenway Feb 28, 2024
01916e6
proto format
ggreenway Feb 28, 2024
2fd2b4c
format
ggreenway Feb 28, 2024
8a17661
Revert "fix circular dependency between matchers and stats, grpc"
ggreenway Feb 29, 2024
43bc93d
Merge remote-tracking branch 'upstream/main' into stringmatcher-exten…
ggreenway Feb 29, 2024
2b765cd
allow luajit use in new extension
ggreenway Feb 29, 2024
31037cf
fix format
ggreenway Feb 29, 2024
a7acad3
add comment
ggreenway Feb 29, 2024
679ff29
fix router check tool
ggreenway Feb 29, 2024
5c5c4c4
extension metadata
ggreenway Feb 29, 2024
36b4595
fix format namespace
ggreenway Feb 29, 2024
ddef77a
docs
ggreenway Feb 29, 2024
a266a1d
fix multi-envoy test, following pattern used for all other singletons
ggreenway Feb 29, 2024
c47edf3
improve test coverage
ggreenway Feb 29, 2024
5792164
fix asan test
ggreenway Mar 1, 2024
0090626
Merge remote-tracking branch 'upstream/main' into stringmatcher-exten…
ggreenway Mar 1, 2024
6684e5d
add comment about singletons
ggreenway Mar 1, 2024
5de8572
Merge remote-tracking branch 'upstream/main' into stringmatcher-exten…
ggreenway Mar 4, 2024
57f2942
changelog
ggreenway Mar 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ extensions/filters/http/oauth2 @derekargueta @mattklein123
/*/extensions/http/early_header_mutation/header_mutation @wbpcode @UNOWNED
# Network matching extensions
/*/extensions/matching/network/ @kyessenov @mattklein123
# String matching extensions
/*/extensions/string_matcher/ @ggreenway @UNOWNED
# Header mutation
/*/extensions/filters/http/header_mutation @wbpcode @htuch @soulxu
# Health checkers
Expand Down
1 change: 1 addition & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ proto_library(
"//envoy/extensions/stat_sinks/graphite_statsd/v3:pkg",
"//envoy/extensions/stat_sinks/open_telemetry/v3:pkg",
"//envoy/extensions/stat_sinks/wasm/v3:pkg",
"//envoy/extensions/string_matcher/lua/v3:pkg",
"//envoy/extensions/tracers/opentelemetry/resource_detectors/v3:pkg",
"//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg",
"//envoy/extensions/transport_sockets/alts/v3:pkg",
Expand Down
12 changes: 12 additions & 0 deletions api/envoy/extensions/string_matcher/lua/v3/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# 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 = [
"//envoy/config/core/v3:pkg",
"@com_github_cncf_xds//udpa/annotations:pkg",
],
)
37 changes: 37 additions & 0 deletions api/envoy/extensions/string_matcher/lua/v3/lua.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
syntax = "proto3";

package envoy.extensions.string_matcher.lua.v3;

import "envoy/config/core/v3/base.proto";

import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.string_matcher.lua.v3";
option java_outer_classname = "LuaProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/string_matcher/lua/v3;luav3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Lua StringMatcher]
// A Lua StringMatcher allows executing a Lua script to determine if a string is a match. The configured source
// code must define a function named `envoy_match`. If the function returns true, the string is considered a match.
// Any other result, including an execution error, is considered a non-match.
//
// Example:
//
// .. code-block:: yaml
//
// source_code:
// inline_string: |
// function envoy_match(str)
// -- Do something.
// return true
// end
//
// [#extension: envoy.string_matcher.lua]

message Lua {
// The Lua code that Envoy will execute
config.core.v3.DataSource source_code = 1 [(validate.rules).message = {required: true}];
}
1 change: 1 addition & 0 deletions api/envoy/type/matcher/v3/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ api_proto_package(
"//envoy/annotations:pkg",
"//envoy/type/v3:pkg",
"@com_github_cncf_xds//udpa/annotations:pkg",
"@com_github_cncf_xds//xds/core/v3:pkg",
],
)
8 changes: 7 additions & 1 deletion api/envoy/type/matcher/v3/string.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package envoy.type.matcher.v3;

import "envoy/type/matcher/v3/regex.proto";

import "xds/core/v3/extension.proto";

import "udpa/annotations/status.proto";
import "udpa/annotations/versioning.proto";
import "validate/validate.proto";
Expand All @@ -17,7 +19,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// [#protodoc-title: String matcher]

// Specifies the way to match a string.
// [#next-free-field: 8]
// [#next-free-field: 9]
message StringMatcher {
option (udpa.annotations.versioning).previous_message_type = "envoy.type.matcher.StringMatcher";

Expand Down Expand Up @@ -61,6 +63,10 @@ message StringMatcher {
//
// * ``abc`` matches the value ``xyz.abc.def``
string contains = 7 [(validate.rules).string = {min_len: 1}];

// Use an extension as the matcher type.
// [#extension-category: envoy.string_matcher]
xds.core.v3.TypedExtensionConfig custom = 8;
}

// If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. This
Expand Down
1 change: 1 addition & 0 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ proto_library(
"//envoy/extensions/stat_sinks/graphite_statsd/v3:pkg",
"//envoy/extensions/stat_sinks/open_telemetry/v3:pkg",
"//envoy/extensions/stat_sinks/wasm/v3:pkg",
"//envoy/extensions/string_matcher/lua/v3:pkg",
"//envoy/extensions/tracers/opentelemetry/resource_detectors/v3:pkg",
"//envoy/extensions/tracers/opentelemetry/samplers/v3:pkg",
"//envoy/extensions/transport_sockets/alts/v3:pkg",
Expand Down
1 change: 1 addition & 0 deletions bazel/repository_locations.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ REPOSITORY_LOCATIONS_SPEC = dict(
extensions = [
"envoy.filters.http.lua",
"envoy.router.cluster_specifier_plugin.lua",
"envoy.string_matcher.lua",
],
cpe = "cpe:2.3:a:luajit:luajit:*",
license = "MIT",
Expand Down
4 changes: 4 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ new_features:
change: |
Added load shed point ``envoy.load_shed_points.hcm_ondata_creating_codec`` that closes connections before creating codec if
Envoy is under pressure, typically memory.
- area: string matcher
change: |
Added an :ref:`extension point for custom string matcher implementations <envoy_v3_api_field_type.matcher.v3.StringMatcher.custom>`.
An implementation for :ref:`running a Lua script <envoy_v3_api_msg_extensions.string_matcher.lua.v3.Lua>` is included.
- area: overload
change: |
added a :ref:`configuration option
Expand Down
1 change: 1 addition & 0 deletions docs/root/api-v3/config/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Extensions
resource_monitor/resource_monitor
retry/retry
stat_sinks/stat_sinks
string_matcher/string_matcher
transport_socket/transport_socket
upstream/upstream
wasm/wasm
Expand Down
8 changes: 8 additions & 0 deletions docs/root/api-v3/config/string_matcher/string_matcher.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
String Matcher
==============

.. toctree::
:glob:
:maxdepth: 2

../../extensions/string_matcher/*/v3/*
1 change: 1 addition & 0 deletions docs/root/configuration/other_features/other_features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Other features
wasm
wasm_service
qatzip
string_matcher
10 changes: 10 additions & 0 deletions docs/root/configuration/other_features/string_matcher.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
String Matcher
==============

:ref:`StringMatcher <envoy_v3_api_msg_type.matcher.v3.StringMatcher>` can be configured
for one of the commonly used modes, or :ref:`extended for custom usecases
<envoy_v3_api_field_type.matcher.v3.StringMatcher.custom>`.

Envoy includes an :ref:`extension for running a Lua script
<envoy_v3_api_msg_extensions.string_matcher.lua.v3.Lua>` to determine
whether a string matches.
6 changes: 6 additions & 0 deletions source/common/common/matchers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "source/common/common/macros.h"
#include "source/common/common/regex.h"
#include "source/common/config/metadata.h"
#include "source/common/config/utility.h"
#include "source/common/http/path_utility.h"

#include "absl/strings/match.h"
Expand Down Expand Up @@ -200,5 +201,10 @@ bool PathMatcher::match(const absl::string_view path) const {
return matcher_.match(Http::PathUtil::removeQueryAndFragment(path));
}

StringMatcherPtr getExtensionStringMatcher(const ::xds::core::v3::TypedExtensionConfig& config) {
auto factory = Config::Utility::getAndCheckFactory<StringMatcherExtensionFactory>(config, false);
return factory->createStringMatcher(config.typed_config());
}

} // namespace Matchers
} // namespace Envoy
84 changes: 62 additions & 22 deletions source/common/common/matchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ class UniversalStringMatcher : public StringMatcher {
bool match(absl::string_view) const override { return true; }
};

StringMatcherPtr getExtensionStringMatcher(const ::xds::core::v3::TypedExtensionConfig& config);

template <class StringMatcherType = envoy::type::matcher::v3::StringMatcher>
class StringMatcherImpl : public ValueMatcher, public StringMatcher {
public:
Expand All @@ -100,32 +102,14 @@ class StringMatcherImpl : public ValueMatcher, public StringMatcher {
// Cache the lowercase conversion of the Contains matcher for future use
lowercase_contains_match_ = absl::AsciiStrToLower(matcher_.contains());
}
} else {
initialize(matcher);
}
}

// StringMatcher
bool match(const absl::string_view value) const override {
switch (matcher_.match_pattern_case()) {
case StringMatcherType::MatchPatternCase::kExact:
return matcher_.ignore_case() ? absl::EqualsIgnoreCase(value, matcher_.exact())
: value == matcher_.exact();
case StringMatcherType::MatchPatternCase::kPrefix:
return matcher_.ignore_case() ? absl::StartsWithIgnoreCase(value, matcher_.prefix())
: absl::StartsWith(value, matcher_.prefix());
case StringMatcherType::MatchPatternCase::kSuffix:
return matcher_.ignore_case() ? absl::EndsWithIgnoreCase(value, matcher_.suffix())
: absl::EndsWith(value, matcher_.suffix());
case StringMatcherType::MatchPatternCase::kContains:
return matcher_.ignore_case()
? absl::StrContains(absl::AsciiStrToLower(value), lowercase_contains_match_)
: absl::StrContains(value, matcher_.contains());
case StringMatcherType::MatchPatternCase::kSafeRegex:
return regex_->match(value);
case StringMatcherType::MatchPatternCase::MATCH_PATTERN_NOT_SET:
break;
}
PANIC("unexpected");
}
bool match(const absl::string_view value) const override { return match(value, matcher_); }

bool match(const ProtobufWkt::Value& value) const override {

if (value.kind_case() != ProtobufWkt::Value::kStringValue) {
Expand Down Expand Up @@ -155,9 +139,65 @@ class StringMatcherImpl : public ValueMatcher, public StringMatcher {
}

private:
// Type `xds::type::matcher::v3::StringMatcher` doesn't have an extension type, so use function
// overloading to only handle that case for type `envoy::type::matcher::v3::StringMatcher` to
// prevent compilation errors on use of `kCustom`.

void initialize(const xds::type::matcher::v3::StringMatcher&) {}

void initialize(const envoy::type::matcher::v3::StringMatcher& matcher) {
if (matcher.has_custom()) {
custom_ = getExtensionStringMatcher(matcher.custom());
}
}

bool match(const absl::string_view value, const xds::type::matcher::v3::StringMatcher&) const {
return matchCommon(value);
}

bool match(const absl::string_view value,
const envoy::type::matcher::v3::StringMatcher& matcher) const {
if (matcher.match_pattern_case() ==
envoy::type::matcher::v3::StringMatcher::MatchPatternCase::kCustom) {
return custom_->match(value);
}
return matchCommon(value);
}

// StringMatcher
bool matchCommon(const absl::string_view value) const {
switch (matcher_.match_pattern_case()) {
case StringMatcherType::MatchPatternCase::kExact:
return matcher_.ignore_case() ? absl::EqualsIgnoreCase(value, matcher_.exact())
: value == matcher_.exact();
case StringMatcherType::MatchPatternCase::kPrefix:
return matcher_.ignore_case() ? absl::StartsWithIgnoreCase(value, matcher_.prefix())
: absl::StartsWith(value, matcher_.prefix());
case StringMatcherType::MatchPatternCase::kSuffix:
return matcher_.ignore_case() ? absl::EndsWithIgnoreCase(value, matcher_.suffix())
: absl::EndsWith(value, matcher_.suffix());
case StringMatcherType::MatchPatternCase::kContains:
return matcher_.ignore_case()
? absl::StrContains(absl::AsciiStrToLower(value), lowercase_contains_match_)
: absl::StrContains(value, matcher_.contains());
case StringMatcherType::MatchPatternCase::kSafeRegex:
return regex_->match(value);
default:
PANIC("unexpected");
}
}

const StringMatcherType matcher_;
Regex::CompiledMatcherPtr regex_;
std::string lowercase_contains_match_;
StringMatcherPtr custom_;
};

class StringMatcherExtensionFactory : public Config::TypedFactory {
public:
virtual StringMatcherPtr createStringMatcher(const ProtobufWkt::Any& config) PURE;

std::string category() const override { return "envoy.string_matcher"; }
};

class ListMatcher : public ValueMatcher {
Expand Down
5 changes: 5 additions & 0 deletions source/extensions/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ EXTENSIONS = {

"envoy.matching.actions.format_string": "//source/extensions/matching/actions/format_string:config",

#
# StringMatchers
#
"envoy.string_matcher.lua": "//source/extensions/string_matcher/lua:config",

#
# HTTP filters
#
Expand Down
7 changes: 7 additions & 0 deletions source/extensions/extensions_metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,13 @@ envoy.stat_sinks.wasm:
status: alpha
type_urls:
- envoy.extensions.stat_sinks.wasm.v3.Wasm
envoy.string_matcher.lua:
categories:
- envoy.string_matcher
security_posture: robust_to_untrusted_downstream_and_upstream
status: alpha
type_urls:
- envoy.extensions.string_matcher.lua.v3.Lua
envoy.tls.cert_validator.spiffe:
categories:
- envoy.tls.cert_validator
Expand Down
21 changes: 21 additions & 0 deletions source/extensions/string_matcher/lua/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_extension",
"envoy_extension_package",
)

licenses(["notice"]) # Apache 2

envoy_extension_package()

envoy_cc_extension(
name = "config",
srcs = ["match.cc"],
hdrs = ["match.h"],
deps = [
"//source/common/common:matchers_lib",
"//source/common/config:datasource_lib",
"//source/extensions/filters/common/lua:lua_lib",
"@envoy_api//envoy/extensions/string_matcher/lua/v3:pkg_cc_proto",
],
)
Loading
Loading