VAULT-34581: retry_join: handle escapes in auto_join config (#29874)

`go-discover` supports being configured with some configuration strings
that include double-quotes, backslashes and escapes. As such, we now use
its own parser when normalizing `auto_join` config that may have
addresses.

Signed-off-by: Ryan Cragun <me@ryan.ec>
This commit is contained in:
Ryan Cragun 2025-03-07 15:20:58 -07:00 committed by GitHub
parent c937b3e254
commit 486b6b7541
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 26 additions and 16 deletions

View file

@ -16,6 +16,7 @@ import (
"strings"
"time"
"github.com/hashicorp/go-discover"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-secure-stdlib/parseutil"
"github.com/hashicorp/hcl"
@ -1101,20 +1102,17 @@ func normalizeRaftRetryJoin(val any) ([]byte, error) {
for k, v := range stanza {
switch k {
case "auto_join":
pairs := strings.Split(v.(string), " ")
for i, pair := range pairs {
pairParts := strings.Split(pair, "=")
if len(pairParts) != 2 {
return nil, fmt.Errorf("malformed auto_join pair %s, expected key=value", pair)
}
cfg, err := discover.Parse(v.(string))
if err != nil {
return nil, err
}
for k, v := range cfg {
// These are auto_join keys that are valid for the provider in go-discover
if slices.Contains([]string{"domain", "auth_url", "url", "host"}, pairParts[0]) {
pairParts[1] = configutil.NormalizeAddr(pairParts[1])
pair = strings.Join(pairParts, "=")
pairs[i] = pair
if slices.Contains([]string{"domain", "auth_url", "url", "host"}, k) {
cfg[k] = configutil.NormalizeAddr(v)
}
}
normalizedStanza[k] = strings.Join(pairs, " ")
normalizedStanza[k] = cfg.String()
case "leader_api_addr":
normalizedStanza[k] = configutil.NormalizeAddr(v.(string))
default:

View file

@ -35,13 +35,16 @@ func testConfigRaftRetryJoin(t *testing.T) {
t.Parallel()
retryJoinExpected := []map[string]string{
// NOTE: Normalization handles IPv6 addresses and returns auto_join with
// sorted stable keys.
{"leader_api_addr": "http://127.0.0.1:8200"},
{"leader_api_addr": "http://[2001:db8::2:1]:8200"},
{"auto_join": "provider=mdns service=consul domain=2001:db8::2:1"},
{"auto_join": "provider=os tag_key=consul tag_value=server username=foo password=bar auth_url=https://[2001:db8::2:1]/auth"},
{"auto_join": "provider=triton account=testaccount url=https://[2001:db8::2:1] key_id=1234 tag_key=consul-role tag_value=server"},
{"auto_join": "provider=packet auth_token=token project=uuid url=https://[2001:db8::2:1] address_type=public_v6"},
{"auto_join": "provider=vsphere category_name=consul-role tag_name=consul-server host=https://[2001:db8::2:1] user=foo password=bar insecure_ssl=false"},
{"auto_join": "provider=mdns domain=2001:db8::2:1 service=consul"},
{"auto_join": "provider=os auth_url=https://[2001:db8::2:1]/auth password=bar tag_key=consul tag_value=server username=foo"},
{"auto_join": "provider=triton account=testaccount key_id=1234 tag_key=consul-role tag_value=server url=https://[2001:db8::2:1]"},
{"auto_join": "provider=packet address_type=public_v6 auth_token=token project=uuid url=https://[2001:db8::2:1]"},
{"auto_join": "provider=vsphere category_name=consul-role host=https://[2001:db8::2:1] insecure_ssl=false password=bar tag_name=consul-server user=foo"},
{"auto_join": "provider=k8s label_selector=\"app.kubernetes.io/name=vault, component=server\" namespace=vault"},
}
for _, cfg := range []string{
"attr",

View file

@ -23,6 +23,9 @@ storage "raft" {
retry_join = [
{ "auto_join" = "provider=vsphere category_name=consul-role tag_name=consul-server host=https://[2001:db8:0:0:0:0:2:1] user=foo password=bar insecure_ssl=false" }
]
retry_join = [
{ "auto_join" = "provider=k8s namespace=vault label_selector=\"app.kubernetes.io/name=vault, component=server\"" }
]
}
listener "tcp" {

View file

@ -26,6 +26,9 @@ storage "raft" {
retry_join {
"auto_join" = "provider=vsphere category_name=consul-role tag_name=consul-server host=https://[2001:db8:0:0:0:0:2:1] user=foo password=bar insecure_ssl=false"
}
retry_join {
"auto_join" = "provider=k8s namespace=vault label_selector=\"app.kubernetes.io/name=vault, component=server\""
}
}
listener "tcp" {

View file

@ -23,6 +23,9 @@ storage "raft" {
retry_join {
"auto_join" = "provider=vsphere category_name=consul-role tag_name=consul-server host=https://[2001:db8:0:0:0:0:2:1] user=foo password=bar insecure_ssl=false"
}
retry_join = [
{ "auto_join" = "provider=k8s namespace=vault label_selector=\"app.kubernetes.io/name=vault, component=server\"" }
]
}
listener "tcp" {