Skip to content

Commit

Permalink
VAULT-33008: ipv6: always display RFC-5952 §4 conformant addresses (#…
Browse files Browse the repository at this point in the history
…29228)

USGv6[0] requires implementing §4.1.1 of the NISTv6-r1 profile[1] for
IPv6-Only capabilities. This section requires that whenever Vault
displays IPv6 addresses (including CLI output, Web UI, logs, etc.) that
_all_ IPv6 addresses must conform to RFC-5952 §4 text representation
recommendations[2].

These recommendations do not prevent us from accepting RFC-4241[3] IPv6
addresses, however, whenever these same addresses are displayed they
must conform to the strict RFC-5952 §4 guidelines.

This PR implements handling of IPv6 address conformance in our
`vault server` routine. We handle conformance normalization for all
server, http_proxy, listener, seal, storage and telemetry
configuration where an input could contain an IPv6 address, whether
configured via an HCL file or via corresponding environment variables.

The approach I've taken is to handle conformance normalization at
parse time to ensure that all log output and subsequent usage
inside of Vaults various subsystems always reference a conformant
address, that way we don't need concern ourselves with conformance
later. This approach ought to be backwards compatible to prior loose
address configuration requirements, with the understanding that
going forward all IPv6 representation will be strict regardless of
what has been configured.

In many cases I've updated our various parser functions to call the
new `configutil.NormalizeAddr()` to apply conformance normalization.
Others required no changes because they rely on standard library URL
string output, which always displays IPv6 URLs in a conformant way.

Not included in this changes is any other vault exec mode other than
server. Client, operator commands, agent mode, proxy mode, etc. will
be included in subsequent changes if necessary.

[0]: https://www.nist.gov/publications/usgv6-profile
[1]: https://www.nist.gov/publications/nist-ipv6-profile
[2]: https://www.rfc-editor.org/rfc/rfc5952.html#section-4
[3]: https://www.rfc-editor.org/rfc/rfc4291

Signed-off-by: Ryan Cragun <me@ryan.ec>
  • Loading branch information
