Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature support connection info in route matching #8453

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b41c9a4
Adding RouteMatcher access to StreamInfo
owlbreeze Sep 30, 2019
15dbd61
Format corrections
owlbreeze Sep 30, 2019
955edea
Add 'expired' and 'presented' credential route matching
owlbreeze Oct 2, 2019
3c9c3e8
Move credential matching to function
owlbreeze Oct 2, 2019
3528df4
Formatting fixups
owlbreeze Oct 2, 2019
878030d
Merged master
owlbreeze Oct 2, 2019
27df1b4
Renamed Credential match to TlsContext match
owlbreeze Oct 9, 2019
9b9cd95
Fixed tests
owlbreeze Oct 9, 2019
013be53
Fixed test build
owlbreeze Oct 9, 2019
5c9138a
Fix format
owlbreeze Oct 9, 2019
dae4bca
Fixed unit-test
owlbreeze Oct 9, 2019
3e263b3
Formatting fixups.
owlbreeze Oct 9, 2019
e83aec4
Fixed unit-test
owlbreeze Oct 9, 2019
a23d508
Fixed unit-tests
owlbreeze Oct 9, 2019
e9a42a5
Fixed format
owlbreeze Oct 9, 2019
a391c38
Fixed format
owlbreeze Oct 9, 2019
7a79963
Change to use has_value & value for optional
owlbreeze Oct 10, 2019
a8a4a99
Fix format
owlbreeze Oct 10, 2019
28d36a3
Fixed copy-paste bug
owlbreeze Oct 11, 2019
91cd14f
Changed vars to snake case, and renamed some files
owlbreeze Oct 13, 2019
e856a49
Removed 'expired' routing to simplify changes to API.
owlbreeze Oct 14, 2019
ac6e312
Removed 'expired' TlsContextMatch'ing from Mock
owlbreeze Oct 15, 2019
01df4ef
Adding Router TlsContextMatcher unit-tests
owlbreeze Oct 16, 2019
cfdc48c
Merge branch 'master' into feature-support-connection-info-in-route-m…
owlbreeze Oct 16, 2019
4c5f55b
Updated router TlsContextMatch unit-test
owlbreeze Oct 16, 2019
aa95768
fix-format
owlbreeze Oct 16, 2019
71cbe83
fix-formating
owlbreeze Oct 16, 2019
d83db11
Removed unnecessary forward decl
owlbreeze Oct 17, 2019
a215c76
Added comment to test case
owlbreeze Oct 17, 2019
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
11 changes: 11 additions & 0 deletions api/envoy/api/v2/route/route.proto
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ message RouteMatch {
message GrpcRouteMatchOptions {
}

message TlsContextMatchOptions {
// If specified, the route will match against whether or not a certificate is presented.
htuch marked this conversation as resolved.
Show resolved Hide resolved
google.protobuf.BoolValue presented = 1;
htuch marked this conversation as resolved.
Show resolved Hide resolved
}

reserved 5;

oneof path_specifier {
Expand Down Expand Up @@ -411,6 +416,12 @@ message RouteMatch {
// that the content-type header has a application/grpc or one of the various
// application/grpc+ values.
GrpcRouteMatchOptions grpc = 8;

// If specified, the client tls context will be matched against the defined
// match options.
jimini-lumox marked this conversation as resolved.
Show resolved Hide resolved
//
// [#next-major-version: unify with RBAC]
TlsContextMatchOptions tls_context = 11;
}

// [#comment:next free field: 11]
Expand Down
11 changes: 11 additions & 0 deletions api/envoy/api/v3alpha/route/route.proto
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,11 @@ message RouteMatch {
message GrpcRouteMatchOptions {
}

message TlsContextMatchOptions {
// If specified, the route will match against whether or not a certificate is presented.
google.protobuf.BoolValue presented = 1;
}

reserved 5, 3;

reserved "regex";
Expand Down Expand Up @@ -397,6 +402,12 @@ message RouteMatch {
// that the content-type header has a application/grpc or one of the various
// application/grpc+ values.
GrpcRouteMatchOptions grpc = 8;

// If specified, the client tls context will be matched against the defined
// match options.
//
// [#next-major-version: unify with RBAC]
TlsContextMatchOptions tls_context = 11;
}

// [#comment:next free field: 11]
Expand Down
16 changes: 16 additions & 0 deletions include/envoy/router/router.h
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,15 @@ class MetadataMatchCriteria {
mergeMatchCriteria(const ProtobufWkt::Struct& metadata_matches) const PURE;
};

class TlsContextMatchCriteria {
public:
virtual ~TlsContextMatchCriteria() = default;

virtual const absl::optional<bool>& presented() const PURE;
};

using TlsContextMatchCriteriaConstPtr = std::unique_ptr<const TlsContextMatchCriteria>;

/**
* Type of path matching that a route entry uses.
*/
Expand Down Expand Up @@ -680,6 +689,12 @@ class RouteEntry : public ResponseEntry {
*/
virtual const envoy::api::v2::core::Metadata& metadata() const PURE;

/**
* @return TlsContextMatchCriteria* the tls context match criterion for this route. If there is no
* tls context match criteria, nullptr is returned.
*/
virtual const TlsContextMatchCriteria* tlsContextMatchCriteria() const PURE;

/**
* @return const PathMatchCriterion& the match criterion for this route.
*/
Expand Down Expand Up @@ -835,6 +850,7 @@ class Config {
* @return the route or nullptr if there is no matching route for the request.
*/
virtual RouteConstSharedPtr route(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const PURE;

/**
Expand Down
6 changes: 5 additions & 1 deletion source/common/http/async_client_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ class AsyncStreamImpl : public AsyncClient::Stream,
};

struct NullConfig : public Router::Config {
Router::RouteConstSharedPtr route(const Http::HeaderMap&, uint64_t) const override {
Router::RouteConstSharedPtr route(const Http::HeaderMap&, const StreamInfo::StreamInfo&,
uint64_t) const override {
return nullptr;
}

Expand Down Expand Up @@ -240,6 +241,9 @@ class AsyncStreamImpl : public AsyncClient::Stream,
const Router::VirtualCluster* virtualCluster(const Http::HeaderMap&) const override {
return nullptr;
}
const Router::TlsContextMatchCriteria* tlsContextMatchCriteria() const override {
return nullptr;
}
const std::multimap<std::string, std::string>& opaqueConfig() const override {
return opaque_config_;
}
Expand Down
2 changes: 1 addition & 1 deletion source/common/http/conn_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1276,7 +1276,7 @@ void ConnectionManagerImpl::ActiveStream::refreshCachedRoute() {
snapScopedRouteConfig();
}
if (snapped_route_config_ != nullptr) {
route = snapped_route_config_->route(*request_headers_, stream_id_);
route = snapped_route_config_->route(*request_headers_, stream_info_, stream_id_);
}
}
stream_info_.route_entry_ = route ? route->routeEntry() : nullptr;
Expand Down
10 changes: 10 additions & 0 deletions source/common/router/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ envoy_cc_library(
],
)

envoy_cc_library(
name = "tls_context_match_criteria_lib",
srcs = ["tls_context_match_criteria_impl.cc"],
hdrs = ["tls_context_match_criteria_impl.h"],
deps = [
"//include/envoy/router:router_interface",
],
)

envoy_cc_library(
name = "config_lib",
srcs = ["config_impl.cc"],
Expand All @@ -29,6 +38,7 @@ envoy_cc_library(
":metadatamatchcriteria_lib",
":retry_state_lib",
":router_ratelimit_lib",
":tls_context_match_criteria_lib",
"//include/envoy/config:typed_metadata_interface",
"//include/envoy/http:header_map_interface",
"//include/envoy/router:router_interface",
Expand Down
44 changes: 38 additions & 6 deletions source/common/router/config_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ RouteEntryImplBase::RouteEntryImplBase(const VirtualHostImpl& vhost,
hash_policy_ = std::make_unique<Http::HashPolicyImpl>(route.route().hash_policy());
}

if (route.match().has_tls_context()) {
tls_context_match_criteria_ =
std::make_unique<TlsContextMatchCriteriaImpl>(route.match().tls_context());
}

// Only set include_vh_rate_limits_ to true if the rate limit policy for the route is empty
// or the route set `include_vh_rate_limits` to true.
include_vh_rate_limits_ =
Expand Down Expand Up @@ -355,7 +360,27 @@ bool RouteEntryImplBase::evaluateRuntimeMatch(const uint64_t random_value) const
random_value);
}

bool RouteEntryImplBase::matchRoute(const Http::HeaderMap& headers, uint64_t random_value) const {
bool RouteEntryImplBase::evaluateTlsContextMatch(const StreamInfo::StreamInfo& stream_info) const {
bool matches = true;

if (!tlsContextMatchCriteria()) {
return matches;
}

const TlsContextMatchCriteria& criteria = *tlsContextMatchCriteria();

if (criteria.presented().has_value()) {
const bool peer_presented = stream_info.downstreamSslConnection() &&
stream_info.downstreamSslConnection()->peerCertificatePresented();
matches &= criteria.presented().value() == peer_presented;
}

return matches;
}

bool RouteEntryImplBase::matchRoute(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const {
bool matches = true;

matches &= evaluateRuntimeMatch(random_value);
Expand All @@ -375,6 +400,8 @@ bool RouteEntryImplBase::matchRoute(const Http::HeaderMap& headers, uint64_t ran
matches &= ConfigUtility::matchQueryParams(query_parameters, config_query_parameters_);
}

matches &= evaluateTlsContextMatch(stream_info);

return matches;
}

Expand Down Expand Up @@ -737,8 +764,9 @@ void PrefixRouteEntryImpl::rewritePathHeader(Http::HeaderMap& headers,
}

RouteConstSharedPtr PrefixRouteEntryImpl::matches(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const {
if (RouteEntryImplBase::matchRoute(headers, random_value) &&
if (RouteEntryImplBase::matchRoute(headers, stream_info, random_value) &&
(case_sensitive_
? absl::StartsWith(headers.Path()->value().getStringView(), prefix_)
: absl::StartsWithIgnoreCase(headers.Path()->value().getStringView(), prefix_))) {
Expand All @@ -758,8 +786,9 @@ void PathRouteEntryImpl::rewritePathHeader(Http::HeaderMap& headers,
}

RouteConstSharedPtr PathRouteEntryImpl::matches(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const {
if (RouteEntryImplBase::matchRoute(headers, random_value)) {
if (RouteEntryImplBase::matchRoute(headers, stream_info, random_value)) {
const Http::HeaderString& path = headers.Path()->value();
absl::string_view query_string = Http::Utility::findQueryStringStart(path);
size_t compare_length = path.size();
Expand Down Expand Up @@ -816,8 +845,9 @@ void RegexRouteEntryImpl::rewritePathHeader(Http::HeaderMap& headers,
}

RouteConstSharedPtr RegexRouteEntryImpl::matches(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const {
if (RouteEntryImplBase::matchRoute(headers, random_value)) {
if (RouteEntryImplBase::matchRoute(headers, stream_info, random_value)) {
if (regex_->match(pathOnly(headers))) {
return clusterEntry(headers, random_value);
}
Expand Down Expand Up @@ -991,6 +1021,7 @@ RouteMatcher::RouteMatcher(const envoy::api::v2::RouteConfiguration& route_confi
}

RouteConstSharedPtr VirtualHostImpl::getRouteFromEntries(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const {
// No x-forwarded-proto header. This normally only happens when ActiveStream::decodeHeaders
// bails early (as it rejects a request), so there is no routing is going to happen anyway.
Expand All @@ -1009,7 +1040,7 @@ RouteConstSharedPtr VirtualHostImpl::getRouteFromEntries(const Http::HeaderMap&

// Check for a route that matches the request.
for (const RouteEntryImplBaseConstSharedPtr& route : routes_) {
RouteConstSharedPtr route_entry = route->matches(headers, random_value);
RouteConstSharedPtr route_entry = route->matches(headers, stream_info, random_value);
if (nullptr != route_entry) {
return route_entry;
}
Expand Down Expand Up @@ -1053,10 +1084,11 @@ const VirtualHostImpl* RouteMatcher::findVirtualHost(const Http::HeaderMap& head
}

RouteConstSharedPtr RouteMatcher::route(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const {
const VirtualHostImpl* virtual_host = findVirtualHost(headers);
if (virtual_host) {
return virtual_host->getRouteFromEntries(headers, random_value);
return virtual_host->getRouteFromEntries(headers, stream_info, random_value);
} else {
return nullptr;
}
Expand Down
41 changes: 33 additions & 8 deletions source/common/router/config_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "common/router/header_parser.h"
#include "common/router/metadatamatchcriteria_impl.h"
#include "common/router/router_ratelimit.h"
#include "common/router/tls_context_match_criteria_impl.h"
#include "common/stats/symbol_table_impl.h"

#include "absl/types/optional.h"
Expand All @@ -47,6 +48,7 @@ class Matchable {
* @return true if input headers match this object.
*/
virtual RouteConstSharedPtr matches(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const PURE;
};

Expand Down Expand Up @@ -153,6 +155,7 @@ class VirtualHostImpl : public VirtualHost {
Server::Configuration::FactoryContext& factory_context, bool validate_clusters);

RouteConstSharedPtr getRouteFromEntries(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const;
const VirtualCluster* virtualClusterFromEntries(const Http::HeaderMap& headers) const;
const ConfigImpl& globalRouteConfig() const { return global_route_config_; }
Expand Down Expand Up @@ -374,7 +377,8 @@ class RouteEntryImplBase : public RouteEntry,
return !host_redirect_.empty() || !path_redirect_.empty() || !prefix_rewrite_redirect_.empty();
}

bool matchRoute(const Http::HeaderMap& headers, uint64_t random_value) const;
bool matchRoute(const Http::HeaderMap& headers, const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const;
void validateClusters(Upstream::ClusterManager& cm) const;

// Router::RouteEntry
Expand All @@ -395,6 +399,9 @@ class RouteEntryImplBase : public RouteEntry,
const MetadataMatchCriteria* metadataMatchCriteria() const override {
return metadata_match_criteria_.get();
}
const TlsContextMatchCriteria* tlsContextMatchCriteria() const override {
return tls_context_match_criteria_.get();
}
Upstream::ResourcePriority priority() const override { return priority_; }
const RateLimitPolicy& rateLimitPolicy() const override { return rate_limit_policy_; }
const RetryPolicy& retryPolicy() const override { return retry_policy_; }
Expand Down Expand Up @@ -505,6 +512,9 @@ class RouteEntryImplBase : public RouteEntry,
const MetadataMatchCriteria* metadataMatchCriteria() const override {
return parent_->metadataMatchCriteria();
}
const TlsContextMatchCriteria* tlsContextMatchCriteria() const override {
return parent_->tlsContextMatchCriteria();
}

const VirtualCluster* virtualCluster(const Http::HeaderMap& headers) const override {
return parent_->virtualCluster(headers);
Expand Down Expand Up @@ -607,6 +617,8 @@ class RouteEntryImplBase : public RouteEntry,

bool evaluateRuntimeMatch(const uint64_t random_value) const;

bool evaluateTlsContextMatch(const StreamInfo::StreamInfo& stream_info) const;

HedgePolicyImpl
buildHedgePolicy(const absl::optional<envoy::api::v2::route::HedgePolicy>& vhost_hedge_policy,
const envoy::api::v2::route::RouteAction& route_config) const;
Expand Down Expand Up @@ -653,6 +665,7 @@ class RouteEntryImplBase : public RouteEntry,
const uint64_t total_cluster_weight_;
std::unique_ptr<const Http::HashPolicyImpl> hash_policy_;
MetadataMatchCriteriaConstPtr metadata_match_criteria_;
TlsContextMatchCriteriaConstPtr tls_context_match_criteria_;
HeaderParserPtr request_headers_parser_;
HeaderParserPtr response_headers_parser_;
envoy::api::v2::core::Metadata metadata_;
Expand Down Expand Up @@ -685,7 +698,9 @@ class PrefixRouteEntryImpl : public RouteEntryImplBase {
PathMatchType matchType() const override { return PathMatchType::Prefix; }

// Router::Matchable
RouteConstSharedPtr matches(const Http::HeaderMap& headers, uint64_t random_value) const override;
RouteConstSharedPtr matches(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const override;

// Router::DirectResponseEntry
void rewritePathHeader(Http::HeaderMap& headers, bool insert_envoy_original_path) const override;
Expand All @@ -707,7 +722,9 @@ class PathRouteEntryImpl : public RouteEntryImplBase {
PathMatchType matchType() const override { return PathMatchType::Exact; }

// Router::Matchable
RouteConstSharedPtr matches(const Http::HeaderMap& headers, uint64_t random_value) const override;
RouteConstSharedPtr matches(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const override;

// Router::DirectResponseEntry
void rewritePathHeader(Http::HeaderMap& headers, bool insert_envoy_original_path) const override;
Expand All @@ -729,7 +746,9 @@ class RegexRouteEntryImpl : public RouteEntryImplBase {
PathMatchType matchType() const override { return PathMatchType::Regex; }

// Router::Matchable
RouteConstSharedPtr matches(const Http::HeaderMap& headers, uint64_t random_value) const override;
RouteConstSharedPtr matches(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const override;

// Router::DirectResponseEntry
void rewritePathHeader(Http::HeaderMap& headers, bool insert_envoy_original_path) const override;
Expand All @@ -751,7 +770,8 @@ class RouteMatcher {
const ConfigImpl& global_http_config,
Server::Configuration::FactoryContext& factory_context, bool validate_clusters);

RouteConstSharedPtr route(const Http::HeaderMap& headers, uint64_t random_value) const;
RouteConstSharedPtr route(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info, uint64_t random_value) const;

private:
const VirtualHostImpl* findVirtualHost(const Http::HeaderMap& headers) const;
Expand Down Expand Up @@ -792,8 +812,10 @@ class ConfigImpl : public Config {
const HeaderParser& responseHeaderParser() const { return *response_headers_parser_; };

// Router::Config
RouteConstSharedPtr route(const Http::HeaderMap& headers, uint64_t random_value) const override {
return route_matcher_->route(headers, random_value);
RouteConstSharedPtr route(const Http::HeaderMap& headers,
const StreamInfo::StreamInfo& stream_info,
uint64_t random_value) const override {
return route_matcher_->route(headers, stream_info, random_value);
}

const std::list<Http::LowerCaseString>& internalOnlyHeaders() const override {
Expand Down Expand Up @@ -825,7 +847,10 @@ class ConfigImpl : public Config {
class NullConfigImpl : public Config {
public:
// Router::Config
RouteConstSharedPtr route(const Http::HeaderMap&, uint64_t) const override { return nullptr; }
RouteConstSharedPtr route(const Http::HeaderMap&, const StreamInfo::StreamInfo&,
uint64_t) const override {
return nullptr;
}

const std::list<Http::LowerCaseString>& internalOnlyHeaders() const override {
return internal_only_headers_;
Expand Down
Loading