From 1824f4428a7e1241f045648c7823d408ddce0266 Mon Sep 17 00:00:00 2001 From: Derek Menteer Date: Fri, 9 Dec 2022 15:59:56 -0600 Subject: [PATCH] Fix DialedDirectly configuration for Consul dataplane. --- .changelog/15760.txt | 3 + agent/consul/discoverychain/compile.go | 10 +- agent/consul/discoverychain/compile_test.go | 118 ++++++++++++++++++++ agent/proxycfg/upstreams.go | 13 ++- agent/structs/discovery_chain.go | 5 +- 5 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 .changelog/15760.txt diff --git a/.changelog/15760.txt b/.changelog/15760.txt new file mode 100644 index 0000000000..83816802b0 --- /dev/null +++ b/.changelog/15760.txt @@ -0,0 +1,3 @@ +```release-note:bug +connect: Fix issue where DialedDirectly configuration was not used by Consul Dataplane. +``` diff --git a/agent/consul/discoverychain/compile.go b/agent/consul/discoverychain/compile.go index 3a9a1f0ed7..dd7dea28df 100644 --- a/agent/consul/discoverychain/compile.go +++ b/agent/consul/discoverychain/compile.go @@ -1007,10 +1007,16 @@ RESOLVE_AGAIN: // Default mesh gateway settings if serviceDefault := c.entries.GetService(targetID); serviceDefault != nil { target.MeshGateway = serviceDefault.MeshGateway + target.TransparentProxy = serviceDefault.TransparentProxy } proxyDefault := c.entries.GetProxyDefaults(targetID.PartitionOrDefault()) - if proxyDefault != nil && target.MeshGateway.Mode == structs.MeshGatewayModeDefault { - target.MeshGateway.Mode = proxyDefault.MeshGateway.Mode + if proxyDefault != nil { + if target.MeshGateway.Mode == structs.MeshGatewayModeDefault { + target.MeshGateway.Mode = proxyDefault.MeshGateway.Mode + } + if target.TransparentProxy.IsZero() { + target.TransparentProxy = proxyDefault.TransparentProxy + } } if c.overrideMeshGateway.Mode != structs.MeshGatewayModeDefault { diff --git a/agent/consul/discoverychain/compile_test.go b/agent/consul/discoverychain/compile_test.go index a4c9c65ed7..590e9f87c7 100644 --- a/agent/consul/discoverychain/compile_test.go +++ b/agent/consul/discoverychain/compile_test.go @@ -82,6 +82,11 @@ func TestCompile(t *testing.T) { // circular references "circular resolver redirect": testcase_Resolver_CircularRedirect(), "circular split": testcase_CircularSplit(), + + // tproxy + "tproxy service defaults only": testcase_ServiceDefaultsTProxy(), + "tproxy proxy defaults only": testcase_ProxyDefaultsTProxy(), + "tproxy service defaults override": testcase_ServiceDefaultsOverrideTProxy(), } for name, tc := range cases { @@ -2942,6 +2947,119 @@ func testcase_LBResolver() compileTestCase { return compileTestCase{entries: entries, expect: expect} } +func testcase_ServiceDefaultsTProxy() compileTestCase { + entries := newEntries() + entries.AddServices( + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "main", + TransparentProxy: structs.TransparentProxyConfig{ + DialedDirectly: true, + }, + }, + ) + + expect := &structs.CompiledDiscoveryChain{ + Protocol: "tcp", + Default: true, + StartNode: "resolver:main.default.default.dc1", + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:main.default.default.dc1": { + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "main.default.default.dc1", + Resolver: &structs.DiscoveryResolver{ + Default: true, + ConnectTimeout: 5 * time.Second, + Target: "main.default.default.dc1", + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, func(t *structs.DiscoveryTarget) { + t.TransparentProxy.DialedDirectly = true + }), + }, + } + return compileTestCase{entries: entries, expect: expect} +} + +func testcase_ProxyDefaultsTProxy() compileTestCase { + entries := newEntries() + entries.AddProxyDefaults(&structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + TransparentProxy: structs.TransparentProxyConfig{ + DialedDirectly: true, + }, + }) + + expect := &structs.CompiledDiscoveryChain{ + Protocol: "tcp", + Default: true, + StartNode: "resolver:main.default.default.dc1", + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:main.default.default.dc1": { + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "main.default.default.dc1", + Resolver: &structs.DiscoveryResolver{ + Default: true, + ConnectTimeout: 5 * time.Second, + Target: "main.default.default.dc1", + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, func(t *structs.DiscoveryTarget) { + t.TransparentProxy.DialedDirectly = true + }), + }, + } + return compileTestCase{entries: entries, expect: expect} +} + +func testcase_ServiceDefaultsOverrideTProxy() compileTestCase { + entries := newEntries() + entries.AddProxyDefaults(&structs.ProxyConfigEntry{ + Kind: structs.ProxyDefaults, + Name: structs.ProxyConfigGlobal, + TransparentProxy: structs.TransparentProxyConfig{ + DialedDirectly: false, + }, + }) + entries.AddServices( + &structs.ServiceConfigEntry{ + Kind: structs.ServiceDefaults, + Name: "main", + TransparentProxy: structs.TransparentProxyConfig{ + DialedDirectly: true, + }, + }, + ) + + expect := &structs.CompiledDiscoveryChain{ + Protocol: "tcp", + Default: true, + StartNode: "resolver:main.default.default.dc1", + Nodes: map[string]*structs.DiscoveryGraphNode{ + "resolver:main.default.default.dc1": { + Type: structs.DiscoveryGraphNodeTypeResolver, + Name: "main.default.default.dc1", + Resolver: &structs.DiscoveryResolver{ + Default: true, + ConnectTimeout: 5 * time.Second, + Target: "main.default.default.dc1", + }, + }, + }, + Targets: map[string]*structs.DiscoveryTarget{ + "main.default.default.dc1": newTarget(structs.DiscoveryTargetOpts{Service: "main"}, func(t *structs.DiscoveryTarget) { + t.TransparentProxy.DialedDirectly = true + }), + }, + } + return compileTestCase{entries: entries, expect: expect} +} + func newSimpleRoute(name string, muts ...func(*structs.ServiceRoute)) structs.ServiceRoute { r := structs.ServiceRoute{ Match: &structs.ServiceRouteMatch{ diff --git a/agent/proxycfg/upstreams.go b/agent/proxycfg/upstreams.go index 4ebbabb65d..38eade7d41 100644 --- a/agent/proxycfg/upstreams.go +++ b/agent/proxycfg/upstreams.go @@ -131,6 +131,7 @@ func (s *handlerUpstreams) handleUpdateUpstreams(ctx context.Context, u UpdateEv } upstreamsSnapshot.WatchedUpstreamEndpoints[uid][targetID] = resp.Nodes + // Skip adding passthroughs unless it's a connect sidecar in tproxy mode. if s.kind != structs.ServiceKindConnectProxy || s.proxyCfg.Mode != structs.ProxyModeTransparent { return nil } @@ -148,7 +149,17 @@ func (s *handlerUpstreams) handleUpdateUpstreams(ctx context.Context, u UpdateEv passthroughs := make(map[string]struct{}) for _, node := range resp.Nodes { - if !node.Service.Proxy.TransparentProxy.DialedDirectly { + dialedDirectly := node.Service.Proxy.TransparentProxy.DialedDirectly + // We must do a manual merge here on the DialedDirectly field, because the service-defaults + // and proxy-defaults are not automatically merged into the CheckServiceNodes when in + // agentless mode (because the streaming backend doesn't yet support the MergeCentralConfig field). + if chain := snap.ConnectProxy.DiscoveryChain[uid]; chain != nil { + if target := chain.Targets[targetID]; target != nil { + dialedDirectly = dialedDirectly || target.TransparentProxy.DialedDirectly + } + } + // Skip adding a passthrough for the upstream node if not DialedDirectly. + if !dialedDirectly { continue } diff --git a/agent/structs/discovery_chain.go b/agent/structs/discovery_chain.go index ca64d070d6..6d1beb1e74 100644 --- a/agent/structs/discovery_chain.go +++ b/agent/structs/discovery_chain.go @@ -192,8 +192,9 @@ type DiscoveryTarget struct { Datacenter string `json:",omitempty"` Peer string `json:",omitempty"` - MeshGateway MeshGatewayConfig `json:",omitempty"` - Subset ServiceResolverSubset `json:",omitempty"` + MeshGateway MeshGatewayConfig `json:",omitempty"` + Subset ServiceResolverSubset `json:",omitempty"` + TransparentProxy TransparentProxyConfig `json:",omitempty"` ConnectTimeout time.Duration `json:",omitempty"`