Fix DialedDirectly configuration for Consul dataplane. (#15760)

Fix DialedDirectly configuration for Consul dataplane.
This commit is contained in:
Derek Menteer 2022-12-13 09:16:31 -06:00 committed by GitHub
parent c73707ca3c
commit 50a5549f8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 161 additions and 11 deletions

3
.changelog/15760.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
connect: Fix issue where DialedDirectly configuration was not used by Consul Dataplane.
```

View File

@ -1007,10 +1007,16 @@ RESOLVE_AGAIN:
// Default mesh gateway settings // Default mesh gateway settings
if serviceDefault := c.entries.GetService(targetID); serviceDefault != nil { if serviceDefault := c.entries.GetService(targetID); serviceDefault != nil {
target.MeshGateway = serviceDefault.MeshGateway target.MeshGateway = serviceDefault.MeshGateway
target.TransparentProxy.DialedDirectly = serviceDefault.TransparentProxy.DialedDirectly
} }
proxyDefault := c.entries.GetProxyDefaults(targetID.PartitionOrDefault()) proxyDefault := c.entries.GetProxyDefaults(targetID.PartitionOrDefault())
if proxyDefault != nil && target.MeshGateway.Mode == structs.MeshGatewayModeDefault { if proxyDefault != nil {
target.MeshGateway.Mode = proxyDefault.MeshGateway.Mode if target.MeshGateway.Mode == structs.MeshGatewayModeDefault {
target.MeshGateway.Mode = proxyDefault.MeshGateway.Mode
}
if !target.TransparentProxy.DialedDirectly {
target.TransparentProxy.DialedDirectly = proxyDefault.TransparentProxy.DialedDirectly
}
} }
if c.overrideMeshGateway.Mode != structs.MeshGatewayModeDefault { if c.overrideMeshGateway.Mode != structs.MeshGatewayModeDefault {

View File

@ -82,6 +82,11 @@ func TestCompile(t *testing.T) {
// circular references // circular references
"circular resolver redirect": testcase_Resolver_CircularRedirect(), "circular resolver redirect": testcase_Resolver_CircularRedirect(),
"circular split": testcase_CircularSplit(), "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 { for name, tc := range cases {
@ -2942,6 +2947,119 @@ func testcase_LBResolver() compileTestCase {
return compileTestCase{entries: entries, expect: expect} 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 { func newSimpleRoute(name string, muts ...func(*structs.ServiceRoute)) structs.ServiceRoute {
r := structs.ServiceRoute{ r := structs.ServiceRoute{
Match: &structs.ServiceRouteMatch{ Match: &structs.ServiceRouteMatch{

View File

@ -2359,7 +2359,16 @@ func TestState_WatchesAndUpdates(t *testing.T) {
{ {
CorrelationID: "discovery-chain:" + dbUID.String(), CorrelationID: "discovery-chain:" + dbUID.String(),
Result: &structs.DiscoveryChainResponse{ Result: &structs.DiscoveryChainResponse{
Chain: discoverychain.TestCompileConfigEntries(t, "db", "default", "default", "dc1", "trustdomain.consul", nil), Chain: discoverychain.TestCompileConfigEntries(
t, "db", "default", "default", "dc1", "trustdomain.consul", nil,
&structs.ServiceConfigEntry{
Kind: structs.ServiceDefaults,
Name: "db",
TransparentProxy: structs.TransparentProxyConfig{
DialedDirectly: true,
},
},
),
}, },
Err: nil, Err: nil,
}, },
@ -2396,7 +2405,7 @@ func TestState_WatchesAndUpdates(t *testing.T) {
Proxy: structs.ConnectProxyConfig{ Proxy: structs.ConnectProxyConfig{
DestinationServiceName: "db", DestinationServiceName: "db",
TransparentProxy: structs.TransparentProxyConfig{ TransparentProxy: structs.TransparentProxyConfig{
DialedDirectly: true, DialedDirectly: false, // This is set true by the service-defaults entry above.
}, },
}, },
RaftIndex: structs.RaftIndex{ RaftIndex: structs.RaftIndex{
@ -2455,7 +2464,7 @@ func TestState_WatchesAndUpdates(t *testing.T) {
Proxy: structs.ConnectProxyConfig{ Proxy: structs.ConnectProxyConfig{
DestinationServiceName: "db", DestinationServiceName: "db",
TransparentProxy: structs.TransparentProxyConfig{ TransparentProxy: structs.TransparentProxyConfig{
DialedDirectly: true, DialedDirectly: false,
}, },
}, },
RaftIndex: structs.RaftIndex{ RaftIndex: structs.RaftIndex{

View File

@ -131,6 +131,7 @@ func (s *handlerUpstreams) handleUpdateUpstreams(ctx context.Context, u UpdateEv
} }
upstreamsSnapshot.WatchedUpstreamEndpoints[uid][targetID] = resp.Nodes 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 { if s.kind != structs.ServiceKindConnectProxy || s.proxyCfg.Mode != structs.ProxyModeTransparent {
return nil return nil
} }
@ -148,7 +149,17 @@ func (s *handlerUpstreams) handleUpdateUpstreams(ctx context.Context, u UpdateEv
passthroughs := make(map[string]struct{}) passthroughs := make(map[string]struct{})
for _, node := range resp.Nodes { 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 continue
} }
@ -179,10 +190,12 @@ func (s *handlerUpstreams) handleUpdateUpstreams(ctx context.Context, u UpdateEv
upstreamsSnapshot.PassthroughIndices[addr] = indexedTarget{idx: csnIdx, upstreamID: uid, targetID: targetID} upstreamsSnapshot.PassthroughIndices[addr] = indexedTarget{idx: csnIdx, upstreamID: uid, targetID: targetID}
passthroughs[addr] = struct{}{} passthroughs[addr] = struct{}{}
} }
// Always clear out the existing target passthroughs list so that clusters are cleaned up
// correctly if no entries are populated.
upstreamsSnapshot.PassthroughUpstreams[uid] = make(map[string]map[string]struct{})
if len(passthroughs) > 0 { if len(passthroughs) > 0 {
upstreamsSnapshot.PassthroughUpstreams[uid] = map[string]map[string]struct{}{ // Add the passthroughs to the target if any were found.
targetID: passthroughs, upstreamsSnapshot.PassthroughUpstreams[uid][targetID] = passthroughs
}
} }
case strings.HasPrefix(u.CorrelationID, "mesh-gateway:"): case strings.HasPrefix(u.CorrelationID, "mesh-gateway:"):

View File

@ -192,8 +192,9 @@ type DiscoveryTarget struct {
Datacenter string `json:",omitempty"` Datacenter string `json:",omitempty"`
Peer string `json:",omitempty"` Peer string `json:",omitempty"`
MeshGateway MeshGatewayConfig `json:",omitempty"` MeshGateway MeshGatewayConfig `json:",omitempty"`
Subset ServiceResolverSubset `json:",omitempty"` Subset ServiceResolverSubset `json:",omitempty"`
TransparentProxy TransparentProxyConfig `json:",omitempty"`
ConnectTimeout time.Duration `json:",omitempty"` ConnectTimeout time.Duration `json:",omitempty"`