diff --git a/docs/configuration/http_conn_man/headers.rst b/docs/configuration/http_conn_man/headers.rst index 03ba36d616499..1b257386a5643 100644 --- a/docs/configuration/http_conn_man/headers.rst +++ b/docs/configuration/http_conn_man/headers.rst @@ -51,6 +51,15 @@ authentication TLS mesh which will make this header fully secure. Like *user-age is determined by the :option:`--service-cluster` command line option. In order to enable this feature you need to set the :ref:`user_agent ` option to true. +.. _config_http_conn_man_headers_downstream-service-node: + +x-envoy-downstream-service-node +------------------------------- + +Internal services may want to know the downstream node request comes from. This header +is quite similar to :ref:`config_http_conn_man_headers_downstream-service-cluster`, except the value is taken from +the :option:`--service-node` option. + .. _config_http_conn_man_headers_x-envoy-external-address: x-envoy-external-address diff --git a/include/envoy/http/header_map.h b/include/envoy/http/header_map.h index 9fe948d479e45..50c940dc185d7 100644 --- a/include/envoy/http/header_map.h +++ b/include/envoy/http/header_map.h @@ -197,6 +197,7 @@ class HeaderEntry { HEADER_FUNC(ContentType) \ HEADER_FUNC(Date) \ HEADER_FUNC(EnvoyDownstreamServiceCluster) \ + HEADER_FUNC(EnvoyDownstreamServiceNode) \ HEADER_FUNC(EnvoyExpectedRequestTimeoutMs) \ HEADER_FUNC(EnvoyExternalAddress) \ HEADER_FUNC(EnvoyForceTrace) \ diff --git a/source/common/http/BUILD b/source/common/http/BUILD index 9817993c4e586..81d5f4a633e8f 100644 --- a/source/common/http/BUILD +++ b/source/common/http/BUILD @@ -104,6 +104,7 @@ envoy_cc_library( "//include/envoy/http:codec_interface", "//include/envoy/http:filter_interface", "//include/envoy/http:header_map_interface", + "//include/envoy/local_info:local_info_interface", "//include/envoy/network:connection_interface", "//include/envoy/network:drain_decision_interface", "//include/envoy/network:filter_interface", diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index fce76e724983a..19d0766927f7b 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -50,11 +50,12 @@ ConnectionManagerTracingStats ConnectionManagerImpl::generateTracingStats(const ConnectionManagerImpl::ConnectionManagerImpl(ConnectionManagerConfig& config, Network::DrainDecision& drain_close, Runtime::RandomGenerator& random_generator, - Tracing::HttpTracer& tracer, Runtime::Loader& runtime) + Tracing::HttpTracer& tracer, Runtime::Loader& runtime, + const LocalInfo::LocalInfo& local_info) : config_(config), stats_(config_.stats()), conn_length_(stats_.named_.downstream_cx_length_ms_.allocateSpan()), drain_close_(drain_close), random_generator_(random_generator), tracer_(tracer), - runtime_(runtime) {} + runtime_(runtime), local_info_(local_info) {} void ConnectionManagerImpl::initializeReadFilterCallbacks(Network::ReadFilterCallbacks& callbacks) { read_callbacks_ = &callbacks; @@ -465,7 +466,7 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(HeaderMapPtr&& headers, ConnectionManagerUtility::mutateRequestHeaders( *request_headers_, connection_manager_.read_callbacks_->connection(), connection_manager_.config_, *snapped_route_config_, connection_manager_.random_generator_, - connection_manager_.runtime_); + connection_manager_.runtime_, connection_manager_.local_info_); // Check if tracing is enabled at all. if (connection_manager_.config_.tracingConfig()) { diff --git a/source/common/http/conn_manager_impl.h b/source/common/http/conn_manager_impl.h index bab674c880671..2926f0c1b82b0 100644 --- a/source/common/http/conn_manager_impl.h +++ b/source/common/http/conn_manager_impl.h @@ -229,7 +229,7 @@ class ConnectionManagerImpl : Logger::Loggable, public: ConnectionManagerImpl(ConnectionManagerConfig& config, Network::DrainDecision& drain_close, Runtime::RandomGenerator& random_generator, Tracing::HttpTracer& tracer, - Runtime::Loader& runtime); + Runtime::Loader& runtime, const LocalInfo::LocalInfo& local_info); ~ConnectionManagerImpl(); static ConnectionManagerStats generateStats(const std::string& prefix, Stats::Store& stats); @@ -504,6 +504,7 @@ class ConnectionManagerImpl : Logger::Loggable, Runtime::RandomGenerator& random_generator_; Tracing::HttpTracer& tracer_; Runtime::Loader& runtime_; + const LocalInfo::LocalInfo& local_info_; Network::ReadFilterCallbacks* read_callbacks_{}; }; diff --git a/source/common/http/conn_manager_utility.cc b/source/common/http/conn_manager_utility.cc index 4880a1c5a9222..8659902a788e4 100644 --- a/source/common/http/conn_manager_utility.cc +++ b/source/common/http/conn_manager_utility.cc @@ -32,7 +32,8 @@ void ConnectionManagerUtility::mutateRequestHeaders(Http::HeaderMap& request_hea ConnectionManagerConfig& config, const Router::Config& route_config, Runtime::RandomGenerator& random, - Runtime::Loader& runtime) { + Runtime::Loader& runtime, + const LocalInfo::LocalInfo& local_info) { // Clean proxy headers. request_headers.removeConnection(); request_headers.removeEnvoyInternalRequest(); @@ -76,6 +77,7 @@ void ConnectionManagerUtility::mutateRequestHeaders(Http::HeaderMap& request_hea } else { if (edge_request) { request_headers.removeEnvoyDownstreamServiceCluster(); + request_headers.removeEnvoyDownstreamServiceNode(); } request_headers.removeEnvoyRetryOn(); @@ -97,6 +99,10 @@ void ConnectionManagerUtility::mutateRequestHeaders(Http::HeaderMap& request_hea if (user_agent_header.value().empty()) { user_agent_header.value(config.userAgent().value()); } + + if (!local_info.nodeName().empty()) { + request_headers.insertEnvoyDownstreamServiceNode().value(local_info.nodeName()); + } } // If we are an external request, AND we are "using remote address" (see above), we set diff --git a/source/common/http/conn_manager_utility.h b/source/common/http/conn_manager_utility.h index 37344d69ddd45..a3db0b075643b 100644 --- a/source/common/http/conn_manager_utility.h +++ b/source/common/http/conn_manager_utility.h @@ -22,7 +22,8 @@ class ConnectionManagerUtility { static void mutateRequestHeaders(Http::HeaderMap& request_headers, Network::Connection& connection, ConnectionManagerConfig& config, const Router::Config& route_config, - Runtime::RandomGenerator& random, Runtime::Loader& runtime); + Runtime::RandomGenerator& random, Runtime::Loader& runtime, + const LocalInfo::LocalInfo& local_info); static void mutateResponseHeaders(Http::HeaderMap& response_headers, const Http::HeaderMap& request_headers, diff --git a/source/common/http/headers.h b/source/common/http/headers.h index 4e2e6d4c3cab6..f3a118efb4273 100644 --- a/source/common/http/headers.h +++ b/source/common/http/headers.h @@ -23,6 +23,7 @@ class HeaderValues { const LowerCaseString Cookie{"cookie"}; const LowerCaseString Date{"date"}; const LowerCaseString EnvoyDownstreamServiceCluster{"x-envoy-downstream-service-cluster"}; + const LowerCaseString EnvoyDownstreamServiceNode{"x-envoy-downstream-service-node"}; const LowerCaseString EnvoyExternalAddress{"x-envoy-external-address"}; const LowerCaseString EnvoyForceTrace{"x-envoy-force-trace"}; const LowerCaseString EnvoyInternalRequest{"x-envoy-internal"}; diff --git a/source/server/config/network/http_connection_manager.cc b/source/server/config/network/http_connection_manager.cc index a78ee2c82a7ca..b71e829c59159 100644 --- a/source/server/config/network/http_connection_manager.cc +++ b/source/server/config/network/http_connection_manager.cc @@ -36,9 +36,9 @@ NetworkFilterFactoryCb HttpConnectionManagerFilterConfigFactory::createFilterFac std::shared_ptr http_config( new HttpConnectionManagerConfig(config, server)); return [http_config, &server](Network::FilterManager& filter_manager) mutable -> void { - filter_manager.addReadFilter(Network::ReadFilterSharedPtr{ - new Http::ConnectionManagerImpl(*http_config, server.drainManager(), server.random(), - server.httpTracer(), server.runtime())}); + filter_manager.addReadFilter(Network::ReadFilterSharedPtr{new Http::ConnectionManagerImpl( + *http_config, server.drainManager(), server.random(), server.httpTracer(), server.runtime(), + server.localInfo())}); }; } diff --git a/source/server/http/admin.cc b/source/server/http/admin.cc index 505b3ea43aa95..5c913ada91ea1 100644 --- a/source/server/http/admin.cc +++ b/source/server/http/admin.cc @@ -382,7 +382,8 @@ Http::ServerConnectionPtr AdminImpl::createCodec(Network::Connection& connection bool AdminImpl::createFilterChain(Network::Connection& connection) { connection.addReadFilter(Network::ReadFilterSharedPtr{new Http::ConnectionManagerImpl( - *this, server_.drainManager(), server_.random(), server_.httpTracer(), server_.runtime())}); + *this, server_.drainManager(), server_.random(), server_.httpTracer(), server_.runtime(), + server_.localInfo())}); return true; } diff --git a/test/common/http/BUILD b/test/common/http/BUILD index c0f85c63bc34e..4651f944ef0c4 100644 --- a/test/common/http/BUILD +++ b/test/common/http/BUILD @@ -98,6 +98,7 @@ envoy_cc_test( "//test/mocks/access_log:access_log_mocks", "//test/mocks/buffer:buffer_mocks", "//test/mocks/http:http_mocks", + "//test/mocks/local_info:local_info_mocks", "//test/mocks/network:network_mocks", "//test/mocks/runtime:runtime_mocks", "//test/mocks/ssl:ssl_mocks", @@ -118,6 +119,7 @@ envoy_cc_test( "//source/common/runtime:runtime_lib", "//source/common/runtime:uuid_util_lib", "//test/mocks/http:http_mocks", + "//test/mocks/local_info:local_info_mocks", "//test/mocks/network:network_mocks", "//test/mocks/runtime:runtime_mocks", "//test/mocks/upstream:upstream_mocks", diff --git a/test/common/http/conn_manager_impl_test.cc b/test/common/http/conn_manager_impl_test.cc index e32be7959cb78..6d7bba15cb509 100644 --- a/test/common/http/conn_manager_impl_test.cc +++ b/test/common/http/conn_manager_impl_test.cc @@ -24,6 +24,7 @@ #include "test/mocks/buffer/mocks.h" #include "test/mocks/common.h" #include "test/mocks/http/mocks.h" +#include "test/mocks/local_info/mocks.h" #include "test/mocks/network/mocks.h" #include "test/mocks/runtime/mocks.h" #include "test/mocks/ssl/mocks.h" @@ -89,7 +90,8 @@ class HttpConnectionManagerImplTest : public Test, public ConnectionManagerConfi ON_CALL(filter_callbacks_.connection_, ssl()).WillByDefault(Return(ssl_connection_.get())); ON_CALL(filter_callbacks_.connection_, remoteAddress()) .WillByDefault(ReturnRef(remote_address_)); - conn_manager_.reset(new ConnectionManagerImpl(*this, drain_close_, random_, tracer_, runtime_)); + conn_manager_.reset( + new ConnectionManagerImpl(*this, drain_close_, random_, tracer_, runtime_, local_info_)); conn_manager_->initializeReadFilterCallbacks(filter_callbacks_); } @@ -177,6 +179,7 @@ class HttpConnectionManagerImplTest : public Test, public ConnectionManagerConfi Optional user_agent_; Optional idle_timeout_; NiceMock random_; + NiceMock local_info_; std::unique_ptr ssl_connection_; RouteConfigProvider route_config_provider_; TracingConnectionManagerConfigPtr tracing_config_; diff --git a/test/common/http/conn_manager_utility_test.cc b/test/common/http/conn_manager_utility_test.cc index 397c5eec57a31..b1bfd4fb2e8a5 100644 --- a/test/common/http/conn_manager_utility_test.cc +++ b/test/common/http/conn_manager_utility_test.cc @@ -8,6 +8,7 @@ #include "common/runtime/uuid_util.h" #include "test/mocks/http/mocks.h" +#include "test/mocks/local_info/mocks.h" #include "test/mocks/network/mocks.h" #include "test/mocks/runtime/mocks.h" #include "test/test_common/printers.h" @@ -42,6 +43,9 @@ class ConnectionManagerUtilityTest : public testing::Test { Optional user_agent_; NiceMock runtime_; Http::TracingConnectionManagerConfig tracing_config_; + NiceMock local_info_; + std::string canary_node_{"canary"}; + std::string empty_node_{""}; }; TEST_F(ConnectionManagerUtilityTest, generateStreamId) { @@ -63,7 +67,7 @@ TEST_F(ConnectionManagerUtilityTest, UseRemoteAddressWhenNotLocalHostRemoteAddre TestHeaderMapImpl headers{}; ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_TRUE(headers.has(Headers::get().ForwardedFor)); EXPECT_EQ(not_local_host_remote_address.ip()->addressAsString(), @@ -80,7 +84,7 @@ TEST_F(ConnectionManagerUtilityTest, UseLocalAddressWhenLocalHostRemoteAddress) TestHeaderMapImpl headers{}; ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_TRUE(headers.has(Headers::get().ForwardedFor)); EXPECT_EQ(local_address.ip()->addressAsString(), headers.get_(Headers::get().ForwardedFor)); @@ -94,10 +98,11 @@ TEST_F(ConnectionManagerUtilityTest, UserAgentDontSet) { TestHeaderMapImpl headers{{"user-agent", "foo"}}; ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_EQ("foo", headers.get_(Headers::get().UserAgent)); EXPECT_FALSE(headers.has(Headers::get().EnvoyDownstreamServiceCluster)); + EXPECT_FALSE(headers.has(Headers::get().EnvoyDownstreamServiceNode)); EXPECT_EQ("true", headers.get_(Headers::get().EnvoyInternalRequest)); } @@ -109,11 +114,13 @@ TEST_F(ConnectionManagerUtilityTest, UserAgentSetWhenIncomingEmpty) { user_agent_.value("bar"); TestHeaderMapImpl headers{{"user-agent", ""}, {"x-envoy-downstream-service-cluster", "foo"}}; + EXPECT_CALL(local_info_, nodeName()).Times(2).WillRepeatedly(ReturnRef(canary_node_)); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_EQ("bar", headers.get_(Headers::get().UserAgent)); EXPECT_EQ("bar", headers.get_(Headers::get().EnvoyDownstreamServiceCluster)); + EXPECT_EQ("canary", headers.get_(Headers::get().EnvoyDownstreamServiceNode)); EXPECT_EQ("true", headers.get_(Headers::get().EnvoyInternalRequest)); } @@ -129,7 +136,7 @@ TEST_F(ConnectionManagerUtilityTest, InternalServiceForceTrace) { EXPECT_CALL(runtime_.snapshot_, featureEnabled("tracing.global_enabled", 100, _)) .WillOnce(Return(true)); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_EQ("f4dca0a9-12c7-a307-8002-969403baf480", headers.get_(Headers::get().RequestId)); } @@ -141,7 +148,7 @@ TEST_F(ConnectionManagerUtilityTest, InternalServiceForceTrace) { EXPECT_CALL(runtime_.snapshot_, featureEnabled("tracing.global_enabled", 100, _)) .WillOnce(Return(true)); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_EQ(uuid, headers.get_(Headers::get().RequestId)); EXPECT_FALSE(headers.has(Headers::get().EnvoyForceTrace)); } @@ -163,9 +170,10 @@ TEST_F(ConnectionManagerUtilityTest, EdgeRequestRegenerateRequestIdAndWipeDownst EXPECT_CALL(runtime_.snapshot_, featureEnabled("tracing.client_enabled", _)).Times(0); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_FALSE(headers.has(Headers::get().EnvoyDownstreamServiceCluster)); + EXPECT_FALSE(headers.has(Headers::get().EnvoyDownstreamServiceNode)); // No changes to generated_uuid as x-client-trace-id is missing. EXPECT_EQ(generated_uuid, headers.get_(Headers::get().RequestId)); } @@ -180,7 +188,7 @@ TEST_F(ConnectionManagerUtilityTest, EdgeRequestRegenerateRequestIdAndWipeDownst .WillOnce(Return(false)); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_FALSE(headers.has(Headers::get().EnvoyDownstreamServiceCluster)); EXPECT_EQ("f4dca0a9-12c7-4307-8002-969403baf480", headers.get_(Headers::get().RequestId)); @@ -197,7 +205,7 @@ TEST_F(ConnectionManagerUtilityTest, EdgeRequestRegenerateRequestIdAndWipeDownst .WillOnce(Return(true)); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_FALSE(headers.has(Headers::get().EnvoyDownstreamServiceCluster)); EXPECT_EQ("f4dca0a9-12c7-b307-8002-969403baf480", headers.get_(Headers::get().RequestId)); @@ -211,10 +219,12 @@ TEST_F(ConnectionManagerUtilityTest, ExternalRequestPreserveRequestIdAndDownstre {"x-request-id", "id"}, {"x-forwarded-for", "34.0.0.1"}}; + EXPECT_CALL(local_info_, nodeName()).Times(0); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_EQ("foo", headers.get_(Headers::get().EnvoyDownstreamServiceCluster)); + EXPECT_FALSE(headers.has(Headers::get().EnvoyDownstreamServiceNode)); EXPECT_EQ("id", headers.get_(Headers::get().RequestId)); EXPECT_FALSE(headers.has(Headers::get().EnvoyInternalRequest)); } @@ -227,9 +237,11 @@ TEST_F(ConnectionManagerUtilityTest, UserAgentSetIncomingUserAgent) { user_agent_.value("bar"); TestHeaderMapImpl headers{{"user-agent", "foo"}, {"x-envoy-downstream-service-cluster", "foo"}}; + EXPECT_CALL(local_info_, nodeName()).WillOnce(ReturnRef(empty_node_)); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); + EXPECT_FALSE(headers.has(Headers::get().EnvoyDownstreamServiceNode)); EXPECT_EQ("foo", headers.get_(Headers::get().UserAgent)); EXPECT_EQ("bar", headers.get_(Headers::get().EnvoyDownstreamServiceCluster)); EXPECT_EQ("true", headers.get_(Headers::get().EnvoyInternalRequest)); @@ -244,7 +256,7 @@ TEST_F(ConnectionManagerUtilityTest, UserAgentSetNoIncomingUserAgent) { user_agent_.value("bar"); TestHeaderMapImpl headers{}; ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_TRUE(headers.has(Headers::get().UserAgent)); EXPECT_EQ("bar", headers.get_(Headers::get().UserAgent)); @@ -258,7 +270,7 @@ TEST_F(ConnectionManagerUtilityTest, RequestIdGeneratedWhenItsNotPresent) { EXPECT_CALL(random_, uuid()).WillOnce(Return("generated_uuid")); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_EQ("generated_uuid", headers.get_("x-request-id")); } @@ -270,7 +282,7 @@ TEST_F(ConnectionManagerUtilityTest, RequestIdGeneratedWhenItsNotPresent) { EXPECT_CALL(random_, uuid()).WillOnce(Return(uuid)); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); // x-request-id should not be set to be traceable as it's not edge request EXPECT_EQ(uuid, headers.get_("x-request-id")); } @@ -285,7 +297,7 @@ TEST_F(ConnectionManagerUtilityTest, DoNotOverrideRequestIdIfPresentWhenInternal EXPECT_CALL(random_, uuid()).Times(0); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_EQ("original_request_id", headers.get_("x-request-id")); } @@ -298,7 +310,7 @@ TEST_F(ConnectionManagerUtilityTest, OverrideRequestIdForExternalRequests) { ON_CALL(config_, useRemoteAddress()).WillByDefault(Return(true)); ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_EQ("override", headers.get_("x-request-id")); } @@ -317,7 +329,7 @@ TEST_F(ConnectionManagerUtilityTest, ExternalAddressExternalRequestUseRemote) { {"x-envoy-expected-rq-timeout-ms", "10"}, {"custom_header", "foo"}}; ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_EQ("50.0.0.1", headers.get_("x-envoy-external-address")); EXPECT_FALSE(headers.has("x-envoy-internal")); EXPECT_FALSE(headers.has("x-envoy-downstream-service-cluster")); @@ -337,7 +349,7 @@ TEST_F(ConnectionManagerUtilityTest, ExternalAddressExternalRequestDontUseRemote TestHeaderMapImpl headers{{"x-envoy-external-address", "60.0.0.1"}, {"x-forwarded-for", "60.0.0.1"}}; ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_EQ("60.0.0.1", headers.get_("x-envoy-external-address")); EXPECT_EQ("60.0.0.1", headers.get_("x-forwarded-for")); EXPECT_FALSE(headers.has("x-envoy-internal")); @@ -351,7 +363,7 @@ TEST_F(ConnectionManagerUtilityTest, ExternalAddressInternalRequestUseRemote) { TestHeaderMapImpl headers{{"x-envoy-external-address", "60.0.0.1"}, {"x-envoy-expected-rq-timeout-ms", "10"}}; ConnectionManagerUtility::mutateRequestHeaders(headers, connection_, config_, route_config_, - random_, runtime_); + random_, runtime_, local_info_); EXPECT_EQ("60.0.0.1", headers.get_("x-envoy-external-address")); EXPECT_EQ("10.0.0.1", headers.get_("x-forwarded-for")); EXPECT_EQ("10", headers.get_("x-envoy-expected-rq-timeout-ms"));