Skip to content

Commit

Permalink
Add flag for transparent proxies to dial individual instances (#10329)
Browse files Browse the repository at this point in the history
  • Loading branch information
freddygv authored and hc-github-team-consul-core committed Jun 9, 2021
1 parent 46dc563 commit 168073c
Show file tree
Hide file tree
Showing 63 changed files with 1,880 additions and 404 deletions.
3 changes: 3 additions & 0 deletions .changelog/10329.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
connect: Support dialing individual service IP addresses through transparent proxies.
```
4 changes: 2 additions & 2 deletions agent/agent_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ func TestAgent_Service(t *testing.T) {
Service: "web-sidecar-proxy",
Port: 8000,
Proxy: expectProxy.ToAPI(),
ContentHash: "9dcdedfd5047d46e",
ContentHash: "518ece989813bc13",
Weights: api.AgentWeights{
Passing: 1,
Warning: 1,
Expand All @@ -413,7 +413,7 @@ func TestAgent_Service(t *testing.T) {
// Copy and modify
updatedResponse := *expectedResponse
updatedResponse.Port = 9999
updatedResponse.ContentHash = "a08487ca7854c7cc"
updatedResponse.ContentHash = "6cc7a4afb000afb1"

// Simple response for non-proxy service registered in TestAgent config
expectWebResponse := &api.AgentService{
Expand Down
1 change: 1 addition & 0 deletions agent/config/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -1764,6 +1764,7 @@ func (b *builder) transparentProxyConfVal(tproxyConf *TransparentProxyConfig) st
}

out.OutboundListenerPort = intVal(tproxyConf.OutboundListenerPort)
out.DialedDirectly = boolVal(tproxyConf.DialedDirectly)
return out
}

Expand Down
7 changes: 6 additions & 1 deletion agent/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -545,8 +545,13 @@ type MeshGatewayConfig struct {
}

type TransparentProxyConfig struct {
// Mesh Gateway Mode
// The port of the listener where outbound application traffic is being redirected to.
OutboundListenerPort *int `mapstructure:"outbound_listener_port"`

// DialedDirectly indicates whether transparent proxies can dial this proxy instance directly.
// The discovery chain is not considered when dialing a service instance directly.
// This setting is useful when addressing stateful services, such as a database cluster with a leader node.
DialedDirectly *bool `mapstructure:"dialed_directly"`
}

// ExposeConfig describes HTTP paths to expose through Envoy outside of Connect.
Expand Down
31 changes: 25 additions & 6 deletions agent/config/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2584,7 +2584,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
},
"mode": "transparent",
"transparent_proxy": {
"outbound_listener_port": 10101
"outbound_listener_port": 10101,
"dialed_directly": true
},
"upstreams": [
{
Expand Down Expand Up @@ -2630,6 +2631,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
mode = "transparent"
transparent_proxy = {
outbound_listener_port = 10101
dialed_directly = true
}
upstreams = [
{
Expand Down Expand Up @@ -2678,6 +2680,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
Upstreams: structs.Upstreams{
structs.Upstream{
Expand Down Expand Up @@ -2741,7 +2744,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
},
"mode": "transparent",
"transparent_proxy": {
"outbound_listener_port": 10101
"outbound_listener_port": 10101,
"dialed_directly": true
},
"upstreams": [
{
Expand Down Expand Up @@ -2782,6 +2786,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
mode = "transparent"
transparent_proxy = {
outbound_listener_port = 10101
dialed_directly = true
}
upstreams = [
{
Expand Down Expand Up @@ -2825,6 +2830,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
Upstreams: structs.Upstreams{
structs.Upstream{
Expand Down Expand Up @@ -3471,7 +3477,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
},
"mode": "transparent",
"transparent_proxy": {
"outbound_listener_port": 10101
"outbound_listener_port": 10101,
"dialed_directly": true
}
}
]
Expand All @@ -3494,6 +3501,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
mode = "transparent"
transparent_proxy = {
outbound_listener_port = 10101
dialed_directly = true
}
}
}`},
Expand All @@ -3516,6 +3524,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
},
}
Expand All @@ -3541,7 +3550,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
},
"Mode": "transparent",
"TransparentProxy": {
"OutboundListenerPort": 10101
"OutboundListenerPort": 10101,
"DialedDirectly": true
}
}
]
Expand All @@ -3564,6 +3574,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
Mode = "transparent"
TransparentProxy = {
OutboundListenerPort = 10101
DialedDirectly = true
}
}
}`},
Expand All @@ -3586,6 +3597,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
},
}
Expand All @@ -3611,7 +3623,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
},
"mode": "transparent",
"transparent_proxy": {
"outbound_listener_port": 10101
"outbound_listener_port": 10101,
"dialed_directly": true
}
}
]
Expand All @@ -3634,6 +3647,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
mode = "transparent"
transparent_proxy = {
outbound_listener_port = 10101
dialed_directly = true
}
}
}`},
Expand All @@ -3656,6 +3670,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
},
}
Expand All @@ -3681,7 +3696,8 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
},
"Mode": "transparent",
"TransparentProxy": {
"OutboundListenerPort": 10101
"OutboundListenerPort": 10101,
"DialedDirectly": true
}
}
]
Expand All @@ -3704,6 +3720,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
Mode = "transparent"
TransparentProxy = {
OutboundListenerPort = 10101
DialedDirectly = true
}
}
}`},
Expand All @@ -3726,6 +3743,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
},
}
Expand Down Expand Up @@ -5670,6 +5688,7 @@ func TestLoad_FullConfig(t *testing.T) {
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
},
Weights: &structs.Weights{
Expand Down
1 change: 1 addition & 0 deletions agent/config/testdata/full-config.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ services = [
mode = "transparent"
transparent_proxy = {
outbound_listener_port = 10101
dialed_directly = true
}
}
},
Expand Down
3 changes: 2 additions & 1 deletion agent/config/testdata/full-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@
},
"mode": "transparent",
"transparent_proxy": {
"outbound_listener_port": 10101
"outbound_listener_port": 10101,
"dialed_directly": true
},
"upstreams": [
{
Expand Down
3 changes: 3 additions & 0 deletions agent/consul/config_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ func (c *ConfigEntry) ResolveServiceConfig(args *structs.ServiceConfigRequest, r
if serviceConf.TransparentProxy.OutboundListenerPort != 0 {
thisReply.TransparentProxy.OutboundListenerPort = serviceConf.TransparentProxy.OutboundListenerPort
}
if serviceConf.TransparentProxy.DialedDirectly {
thisReply.TransparentProxy.DialedDirectly = serviceConf.TransparentProxy.DialedDirectly
}
if serviceConf.Mode != structs.ProxyModeDefault {
thisReply.Mode = serviceConf.Mode
}
Expand Down
61 changes: 41 additions & 20 deletions agent/consul/config_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -911,19 +911,25 @@ func TestConfigEntry_ResolveServiceConfig_TransparentProxy(t *testing.T) {
name: "from proxy-defaults",
entries: []structs.ConfigEntry{
&structs.ProxyConfigEntry{
Kind: structs.ProxyDefaults,
Name: structs.ProxyConfigGlobal,
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{OutboundListenerPort: 10101},
Kind: structs.ProxyDefaults,
Name: structs.ProxyConfigGlobal,
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
},
},
request: structs.ServiceConfigRequest{
Name: "foo",
Datacenter: "dc1",
},
expect: structs.ServiceConfigResponse{
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{OutboundListenerPort: 10101},
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
},
},
{
Expand All @@ -949,25 +955,34 @@ func TestConfigEntry_ResolveServiceConfig_TransparentProxy(t *testing.T) {
name: "service-defaults overrides proxy-defaults",
entries: []structs.ConfigEntry{
&structs.ProxyConfigEntry{
Kind: structs.ProxyDefaults,
Name: structs.ProxyConfigGlobal,
Mode: structs.ProxyModeDirect,
TransparentProxy: structs.TransparentProxyConfig{OutboundListenerPort: 10101},
Kind: structs.ProxyDefaults,
Name: structs.ProxyConfigGlobal,
Mode: structs.ProxyModeDirect,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: false,
},
},
&structs.ServiceConfigEntry{
Kind: structs.ServiceDefaults,
Name: "foo",
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{OutboundListenerPort: 808},
Kind: structs.ServiceDefaults,
Name: "foo",
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 808,
DialedDirectly: true,
},
},
},
request: structs.ServiceConfigRequest{
Name: "foo",
Datacenter: "dc1",
},
expect: structs.ServiceConfigResponse{
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{OutboundListenerPort: 808},
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 808,
DialedDirectly: true,
},
},
},
}
Expand Down Expand Up @@ -1303,8 +1318,11 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
},

// TransparentProxy on the config entry but not the config request
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{OutboundListenerPort: 10101},
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
},
},
request: structs.ServiceConfigRequest{
Expand All @@ -1314,8 +1332,11 @@ func TestConfigEntry_ResolveServiceConfig_Upstreams(t *testing.T) {
// Empty Upstreams/UpstreamIDs
},
expect: structs.ServiceConfigResponse{
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{OutboundListenerPort: 10101},
Mode: structs.ProxyModeTransparent,
TransparentProxy: structs.TransparentProxyConfig{
OutboundListenerPort: 10101,
DialedDirectly: true,
},
UpstreamIDConfigs: structs.OpaqueUpstreamConfigs{
{
Upstream: wildcard,
Expand Down
2 changes: 2 additions & 0 deletions agent/proxycfg/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ func TestManager_BasicLifecycle(t *testing.T) {
upstreams[1].Identifier(): &upstreams[1],
upstreams[2].Identifier(): &upstreams[2],
},
PassthroughUpstreams: map[string]ServicePassthroughAddrs{},
},
PreparedQueryEndpoints: map[string]structs.CheckServiceNodes{},
WatchedServiceChecks: map[structs.ServiceID][]structs.CheckType{},
Expand Down Expand Up @@ -293,6 +294,7 @@ func TestManager_BasicLifecycle(t *testing.T) {
upstreams[1].Identifier(): &upstreams[1],
upstreams[2].Identifier(): &upstreams[2],
},
PassthroughUpstreams: map[string]ServicePassthroughAddrs{},
},
PreparedQueryEndpoints: map[string]structs.CheckServiceNodes{},
WatchedServiceChecks: map[structs.ServiceID][]structs.CheckType{},
Expand Down
13 changes: 13 additions & 0 deletions agent/proxycfg/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ type ConfigSnapshotUpstreams struct {

// UpstreamConfig is a map to an upstream's configuration.
UpstreamConfig map[string]*structs.Upstream

// PassthroughEndpoints is a map of: ServiceName -> ServicePassthroughAddrs.
PassthroughUpstreams map[string]ServicePassthroughAddrs
}

// ServicePassthroughAddrs contains the LAN addrs
type ServicePassthroughAddrs struct {
// SNI is the Service SNI of the upstream.
SNI string

// Addrs is a set of the best LAN addresses for the instances of the upstream.
Addrs map[string]struct{}
}

type configSnapshotConnectProxy struct {
Expand Down Expand Up @@ -80,6 +92,7 @@ func (c *configSnapshotConnectProxy) IsEmpty() bool {
len(c.WatchedServiceChecks) == 0 &&
len(c.PreparedQueryEndpoints) == 0 &&
len(c.UpstreamConfig) == 0 &&
len(c.PassthroughUpstreams) == 0 &&
!c.MeshConfigSet
}

Expand Down
Loading

0 comments on commit 168073c

Please sign in to comment.