Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 0 additions & 13 deletions api/envoy/extensions/filters/http/ext_authz/v3/ext_authz.proto
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,6 @@ message ExtAuthzPerRoute {
}

// Extra settings for the check request.
// [#next-free-field: 6]
message CheckSettings {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.filter.http.ext_authz.v2.CheckSettings";
Expand Down Expand Up @@ -514,16 +513,4 @@ message CheckSettings {
// :ref:`disable_request_body_buffering <envoy_v3_api_field_extensions.filters.http.ext_authz.v3.CheckSettings.disable_request_body_buffering>`
// may be specified.
BufferSettings with_request_body = 3;

// Override the external authorization service for this route.
// This allows different routes to use different external authorization service backends
// and service types (gRPC or HTTP). If specified, this overrides the filter-level service
// configuration regardless of the original service type.
oneof service_override {
// Override with a gRPC service configuration.
config.core.v3.GrpcService grpc_service = 4;

// Override with an HTTP service configuration.
HttpService http_service = 5;
}
}
12 changes: 3 additions & 9 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,9 @@ new_features:
for more details.
- area: socket
change: |
Added ``network_namespace_filepath`` to :ref:`SocketAddress <envoy_v3_api_msg_config.core.v3.SocketAddress>`. This field allows
specifying a Linux network namespace filepath for socket creation, enabling network isolation in containerized environments.
Added :ref:``network_namespace_filepath <envoy_v3_api_msg_config.core.v3.SocketAddress.network_namespace_filepath>`` to
:ref:`SocketAddress <envoy_v3_api_msg_config.core.v3.SocketAddress>`. This field allows specifying a Linux network namespace filepath
for socket creation, enabling network isolation in containerized environments.
- area: ratelimit
change: |
Add the :ref:`rate_limits
Expand Down Expand Up @@ -255,13 +256,6 @@ new_features:
Added ``virtualHost()`` to the Stream handle API, allowing Lua scripts to retrieve virtual host information. So far, the only method
implemented is ``metadata()``, allowing Lua scripts to access virtual host metadata scoped to the specific filter name. See
:ref:`Virtual host object API <config_http_filters_lua_virtual_host_wrapper>` for more details.
- area: ext_authz
change: |
Added support for per-route gRPC service override in the ``ext_authz`` HTTP filter. This allows different routes
to use different external authorization backends by configuring a
:ref:`grpc_service <envoy_v3_api_field_extensions.filters.http.ext_authz.v3.CheckSettings.grpc_service>`
in the per-route ``check_settings``. Routes without this configuration continue to use the default
authorization service.
- area: tracing
change: |
Added :ref:`trace_context_option <envoy_v3_api_field_config.trace.v3.ZipkinConfig.trace_context_option>` enum
Expand Down
24 changes: 0 additions & 24 deletions source/extensions/filters/common/ext_authz/ext_authz_http_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,30 +133,6 @@ ClientConfig::ClientConfig(const envoy::extensions::filters::http::ext_authz::v3
Router::HeaderParserPtr)),
encode_raw_headers_(config.encode_raw_headers()) {}

ClientConfig::ClientConfig(
const envoy::extensions::filters::http::ext_authz::v3::HttpService& http_service,
bool encode_raw_headers, uint32_t timeout, Server::Configuration::CommonFactoryContext& context)
: client_header_matchers_(toClientMatchers(
http_service.authorization_response().allowed_client_headers(), context)),
client_header_on_success_matchers_(toClientMatchersOnSuccess(
http_service.authorization_response().allowed_client_headers_on_success(), context)),
to_dynamic_metadata_matchers_(toDynamicMetadataMatchers(
http_service.authorization_response().dynamic_metadata_from_headers(), context)),
upstream_header_matchers_(toUpstreamMatchers(
http_service.authorization_response().allowed_upstream_headers(), context)),
upstream_header_to_append_matchers_(toUpstreamMatchers(
http_service.authorization_response().allowed_upstream_headers_to_append(), context)),
cluster_name_(http_service.server_uri().cluster()), timeout_(timeout),
path_prefix_(
THROW_OR_RETURN_VALUE(validatePathPrefix(http_service.path_prefix()), std::string)),
tracing_name_(fmt::format("async {} egress", http_service.server_uri().cluster())),
request_headers_parser_(THROW_OR_RETURN_VALUE(
Router::HeaderParser::configure(
http_service.authorization_request().headers_to_add(),
envoy::config::core::v3::HeaderValueOption::OVERWRITE_IF_EXISTS_OR_ADD),
Router::HeaderParserPtr)),
encode_raw_headers_(encode_raw_headers) {}

MatcherSharedPtr
ClientConfig::toClientMatchersOnSuccess(const envoy::type::matcher::v3::ListStringMatcher& list,
Server::Configuration::CommonFactoryContext& context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,6 @@ class ClientConfig {
uint32_t timeout, absl::string_view path_prefix,
Server::Configuration::CommonFactoryContext& context);

// Build config directly from HttpService without constructing a temporary ExtAuthz.
ClientConfig(const envoy::extensions::filters::http::ext_authz::v3::HttpService& http_service,
bool encode_raw_headers, uint32_t timeout,
Server::Configuration::CommonFactoryContext& context);

/**
* Returns the name of the authorization cluster.
*/
Expand Down
6 changes: 2 additions & 4 deletions source/extensions/filters/http/ext_authz/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoWithServ
&server_context](Http::FilterChainFactoryCallbacks& callbacks) {
auto client = std::make_unique<Extensions::Filters::Common::ExtAuthz::RawHttpClientImpl>(
server_context.clusterManager(), client_config);
callbacks.addStreamFilter(
std::make_shared<Filter>(filter_config, std::move(client), server_context));
callbacks.addStreamFilter(std::make_shared<Filter>(filter_config, std::move(client)));
};
} else {
// gRPC client.
Expand All @@ -58,8 +57,7 @@ Http::FilterFactoryCb ExtAuthzFilterConfig::createFilterFactoryFromProtoWithServ
THROW_IF_NOT_OK_REF(client_or_error.status());
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), server_context));
callbacks.addStreamFilter(std::make_shared<Filter>(filter_config, std::move(client)));
};
}
return callback;
Expand Down
135 changes: 6 additions & 129 deletions source/extensions/filters/http/ext_authz/ext_authz.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "ext_authz.h"
#include "source/extensions/filters/http/ext_authz/ext_authz.h"

#include <chrono>
Expand All @@ -20,9 +21,6 @@ namespace ExtAuthz {

namespace {

// Default timeout for per-route gRPC client creation.
constexpr uint32_t kDefaultPerRouteTimeoutMs = 200;

using MetadataProto = ::envoy::config::core::v3::Metadata;
using Filters::Common::MutationRules::CheckOperation;
using Filters::Common::MutationRules::CheckResult;
Expand Down Expand Up @@ -174,86 +172,6 @@ void FilterConfigPerRoute::merge(const FilterConfigPerRoute& other) {
}
}

// Constructor used for merging configurations from different levels (vhost, route, etc.)
FilterConfigPerRoute::FilterConfigPerRoute(const FilterConfigPerRoute& less_specific,
const FilterConfigPerRoute& more_specific)
: context_extensions_(less_specific.context_extensions_),
check_settings_(more_specific.check_settings_), disabled_(more_specific.disabled_),
// Only use the most specific per-route override. Do not inherit overrides from less
// specific configuration. If the more specific configuration has no override, leave both
// unset so that the main filter configuration is used.
grpc_service_(more_specific.grpc_service_.has_value() ? more_specific.grpc_service_
: absl::nullopt),
http_service_(more_specific.http_service_.has_value() ? more_specific.http_service_
: absl::nullopt) {
// Merge context extensions from more specific configuration, overriding less specific ones.
for (const auto& extension : more_specific.context_extensions_) {
context_extensions_[extension.first] = extension.second;
}
}

Filters::Common::ExtAuthz::ClientPtr
Filter::createPerRouteGrpcClient(const envoy::config::core::v3::GrpcService& grpc_service) {
if (server_context_ == nullptr) {
ENVOY_STREAM_LOG(
debug, "ext_authz filter: server context not available for per-route gRPC client creation.",
*decoder_callbacks_);
return nullptr;
}

// Use the timeout from the gRPC service configuration, use default if not specified.
const uint32_t timeout_ms =
PROTOBUF_GET_MS_OR_DEFAULT(grpc_service, timeout, kDefaultPerRouteTimeoutMs);

// We can skip transport version check for per-route gRPC service here.
// The transport version is already validated at the main configuration level.
Envoy::Grpc::GrpcServiceConfigWithHashKey config_with_hash_key =
Envoy::Grpc::GrpcServiceConfigWithHashKey(grpc_service);

auto client_or_error = server_context_->clusterManager()
.grpcAsyncClientManager()
.getOrCreateRawAsyncClientWithHashKey(config_with_hash_key,
server_context_->scope(), true);
if (!client_or_error.ok()) {
ENVOY_STREAM_LOG(warn,
"ext_authz filter: failed to create per-route gRPC client: {}. Falling back "
"to default client.",
*decoder_callbacks_, client_or_error.status().ToString());
return nullptr;
}

ENVOY_STREAM_LOG(debug, "ext_authz filter: created per-route gRPC client for cluster: {}.",
*decoder_callbacks_,
grpc_service.has_envoy_grpc() ? grpc_service.envoy_grpc().cluster_name()
: "google_grpc");

return std::make_unique<Filters::Common::ExtAuthz::GrpcClientImpl>(
client_or_error.value(), std::chrono::milliseconds(timeout_ms));
}

Filters::Common::ExtAuthz::ClientPtr Filter::createPerRouteHttpClient(
const envoy::extensions::filters::http::ext_authz::v3::HttpService& http_service) {
if (server_context_ == nullptr) {
ENVOY_STREAM_LOG(
debug, "ext_authz filter: server context not available for per-route HTTP client creation.",
*decoder_callbacks_);
return nullptr;
}

// Use the timeout from the HTTP service configuration, use default if not specified.
const uint32_t timeout_ms =
PROTOBUF_GET_MS_OR_DEFAULT(http_service.server_uri(), timeout, kDefaultPerRouteTimeoutMs);

ENVOY_STREAM_LOG(debug, "ext_authz filter: creating per-route HTTP client for URI: {}.",
*decoder_callbacks_, http_service.server_uri().uri());

const auto client_config = std::make_shared<Extensions::Filters::Common::ExtAuthz::ClientConfig>(
http_service, config_->headersAsBytes(), timeout_ms, *server_context_);

return std::make_unique<Extensions::Filters::Common::ExtAuthz::RawHttpClientImpl>(
server_context_->clusterManager(), client_config);
}

void Filter::initiateCall(const Http::RequestHeaderMap& headers) {
if (filter_return_ == FilterReturn::StopDecoding) {
return;
Expand Down Expand Up @@ -287,10 +205,9 @@ void Filter::initiateCall(const Http::RequestHeaderMap& headers) {
for (const FilterConfigPerRoute& cfg :
Http::Utility::getAllPerFilterConfig<FilterConfigPerRoute>(decoder_callbacks_)) {
if (maybe_merged_per_route_config.has_value()) {
FilterConfigPerRoute current_config = maybe_merged_per_route_config.value();
maybe_merged_per_route_config.emplace(current_config, cfg);
maybe_merged_per_route_config.value().merge(cfg);
} else {
maybe_merged_per_route_config.emplace(cfg);
maybe_merged_per_route_config = cfg;
}
}

Expand All @@ -299,46 +216,6 @@ void Filter::initiateCall(const Http::RequestHeaderMap& headers) {
context_extensions = maybe_merged_per_route_config.value().takeContextExtensions();
}

// Check if we need to use a per-route service override (gRPC or HTTP).
Filters::Common::ExtAuthz::Client* client_to_use = client_.get();
if (maybe_merged_per_route_config) {
if (maybe_merged_per_route_config->grpcService().has_value()) {
const auto& grpc_service = maybe_merged_per_route_config->grpcService().value();
ENVOY_STREAM_LOG(debug, "ext_authz filter: using per-route gRPC service configuration.",
*decoder_callbacks_);

// Create a new gRPC client for this route.
per_route_client_ = createPerRouteGrpcClient(grpc_service);
if (per_route_client_ != nullptr) {
client_to_use = per_route_client_.get();
ENVOY_STREAM_LOG(debug, "ext_authz filter: successfully created per-route gRPC client.",
*decoder_callbacks_);
} else {
ENVOY_STREAM_LOG(
warn,
"ext_authz filter: failed to create per-route gRPC client, falling back to default.",
*decoder_callbacks_);
}
} else if (maybe_merged_per_route_config->httpService().has_value()) {
const auto& http_service = maybe_merged_per_route_config->httpService().value();
ENVOY_STREAM_LOG(debug, "ext_authz filter: using per-route HTTP service configuration.",
*decoder_callbacks_);

// Create a new HTTP client for this route.
per_route_client_ = createPerRouteHttpClient(http_service);
if (per_route_client_ != nullptr) {
client_to_use = per_route_client_.get();
ENVOY_STREAM_LOG(debug, "ext_authz filter: successfully created per-route HTTP client.",
*decoder_callbacks_);
} else {
ENVOY_STREAM_LOG(
warn,
"ext_authz filter: failed to create per-route HTTP client, falling back to default.",
*decoder_callbacks_);
}
}
}

// If metadata_context_namespaces or typed_metadata_context_namespaces is specified,
// pass matching filter metadata to the ext_authz service.
// If metadata key is set in both the connection and request metadata,
Expand All @@ -364,7 +241,7 @@ void Filter::initiateCall(const Http::RequestHeaderMap& headers) {
config_->destinationLabels(), config_->allowedHeadersMatcher(),
config_->disallowedHeadersMatcher());

ENVOY_STREAM_LOG(trace, "ext_authz filter calling authorization server.", *decoder_callbacks_);
ENVOY_STREAM_LOG(trace, "ext_authz filter calling authorization server", *decoder_callbacks_);
// Store start time of ext_authz filter call
start_time_ = decoder_callbacks_->dispatcher().timeSource().monotonicTime();

Expand All @@ -373,8 +250,8 @@ void Filter::initiateCall(const Http::RequestHeaderMap& headers) {
// going to invoke check call.
cluster_ = decoder_callbacks_->clusterInfo();
initiating_call_ = true;
client_to_use->check(*this, check_request_, decoder_callbacks_->activeSpan(),
decoder_callbacks_->streamInfo());
client_->check(*this, check_request_, decoder_callbacks_->activeSpan(),
decoder_callbacks_->streamInfo());
initiating_call_ = false;
}

Expand Down
Loading