backport of commit 4c1a7b53d362ee733707de2fa3280596e35d7f03 (#21609)

Co-authored-by: Bianca Moreira <48203644+biazmoreira@users.noreply.github.com>
This commit is contained in:
hc-github-team-secure-vault-core 2023-07-06 06:05:43 -04:00 committed by GitHub
parent d1e9b99233
commit 7e8c0a1cae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 166 additions and 58 deletions

4
changelog/21215.txt Normal file
View File

@ -0,0 +1,4 @@
```release-note:change
core/namespace (enterprise): Introduce the concept of high-privilege namespace (administrative namespace),
which will have access to some system backend paths that were previously only accessible in the root namespace.
```

View File

@ -1432,6 +1432,9 @@ func (c *ServerCommand) Run(args []string) int {
info["HCP resource ID"] = config.HCPLinkConf.Resource.ID info["HCP resource ID"] = config.HCPLinkConf.Resource.ID
} }
infoKeys = append(infoKeys, "administrative namespace")
info["administrative namespace"] = config.AdministrativeNamespacePath
sort.Strings(infoKeys) sort.Strings(infoKeys)
c.UI.Output("==> Vault server configuration:\n") c.UI.Output("==> Vault server configuration:\n")
@ -2794,6 +2797,7 @@ func createCoreConfig(c *ServerCommand, config *server.Config, backend physical.
LicensePath: config.LicensePath, LicensePath: config.LicensePath,
DisableSSCTokens: config.DisableSSCTokens, DisableSSCTokens: config.DisableSSCTokens,
Experiments: config.Experiments, Experiments: config.Experiments,
AdministrativeNamespacePath: config.AdministrativeNamespacePath,
} }
if c.flagDev { if c.flagDev {

View File

@ -447,6 +447,11 @@ func (c *Config) Merge(c2 *Config) *Config {
} }
} }
result.AdministrativeNamespacePath = c.AdministrativeNamespacePath
if c2.AdministrativeNamespacePath != "" {
result.AdministrativeNamespacePath = c2.AdministrativeNamespacePath
}
result.entConfig = c.entConfig.Merge(c2.entConfig) result.entConfig = c.entConfig.Merge(c2.entConfig)
result.Experiments = mergeExperiments(c.Experiments, c2.Experiments) result.Experiments = mergeExperiments(c.Experiments, c2.Experiments)

View File

@ -64,6 +64,12 @@ func TestParseStorage(t *testing.T) {
testParseStorageTemplate(t) testParseStorageTemplate(t)
} }
// TestConfigWithAdministrativeNamespace tests that .hcl and .json configurations are correctly parsed when the administrative_namespace_path is present.
func TestConfigWithAdministrativeNamespace(t *testing.T) {
testConfigWithAdministrativeNamespaceHcl(t)
testConfigWithAdministrativeNamespaceJson(t)
}
func TestUnknownFieldValidation(t *testing.T) { func TestUnknownFieldValidation(t *testing.T) {
testUnknownFieldValidation(t) testUnknownFieldValidation(t)
} }

View File

