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
35 changes: 32 additions & 3 deletions source/extensions/filters/http/peer_metadata/filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<PeerInfo> 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<PeerInfo> 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();
Expand All @@ -64,6 +79,20 @@ absl::optional<PeerInfo> 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");
Expand Down
1 change: 1 addition & 0 deletions source/extensions/filters/http/peer_metadata/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ using ::Envoy::Extensions::Filters::Common::Expr::CelStateType;
struct HeaderValues {
const Http::LowerCaseString ExchangeMetadataHeader{"x-envoy-peer-metadata"};
const Http::LowerCaseString ExchangeMetadataHeaderId{"x-envoy-peer-metadata-id"};
const Http::LowerCaseString ExchangeMetadataOriginNetwork{"x-istio-origin-network"};
};

using Headers = ConstSingleton<HeaderValues>;
Expand Down
63 changes: 63 additions & 0 deletions source/extensions/filters/http/peer_metadata/filter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,30 @@ 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<WorkloadMetadataObject> {
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, "");
Expand Down Expand Up @@ -210,6 +234,45 @@ TEST_F(PeerMetadataTest, UpstreamXDSInternal) {
checkPeerNamespace(false, "foo");
}

TEST_F(PeerMetadataTest, UpstreamXDSInternalCrossNetwork) {
Network::Address::InstanceConstSharedPtr upstream_address =
std::make_shared<Network::Address::EnvoyInternalInstance>("internal_address", "endpoint_id");
std::shared_ptr<NiceMock<Envoy::Upstream::MockHostDescription>> upstream_host(
new NiceMock<Envoy::Upstream::MockHostDescription>());
EXPECT_CALL(*upstream_host, address()).WillRepeatedly(Return(upstream_address));
stream_info_.upstreamInfo()->setUpstreamHost(upstream_host);
auto host_metadata = std::make_shared<envoy::config::core::v3::Metadata>();
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<WorkloadMetadataObject> {
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:
Expand Down