ryancragun authored Jan 27, 2025
1 parent 9456671 commit 012cd5a
Show file tree
Hide file tree
Showing 20 changed files with 1,421 additions and 139 deletions.
3 changes: 3 additions & 0 deletions changelog/29228.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:change
server/config: Configuration values including IPv6 addresses will be automatically translated and displayed conformant to RFC-5952 §4.
```
24 changes: 12 additions & 12 deletions command/operator_migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,23 +190,23 @@ func TestMigration(t *testing.T) {
cmd := new(OperatorMigrateCommand)
cfgName := filepath.Join(t.TempDir(), "migrator")
os.WriteFile(cfgName, []byte(`
storage_source "src_type" {
storage_source "consul" {
path = "src_path"
}
storage_destination "dest_type" {
storage_destination "raft" {
path = "dest_path"
}`), 0o644)

expCfg := &migratorConfig{
StorageSource: &server.Storage{
Type: "src_type",
Type: "consul",
Config: map[string]string{
"path": "src_path",
},
},
StorageDestination: &server.Storage{
Type: "dest_type",
Type: "raft",
Config: map[string]string{
"path": "dest_path",
},
Expand All @@ -230,41 +230,41 @@ storage_destination "dest_type" {

// missing source
verifyBad(`
storage_destination "dest_type" {
storage_destination "raft" {
path = "dest_path"
}`)

// missing destination
verifyBad(`
storage_source "src_type" {
storage_source "consul" {
path = "src_path"
}`)

// duplicate source
verifyBad(`
storage_source "src_type" {
storage_source "consul" {
path = "src_path"
}
storage_source "src_type2" {
storage_source "raft" {
path = "src_path"
}
storage_destination "dest_type" {
storage_destination "raft" {
path = "dest_path"
}`)

// duplicate destination
verifyBad(`
storage_source "src_type" {
storage_source "consul" {
path = "src_path"
}
storage_destination "dest_type" {
storage_destination "raft" {
path = "dest_path"
}
storage_destination "dest_type2" {
storage_destination "consul" {
path = "dest_path"
}`)
})
Expand Down
22 changes: 11 additions & 11 deletions command/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ func (c *ServerCommand) runRecoveryMode() int {
}
if config.Storage.Type == storageTypeRaft || (config.HAStorage != nil && config.HAStorage.Type == storageTypeRaft) {
if envCA := os.Getenv("VAULT_CLUSTER_ADDR"); envCA != "" {
config.ClusterAddr = envCA
config.ClusterAddr = configutil.NormalizeAddr(envCA)
}

if len(config.ClusterAddr) == 0 {
Expand Down Expand Up @@ -742,9 +742,9 @@ func (c *ServerCommand) runRecoveryMode() int {
func logProxyEnvironmentVariables(logger hclog.Logger) {
proxyCfg := httpproxy.FromEnvironment()
cfgMap := map[string]string{
"http_proxy": proxyCfg.HTTPProxy,
"https_proxy": proxyCfg.HTTPSProxy,
"no_proxy": proxyCfg.NoProxy,
"http_proxy": configutil.NormalizeAddr(proxyCfg.HTTPProxy),
"https_proxy": configutil.NormalizeAddr(proxyCfg.HTTPSProxy),
"no_proxy": configutil.NormalizeAddr(proxyCfg.NoProxy),
}
for k, v := range cfgMap {
u, err := url.Parse(v)
Expand Down Expand Up @@ -2243,7 +2243,7 @@ func (c *ServerCommand) detectRedirect(detect physical.RedirectDetect,
}

// Return the URL string
return url.String(), nil
return configutil.NormalizeAddr(url.String()), nil
}

func (c *ServerCommand) Reload(lock *sync.RWMutex, reloadFuncs *map[string][]reloadutil.ReloadFunc, configPath []string, core *vault.Core) error {
Expand Down Expand Up @@ -2749,11 +2749,11 @@ func initHaBackend(c *ServerCommand, config *server.Config, coreConfig *vault.Co
func determineRedirectAddr(c *ServerCommand, coreConfig *vault.CoreConfig, config *server.Config) error {
var retErr error
if envRA := os.Getenv("VAULT_API_ADDR"); envRA != "" {
coreConfig.RedirectAddr = envRA
coreConfig.RedirectAddr = configutil.NormalizeAddr(envRA)
} else if envRA := os.Getenv("VAULT_REDIRECT_ADDR"); envRA != "" {
coreConfig.RedirectAddr = envRA
coreConfig.RedirectAddr = configutil.NormalizeAddr(envRA)
} else if envAA := os.Getenv("VAULT_ADVERTISE_ADDR"); envAA != "" {
coreConfig.RedirectAddr = envAA
coreConfig.RedirectAddr = configutil.NormalizeAddr(envAA)
}

// Attempt to detect the redirect address, if possible
Expand Down Expand Up @@ -2785,7 +2785,7 @@ func determineRedirectAddr(c *ServerCommand, coreConfig *vault.CoreConfig, confi
if c.flagDevTLS {
protocol = "https"
}
coreConfig.RedirectAddr = fmt.Sprintf("%s://%s", protocol, config.Listeners[0].Address)
coreConfig.RedirectAddr = configutil.NormalizeAddr(fmt.Sprintf("%s://%s", protocol, config.Listeners[0].Address))
}
return retErr
}
Expand All @@ -2794,7 +2794,7 @@ func findClusterAddress(c *ServerCommand, coreConfig *vault.CoreConfig, config *
if disableClustering {
coreConfig.ClusterAddr = ""
} else if envCA := os.Getenv("VAULT_CLUSTER_ADDR"); envCA != "" {
coreConfig.ClusterAddr = envCA
coreConfig.ClusterAddr = configutil.NormalizeAddr(envCA)
} else {
var addrToUse string
switch {
Expand Down Expand Up @@ -2826,7 +2826,7 @@ func findClusterAddress(c *ServerCommand, coreConfig *vault.CoreConfig, config *
u.Host = net.JoinHostPort(host, strconv.Itoa(nPort+1))
// Will always be TLS-secured
u.Scheme = "https"
coreConfig.ClusterAddr = u.String()
coreConfig.ClusterAddr = configutil.NormalizeAddr(u.String())
}

CLUSTER_SYNTHESIS_COMPLETE:
Expand Down
Loading

0 comments on commit 012cd5a

Please sign in to comment.