@ -572,6 +572,28 @@ func testUnknownFieldValidationHcl(t *testing.T) {
} }
} }
// testConfigWithAdministrativeNamespaceJson tests that a config with a valid administrative namespace path is correctly validated and loaded.
func testConfigWithAdministrativeNamespaceJson(t *testing.T) {
config, err := LoadConfigFile("./test-fixtures/config_with_valid_admin_ns.json")
require.NoError(t, err)
configErrors := config.Validate("./test-fixtures/config_with_valid_admin_ns.json")
require.Empty(t, configErrors)
require.NotEmpty(t, config.AdministrativeNamespacePath)
}
// testConfigWithAdministrativeNamespaceHcl tests that a config with a valid administrative namespace path is correctly validated and loaded.
func testConfigWithAdministrativeNamespaceHcl(t *testing.T) {
config, err := LoadConfigFile("./test-fixtures/config_with_valid_admin_ns.hcl")
require.NoError(t, err)
configErrors := config.Validate("./test-fixtures/config_with_valid_admin_ns.hcl")
require.Empty(t, configErrors)
require.NotEmpty(t, config.AdministrativeNamespacePath)
}
func testLoadConfigFile_json(t *testing.T) { func testLoadConfigFile_json(t *testing.T) {
config, err := LoadConfigFile("./test-fixtures/config.hcl.json") config, err := LoadConfigFile("./test-fixtures/config.hcl.json")
if err != nil { if err != nil {
@ -819,6 +841,7 @@ func testConfig_Sanitized(t *testing.T) {
"num_lease_metrics_buckets": 168, "num_lease_metrics_buckets": 168,
"add_lease_metrics_namespace_labels": false, "add_lease_metrics_namespace_labels": false,
}, },
"administrative_namespace_path": "admin/",
} }
addExpectedEntSanitizedConfig(expected, []string{"http"}) addExpectedEntSanitizedConfig(expected, []string{"http"})

View File

@ -55,3 +55,4 @@ pid_file = "./pidfile"
raw_storage_endpoint = true raw_storage_endpoint = true
disable_sealwrap = true disable_sealwrap = true
disable_sentinel_trace = true disable_sentinel_trace = true
administrative_namespace_path = "admin/"

View File

@ -0,0 +1,19 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0
storage "raft" {
path = "/path/to/raft"
node_id = "raft_node_1"
}
listener "tcp" {
address = "127.0.0.1:8200"
tls_cert_file = "/path/to/cert.pem"
tls_key_file = "/path/to/key.key"
}
seal "awskms" {
kms_key_id = "alias/kms-unseal-key"
}
service_registration "consul" {
address = "127.0.0.1:8500"
}
administrative_namespace_path = "admin/"

View File

@ -0,0 +1,28 @@
{
"listener": {
"tcp": {
"address": "0.0.0.0:8200",
"tls_cert_file": "/path/to/cert.pem",
"tls_key_file": "/path/to/key.key"
}
},
"seal": {
"awskms": {
"kms_key_id": "alias/kms-unseal-key"
}
},
"storage": {
"raft": {
"path": "/path/to/raft",
"node_id": "raft_node_1"
}
},
"cluster_addr": "http://127.0.0.1:8201",
"api_addr": "http://127.0.0.1:8200",
"service_registration": {
"consul": {
"address": "127.0.0.1:8500"
}
},
"administrative_namespace_path": "admin/"
}

View File

@ -174,6 +174,7 @@ func TestSysConfigState_Sanitized(t *testing.T) {
}, },
}, },
"storage": tc.expectedStorageOutput, "storage": tc.expectedStorageOutput,
"administrative_namespace_path": "",
} }
if tc.expectedHAStorageOutput != nil { if tc.expectedHAStorageOutput != nil {

View File

@ -53,6 +53,8 @@ type SharedConfig struct {
PidFile string `hcl:"pid_file"` PidFile string `hcl:"pid_file"`
ClusterName string `hcl:"cluster_name"` ClusterName string `hcl:"cluster_name"`
AdministrativeNamespacePath string `hcl:"administrative_namespace_path"`
} }
func ParseConfig(d string) (*SharedConfig, error) { func ParseConfig(d string) (*SharedConfig, error) {
@ -167,12 +169,13 @@ func (c *SharedConfig) Sanitized() map[string]interface{} {
} }
result := map[string]interface{}{ result := map[string]interface{}{
"cluster_name": c.ClusterName,
"default_max_request_duration": c.DefaultMaxRequestDuration, "default_max_request_duration": c.DefaultMaxRequestDuration,
"disable_mlock": c.DisableMlock, "disable_mlock": c.DisableMlock,
"log_format": c.LogFormat,
"log_level": c.LogLevel, "log_level": c.LogLevel,
"log_format": c.LogFormat,
"pid_file": c.PidFile, "pid_file": c.PidFile,
"cluster_name": c.ClusterName,
"administrative_namespace_path": c.AdministrativeNamespacePath,
} }
// Optional log related settings // Optional log related settings

View File

@ -609,6 +609,8 @@ func (n *DockerClusterNode) Start(ctx context.Context, opts *DockerClusterOption
vaultCfg["api_addr"] = `https://{{- GetAllInterfaces | exclude "flags" "loopback" | attr "address" -}}:8200` vaultCfg["api_addr"] = `https://{{- GetAllInterfaces | exclude "flags" "loopback" | attr "address" -}}:8200`
vaultCfg["cluster_addr"] = `https://{{- GetAllInterfaces | exclude "flags" "loopback" | attr "address" -}}:8201` vaultCfg["cluster_addr"] = `https://{{- GetAllInterfaces | exclude "flags" "loopback" | attr "address" -}}:8201`
vaultCfg["administrative_namespace_path"] = opts.AdministrativeNamespacePath
systemJSON, err := json.Marshal(vaultCfg) systemJSON, err := json.Marshal(vaultCfg)
if err != nil { if err != nil {
return err return err

View File

@ -99,6 +99,7 @@ type ClusterOptions struct {
Logger hclog.Logger Logger hclog.Logger
VaultNodeConfig *VaultNodeConfig VaultNodeConfig *VaultNodeConfig
VaultLicense string VaultLicense string
AdministrativeNamespacePath string
} }
type CA struct { type CA struct {

View File

@ -852,6 +852,10 @@ type CoreConfig struct {
PendingRemovalMountsAllowed bool PendingRemovalMountsAllowed bool
ExpirationRevokeRetryBase time.Duration ExpirationRevokeRetryBase time.Duration
// AdministrativeNamespacePath is used to configure the administrative namespace, which has access to some sys endpoints that are
// only accessible in the root namespace, currently sys/audit-hash and sys/monitor.
AdministrativeNamespacePath string
} }
// GetServiceRegistration returns the config's ServiceRegistration, or nil if it does // GetServiceRegistration returns the config's ServiceRegistration, or nil if it does
@ -1204,7 +1208,7 @@ func NewCore(conf *CoreConfig) (*Core, error) {
c.AddLogger(identityLogger) c.AddLogger(identityLogger)
return NewIdentityStore(ctx, c, config, identityLogger) return NewIdentityStore(ctx, c, config, identityLogger)
} }
addExtraLogicalBackends(c, logicalBackends) addExtraLogicalBackends(c, logicalBackends, conf.AdministrativeNamespacePath)
c.logicalBackends = logicalBackends c.logicalBackends = logicalBackends
credentialBackends := make(map[string]logical.Factory) credentialBackends := make(map[string]logical.Factory)

View File

@ -81,7 +81,7 @@ func (c *Core) PersistUndoLogs() error { return nil }
func (c *Core) teardownReplicationResolverHandler() {} func (c *Core) teardownReplicationResolverHandler() {}
func createSecondaries(*Core, *CoreConfig) {} func createSecondaries(*Core, *CoreConfig) {}
func addExtraLogicalBackends(*Core, map[string]logical.Factory) {} func addExtraLogicalBackends(*Core, map[string]logical.Factory, string) {}
func addExtraCredentialBackends(*Core, map[string]logical.Factory) {} func addExtraCredentialBackends(*Core, map[string]logical.Factory) {}

View File

@ -1486,9 +1486,8 @@ func (b *SystemBackend) statusPaths() []*framework.Path {
} }
} }
func (b *SystemBackend) auditPaths() []*framework.Path { func (b *SystemBackend) auditHashPath() *framework.Path {
return []*framework.Path{ return &framework.Path{
{
Pattern: "audit-hash/(?P<path>.+)", Pattern: "audit-hash/(?P<path>.+)",
DisplayAttrs: &framework.DisplayAttributes{ DisplayAttrs: &framework.DisplayAttributes{
@ -1527,7 +1526,12 @@ func (b *SystemBackend) auditPaths() []*framework.Path {
HelpSynopsis: strings.TrimSpace(sysHelp["audit-hash"][0]), HelpSynopsis: strings.TrimSpace(sysHelp["audit-hash"][0]),
HelpDescription: strings.TrimSpace(sysHelp["audit-hash"][1]), HelpDescription: strings.TrimSpace(sysHelp["audit-hash"][1]),
}, }
}
func (b *SystemBackend) auditPaths() []*framework.Path {
return []*framework.Path{
b.auditHashPath(),
{ {
Pattern: "audit$", Pattern: "audit$",

View File

@ -1702,6 +1702,7 @@ func (c *Core) newLogicalBackend(ctx context.Context, entry *MountEntry, sysView
config.EventsSender = pluginEventSender config.EventsSender = pluginEventSender
} }
ctx = namespace.ContextWithNamespace(ctx, entry.namespace)
ctx = context.WithValue(ctx, "core_number", c.coreNumber) ctx = context.WithValue(ctx, "core_number", c.coreNumber)
b, err := f(ctx, config) b, err := f(ctx, config)
if err != nil { if err != nil {

View File

@ -219,6 +219,7 @@ func TestCoreWithSealAndUINoCleanup(t testing.T, opts *CoreConfig) *Core {
conf.DetectDeadlocks = opts.DetectDeadlocks conf.DetectDeadlocks = opts.DetectDeadlocks
conf.Experiments = []string{experiments.VaultExperimentEventsAlpha1} conf.Experiments = []string{experiments.VaultExperimentEventsAlpha1}
conf.CensusAgent = opts.CensusAgent conf.CensusAgent = opts.CensusAgent
conf.AdministrativeNamespacePath = opts.AdministrativeNamespacePath
if opts.Logger != nil { if opts.Logger != nil {
conf.Logger = opts.Logger conf.Logger = opts.Logger
@ -1543,6 +1544,7 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te
coreConfig.DisableSentinelTrace = base.DisableSentinelTrace coreConfig.DisableSentinelTrace = base.DisableSentinelTrace
coreConfig.ClusterName = base.ClusterName coreConfig.ClusterName = base.ClusterName
coreConfig.DisableAutopilot = base.DisableAutopilot coreConfig.DisableAutopilot = base.DisableAutopilot
coreConfig.AdministrativeNamespacePath = base.AdministrativeNamespacePath
if base.BuiltinRegistry != nil { if base.BuiltinRegistry != nil {
coreConfig.BuiltinRegistry = base.BuiltinRegistry coreConfig.BuiltinRegistry = base.BuiltinRegistry