Skip to content

Commit

Permalink
SNI-based dynamic forward proxy filter (envoyproxy#10448)
Browse files Browse the repository at this point in the history
Signed-off-by: Lizan Zhou <[email protected]>
  • Loading branch information
lizan authored Apr 16, 2020
1 parent e615e99 commit bc4ea0a
Show file tree
Hide file tree
Showing 28 changed files with 797 additions and 40 deletions.
2 changes: 2 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ extensions/filters/common/original_src @snowp @klarose
/*/extensions/transport_sockets/tls @PiotrSikora @lizan
# sni_cluster extension
/*/extensions/filters/network/sni_cluster @rshriram @lizan
# sni_dynamic_forward_proxy extension
/*/extensions/filters/network/sni_dynamic_forward_proxy @rshriram @lizan
# tracers.datadog extension
/*/extensions/tracers/datadog @cgilmour @palazzem @mattklein123
# tracers.xray extension
Expand Down
1 change: 1 addition & 0 deletions api/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ proto_library(
"//envoy/extensions/filters/network/rbac/v3:pkg",
"//envoy/extensions/filters/network/redis_proxy/v3:pkg",
"//envoy/extensions/filters/network/sni_cluster/v3:pkg",
"//envoy/extensions/filters/network/sni_dynamic_forward_proxy/v3alpha:pkg",
"//envoy/extensions/filters/network/tcp_proxy/v3:pkg",
"//envoy/extensions/filters/network/thrift_proxy/filters/ratelimit/v3:pkg",
"//envoy/extensions/filters/network/thrift_proxy/v3:pkg",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# DO NOT EDIT. This file is generated by tools/proto_sync.py.

load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

licenses(["notice"]) # Apache 2

api_proto_package(
deps = [
"//envoy/extensions/common/dynamic_forward_proxy/v3:pkg",
"@com_github_cncf_udpa//udpa/annotations:pkg",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
syntax = "proto3";

package envoy.extensions.filters.network.sni_dynamic_forward_proxy.v3alpha;

import "envoy/extensions/common/dynamic_forward_proxy/v3/dns_cache.proto";

import "udpa/annotations/status.proto";
import "udpa/annotations/versioning.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.filters.network.sni_dynamic_forward_proxy.v3alpha";
option java_outer_classname = "SniDynamicForwardProxyProto";
option java_multiple_files = true;
option (udpa.annotations.file_status).work_in_progress = true;
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: SNI dynamic forward proxy]

// Configuration for the SNI-based dynamic forward proxy filter. See the
// :ref:`architecture overview <arch_overview_http_dynamic_forward_proxy>` for
// more information. Note this filter must be configured along with
// :ref:`TLS inspector listener filter <config_listener_filters_tls_inspector>`
// to work.
// [#extension: envoy.filters.network.sni_dynamic_forward_proxy]
message FilterConfig {
// The DNS cache configuration that the filter will attach to. Note this
// configuration must match that of associated :ref:`dynamic forward proxy
// cluster configuration
// <envoy_api_field_extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig.dns_cache_config>`.
common.dynamic_forward_proxy.v3.DnsCacheConfig dns_cache_config = 1
[(validate.rules).message = {required: true}];

oneof port_specifier {
// The port number to connect to the upstream.
uint32 port_value = 2 [(validate.rules).uint32 = {lte: 65535 gt: 0}];
}
}
1 change: 1 addition & 0 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ proto_library(
"//envoy/extensions/filters/network/rbac/v3:pkg",
"//envoy/extensions/filters/network/redis_proxy/v3:pkg",
"//envoy/extensions/filters/network/sni_cluster/v3:pkg",
"//envoy/extensions/filters/network/sni_dynamic_forward_proxy/v3alpha:pkg",
"//envoy/extensions/filters/network/tcp_proxy/v3:pkg",
"//envoy/extensions/filters/network/thrift_proxy/filters/ratelimit/v3:pkg",
"//envoy/extensions/filters/network/thrift_proxy/v3:pkg",
Expand Down
2 changes: 1 addition & 1 deletion docs/root/api-v3/config/filter/network/network.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ Network filters
:maxdepth: 2

*/empty/*
../../../extensions/filters/network/*/v3/*
../../../extensions/filters/network/*/v3*/*
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ filters.
tcp_proxy_filter
thrift_proxy_filter
sni_cluster_filter
sni_dynamic_forward_proxy_filter
zookeeper_proxy_filter
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
.. _config_network_filters_sni_dynamic_forward_proxy:

SNI dynamic forward proxy
=========================

.. attention::

SNI dynamic forward proxy support should be considered alpha and not production ready.

Through the combination of :ref:`TLS inspector <config_listener_filters_tls_inspector>` listener filter,
this network filter and the
:ref:`dynamic forward proxy cluster <envoy_api_msg_config.cluster.dynamic_forward_proxy.v2alpha.ClusterConfig>`,
Envoy supports SNI based dynamic forward proxy. The implementation works just like the
:ref:`HTTP dynamic forward proxy <arch_overview_http_dynamic_forward_proxy>`, but using the value in
SNI as target host instead.

The following is a complete configuration that configures both this filter
as well as the :ref:`dynamic forward proxy cluster
<envoy_api_msg_config.cluster.dynamic_forward_proxy.v2alpha.ClusterConfig>`. Both filter and cluster
must be configured together and point to the same DNS cache parameters for Envoy to operate as an
SNI dynamic forward proxy.

.. note::

The following config doesn't terminate TLS in listener, so there is no need to configure TLS context
in cluster. The TLS handshake is passed through by Envoy.

.. code-block:: yaml
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address:
protocol: TCP
address: 127.0.0.1
port_value: 9901
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10000
listener_filters:
- name: envoy.filters.listener.tls_inspector
filter_chains:
- filters:
- name: envoy.filters.network.sni_dynamic_forward_proxy
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.sni_dynamic_forward_proxy.v2alpha.FilterConfig
port_value: 443
dns_cache_config:
name: dynamic_forward_proxy_cache_config
dns_lookup_family: V4_ONLY
- name: envoy.tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.tcp_proxy.v2.TcpProxy
stat_prefix: tcp
cluster: dynamic_forward_proxy_cluster
clusters:
- name: dynamic_forward_proxy_cluster
connect_timeout: 1s
lb_policy: CLUSTER_PROVIDED
cluster_type:
name: envoy.clusters.dynamic_forward_proxy
typed_config:
"@type": type.googleapis.com/envoy.config.cluster.dynamic_forward_proxy.v2alpha.ClusterConfig
dns_cache_config:
name: dynamic_forward_proxy_cache_config
dns_lookup_family: V4_ONLY
1 change: 1 addition & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Changes
-------

* access loggers: added GRPC_STATUS operator on logging format.
* dynamic forward proxy: added :ref:`SNI based dynamic forward proxy <config_network_filters_sni_dynamic_forward_proxy>` support.
* fault: added support for controlling the percentage of requests that abort, delay and response rate limits faults
are applied to using :ref:`HTTP headers <config_http_filters_fault_injection_http_header>` to the HTTP fault filter.
* http: fixed a bug where the upgrade header was not cleared on responses to non-upgrade requests.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 13 additions & 3 deletions source/extensions/clusters/dynamic_forward_proxy/cluster.cc
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,22 @@ void Cluster::onDnsHostRemove(const std::string& host) {

Upstream::HostConstSharedPtr
Cluster::LoadBalancer::chooseHost(Upstream::LoadBalancerContext* context) {
if (!context || !context->downstreamHeaders()) {
if (!context) {
return nullptr;
}

const auto host_it =
host_map_->find(context->downstreamHeaders()->Host()->value().getStringView());
absl::string_view host;
if (context->downstreamHeaders()) {
host = context->downstreamHeaders()->Host()->value().getStringView();
} else if (context->downstreamConnection()) {
host = context->downstreamConnection()->requestedServerName();
}

if (host.empty()) {
return nullptr;
}

const auto host_it = host_map_->find(host);
if (host_it == host_map_->end()) {
return nullptr;
} else {
Expand Down
1 change: 1 addition & 0 deletions source/extensions/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ EXTENSIONS = {
"envoy.filters.network.tcp_proxy": "//source/extensions/filters/network/tcp_proxy:config",
"envoy.filters.network.thrift_proxy": "//source/extensions/filters/network/thrift_proxy:config",
"envoy.filters.network.sni_cluster": "//source/extensions/filters/network/sni_cluster:config",
"envoy.filters.network.sni_dynamic_forward_proxy": "//source/extensions/filters/network/sni_dynamic_forward_proxy:config",
"envoy.filters.network.zookeeper_proxy": "//source/extensions/filters/network/zookeeper_proxy:config",

#
Expand Down
40 changes: 40 additions & 0 deletions source/extensions/filters/network/sni_dynamic_forward_proxy/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
licenses(["notice"]) # Apache 2

load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_extension",
"envoy_cc_library",
"envoy_package",
)

envoy_package()

envoy_cc_library(
name = "proxy_filter_lib",
srcs = ["proxy_filter.cc"],
hdrs = ["proxy_filter.h"],
deps = [
"//include/envoy/network:connection_interface",
"//include/envoy/network:filter_interface",
"//source/common/common:assert_lib",
"//source/common/common:minimal_logger_lib",
"//source/common/tcp_proxy",
"//source/extensions/common/dynamic_forward_proxy:dns_cache_interface",
"@envoy_api//envoy/extensions/filters/network/sni_dynamic_forward_proxy/v3alpha:pkg_cc_proto",
],
)

envoy_cc_extension(
name = "config",
srcs = ["config.cc"],
hdrs = ["config.h"],
security_posture = "unknown",
status = "alpha",
deps = [
":proxy_filter_lib",
"//source/extensions/common/dynamic_forward_proxy:dns_cache_manager_impl",
"//source/extensions/filters/network:well_known_names",
"//source/extensions/filters/network/common:factory_base_lib",
"@envoy_api//envoy/extensions/filters/network/sni_dynamic_forward_proxy/v3alpha:pkg_cc_proto",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "extensions/filters/network/sni_dynamic_forward_proxy/config.h"

#include "envoy/registry/registry.h"
#include "envoy/server/filter_config.h"

#include "extensions/common/dynamic_forward_proxy/dns_cache_manager_impl.h"
#include "extensions/filters/network/sni_dynamic_forward_proxy/proxy_filter.h"

namespace Envoy {
namespace Extensions {
namespace NetworkFilters {
namespace SniDynamicForwardProxy {

SniDynamicForwardProxyNetworkFilterConfigFactory::SniDynamicForwardProxyNetworkFilterConfigFactory()
: FactoryBase(NetworkFilterNames::get().SniDynamicForwardProxy) {}

Network::FilterFactoryCb
SniDynamicForwardProxyNetworkFilterConfigFactory::createFilterFactoryFromProtoTyped(
const FilterConfig& proto_config, Server::Configuration::FactoryContext& context) {

Extensions::Common::DynamicForwardProxy::DnsCacheManagerFactoryImpl cache_manager_factory(
context.singletonManager(), context.dispatcher(), context.threadLocal(), context.random(),
context.scope());
ProxyFilterConfigSharedPtr filter_config(std::make_shared<ProxyFilterConfig>(
proto_config, cache_manager_factory, context.clusterManager()));

return [filter_config](Network::FilterManager& filter_manager) -> void {
filter_manager.addReadFilter(std::make_shared<ProxyFilter>(filter_config));
};
}

/**
* Static registration for the sni_dynamic_forward_proxy filter. @see RegisterFactory.
*/
REGISTER_FACTORY(SniDynamicForwardProxyNetworkFilterConfigFactory,
Server::Configuration::NamedNetworkFilterConfigFactory);

} // namespace SniDynamicForwardProxy
} // namespace NetworkFilters
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include "envoy/extensions/filters/network/sni_dynamic_forward_proxy/v3alpha/sni_dynamic_forward_proxy.pb.h"
#include "envoy/extensions/filters/network/sni_dynamic_forward_proxy/v3alpha/sni_dynamic_forward_proxy.pb.validate.h"

#include "extensions/filters/network/common/factory_base.h"
#include "extensions/filters/network/well_known_names.h"

namespace Envoy {
namespace Extensions {
namespace NetworkFilters {
namespace SniDynamicForwardProxy {

using FilterConfig =
envoy::extensions::filters::network::sni_dynamic_forward_proxy::v3alpha::FilterConfig;

/**
* Config registration for the sni_dynamic_forward_proxy filter. @see
* NamedNetworkFilterConfigFactory.
*/
class SniDynamicForwardProxyNetworkFilterConfigFactory : public Common::FactoryBase<FilterConfig> {
public:
SniDynamicForwardProxyNetworkFilterConfigFactory();

private:
Network::FilterFactoryCb
createFilterFactoryFromProtoTyped(const FilterConfig& proto_config,
Server::Configuration::FactoryContext& context) override;
};

} // namespace SniDynamicForwardProxy
} // namespace NetworkFilters
} // namespace Extensions
} // namespace Envoy
Loading

0 comments on commit bc4ea0a

Please sign in to comment.