controlplane: only add listener virtual domains for addresses matching the current TLS domain (#1823)

This commit is contained in:
Caleb Doxsey 2021-01-26 09:01:24 -07:00 committed by GitHub
parent 84e8f6cc05
commit a14b65ec3f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 90 additions and 36 deletions

View file

@ -0,0 +1,23 @@
function envoy_on_request(request_handle)
local headers = request_handle:headers()
local dynamic_meta = request_handle:streamInfo():dynamicMetadata()
local authority = headers:get(":authority")
-- store the authority header in the metadata so we can retrieve it in the response
dynamic_meta:set("envoy.filters.http.lua", "request.authority", authority)
end
function envoy_on_response(response_handle)
local headers = response_handle:headers()
local dynamic_meta = response_handle:streamInfo():dynamicMetadata()
local authority =
dynamic_meta:get("envoy.filters.http.lua")["request.authority"]
-- if we got a 404 (no route found) and the authority header doens't match
-- assume we've coalesced http/2 connections and return a 421
if headers:get(":status") == "404" and authority ~= "%s" then
headers:replace(":status", "421")
end
end

File diff suppressed because one or more lines are too long

View file

@ -2,6 +2,7 @@ package controlplane
import (
"encoding/base64"
"fmt"
"net"
"net/url"
"sort"
@ -66,7 +67,7 @@ func (srv *Server) buildMainListener(cfg *config.Config) *envoy_config_listener_
if cfg.Options.InsecureServer {
filter := buildMainHTTPConnectionManagerFilter(cfg.Options,
getAllRouteableDomains(cfg.Options, cfg.Options.Addr))
getAllRouteableDomains(cfg.Options, cfg.Options.Addr), "")
return &envoy_config_listener_v3.Listener{
Name: "http-ingress",
@ -94,7 +95,7 @@ func (srv *Server) buildMainListener(cfg *config.Config) *envoy_config_listener_
ListenerFilters: listenerFilters,
FilterChains: buildFilterChains(cfg.Options, cfg.Options.Addr,
func(tlsDomain string, httpDomains []string) *envoy_config_listener_v3.FilterChain {
filter := buildMainHTTPConnectionManagerFilter(cfg.Options, httpDomains)
filter := buildMainHTTPConnectionManagerFilter(cfg.Options, httpDomains, tlsDomain)
filterChain := &envoy_config_listener_v3.FilterChain{
Filters: []*envoy_config_listener_v3.Filter{filter},
}
@ -128,14 +129,18 @@ func buildFilterChains(
var chains []*envoy_config_listener_v3.FilterChain
for _, domain := range tlsDomains {
// first we match on SNI
chains = append(chains, callback(domain, allDomains))
chains = append(chains, callback(domain, getRouteableDomainsForTLSDomain(options, addr, domain)))
}
// if there are no SNI matches we match on HTTP host
chains = append(chains, callback("*", allDomains))
return chains
}
func buildMainHTTPConnectionManagerFilter(options *config.Options, domains []string) *envoy_config_listener_v3.Filter {
func buildMainHTTPConnectionManagerFilter(
options *config.Options,
domains []string,
tlsDomain string,
) *envoy_config_listener_v3.Filter {
var virtualHosts []*envoy_config_route_v3.VirtualHost
for _, domain := range domains {
vh := &envoy_config_route_v3.VirtualHost{
@ -203,18 +208,7 @@ func buildMainHTTPConnectionManagerFilter(options *config.Options, domains []str
InlineCode: luascripts.RemoveImpersonateHeaders,
})
var maxStreamDuration *durationpb.Duration
if options.WriteTimeout > 0 {
maxStreamDuration = ptypes.DurationProto(options.WriteTimeout)
}
tc := marshalAny(&envoy_http_connection_manager.HttpConnectionManager{
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
StatPrefix: "ingress",
RouteSpecifier: &envoy_http_connection_manager.HttpConnectionManager_RouteConfig{
RouteConfig: buildRouteConfiguration("main", virtualHosts),
},
HttpFilters: []*envoy_http_connection_manager.HttpFilter{
filters := []*envoy_http_connection_manager.HttpFilter{
{
Name: "envoy.filters.http.lua",
ConfigType: &envoy_http_connection_manager.HttpFilter_TypedConfig{
@ -239,10 +233,34 @@ func buildMainHTTPConnectionManagerFilter(options *config.Options, domains []str
TypedConfig: cleanUpstreamLua,
},
},
{
}
if tlsDomain != "" && tlsDomain != "*" {
fixMisdirectedLua := marshalAny(&envoy_extensions_filters_http_lua_v3.Lua{
InlineCode: fmt.Sprintf(luascripts.FixMisdirected),
})
filters = append(filters, &envoy_http_connection_manager.HttpFilter{
Name: "envoy.filters.http.lua",
ConfigType: &envoy_http_connection_manager.HttpFilter_TypedConfig{
TypedConfig: fixMisdirectedLua,
},
})
}
filters = append(filters, &envoy_http_connection_manager.HttpFilter{
Name: "envoy.filters.http.router",
})
var maxStreamDuration *durationpb.Duration
if options.WriteTimeout > 0 {
maxStreamDuration = ptypes.DurationProto(options.WriteTimeout)
}
tc := marshalAny(&envoy_http_connection_manager.HttpConnectionManager{
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
StatPrefix: "ingress",
RouteSpecifier: &envoy_http_connection_manager.HttpConnectionManager_RouteConfig{
RouteConfig: buildRouteConfiguration("main", virtualHosts),
},
},
HttpFilters: filters,
AccessLog: buildAccessLogs(options),
CommonHttpProtocolOptions: &envoy_config_core_v3.HttpProtocolOptions{
IdleTimeout: ptypes.DurationProto(options.IdleTimeout),
@ -421,6 +439,17 @@ func (srv *Server) buildDownstreamTLSContext(cfg *config.Config, domain string)
}
}
func getRouteableDomainsForTLSDomain(options *config.Options, addr string, tlsDomain string) []string {
allDomains := getAllRouteableDomains(options, addr)
var filtered []string
for _, domain := range allDomains {
if urlutil.StripPort(domain) == tlsDomain {
filtered = append(filtered, domain)
}
}
return filtered
}
func getAllRouteableDomains(options *config.Options, addr string) []string {
lookup := map[string]struct{}{}
if config.IsAuthenticate(options.Services) && addr == options.Addr {

View file

@ -23,7 +23,7 @@ const (
func Test_buildMainHTTPConnectionManagerFilter(t *testing.T) {
options := config.NewDefaultOptions()
options.SkipXffAppend = true
filter := buildMainHTTPConnectionManagerFilter(options, []string{"example.com"})
filter := buildMainHTTPConnectionManagerFilter(options, []string{"example.com"}, "*")
testutil.AssertProtoJSONEqual(t, `{
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {

View file

@ -16,6 +16,7 @@ var luascripts struct {
ExtAuthzSetCookie string
CleanUpstream string
RemoveImpersonateHeaders string
FixMisdirected string
}
func init() {
@ -28,6 +29,7 @@ func init() {
"/clean-upstream.lua": &luascripts.CleanUpstream,
"/ext-authz-set-cookie.lua": &luascripts.ExtAuthzSetCookie,
"/remove-impersonate-headers.lua": &luascripts.RemoveImpersonateHeaders,
"/fix-misdirected.lua": &luascripts.FixMisdirected,
}
err = fs.Walk(hfs, "/", func(p string, fi os.FileInfo, err error) error {