diff --git a/WORKSPACE b/WORKSPACE index cd6966b5355..67f58670866 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -22,10 +22,10 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # 1. Determine SHA256 `wget https://github.com/envoyproxy/envoy/archive/$COMMIT.tar.gz && sha256sum $COMMIT.tar.gz` # 2. Update .bazelversion, envoy.bazelrc and .bazelrc if needed. # -# Commit date: 2026-01-20 -ENVOY_SHA = "9c7136b8f8c559075fb7c76bcc7e0113b356a78a" +# Commit date: 2026-01-27 +ENVOY_SHA = "450b21f19863373396d3c586437d3cb49c88486c" -ENVOY_SHA256 = "d83c1f66ec79a7b9d1ddabe1a36456d2915101c80b597cde0ec02f3fa0d4b49b" +ENVOY_SHA256 = "9365d37689c24c1de63f21c4fa6cae148fcc9e9721b69e72da64d2d5a4c2cae2" ENVOY_ORG = "envoyproxy" diff --git a/envoy.bazelrc b/envoy.bazelrc index 5af2c3c3a66..ab664f185fe 100644 --- a/envoy.bazelrc +++ b/envoy.bazelrc @@ -209,7 +209,6 @@ build:compile-time-options --define=log_debug_assert_in_release=enabled build:compile-time-options --define=path_normalization_by_default=true build:compile-time-options --define=deprecated_features=disabled build:compile-time-options --define=tcmalloc=gperftools -build:compile-time-options --define=zlib=ng build:compile-time-options --define=uhv=enabled # gRPC has a lot of deprecated-enum-enum-conversion warnings with C++20 build:compile-time-options --copt=-Wno-error=deprecated-enum-enum-conversion diff --git a/go.mod b/go.mod index d9c6cc373eb..f211e106beb 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.24.0 require ( github.com/cncf/xds/go v0.0.0-20251110193048-8bfbf64dc13e github.com/envoyproxy/go-control-plane v0.14.1-0.20260103185439-d6ff64e48402 - github.com/envoyproxy/go-control-plane/envoy v1.36.1-0.20260117034604-3a80eae751cf + github.com/envoyproxy/go-control-plane/envoy v1.36.1-0.20260124093652-ddecef433399 github.com/golang/protobuf v1.5.4 github.com/google/go-cmp v0.7.0 github.com/prometheus/client_model v0.6.2 diff --git a/go.sum b/go.sum index f6278bd8c8e..53f55698d1d 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.14.1-0.20260103185439-d6ff64e48402 h1:Jm3kw/Enxm3pcwPwKpjNanZSVq6N/XyA0pkcLI9BVpk= github.com/envoyproxy/go-control-plane v0.14.1-0.20260103185439-d6ff64e48402/go.mod h1:iuP4OVLgz85ISHlL+dS0cf6wg5cCz/KmuySk+g+F3uY= -github.com/envoyproxy/go-control-plane/envoy v1.36.1-0.20260117034604-3a80eae751cf h1:xZp0i/4HHESpsaPxpTy1am8g0JUFjw7JMR58ECOD7Qo= -github.com/envoyproxy/go-control-plane/envoy v1.36.1-0.20260117034604-3a80eae751cf/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A= +github.com/envoyproxy/go-control-plane/envoy v1.36.1-0.20260124093652-ddecef433399 h1:cTrEVtd48YOyrc24AcZHJGAxg8uvaYjqWlq1/QTp++U= +github.com/envoyproxy/go-control-plane/envoy v1.36.1-0.20260124093652-ddecef433399/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= diff --git a/source/extensions/filters/http/peer_metadata/filter.cc b/source/extensions/filters/http/peer_metadata/filter.cc index f511cdf2305..81974201947 100644 --- a/source/extensions/filters/http/peer_metadata/filter.cc +++ b/source/extensions/filters/http/peer_metadata/filter.cc @@ -35,23 +35,38 @@ class XDSMethod : public DiscoveryMethod { public: XDSMethod(bool downstream, Server::Configuration::ServerFactoryContext& factory_context) : downstream_(downstream), - metadata_provider_(Extensions::Common::WorkloadDiscovery::GetProvider(factory_context)) {} + metadata_provider_(Extensions::Common::WorkloadDiscovery::GetProvider(factory_context)), + local_info_(factory_context.localInfo()) {} absl::optional derivePeerInfo(const StreamInfo::StreamInfo&, Http::HeaderMap&, Context&) const override; private: const bool downstream_; Extensions::Common::WorkloadDiscovery::WorkloadMetadataProviderSharedPtr metadata_provider_; + const LocalInfo::LocalInfo& local_info_; }; absl::optional XDSMethod::derivePeerInfo(const StreamInfo::StreamInfo& info, - Http::HeaderMap&, Context&) const { + Http::HeaderMap& headers, Context&) const { if (!metadata_provider_) { return {}; } Network::Address::InstanceConstSharedPtr peer_address; if (downstream_) { - peer_address = info.downstreamAddressProvider().remoteAddress(); + const auto origin_network_header = headers.get(Headers::get().ExchangeMetadataOriginNetwork); + const auto& local_metadata = local_info_.node().metadata(); + const auto& it = local_metadata.fields().find("NETWORK"); + // We might not have a local network configured in the single cluster case, so default to empty. + auto local_network = it != local_metadata.fields().end() ? it->second.string_value() : ""; + if (!origin_network_header.empty() && + origin_network_header[0]->value().getStringView() != local_network) { + ENVOY_LOG_MISC(debug, + "Origin network header present: {}; skipping downstream workload discovery", + origin_network_header[0]->value().getStringView()); + peer_address = {}; + } else { + peer_address = info.downstreamAddressProvider().remoteAddress(); + } } else { if (info.upstreamInfo().has_value()) { auto upstream_host = info.upstreamInfo().value().get().upstreamHost(); @@ -64,6 +79,20 @@ absl::optional XDSMethod::derivePeerInfo(const StreamInfo::StreamInfo& case Network::Address::Type::EnvoyInternal: if (upstream_host->metadata()) { const auto& filter_metadata = upstream_host->metadata()->filter_metadata(); + const auto& istio_it = filter_metadata.find("istio"); + if (istio_it != filter_metadata.end()) { + const auto& double_hbone_it = istio_it->second.fields().find("double_hbone"); + // This is an E/W gateway endpoint, so we should explicitly not use workload discovery + if (double_hbone_it != istio_it->second.fields().end()) { + ENVOY_LOG_MISC( + debug, + "Skipping upstream workload discovery for an endpoint on a remote network"); + peer_address = nullptr; + break; + } + } else { + ENVOY_LOG_MISC(debug, "No istio metadata found on upstream host."); + } const auto& it = filter_metadata.find("envoy.filters.listener.original_dst"); if (it != filter_metadata.end()) { const auto& destination_it = it->second.fields().find("local"); diff --git a/source/extensions/filters/http/peer_metadata/filter.h b/source/extensions/filters/http/peer_metadata/filter.h index 33c470826f4..4a04f76a8d1 100644 --- a/source/extensions/filters/http/peer_metadata/filter.h +++ b/source/extensions/filters/http/peer_metadata/filter.h @@ -34,6 +34,7 @@ struct HeaderValues { const Http::LowerCaseString Baggage{"baggage"}; const Http::LowerCaseString ExchangeMetadataHeader{"x-envoy-peer-metadata"}; const Http::LowerCaseString ExchangeMetadataHeaderId{"x-envoy-peer-metadata-id"}; + const Http::LowerCaseString ExchangeMetadataOriginNetwork{"x-forwarded-network"}; }; using Headers = ConstSingleton; diff --git a/source/extensions/filters/http/peer_metadata/filter_test.cc b/source/extensions/filters/http/peer_metadata/filter_test.cc index fea790e7209..6c0dd8b3b89 100644 --- a/source/extensions/filters/http/peer_metadata/filter_test.cc +++ b/source/extensions/filters/http/peer_metadata/filter_test.cc @@ -151,6 +151,31 @@ TEST_F(PeerMetadataTest, DownstreamXDS) { checkShared(false); } +TEST_F(PeerMetadataTest, DownstreamXDSCrossNetwork) { + request_headers_.setReference(Headers::get().ExchangeMetadataOriginNetwork, "remote-network"); + const WorkloadMetadataObject pod("pod-foo-1234", "my-cluster", "default", "foo", "foo-service", + "v1alpha3", "", "", Istio::Common::WorkloadType::Pod, "", "", + ""); + EXPECT_CALL(*metadata_provider_, GetMetadata(_)) + .WillRepeatedly(Invoke([&](const Network::Address::InstanceConstSharedPtr& address) + -> std::optional { + if (absl::StartsWith(address->asStringView(), "127.0.0.1")) { + return {pod}; + } + return {}; + })); + initialize(R"EOF( + downstream_discovery: + - workload_discovery: {} + )EOF"); + EXPECT_EQ(1, request_headers_.size()); // We don't remove the header because we terminate the + // tunnel that delivered it + EXPECT_EQ(0, response_headers_.size()); + checkNoPeer(true); // No downstream peer because it's a cross-network request + checkNoPeer(false); + checkShared(false); +} + TEST_F(PeerMetadataTest, UpstreamXDS) { const WorkloadMetadataObject pod("pod-foo-1234", "my-cluster", "foo", "foo", "foo-service", "v1alpha3", "", "", Istio::Common::WorkloadType::Pod, "", "", @@ -210,6 +235,46 @@ TEST_F(PeerMetadataTest, UpstreamXDSInternal) { checkPeerNamespace(false, "foo"); } +TEST_F(PeerMetadataTest, UpstreamXDSInternalCrossNetwork) { + Network::Address::InstanceConstSharedPtr upstream_address = + std::make_shared("internal_address", "endpoint_id"); + std::shared_ptr> upstream_host( + new NiceMock()); + EXPECT_CALL(*upstream_host, address()).WillRepeatedly(Return(upstream_address)); + stream_info_.upstreamInfo()->setUpstreamHost(upstream_host); + auto host_metadata = std::make_shared(); + ON_CALL(*upstream_host, metadata()).WillByDefault(testing::Return(host_metadata)); + TestUtility::loadFromYaml(R"EOF( + filter_metadata: + envoy.filters.listener.original_dst: + local: 127.0.0.100:80 + istio: + double_hbone: + hbone_target_address: 10.0.0.1 + )EOF", + *host_metadata); + + const WorkloadMetadataObject pod("pod-foo-1234", "my-cluster", "foo", "foo", "foo-service", + "v1alpha3", "", "", Istio::Common::WorkloadType::Pod, "", "", + ""); + EXPECT_CALL(*metadata_provider_, GetMetadata(_)) + .WillRepeatedly(Invoke([&](const Network::Address::InstanceConstSharedPtr& address) + -> std::optional { + if (absl::StartsWith(address->asStringView(), "127.0.0.100")) { + return {pod}; + } + return {}; + })); + initialize(R"EOF( + upstream_discovery: + - workload_discovery: {} + )EOF"); + EXPECT_EQ(0, request_headers_.size()); + EXPECT_EQ(0, response_headers_.size()); + checkNoPeer(true); + checkNoPeer(false); // Shouldn't be any upstream filter state since it's a cross-network endpoint +} + TEST_F(PeerMetadataTest, DownstreamMXEmpty) { initialize(R"EOF( downstream_discovery: