Update filter chain creation for sidecar/ingress listeners (#11245)
The duo of `makeUpstreamFilterChainForDiscoveryChain` and `makeListenerForDiscoveryChain` were really hard to reason about, and led to concealing a bug in their branching logic. There were several issues here: - They tried to accomplish too much: determining filter name, cluster name, and whether RDS should be used. - They embedded logic to handle significantly different kinds of upstream listeners (passthrough, prepared query, typical services, and catch-all) - They needed to coalesce different data sources (Upstream and CompiledDiscoveryChain) Rather than handling all of those tasks inside of these functions, this PR pulls out the RDS/clusterName/filterName logic. This refactor also fixed a bug with the handling of [UpstreamDefaults](https://www.consul.io/docs/connect/config-entries/service-defaults#defaults). These defaults get stored as UpstreamConfig in the proxy snapshot with a DestinationName of "*", since they apply to all upstreams. However, this wildcard destination name must not be used when creating the name of the associated upstream cluster. The coalescing logic in the original functions here was in some situations creating clusters with a `*.` prefix, which is not a valid destination.
This commit is contained in:
parent
ab55e230bd
commit
eb2b40b22d
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:bug
|
||||||
|
connect: fix issue with attempting to generate an invalid upstream cluster from UpstreamConfig.Defaults.
|
||||||
|
```
|
|
@ -114,11 +114,12 @@ func copyProxyConfig(ns *structs.NodeService) (structs.ConnectProxyConfig, error
|
||||||
for idx := range proxyCfg.Upstreams {
|
for idx := range proxyCfg.Upstreams {
|
||||||
us := &proxyCfg.Upstreams[idx]
|
us := &proxyCfg.Upstreams[idx]
|
||||||
if us.DestinationType != structs.UpstreamDestTypePreparedQuery && us.DestinationNamespace == "" {
|
if us.DestinationType != structs.UpstreamDestTypePreparedQuery && us.DestinationNamespace == "" {
|
||||||
// default the upstreams target namespace to the namespace of the proxy
|
// default the upstreams target namespace and partition to those of the proxy
|
||||||
// doing this here prevents needing much more complex logic a bunch of other
|
// doing this here prevents needing much more complex logic a bunch of other
|
||||||
// places and makes tracking these upstreams simpler as we can dedup them
|
// places and makes tracking these upstreams simpler as we can dedup them
|
||||||
// with the maps tracking upstream ids being watched.
|
// with the maps tracking upstream ids being watched.
|
||||||
proxyCfg.Upstreams[idx].DestinationNamespace = ns.EnterpriseMeta.NamespaceOrDefault()
|
proxyCfg.Upstreams[idx].DestinationNamespace = ns.EnterpriseMeta.NamespaceOrDefault()
|
||||||
|
proxyCfg.Upstreams[idx].DestinationPartition = ns.EnterpriseMeta.PartitionOrDefault()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1686,6 +1686,7 @@ func TestState_WatchesAndUpdates(t *testing.T) {
|
||||||
db.String(): {
|
db.String(): {
|
||||||
DestinationName: "db",
|
DestinationName: "db",
|
||||||
DestinationNamespace: structs.IntentionDefaultNamespace,
|
DestinationNamespace: structs.IntentionDefaultNamespace,
|
||||||
|
DestinationPartition: structs.IntentionDefaultNamespace,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
require.Equal(t, expectUpstreams, snap.ConnectProxy.UpstreamConfig)
|
require.Equal(t, expectUpstreams, snap.ConnectProxy.UpstreamConfig)
|
||||||
|
|
|
@ -107,17 +107,31 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RDS, Envoy's Route Discovery Service, is only used for HTTP services with a customized discovery chain.
|
||||||
|
useRDS := chain.Protocol != "tcp" && !chain.IsDefault()
|
||||||
|
|
||||||
|
var clusterName string
|
||||||
|
if !useRDS {
|
||||||
|
// When not using RDS we must generate a cluster name to attach to the filter chain.
|
||||||
|
// With RDS, cluster names get attached to the dynamic routes instead.
|
||||||
|
target, err := simpleChainTarget(chain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clusterName = CustomizeClusterName(target.Name, chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
filterName := fmt.Sprintf("%s.%s.%s.%s", chain.ServiceName, chain.Namespace, chain.Partition, chain.Datacenter)
|
||||||
|
|
||||||
// Generate the upstream listeners for when they are explicitly set with a local bind port or socket path
|
// Generate the upstream listeners for when they are explicitly set with a local bind port or socket path
|
||||||
if outboundListener == nil || (upstreamCfg != nil && upstreamCfg.HasLocalPortOrSocket()) {
|
if upstreamCfg != nil && upstreamCfg.HasLocalPortOrSocket() {
|
||||||
filterChain, err := s.makeUpstreamFilterChainForDiscoveryChain(
|
filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{
|
||||||
id,
|
routeName: id,
|
||||||
"",
|
clusterName: clusterName,
|
||||||
cfg.Protocol,
|
filterName: filterName,
|
||||||
upstreamCfg,
|
protocol: cfg.Protocol,
|
||||||
chain,
|
useRDS: useRDS,
|
||||||
cfgSnap,
|
})
|
||||||
nil,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -135,15 +149,14 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg.
|
||||||
// The rest of this loop is used exclusively for transparent proxies.
|
// The rest of this loop is used exclusively for transparent proxies.
|
||||||
// Below we create a filter chain per upstream, rather than a listener per upstream
|
// Below we create a filter chain per upstream, rather than a listener per upstream
|
||||||
// as we do for explicit upstreams above.
|
// as we do for explicit upstreams above.
|
||||||
filterChain, err := s.makeUpstreamFilterChainForDiscoveryChain(
|
|
||||||
id,
|
filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{
|
||||||
"",
|
routeName: id,
|
||||||
cfg.Protocol,
|
clusterName: clusterName,
|
||||||
upstreamCfg,
|
filterName: filterName,
|
||||||
chain,
|
protocol: cfg.Protocol,
|
||||||
cfgSnap,
|
useRDS: useRDS,
|
||||||
nil,
|
})
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -188,17 +201,13 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg.
|
||||||
DestinationPartition: sn.PartitionOrDefault(),
|
DestinationPartition: sn.PartitionOrDefault(),
|
||||||
}
|
}
|
||||||
|
|
||||||
filterChain, err := s.makeUpstreamFilterChainForDiscoveryChain(
|
filterName := fmt.Sprintf("%s.%s.%s.%s", u.DestinationName, u.DestinationNamespace, u.DestinationPartition, cfgSnap.Datacenter)
|
||||||
"",
|
|
||||||
"passthrough~"+passthrough.SNI,
|
|
||||||
|
|
||||||
// TODO(tproxy) This should use the protocol configured on the upstream's config entry
|
filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{
|
||||||
"tcp",
|
clusterName: "passthrough~" + passthrough.SNI,
|
||||||
&u,
|
filterName: filterName,
|
||||||
nil,
|
protocol: "tcp",
|
||||||
cfgSnap,
|
})
|
||||||
nil,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -219,15 +228,11 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg.
|
||||||
if cfgSnap.ConnectProxy.MeshConfig == nil ||
|
if cfgSnap.ConnectProxy.MeshConfig == nil ||
|
||||||
!cfgSnap.ConnectProxy.MeshConfig.TransparentProxy.MeshDestinationsOnly {
|
!cfgSnap.ConnectProxy.MeshConfig.TransparentProxy.MeshDestinationsOnly {
|
||||||
|
|
||||||
filterChain, err := s.makeUpstreamFilterChainForDiscoveryChain(
|
filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{
|
||||||
"",
|
clusterName: OriginalDestinationClusterName,
|
||||||
OriginalDestinationClusterName,
|
filterName: OriginalDestinationClusterName,
|
||||||
"tcp",
|
protocol: "tcp",
|
||||||
nil,
|
})
|
||||||
nil,
|
|
||||||
cfgSnap,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -268,15 +273,13 @@ func (s *ResourceGenerator) listenersFromSnapshotConnectProxy(cfgSnap *proxycfg.
|
||||||
|
|
||||||
upstreamListener := makeListener(id, u, envoy_core_v3.TrafficDirection_OUTBOUND)
|
upstreamListener := makeListener(id, u, envoy_core_v3.TrafficDirection_OUTBOUND)
|
||||||
|
|
||||||
filterChain, err := s.makeUpstreamFilterChainForDiscoveryChain(
|
filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{
|
||||||
id,
|
// TODO (SNI partition) add partition for upstream SNI
|
||||||
"",
|
clusterName: connect.UpstreamSNI(u, "", cfgSnap.Datacenter, cfgSnap.Roots.TrustDomain),
|
||||||
cfg.Protocol,
|
filterName: id,
|
||||||
u,
|
routeName: id,
|
||||||
nil,
|
protocol: cfg.Protocol,
|
||||||
cfgSnap,
|
})
|
||||||
nil,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1212,112 +1215,32 @@ func (s *ResourceGenerator) makeMeshGatewayListener(name, addr string, port int,
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ResourceGenerator) makeUpstreamFilterChainForDiscoveryChain(
|
type filterChainOpts struct {
|
||||||
id string,
|
routeName string
|
||||||
overrideCluster string,
|
|
||||||
protocol string,
|
|
||||||
u *structs.Upstream,
|
|
||||||
chain *structs.CompiledDiscoveryChain,
|
|
||||||
cfgSnap *proxycfg.ConfigSnapshot,
|
|
||||||
tlsContext *envoy_tls_v3.DownstreamTlsContext,
|
|
||||||
) (*envoy_listener_v3.FilterChain, error) {
|
|
||||||
// TODO (freddy) Make this actually legible
|
|
||||||
useRDS := true
|
|
||||||
|
|
||||||
var (
|
|
||||||
clusterName string
|
clusterName string
|
||||||
destination, datacenter, partition, namespace string
|
filterName string
|
||||||
)
|
protocol string
|
||||||
|
useRDS bool
|
||||||
|
tlsContext *envoy_tls_v3.DownstreamTlsContext
|
||||||
|
}
|
||||||
|
|
||||||
// TODO (SNI partition) add partition for SNI
|
func (s *ResourceGenerator) makeUpstreamFilterChain(opts filterChainOpts) (*envoy_listener_v3.FilterChain, error) {
|
||||||
if chain != nil {
|
filter, err := makeListenerFilter(listenerFilterOpts{
|
||||||
destination, datacenter, partition, namespace = chain.ServiceName, chain.Datacenter, chain.Partition, chain.Namespace
|
useRDS: opts.useRDS,
|
||||||
}
|
protocol: opts.protocol,
|
||||||
if (chain == nil || chain.IsDefault()) && u != nil {
|
filterName: opts.filterName,
|
||||||
useRDS = false
|
routeName: opts.routeName,
|
||||||
|
cluster: opts.clusterName,
|
||||||
if datacenter == "" {
|
|
||||||
datacenter = u.Datacenter
|
|
||||||
}
|
|
||||||
if datacenter == "" {
|
|
||||||
datacenter = cfgSnap.Datacenter
|
|
||||||
}
|
|
||||||
if destination == "" {
|
|
||||||
destination = u.DestinationName
|
|
||||||
}
|
|
||||||
if partition == "" {
|
|
||||||
partition = u.DestinationPartition
|
|
||||||
}
|
|
||||||
if namespace == "" {
|
|
||||||
namespace = u.DestinationNamespace
|
|
||||||
}
|
|
||||||
|
|
||||||
sni := connect.UpstreamSNI(u, "", datacenter, cfgSnap.Roots.TrustDomain)
|
|
||||||
clusterName = CustomizeClusterName(sni, chain)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if protocol == "tcp" && chain != nil {
|
|
||||||
useRDS = false
|
|
||||||
|
|
||||||
startNode := chain.Nodes[chain.StartNode]
|
|
||||||
if startNode == nil {
|
|
||||||
return nil, fmt.Errorf("missing first node in compiled discovery chain for: %s", chain.ServiceName)
|
|
||||||
}
|
|
||||||
if startNode.Type != structs.DiscoveryGraphNodeTypeResolver {
|
|
||||||
return nil, fmt.Errorf("unexpected first node in discovery chain using protocol=%q: %s", protocol, startNode.Type)
|
|
||||||
}
|
|
||||||
targetID := startNode.Resolver.Target
|
|
||||||
target := chain.Targets[targetID]
|
|
||||||
|
|
||||||
clusterName = CustomizeClusterName(target.Name, chain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default the namespace to match how SNIs are generated
|
|
||||||
if namespace == "" {
|
|
||||||
namespace = structs.IntentionDefaultNamespace
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default the partition to match how SNIs are generated
|
|
||||||
if partition == "" {
|
|
||||||
partition = structs.IntentionDefaultNamespace
|
|
||||||
}
|
|
||||||
|
|
||||||
filterName := fmt.Sprintf("%s.%s.%s.%s", destination, namespace, partition, datacenter)
|
|
||||||
if u != nil && u.DestinationType == structs.UpstreamDestTypePreparedQuery {
|
|
||||||
// Avoid encoding dc and namespace for prepared queries.
|
|
||||||
// Those are defined in the query itself and are not available here.
|
|
||||||
filterName = id
|
|
||||||
}
|
|
||||||
if overrideCluster != "" {
|
|
||||||
useRDS = false
|
|
||||||
clusterName = overrideCluster
|
|
||||||
|
|
||||||
if destination == "" {
|
|
||||||
filterName = overrideCluster
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := listenerFilterOpts{
|
|
||||||
useRDS: useRDS,
|
|
||||||
protocol: protocol,
|
|
||||||
filterName: filterName,
|
|
||||||
routeName: id,
|
|
||||||
cluster: clusterName,
|
|
||||||
statPrefix: "upstream.",
|
statPrefix: "upstream.",
|
||||||
routePath: "",
|
})
|
||||||
ingressGateway: false,
|
|
||||||
httpAuthzFilter: nil,
|
|
||||||
}
|
|
||||||
filter, err := makeListenerFilter(opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
transportSocket, err := makeDownstreamTLSTransportSocket(tlsContext)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transportSocket, err := makeDownstreamTLSTransportSocket(opts.tlsContext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return &envoy_listener_v3.FilterChain{
|
return &envoy_listener_v3.FilterChain{
|
||||||
Filters: []*envoy_listener_v3.Filter{
|
Filters: []*envoy_listener_v3.Filter{
|
||||||
filter,
|
filter,
|
||||||
|
@ -1326,111 +1249,19 @@ func (s *ResourceGenerator) makeUpstreamFilterChainForDiscoveryChain(
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(freddy) Replace in favor of new function above. Currently in use for ingress gateways.
|
// simpleChainTarget returns the discovery target for a chain with a single node.
|
||||||
func (s *ResourceGenerator) makeUpstreamListenerForDiscoveryChain(
|
// A chain can have a single target if it is for a TCP service or an HTTP service without
|
||||||
u *structs.Upstream,
|
// multiple splits/routes/failovers.
|
||||||
address string,
|
func simpleChainTarget(chain *structs.CompiledDiscoveryChain) (*structs.DiscoveryTarget, error) {
|
||||||
chain *structs.CompiledDiscoveryChain,
|
|
||||||
cfgSnap *proxycfg.ConfigSnapshot,
|
|
||||||
tlsContext *envoy_tls_v3.DownstreamTlsContext,
|
|
||||||
) (proto.Message, error) {
|
|
||||||
|
|
||||||
// Best understanding is this only makes sense for port listeners....
|
|
||||||
if u.LocalBindSocketPath != "" {
|
|
||||||
return nil, fmt.Errorf("makeUpstreamListenerForDiscoveryChain not supported for unix domain sockets %s %+v",
|
|
||||||
address, u)
|
|
||||||
}
|
|
||||||
|
|
||||||
upstreamID := u.Identifier()
|
|
||||||
l := makePortListenerWithDefault(upstreamID, address, u.LocalBindPort, envoy_core_v3.TrafficDirection_OUTBOUND)
|
|
||||||
cfg := s.getAndModifyUpstreamConfigForListener(upstreamID, u, chain)
|
|
||||||
if cfg.EnvoyListenerJSON != "" {
|
|
||||||
return makeListenerFromUserConfig(cfg.EnvoyListenerJSON)
|
|
||||||
}
|
|
||||||
|
|
||||||
useRDS := true
|
|
||||||
var (
|
|
||||||
clusterName string
|
|
||||||
destination, datacenter, partition, namespace string
|
|
||||||
)
|
|
||||||
if chain == nil || chain.IsDefault() {
|
|
||||||
useRDS = false
|
|
||||||
|
|
||||||
dc := u.Datacenter
|
|
||||||
if dc == "" {
|
|
||||||
dc = cfgSnap.Datacenter
|
|
||||||
}
|
|
||||||
destination, datacenter, partition, namespace = u.DestinationName, dc, u.DestinationPartition, u.DestinationNamespace
|
|
||||||
|
|
||||||
sni := connect.UpstreamSNI(u, "", dc, cfgSnap.Roots.TrustDomain)
|
|
||||||
clusterName = CustomizeClusterName(sni, chain)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
destination, datacenter, partition, namespace = chain.ServiceName, chain.Datacenter, chain.Partition, chain.Namespace
|
|
||||||
|
|
||||||
if cfg.Protocol == "tcp" {
|
|
||||||
useRDS = false
|
|
||||||
|
|
||||||
startNode := chain.Nodes[chain.StartNode]
|
startNode := chain.Nodes[chain.StartNode]
|
||||||
if startNode == nil {
|
if startNode == nil {
|
||||||
return nil, fmt.Errorf("missing first node in compiled discovery chain for: %s", chain.ServiceName)
|
return nil, fmt.Errorf("missing first node in compiled discovery chain for: %s", chain.ServiceName)
|
||||||
}
|
}
|
||||||
if startNode.Type != structs.DiscoveryGraphNodeTypeResolver {
|
if startNode.Type != structs.DiscoveryGraphNodeTypeResolver {
|
||||||
return nil, fmt.Errorf("unexpected first node in discovery chain using protocol=%q: %s", cfg.Protocol, startNode.Type)
|
return nil, fmt.Errorf("expected discovery chain with single node, found unexpected start node: %s", startNode.Type)
|
||||||
}
|
}
|
||||||
targetID := startNode.Resolver.Target
|
targetID := startNode.Resolver.Target
|
||||||
target := chain.Targets[targetID]
|
return chain.Targets[targetID], nil
|
||||||
|
|
||||||
clusterName = CustomizeClusterName(target.Name, chain)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default the namespace to match how SNIs are generated
|
|
||||||
if namespace == "" {
|
|
||||||
namespace = structs.IntentionDefaultNamespace
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default the partition to match how SNIs are generated
|
|
||||||
if partition == "" {
|
|
||||||
partition = structs.IntentionDefaultNamespace
|
|
||||||
}
|
|
||||||
filterName := fmt.Sprintf("%s.%s.%s.%s", destination, namespace, partition, datacenter)
|
|
||||||
|
|
||||||
if u.DestinationType == structs.UpstreamDestTypePreparedQuery {
|
|
||||||
// Avoid encoding dc and namespace for prepared queries.
|
|
||||||
// Those are defined in the query itself and are not available here.
|
|
||||||
filterName = upstreamID
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := listenerFilterOpts{
|
|
||||||
useRDS: useRDS,
|
|
||||||
protocol: cfg.Protocol,
|
|
||||||
filterName: filterName,
|
|
||||||
routeName: upstreamID,
|
|
||||||
cluster: clusterName,
|
|
||||||
statPrefix: "upstream.",
|
|
||||||
routePath: "",
|
|
||||||
httpAuthzFilter: nil,
|
|
||||||
}
|
|
||||||
filter, err := makeListenerFilter(opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
transportSocket, err := makeDownstreamTLSTransportSocket(tlsContext)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
l.FilterChains = []*envoy_listener_v3.FilterChain{
|
|
||||||
{
|
|
||||||
Filters: []*envoy_listener_v3.Filter{
|
|
||||||
filter,
|
|
||||||
},
|
|
||||||
TransportSocket: transportSocket,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return l, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ResourceGenerator) getAndModifyUpstreamConfigForListener(id string, u *structs.Upstream, chain *structs.CompiledDiscoveryChain) structs.UpstreamConfig {
|
func (s *ResourceGenerator) getAndModifyUpstreamConfigForListener(id string, u *structs.Upstream, chain *structs.CompiledDiscoveryChain) structs.UpstreamConfig {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package xds
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
envoy_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
envoy_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||||
envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||||
envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
|
||||||
|
@ -54,19 +53,47 @@ func (s *ResourceGenerator) makeIngressGatewayListeners(address string, cfgSnap
|
||||||
id := u.Identifier()
|
id := u.Identifier()
|
||||||
|
|
||||||
chain := cfgSnap.IngressGateway.DiscoveryChain[id]
|
chain := cfgSnap.IngressGateway.DiscoveryChain[id]
|
||||||
|
if chain == nil {
|
||||||
|
// Wait until a chain is present in the snapshot.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
var upstreamListener proto.Message
|
cfg := s.getAndModifyUpstreamConfigForListener(id, &u, chain)
|
||||||
upstreamListener, err := s.makeUpstreamListenerForDiscoveryChain(
|
|
||||||
&u,
|
// RDS, Envoy's Route Discovery Service, is only used for HTTP services with a customized discovery chain.
|
||||||
address,
|
// TODO(freddy): Why can the protocol of the listener be overridden here?
|
||||||
chain,
|
useRDS := cfg.Protocol != "tcp" && !chain.IsDefault()
|
||||||
cfgSnap,
|
|
||||||
tlsContext,
|
var clusterName string
|
||||||
)
|
if !useRDS {
|
||||||
|
// When not using RDS we must generate a cluster name to attach to the filter chain.
|
||||||
|
// With RDS, cluster names get attached to the dynamic routes instead.
|
||||||
|
target, err := simpleChainTarget(chain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resources = append(resources, upstreamListener)
|
clusterName = CustomizeClusterName(target.Name, chain)
|
||||||
|
}
|
||||||
|
|
||||||
|
filterName := fmt.Sprintf("%s.%s.%s.%s", chain.ServiceName, chain.Namespace, chain.Partition, chain.Datacenter)
|
||||||
|
|
||||||
|
l := makePortListenerWithDefault(id, address, u.LocalBindPort, envoy_core_v3.TrafficDirection_OUTBOUND)
|
||||||
|
filterChain, err := s.makeUpstreamFilterChain(filterChainOpts{
|
||||||
|
routeName: id,
|
||||||
|
useRDS: useRDS,
|
||||||
|
clusterName: clusterName,
|
||||||
|
filterName: filterName,
|
||||||
|
protocol: cfg.Protocol,
|
||||||
|
tlsContext: tlsContext,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l.FilterChains = []*envoy_listener_v3.FilterChain{
|
||||||
|
filterChain,
|
||||||
|
}
|
||||||
|
resources = append(resources, l)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// If multiple upstreams share this port, make a special listener for the protocol.
|
// If multiple upstreams share this port, make a special listener for the protocol.
|
||||||
listener := makePortListener(listenerKey.Protocol, address, listenerKey.Port, envoy_core_v3.TrafficDirection_OUTBOUND)
|
listener := makePortListener(listenerKey.Protocol, address, listenerKey.Port, envoy_core_v3.TrafficDirection_OUTBOUND)
|
||||||
|
|
|
@ -259,6 +259,23 @@ func TestListenersFromSnapshot(t *testing.T) {
|
||||||
create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughLocalGateway,
|
create: proxycfg.TestConfigSnapshotDiscoveryChainWithFailoverThroughLocalGateway,
|
||||||
setup: nil,
|
setup: nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "connect-proxy-upstream-defaults",
|
||||||
|
create: proxycfg.TestConfigSnapshot,
|
||||||
|
setup: func(snap *proxycfg.ConfigSnapshot) {
|
||||||
|
for _, v := range snap.ConnectProxy.UpstreamConfig {
|
||||||
|
// Prepared queries do not get centrally configured upstream defaults merged into them.
|
||||||
|
if v.DestinationType == structs.UpstreamDestTypePreparedQuery {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Represent upstream config as if it came from centrally configured upstream defaults.
|
||||||
|
// The name/namespace must not make it onto the cluster name attached to the outbound listener.
|
||||||
|
v.CentrallyConfigured = true
|
||||||
|
v.DestinationNamespace = structs.WildcardSpecifier
|
||||||
|
v.DestinationName = structs.WildcardSpecifier
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "expose-paths-local-app-paths",
|
name: "expose-paths-local-app-paths",
|
||||||
create: proxycfg.TestConfigSnapshotExposeConfig,
|
create: proxycfg.TestConfigSnapshotExposeConfig,
|
||||||
|
@ -567,7 +584,7 @@ func TestListenersFromSnapshot(t *testing.T) {
|
||||||
snap.IngressGateway.Upstreams = map[proxycfg.IngressListenerKey]structs.Upstreams{
|
snap.IngressGateway.Upstreams = map[proxycfg.IngressListenerKey]structs.Upstreams{
|
||||||
{Protocol: "tcp", Port: 8080}: {
|
{Protocol: "tcp", Port: 8080}: {
|
||||||
{
|
{
|
||||||
DestinationName: "foo",
|
DestinationName: "db",
|
||||||
LocalBindPort: 8080,
|
LocalBindPort: 8080,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -640,6 +657,30 @@ func TestListenersFromSnapshot(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Every ingress upstream has an associated discovery chain in the snapshot
|
||||||
|
secureChain := discoverychain.TestCompileConfigEntries(
|
||||||
|
t,
|
||||||
|
"secure",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"dc1",
|
||||||
|
connect.TestClusterID+".consul",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
snap.IngressGateway.DiscoveryChain["secure"] = secureChain
|
||||||
|
|
||||||
|
insecureChain := discoverychain.TestCompileConfigEntries(
|
||||||
|
t,
|
||||||
|
"insecure",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"dc1",
|
||||||
|
connect.TestClusterID+".consul",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
snap.IngressGateway.DiscoveryChain["insecure"] = insecureChain
|
||||||
|
|
||||||
snap.IngressGateway.Listeners = map[proxycfg.IngressListenerKey]structs.IngressListener{
|
snap.IngressGateway.Listeners = map[proxycfg.IngressListenerKey]structs.IngressListener{
|
||||||
{Protocol: "tcp", Port: 8080}: {
|
{Protocol: "tcp", Port: 8080}: {
|
||||||
Port: 8080,
|
Port: 8080,
|
||||||
|
|
119
agent/xds/testdata/listeners/connect-proxy-upstream-defaults.envoy-1-20-x.golden
vendored
Normal file
119
agent/xds/testdata/listeners/connect-proxy-upstream-defaults.envoy-1-20-x.golden
vendored
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
{
|
||||||
|
"versionInfo": "00000001",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "db:127.0.0.1:9191",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"portValue": 9191
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "upstream.db.default.default.dc1",
|
||||||
|
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "prepared_query:geo-cache:127.10.10.10:8181",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "127.10.10.10",
|
||||||
|
"portValue": 8181
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "upstream.prepared_query_geo-cache",
|
||||||
|
"cluster": "geo-cache.default.dc1.query.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "OUTBOUND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"name": "public_listener:0.0.0.0:9999",
|
||||||
|
"address": {
|
||||||
|
"socketAddress": {
|
||||||
|
"address": "0.0.0.0",
|
||||||
|
"portValue": 9999
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filterChains": [
|
||||||
|
{
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.rbac",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.rbac.v3.RBAC",
|
||||||
|
"rules": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"statPrefix": "connect_authz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
|
"statPrefix": "public_listener",
|
||||||
|
"cluster": "local_app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transportSocket": {
|
||||||
|
"name": "tls",
|
||||||
|
"typedConfig": {
|
||||||
|
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
|
||||||
|
"commonTlsContext": {
|
||||||
|
"tlsParams": {
|
||||||
|
|
||||||
|
},
|
||||||
|
"tlsCertificates": [
|
||||||
|
{
|
||||||
|
"certificateChain": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICjDCCAjKgAwIBAgIIC5llxGV1gB8wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowDjEMMAoG\nA1UEAxMDd2ViMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADPv1RHVNRfa2VKR\nAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Favq5E0ivpNtv1QnFhxtPd7d5k4e+T7\nSkW1TaOCAXIwggFuMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcD\nAgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADBoBgNVHQ4EYQRfN2Q6MDc6ODc6M2E6\nNDA6MTk6NDc6YzM6NWE6YzA6YmE6NjI6ZGY6YWY6NGI6ZDQ6MDU6MjU6NzY6M2Q6\nNWE6OGQ6MTY6OGQ6Njc6NWU6MmU6YTA6MzQ6N2Q6ZGM6ZmYwagYDVR0jBGMwYYBf\nZDE6MTE6MTE6YWM6MmE6YmE6OTc6YjI6M2Y6YWM6N2I6YmQ6ZGE6YmU6YjE6OGE6\nZmM6OWE6YmE6YjU6YmM6ODM6ZTc6NWU6NDE6NmY6ZjI6NzM6OTU6NTg6MGM6ZGIw\nWQYDVR0RBFIwUIZOc3BpZmZlOi8vMTExMTExMTEtMjIyMi0zMzMzLTQ0NDQtNTU1\nNTU1NTU1NTU1LmNvbnN1bC9ucy9kZWZhdWx0L2RjL2RjMS9zdmMvd2ViMAoGCCqG\nSM49BAMCA0gAMEUCIGC3TTvvjj76KMrguVyFf4tjOqaSCRie3nmHMRNNRav7AiEA\npY0heYeK9A6iOLrzqxSerkXXQyj5e9bE4VgUnxgPU6g=\n-----END CERTIFICATE-----\n"
|
||||||
|
},
|
||||||
|
"privateKey": {
|
||||||
|
"inlineString": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIMoTkpRggp3fqZzFKh82yS4LjtJI+XY+qX/7DefHFrtdoAoGCCqGSM49\nAwEHoUQDQgAEADPv1RHVNRfa2VKRAB16b6rZnEt7tuhaxCFpQXPj7M2omb0B9Fav\nq5E0ivpNtv1QnFhxtPd7d5k4e+T7SkW1TQ==\n-----END EC PRIVATE KEY-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validationContext": {
|
||||||
|
"trustedCa": {
|
||||||
|
"inlineString": "-----BEGIN CERTIFICATE-----\nMIICXDCCAgKgAwIBAgIICpZq70Z9LyUwCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ\nVGVzdCBDQSAyMB4XDTE5MDMyMjEzNTgyNloXDTI5MDMyMjEzNTgyNlowFDESMBAG\nA1UEAxMJVGVzdCBDQSAyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIhywH1gx\nAsMwuF3ukAI5YL2jFxH6Usnma1HFSfVyxbXX1/uoZEYrj8yCAtdU2yoHETyd+Zx2\nThhRLP79pYegCaOCATwwggE4MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTAD\nAQH/MGgGA1UdDgRhBF9kMToxMToxMTphYzoyYTpiYTo5NzpiMjozZjphYzo3Yjpi\nZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1ZTo0MTo2ZjpmMjo3\nMzo5NTo1ODowYzpkYjBqBgNVHSMEYzBhgF9kMToxMToxMTphYzoyYTpiYTo5Nzpi\nMjozZjphYzo3YjpiZDpkYTpiZTpiMTo4YTpmYzo5YTpiYTpiNTpiYzo4MzplNzo1\nZTo0MTo2ZjpmMjo3Mzo5NTo1ODowYzpkYjA/BgNVHREEODA2hjRzcGlmZmU6Ly8x\nMTExMTExMS0yMjIyLTMzMzMtNDQ0NC01NTU1NTU1NTU1NTUuY29uc3VsMAoGCCqG\nSM49BAMCA0gAMEUCICOY0i246rQHJt8o8Oya0D5PLL1FnmsQmQqIGCi31RwnAiEA\noR5f6Ku+cig2Il8T8LJujOp2/2A72QcHZA57B13y+8o=\n-----END CERTIFICATE-----\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"requireClientCertificate": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trafficDirection": "INBOUND"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
|
"nonce": "00000001"
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
"resources": [
|
"resources": [
|
||||||
{
|
{
|
||||||
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
"@type": "type.googleapis.com/envoy.config.listener.v3.Listener",
|
||||||
"name": "foo:1.2.3.4:8080",
|
"name": "db:1.2.3.4:8080",
|
||||||
"address": {
|
"address": {
|
||||||
"socketAddress": {
|
"socketAddress": {
|
||||||
"address": "1.2.3.4",
|
"address": "1.2.3.4",
|
||||||
|
@ -17,8 +17,8 @@
|
||||||
"name": "envoy.filters.network.tcp_proxy",
|
"name": "envoy.filters.network.tcp_proxy",
|
||||||
"typedConfig": {
|
"typedConfig": {
|
||||||
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
"@type": "type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy",
|
||||||
"statPrefix": "upstream.foo.default.default.dc1",
|
"statPrefix": "upstream.db.default.default.dc1",
|
||||||
"cluster": "foo.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
"cluster": "db.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in New Issue