Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7236a7a
add partial_body field to attribute_context
brectanus-sigsci Apr 12, 2019
7cfd880
update changelog
brectanus-sigsci Apr 15, 2019
fbeba65
fixed ref in changelog
brectanus-sigsci Apr 15, 2019
944ff2b
added a constant for the new metadata header
brectanus-sigsci Apr 16, 2019
12e3e10
changed from a new field to adding a metadata header to indicate part…
brectanus-sigsci Apr 16, 2019
d69fceb
document the metadata header being added to the authorization request…
brectanus-sigsci Apr 16, 2019
9a2f45b
update release notes
brectanus-sigsci Apr 16, 2019
950e7cf
fix formatting
brectanus-sigsci Apr 17, 2019
6e196c2
make sure that a client supplied EnvoyAuthPartialBody header is not used
brectanus-sigsci Apr 18, 2019
cebcc3c
fixed changelog order
brectanus-sigsci Apr 18, 2019
2b3b7dd
Merge branch 'master' into buffered_authz_partial_flag
brectanus-sigsci Apr 18, 2019
20a3ce9
reorder changelog entry again after merge destroyed alpha order, lol
brectanus-sigsci Apr 18, 2019
31a2079
Merge branch 'master' into buffered_authz_partial_flag
brectanus-sigsci Apr 20, 2019
6f1f781
change header values from `0|1` to `false|true`
brectanus-sigsci Apr 20, 2019
568b9c7
fix formatting
brectanus-sigsci Apr 21, 2019
9d3255a
Merge branch 'master' into buffered_authz_partial_flag
brectanus-sigsci Apr 22, 2019
d2f0bc4
synced changelog with master to fix docs test issues
brectanus-sigsci Apr 22, 2019
3893170
Merge branch 'master' into buffered_authz_partial_flag
brectanus-sigsci Apr 22, 2019
b1ce1f6
fix conflict in changelog
brectanus-sigsci Apr 23, 2019
7507afe
Merge branch 'master' into buffered_authz_partial_flag
brectanus-sigsci Apr 23, 2019
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 api/envoy/config/filter/http/ext_authz/v2/ext_authz.proto
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ message ExtAuthz {
bool use_alpha = 4 [deprecated = true];

// Enables filter to buffer the client request body and send it within the authorization request.
// A ``x-envoy-auth-partial-body: false|true`` metadata header will be added to the authorization
// request message indicating if the body data is partial.
BufferSettings with_request_body = 5;

// Clears route cache in order to allow the external authorization service to correctly affect
Expand Down
1 change: 1 addition & 0 deletions docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Version history
* dubbo_proxy: support the :ref:`Dubbo proxy filter <config_network_filters_dubbo_proxy>`.
* eds: added support to specify max time for which endpoints can be used :ref:`gRPC filter <envoy_api_msg_ClusterLoadAssignment.Policy>`.
* event: added :ref:`loop duration and poll delay statistics <operations_performance>`.
* ext_authz: added a `x-envoy-auth-partial-body` metadata header set to `false|true` indicating if there is a partial body sent in the authorization request message.
* ext_authz: added option to `ext_authz` that allows the filter clearing route cache.
* http: mitigated a race condition with the :ref:`delayed_close_timeout<envoy_api_field_config.filter.network.http_connection_manager.v2.HttpConnectionManager.delayed_close_timeout>` where it could trigger while actively flushing a pending write buffer for a downstream connection.
* redis: added :ref:`prefix routing <envoy_api_field_config.filter.network.redis_proxy.v2.RedisProxy.prefix_routes>` to enable routing commands based on their key's prefix to different upstream.
Expand Down
1 change: 1 addition & 0 deletions source/common/http/headers.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class HeaderValues {
const LowerCaseString Cookie{"cookie"};
const LowerCaseString Date{"date"};
const LowerCaseString EnvoyAttemptCount{"x-envoy-attempt-count"};
const LowerCaseString EnvoyAuthPartialBody{"x-envoy-auth-partial-body"};
const LowerCaseString EnvoyDegraded{"x-envoy-degraded"};
const LowerCaseString EnvoyDownstreamServiceCluster{"x-envoy-downstream-service-cluster"};
const LowerCaseString EnvoyDownstreamServiceNode{"x-envoy-downstream-service-node"};
Expand Down
19 changes: 13 additions & 6 deletions source/extensions/filters/common/ext_authz/check_request_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,15 @@ void CheckRequestUtils::setHttpRequest(
auto mutable_headers = httpreq.mutable_headers();
headers.iterate(
[](const Envoy::Http::HeaderEntry& e, void* ctx) {
Envoy::Protobuf::Map<Envoy::ProtobufTypes::String, Envoy::ProtobufTypes::String>*
mutable_headers = static_cast<
Envoy::Protobuf::Map<Envoy::ProtobufTypes::String, Envoy::ProtobufTypes::String>*>(
ctx);
(*mutable_headers)[std::string(e.key().getStringView())] =
std::string(e.value().getStringView());
// Skip any client EnvoyAuthPartialBody header, which could interfere with internal use.
if (e.key().getStringView() != Http::Headers::get().EnvoyAuthPartialBody.get()) {
Envoy::Protobuf::Map<Envoy::ProtobufTypes::String, Envoy::ProtobufTypes::String>*
mutable_headers =
static_cast<Envoy::Protobuf::Map<Envoy::ProtobufTypes::String,
Envoy::ProtobufTypes::String>*>(ctx);
(*mutable_headers)[std::string(e.key().getStringView())] =
std::string(e.value().getStringView());
}
return Envoy::Http::HeaderMap::Iterate::Continue;
},
mutable_headers);
Expand All @@ -124,6 +127,10 @@ void CheckRequestUtils::setHttpRequest(
std::string data(length, 0);
buffer->copyOut(0, length, &data[0]);
httpreq.set_body(std::move(data));

// Add in a header to detect when a partial body is used.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may also want to check that this header does not exist when the request is not a partial message. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly sure what you mean here. Only send the header if the body was actually truncated? Or only send the header if the allow_partial_message option is set...

The metadata header is currently only there if max_request_bytes is set. In order to detect if this feature is available, I needed to send it with a bool (0|1) value (vs only sending the header if the body is partial). This way, in the gRPC service, you can use the logic "if the header is there, then it is coming from an envoy with this feature (v1.11+) and the value indicates partial or not. In this case the work is done for you, otherwise this is an older envoy and you need to detect this on your own using C-L header or other means."

Now, if you mean only write the header if the config option allow_partial_message: true, then yeah, that could be done, but I did not want to add another parameter to CheckRequestUtils::setHttpRequest to expose a check for this. I did not think it was worth it as it meant it was harder to determine from the gRPC service if the new partial flag feature was available. That is, if the header is not sent when allow_partial_message: false, then the gRPC service cannot tell if it is envoy v1.10 or the partial feature is disabled in v1.11.

If you think that the metadata header may get in people's way when allow_partial_message: false, then I can expose the config option as a parameter to CheckRequestUtils::setHttpRequest. Unless maybe you see another way to get access to the config option without it as a parameter?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the client request contains x-envoy-auth-partial-body: 1 header? Not sure if we should trust the client.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I'll skip that header during the copy.

(*mutable_headers)[Http::Headers::get().EnvoyAuthPartialBody.get()] =
length != buffer->length() ? "true" : "false";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,24 @@ TEST_F(CheckRequestUtilsTest, BasicTcp) {

// Verify that createHttpCheck's dependencies are invoked when it's called.
// Verify that check request object has no request data.
// Verify that a client supplied EnvoyAuthPartialBody will not affect the
// CheckRequest call.
TEST_F(CheckRequestUtilsTest, BasicHttp) {
const uint64_t size = 0;
Http::HeaderMapImpl headers_;
envoy::service::auth::v2::CheckRequest request_;

// A client supplied EnvoyAuthPartialBody header should be ignored.
Http::TestHeaderMapImpl request_headers{{Http::Headers::get().EnvoyAuthPartialBody.get(), "1"}};

ExpectBasicHttp();
CheckRequestUtils::createHttpCheck(&callbacks_, headers_,
CheckRequestUtils::createHttpCheck(&callbacks_, request_headers,
Protobuf::Map<ProtobufTypes::String, ProtobufTypes::String>(),
request_, size);
ASSERT_EQ(size, request_.attributes().request().http().body().size());
EXPECT_EQ(buffer_->toString().substr(0, size), request_.attributes().request().http().body());
EXPECT_EQ(request_.attributes().request().http().headers().end(),
request_.attributes().request().http().headers().find(
Http::Headers::get().EnvoyAuthPartialBody.get()));
}

// Verify that check request object has only a portion of the request data.
Expand All @@ -100,6 +107,8 @@ TEST_F(CheckRequestUtilsTest, BasicHttpWithPartialBody) {
request_, size);
ASSERT_EQ(size, request_.attributes().request().http().body().size());
EXPECT_EQ(buffer_->toString().substr(0, size), request_.attributes().request().http().body());
EXPECT_EQ("true", request_.attributes().request().http().headers().at(
Http::Headers::get().EnvoyAuthPartialBody.get()));
}

// Verify that check request object has all the request data.
Expand All @@ -114,6 +123,8 @@ TEST_F(CheckRequestUtilsTest, BasicHttpWithFullBody) {
ASSERT_EQ(buffer_->length(), request_.attributes().request().http().body().size());
EXPECT_EQ(buffer_->toString().substr(0, buffer_->length()),
request_.attributes().request().http().body());
EXPECT_EQ("false", request_.attributes().request().http().headers().at(
Http::Headers::get().EnvoyAuthPartialBody.get()));
}

// Verify that createHttpCheck extract the proper attributes from the http request into CheckRequest
Expand Down