Skip to content

Commit

Permalink
Consul Connect over IPv6 (except tproxy) (#24203)
Browse files Browse the repository at this point in the history
* detect ipv6 on "bridge" network and set
  service.connect.sidecar_proxy.config.bind_address
  for envoy to "::" instead of "0.0.0.0"
* allow users to set bind_address in jobspec
  e.g. "" would defer to consul proxy-defaults
* caveat: tproxy still does not work, because
  the CNI plugin does not configure ip6tables
  • Loading branch information
gulducat authored Oct 14, 2024
1 parent 5beb1ce commit 067afcd
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 8 deletions.
17 changes: 14 additions & 3 deletions command/agent/consul/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func connectSidecarProxy(info structs.AllocInfo, proxy *structs.ConsulProxy, cPo
Mode: mode,
LocalServiceAddress: proxy.LocalServiceAddress,
LocalServicePort: proxy.LocalServicePort,
Config: connectProxyConfig(proxy.Config, cPort, info),
Config: connectProxyConfig(proxy.Config, cPort, info, networks),
Upstreams: connectUpstreams(proxy.Upstreams),
Expose: expose,
}, nil
Expand Down Expand Up @@ -243,11 +243,13 @@ func connectMeshGateway(in structs.ConsulMeshGateway) api.MeshGatewayConfig {
return gw
}

func connectProxyConfig(cfg map[string]interface{}, port int, info structs.AllocInfo) map[string]interface{} {
func connectProxyConfig(cfg map[string]interface{}, port int, info structs.AllocInfo, networks structs.Networks) map[string]interface{} {
if cfg == nil {
cfg = make(map[string]interface{})
}
cfg["bind_address"] = "0.0.0.0"
if _, ok := cfg["bind_address"]; !ok {
cfg["bind_address"] = connectProxyBindAddress(networks)
}
cfg["bind_port"] = port

tags := map[string]string{
Expand All @@ -260,6 +262,15 @@ func connectProxyConfig(cfg map[string]interface{}, port int, info structs.Alloc
return cfg
}

func connectProxyBindAddress(networks structs.Networks) string {
for _, n := range networks {
if n.Mode == "bridge" && n.IsIPv6() {
return "::"
}
}
return "0.0.0.0"
}

// injectNomadInfo merges nomad information into cfg=>envoy_stats_tags
//
// cfg must not be nil
Expand Down
32 changes: 27 additions & 5 deletions command/agent/consul/connect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,22 +409,44 @@ func TestConnect_connectProxyConfig(t *testing.T) {
ci.Parallel(t)

t.Run("nil map", func(t *testing.T) {
require.Equal(t, map[string]interface{}{
must.Eq(t, map[string]any{
"bind_address": "0.0.0.0",
"bind_port": 42,
"envoy_stats_tags": []string{"nomad.alloc_id=test_alloc1"},
}, connectProxyConfig(nil, 42, structs.AllocInfo{AllocID: "test_alloc1"}))
}, connectProxyConfig(nil, 42, structs.AllocInfo{AllocID: "test_alloc1"}, nil))
})

t.Run("pre-existing map", func(t *testing.T) {
require.Equal(t, map[string]interface{}{
must.Eq(t, map[string]any{
"bind_address": "0.0.0.0",
"bind_port": 42,
"foo": "bar",
"envoy_stats_tags": []string{"nomad.alloc_id=test_alloc2"},
}, connectProxyConfig(map[string]interface{}{
}, connectProxyConfig(map[string]any{
"foo": "bar",
}, 42, structs.AllocInfo{AllocID: "test_alloc2"}))
}, 42, structs.AllocInfo{AllocID: "test_alloc2"}, nil))
})

t.Run("bind_address override", func(t *testing.T) {
must.Eq(t, map[string]any{
"bind_address": "anything",
"bind_port": 42,
"envoy_stats_tags": []string{"nomad.alloc_id=custom_bind_alloc"},
}, connectProxyConfig(map[string]any{
"bind_address": "anything",
}, 42, structs.AllocInfo{AllocID: "custom_bind_alloc"}, nil))
})

t.Run("bind_address ipv6", func(t *testing.T) {
must.Eq(t, map[string]any{
"bind_address": "::",
"bind_port": 42,
"envoy_stats_tags": []string{"nomad.alloc_id=ipv6_alloc"},
}, connectProxyConfig(map[string]any{
"bind_address": "::",
}, 42, structs.AllocInfo{AllocID: "ipv6_alloc"}, []*structs.NetworkResource{
{Mode: "bridge", IP: "fd00:a110:c8::1"},
}))
})
}

Expand Down
5 changes: 5 additions & 0 deletions nomad/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3037,6 +3037,11 @@ func (n *NetworkResource) PortLabels() map[string]int {
return labelValues
}

func (n *NetworkResource) IsIPv6() bool {
ip := net.ParseIP(n.IP)
return ip != nil && ip.To4() == nil
}

// Networks defined for a task on the Resources struct.
type Networks []*NetworkResource

Expand Down

0 comments on commit 067afcd

Please sign in to comment.