Skip to content

Commit

Permalink
ext_authz: create filter from server context (envoyproxy#35557)
Browse files Browse the repository at this point in the history
<!--
!!!ATTENTION!!!

If you are fixing *any* crash or *any* potential security issue, *do
not*
open a pull request in this repo. Please report the issue via emailing
envoy-security@googlegroups.com where the issue will be triaged
appropriately.
Thank you in advance for helping to keep Envoy secure.

!!!ATTENTION!!!

For an explanation of how to fill out the fields, please see the
relevant section
in
[PULL_REQUESTS.md](https://github.com/envoyproxy/envoy/blob/main/PULL_REQUESTS.md)
-->

Commit Message: Prior art:
[ext_proc](https://github.com/envoyproxy/envoy/blob/f58a812ed24bf7d552ece3642bdf9336ee1a7e20/source/extensions/filters/http/ext_proc/config.cc#L45).
And we have use this approach in production
Risk Level: low
Testing: unit test

Signed-off-by: tyxia <tyxia@google.com>
  • Loading branch information
tyxia committed Aug 5, 2024
1 parent ceb0ccd commit 0beb3cb
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 16 deletions.
24 changes: 9 additions & 15 deletions source/extensions/filters/http/ext_authz/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,14 @@ namespace Extensions {
namespace HttpFilters {
namespace ExtAuthz {

Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoTyped(
Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoWithServerContextTyped(
const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz& proto_config,
const std::string& stats_prefix, Server::Configuration::FactoryContext& context) {
auto& server_context = context.serverFactoryContext();

const auto filter_config =
std::make_shared<FilterConfig>(proto_config, context.scope(), stats_prefix, server_context);
const std::string& stats_prefix, Server::Configuration::ServerFactoryContext& server_context) {
const auto filter_config = std::make_shared<FilterConfig>(proto_config, server_context.scope(),
stats_prefix, server_context);
// The callback is created in main thread and executed in worker thread, variables except factory
// context must be captured by value into the callback.
Http::FilterFactoryCb callback;

if (proto_config.has_http_service()) {
// Raw HTTP client.
const uint32_t timeout_ms = PROTOBUF_GET_MS_OR_DEFAULT(proto_config.http_service().server_uri(),
Expand All @@ -48,24 +45,21 @@ Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoTyped(
// gRPC client.
const uint32_t timeout_ms =
PROTOBUF_GET_MS_OR_DEFAULT(proto_config.grpc_service(), timeout, DefaultTimeout);

THROW_IF_NOT_OK(Config::Utility::checkTransportVersion(proto_config));
Envoy::Grpc::GrpcServiceConfigWithHashKey config_with_hash_key =
Envoy::Grpc::GrpcServiceConfigWithHashKey(proto_config.grpc_service());
callback = [&context, filter_config, timeout_ms,
callback = [&server_context, filter_config, timeout_ms,
config_with_hash_key](Http::FilterChainFactoryCallbacks& callbacks) {
auto client_or_error =
context.serverFactoryContext()
.clusterManager()
.grpcAsyncClientManager()
.getOrCreateRawAsyncClientWithHashKey(config_with_hash_key, context.scope(), true);
auto client_or_error = server_context.clusterManager()
.grpcAsyncClientManager()
.getOrCreateRawAsyncClientWithHashKey(
config_with_hash_key, server_context.scope(), true);
THROW_IF_STATUS_NOT_OK(client_or_error, throw);
auto client = std::make_unique<Filters::Common::ExtAuthz::GrpcClientImpl>(
client_or_error.value(), std::chrono::milliseconds(timeout_ms));
callbacks.addStreamFilter(std::make_shared<Filter>(filter_config, std::move(client)));
};
}

return callback;
}

Expand Down
10 changes: 9 additions & 1 deletion source/extensions/filters/http/ext_authz/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,15 @@ class ExtAuthzFilterConfig
static constexpr uint64_t DefaultTimeout = 200;
Http::FilterFactoryCb createFilterFactoryFromProtoTyped(
const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz& proto_config,
const std::string& stats_prefix, Server::Configuration::FactoryContext& context) override;
const std::string& stats_prefix, Server::Configuration::FactoryContext& context) override {
return createFilterFactoryFromProtoWithServerContextTyped(proto_config, stats_prefix,
context.serverFactoryContext());
}

Http::FilterFactoryCb createFilterFactoryFromProtoWithServerContextTyped(
const envoy::extensions::filters::http::ext_authz::v3::ExtAuthz& proto_config,
const std::string& stats_prefix,
Server::Configuration::ServerFactoryContext& server_context) override;

Router::RouteSpecificFilterConfigConstSharedPtr createRouteSpecificFilterConfigTyped(
const envoy::extensions::filters::http::ext_authz::v3::ExtAuthzPerRoute& proto_config,
Expand Down
54 changes: 54 additions & 0 deletions test/extensions/filters/http/ext_authz/config_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,60 @@ TEST_F(ExtAuthzFilterHttpTest, ExtAuthzFilterFactoryTestHttp) {
testFilterFactory(ext_authz_config_yaml);
}

TEST_F(ExtAuthzFilterHttpTest, FilterWithServerContext) {
const std::string ext_authz_config_yaml = R"EOF(
stat_prefix: "wall"
allowed_headers:
patterns:
- exact: baz
- prefix: x-
http_service:
server_uri:
uri: "ext_authz:9000"
cluster: "ext_authz"
timeout: 0.25s
authorization_request:
headers_to_add:
- key: foo
value: bar
- key: bar
value: foo
authorization_response:
allowed_upstream_headers:
patterns:
- exact: baz
- prefix: x-success
allowed_client_headers:
patterns:
- exact: baz
- prefix: x-fail
allowed_upstream_headers_to_append:
patterns:
- exact: baz-append
- prefix: x-append
path_prefix: /extauth
failure_mode_allow: true
with_request_body:
max_request_bytes: 100
pack_as_bytes: true
)EOF";

ExtAuthzFilterConfig factory;
ProtobufTypes::MessagePtr proto_config = factory.createEmptyConfigProto();
TestUtility::loadFromYaml(ext_authz_config_yaml, *proto_config);

testing::NiceMock<Server::Configuration::MockServerFactoryContext> context;
EXPECT_CALL(context, messageValidationVisitor());
Http::FilterFactoryCb cb =
factory.createFilterFactoryFromProtoWithServerContext(*proto_config, "stats", context);
Http::MockFilterChainFactoryCallbacks filter_callback;
EXPECT_CALL(filter_callback, addStreamFilter(_));
cb(filter_callback);
}

class ExtAuthzFilterGrpcTest : public ExtAuthzFilterTest {
public:
void testFilterFactoryAndFilterWithGrpcClient(const std::string& ext_authz_config_yaml) {
Expand Down

0 comments on commit 0beb3cb

Please sign in to comment.