From cae3e7ceb45607e28ee1318a8240af758e2c3731 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Fri, 22 Sep 2023 19:54:10 +0000 Subject: [PATCH] filter state: add more well-known objects Signed-off-by: Kuat Yessenov --- .../advanced/well_known_filter_state.rst | 14 +++++++++++ source/common/network/BUILD | 3 +++ source/common/network/application_protocol.cc | 15 ++++++++++++ source/common/network/upstream_server_name.cc | 15 ++++++++++++ .../network/upstream_subject_alt_names.cc | 15 ++++++++++++ .../transport_socket_options_impl_test.cc | 24 +++++++++++++++++++ 6 files changed, 86 insertions(+) diff --git a/docs/root/configuration/advanced/well_known_filter_state.rst b/docs/root/configuration/advanced/well_known_filter_state.rst index 6fab1cdcb7d5..909cfc9ea434 100644 --- a/docs/root/configuration/advanced/well_known_filter_state.rst +++ b/docs/root/configuration/advanced/well_known_filter_state.rst @@ -12,6 +12,20 @@ The following list of filter state objects are consumed by Envoy extensions: * - **Filter state key** - **Purpose** + * - ``envoy.network.upstream_server_name`` + - | Sets the transport socket option to override the + | `SNI ` + | in the upstream connections. + | Accepts a host name as a constructor, e.g. "lyft.com". + * - ``envoy.network.application_protocols`` + - | Sets the transport socket option to override the + | `ALPN ` list + | in the upstream connections. This setting takes precedence over the upstream cluster + | configuration. + | Accepts a comma-separated list of protocols as a constructor, e.g. "h2,http/1.1". + * - ``envoy.network.upstream_subject_alt_names`` + | Enables additional verification of the upstream peer certificate SAN names. + | Accepts a comma-separated list of SAN names as a constructor. * - ``envoy.tcp_proxy.cluster`` - | :ref:`TCP proxy ` dynamic cluster name selection | on a per-connection basis. diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 5f2b3cb5cabb..d931245afd09 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -32,6 +32,7 @@ envoy_cc_library( srcs = ["application_protocol.cc"], hdrs = ["application_protocol.h"], deps = [ + "//envoy/registry", "//envoy/stream_info:filter_state_interface", "//source/common/common:macros", ], @@ -520,6 +521,7 @@ envoy_cc_library( srcs = ["upstream_server_name.cc"], hdrs = ["upstream_server_name.h"], deps = [ + "//envoy/registry", "//envoy/stream_info:filter_state_interface", "//source/common/common:macros", ], @@ -530,6 +532,7 @@ envoy_cc_library( srcs = ["upstream_subject_alt_names.cc"], hdrs = ["upstream_subject_alt_names.h"], deps = [ + "//envoy/registry", "//envoy/stream_info:filter_state_interface", "//source/common/common:macros", ], diff --git a/source/common/network/application_protocol.cc b/source/common/network/application_protocol.cc index 6794194ac90d..047c72d3c3fc 100644 --- a/source/common/network/application_protocol.cc +++ b/source/common/network/application_protocol.cc @@ -1,5 +1,8 @@ #include "source/common/network/application_protocol.h" +#include "envoy/registry/registry.h" +#include "envoy/stream_info/filter_state.h" + #include "source/common/common/macros.h" namespace Envoy { @@ -8,5 +11,17 @@ namespace Network { const std::string& ApplicationProtocols::key() { CONSTRUCT_ON_FIRST_USE(std::string, "envoy.network.application_protocols"); } + +class ApplicationProtocolsObjectFactory : public StreamInfo::FilterState::ObjectFactory { +public: + std::string name() const override { return ApplicationProtocols::key(); } + std::unique_ptr + createFromBytes(absl::string_view data) const override { + const std::vector parts = absl::StrSplit(data, ','); + return std::make_unique(parts); + } +}; + +REGISTER_FACTORY(ApplicationProtocolsObjectFactory, StreamInfo::FilterState::ObjectFactory); } // namespace Network } // namespace Envoy diff --git a/source/common/network/upstream_server_name.cc b/source/common/network/upstream_server_name.cc index c6bc2559679e..941d7648e2e2 100644 --- a/source/common/network/upstream_server_name.cc +++ b/source/common/network/upstream_server_name.cc @@ -1,5 +1,8 @@ #include "source/common/network/upstream_server_name.h" +#include "envoy/registry/registry.h" +#include "envoy/stream_info/filter_state.h" + #include "source/common/common/macros.h" namespace Envoy { @@ -8,5 +11,17 @@ namespace Network { const std::string& UpstreamServerName::key() { CONSTRUCT_ON_FIRST_USE(std::string, "envoy.network.upstream_server_name"); } + +class UpstreamServerNameObjectFactory : public StreamInfo::FilterState::ObjectFactory { +public: + std::string name() const override { return UpstreamServerName::key(); } + std::unique_ptr + createFromBytes(absl::string_view data) const override { + return std::make_unique(data); + } +}; + +REGISTER_FACTORY(UpstreamServerNameObjectFactory, StreamInfo::FilterState::ObjectFactory); + } // namespace Network } // namespace Envoy diff --git a/source/common/network/upstream_subject_alt_names.cc b/source/common/network/upstream_subject_alt_names.cc index df8aa9adb184..d4126444d110 100644 --- a/source/common/network/upstream_subject_alt_names.cc +++ b/source/common/network/upstream_subject_alt_names.cc @@ -1,5 +1,8 @@ #include "source/common/network/upstream_subject_alt_names.h" +#include "envoy/registry/registry.h" +#include "envoy/stream_info/filter_state.h" + #include "source/common/common/macros.h" namespace Envoy { @@ -8,5 +11,17 @@ namespace Network { const std::string& UpstreamSubjectAltNames::key() { CONSTRUCT_ON_FIRST_USE(std::string, "envoy.network.upstream_subject_alt_names"); } + +class UpstreamSubjectAltNamesObjectFactory : public StreamInfo::FilterState::ObjectFactory { +public: + std::string name() const override { return UpstreamSubjectAltNames::key(); } + std::unique_ptr + createFromBytes(absl::string_view data) const override { + const std::vector parts = absl::StrSplit(data, ','); + return std::make_unique(parts); + } +}; + +REGISTER_FACTORY(UpstreamSubjectAltNamesObjectFactory, StreamInfo::FilterState::ObjectFactory); } // namespace Network } // namespace Envoy diff --git a/test/common/network/transport_socket_options_impl_test.cc b/test/common/network/transport_socket_options_impl_test.cc index bdf54a5198e8..122ba78f9217 100644 --- a/test/common/network/transport_socket_options_impl_test.cc +++ b/test/common/network/transport_socket_options_impl_test.cc @@ -6,6 +6,7 @@ #include "source/common/network/proxy_protocol_filter_state.h" #include "source/common/network/transport_socket_options_impl.h" #include "source/common/network/upstream_server_name.h" +#include "source/common/network/upstream_subject_alt_names.h" #include "source/common/stream_info/filter_state_impl.h" #include "gtest/gtest.h" @@ -18,6 +19,16 @@ class TransportSocketOptionsImplTest : public testing::Test { public: TransportSocketOptionsImplTest() : filter_state_(StreamInfo::FilterState::LifeSpan::FilterChain) {} + void setFilterStateObject(const std::string& key, const std::string& value) { + auto* factory = + Registry::FactoryRegistry::getFactory(key); + ASSERT_NE(nullptr, factory); + EXPECT_EQ(key, factory->name()); + auto object = factory->createFromBytes(value); + ASSERT_NE(nullptr, object); + filter_state_.setData(key, std::move(object), StreamInfo::FilterState::StateType::ReadOnly, + StreamInfo::FilterState::LifeSpan::FilterChain); + } protected: StreamInfo::FilterStateImpl filter_state_; @@ -128,6 +139,19 @@ TEST_F(TransportSocketOptionsImplTest, FilterStateNonHashable) { EXPECT_EQ(keys.size(), 0); } +TEST_F(TransportSocketOptionsImplTest, DynamicObjects) { + setFilterStateObject(UpstreamServerName::key(), "www.example.com"); + setFilterStateObject(ApplicationProtocols::key(), "h2,http/1.1"); + setFilterStateObject(UpstreamSubjectAltNames::key(), "www.example.com,example.com"); + auto transport_socket_options = TransportSocketOptionsUtility::fromFilterState(filter_state_); + EXPECT_EQ(absl::make_optional("www.example.com"), + transport_socket_options->serverNameOverride()); + std::vector http_alpns{"h2", "http/1.1"}; + EXPECT_EQ(http_alpns, transport_socket_options->applicationProtocolListOverride()); + std::vector sans{"www.example.com", "example.com"}; + EXPECT_EQ(sans, transport_socket_options->verifySubjectAltNameListOverride()); +} + } // namespace } // namespace Network } // namespace Envoy