backport of commit 4c1a7b53d362ee733707de2fa3280596e35d7f03 (#21609)
Co-authored-by: Bianca Moreira <48203644+biazmoreira@users.noreply.github.com>
This commit is contained in:
parent
d1e9b99233
commit
7e8c0a1cae
|
@ -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.
|
||||
```
|
|
@ -1432,6 +1432,9 @@ func (c *ServerCommand) Run(args []string) int {
|
|||
info["HCP resource ID"] = config.HCPLinkConf.Resource.ID
|
||||
}
|
||||
|
||||
infoKeys = append(infoKeys, "administrative namespace")
|
||||
info["administrative namespace"] = config.AdministrativeNamespacePath
|
||||
|
||||
sort.Strings(infoKeys)
|
||||
c.UI.Output("==> Vault server configuration:\n")
|
||||
|
||||
|
@ -2794,6 +2797,7 @@ func createCoreConfig(c *ServerCommand, config *server.Config, backend physical.
|
|||
LicensePath: config.LicensePath,
|
||||
DisableSSCTokens: config.DisableSSCTokens,
|
||||
Experiments: config.Experiments,
|
||||
AdministrativeNamespacePath: config.AdministrativeNamespacePath,
|
||||
}
|
||||
|
||||
if c.flagDev {
|
||||
|
|
|
@ -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.Experiments = mergeExperiments(c.Experiments, c2.Experiments)
|
||||
|
|
|
@ -64,6 +64,12 @@ func TestParseStorage(t *testing.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) {
|
||||
testUnknownFieldValidation(t)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
config, err := LoadConfigFile("./test-fixtures/config.hcl.json")
|
||||
if err != nil {
|
||||
|
@ -819,6 +841,7 @@ func testConfig_Sanitized(t *testing.T) {
|
|||
"num_lease_metrics_buckets": 168,
|
||||
"add_lease_metrics_namespace_labels": false,
|
||||
},
|
||||
"administrative_namespace_path": "admin/",
|
||||
}
|
||||
|
||||
addExpectedEntSanitizedConfig(expected, []string{"http"})
|
||||
|
|
|
@ -55,3 +55,4 @@ pid_file = "./pidfile"
|
|||
raw_storage_endpoint = true
|
||||
disable_sealwrap = true
|
||||
disable_sentinel_trace = true
|
||||
administrative_namespace_path = "admin/"
|
||||
|
|
|
@ -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/"
|
|
@ -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/"
|
||||
}
|
|
@ -173,7 +173,8 @@ func TestSysConfigState_Sanitized(t *testing.T) {
|
|||
"type": "tcp",
|
||||
},
|
||||
},
|
||||
"storage": tc.expectedStorageOutput,
|
||||
"storage": tc.expectedStorageOutput,
|
||||
"administrative_namespace_path": "",
|
||||
}
|
||||
|
||||
if tc.expectedHAStorageOutput != nil {
|
||||
|
|
|
@ -53,6 +53,8 @@ type SharedConfig struct {
|
|||
PidFile string `hcl:"pid_file"`
|
||||
|
||||
ClusterName string `hcl:"cluster_name"`
|
||||
|
||||
AdministrativeNamespacePath string `hcl:"administrative_namespace_path"`
|
||||
}
|
||||
|
||||
func ParseConfig(d string) (*SharedConfig, error) {
|
||||
|
@ -167,12 +169,13 @@ func (c *SharedConfig) Sanitized() map[string]interface{} {
|
|||
}
|
||||
|
||||
result := map[string]interface{}{
|
||||
"cluster_name": c.ClusterName,
|
||||
"default_max_request_duration": c.DefaultMaxRequestDuration,
|
||||
"disable_mlock": c.DisableMlock,
|
||||
"log_format": c.LogFormat,
|
||||
"log_level": c.LogLevel,
|
||||
"pid_file": c.PidFile,
|
||||
"default_max_request_duration": c.DefaultMaxRequestDuration,
|
||||
"disable_mlock": c.DisableMlock,
|
||||
"log_level": c.LogLevel,
|
||||
"log_format": c.LogFormat,
|
||||
"pid_file": c.PidFile,
|
||||
"cluster_name": c.ClusterName,
|
||||
"administrative_namespace_path": c.AdministrativeNamespacePath,
|
||||
}
|
||||
|
||||
// Optional log related settings
|
||||
|
|
|
@ -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["cluster_addr"] = `https://{{- GetAllInterfaces | exclude "flags" "loopback" | attr "address" -}}:8201`
|
||||
|
||||
vaultCfg["administrative_namespace_path"] = opts.AdministrativeNamespacePath
|
||||
|
||||
systemJSON, err := json.Marshal(vaultCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -90,15 +90,16 @@ type ClusterJson struct {
|
|||
}
|
||||
|
||||
type ClusterOptions struct {
|
||||
ClusterName string
|
||||
KeepStandbysSealed bool
|
||||
SkipInit bool
|
||||
CACert []byte
|
||||
NumCores int
|
||||
TmpDir string
|
||||
Logger hclog.Logger
|
||||
VaultNodeConfig *VaultNodeConfig
|
||||
VaultLicense string
|
||||
ClusterName string
|
||||
KeepStandbysSealed bool
|
||||
SkipInit bool
|
||||
CACert []byte
|
||||
NumCores int
|
||||
TmpDir string
|
||||
Logger hclog.Logger
|
||||
VaultNodeConfig *VaultNodeConfig
|
||||
VaultLicense string
|
||||
AdministrativeNamespacePath string
|
||||
}
|
||||
|
||||
type CA struct {
|
||||
|
|
|
@ -852,6 +852,10 @@ type CoreConfig struct {
|
|||
PendingRemovalMountsAllowed bool
|
||||
|
||||
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
|
||||
|
@ -1204,7 +1208,7 @@ func NewCore(conf *CoreConfig) (*Core, error) {
|
|||
c.AddLogger(identityLogger)
|
||||
return NewIdentityStore(ctx, c, config, identityLogger)
|
||||
}
|
||||
addExtraLogicalBackends(c, logicalBackends)
|
||||
addExtraLogicalBackends(c, logicalBackends, conf.AdministrativeNamespacePath)
|
||||
c.logicalBackends = logicalBackends
|
||||
|
||||
credentialBackends := make(map[string]logical.Factory)
|
||||
|
|
|
@ -81,7 +81,7 @@ func (c *Core) PersistUndoLogs() error { return nil }
|
|||
func (c *Core) teardownReplicationResolverHandler() {}
|
||||
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) {}
|
||||
|
||||
|
|
|
@ -1486,48 +1486,52 @@ func (b *SystemBackend) statusPaths() []*framework.Path {
|
|||
}
|
||||
}
|
||||
|
||||
func (b *SystemBackend) auditHashPath() *framework.Path {
|
||||
return &framework.Path{
|
||||
Pattern: "audit-hash/(?P<path>.+)",
|
||||
|
||||
DisplayAttrs: &framework.DisplayAttributes{
|
||||
OperationPrefix: "auditing",
|
||||
OperationVerb: "calculate",
|
||||
OperationSuffix: "hash",
|
||||
},
|
||||
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"path": {
|
||||
Type: framework.TypeString,
|
||||
Description: strings.TrimSpace(sysHelp["audit_path"][0]),
|
||||
},
|
||||
|
||||
"input": {
|
||||
Type: framework.TypeString,
|
||||
},
|
||||
},
|
||||
|
||||
Operations: map[logical.Operation]framework.OperationHandler{
|
||||
logical.UpdateOperation: &framework.PathOperation{
|
||||
Callback: b.handleAuditHash,
|
||||
Responses: map[int][]framework.Response{
|
||||
http.StatusOK: {{
|
||||
Description: "OK",
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"hash": {
|
||||
Type: framework.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
HelpSynopsis: strings.TrimSpace(sysHelp["audit-hash"][0]),
|
||||
HelpDescription: strings.TrimSpace(sysHelp["audit-hash"][1]),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SystemBackend) auditPaths() []*framework.Path {
|
||||
return []*framework.Path{
|
||||
{
|
||||
Pattern: "audit-hash/(?P<path>.+)",
|
||||
|
||||
DisplayAttrs: &framework.DisplayAttributes{
|
||||
OperationPrefix: "auditing",
|
||||
OperationVerb: "calculate",
|
||||
OperationSuffix: "hash",
|
||||
},
|
||||
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"path": {
|
||||
Type: framework.TypeString,
|
||||
Description: strings.TrimSpace(sysHelp["audit_path"][0]),
|
||||
},
|
||||
|
||||
"input": {
|
||||
Type: framework.TypeString,
|
||||
},
|
||||
},
|
||||
|
||||
Operations: map[logical.Operation]framework.OperationHandler{
|
||||
logical.UpdateOperation: &framework.PathOperation{
|
||||
Callback: b.handleAuditHash,
|
||||
Responses: map[int][]framework.Response{
|
||||
http.StatusOK: {{
|
||||
Description: "OK",
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"hash": {
|
||||
Type: framework.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
HelpSynopsis: strings.TrimSpace(sysHelp["audit-hash"][0]),
|
||||
HelpDescription: strings.TrimSpace(sysHelp["audit-hash"][1]),
|
||||
},
|
||||
b.auditHashPath(),
|
||||
|
||||
{
|
||||
Pattern: "audit$",
|
||||
|
|
|
@ -1702,6 +1702,7 @@ func (c *Core) newLogicalBackend(ctx context.Context, entry *MountEntry, sysView
|
|||
config.EventsSender = pluginEventSender
|
||||
}
|
||||
|
||||
ctx = namespace.ContextWithNamespace(ctx, entry.namespace)
|
||||
ctx = context.WithValue(ctx, "core_number", c.coreNumber)
|
||||
b, err := f(ctx, config)
|
||||
if err != nil {
|
||||
|
|
|
@ -219,6 +219,7 @@ func TestCoreWithSealAndUINoCleanup(t testing.T, opts *CoreConfig) *Core {
|
|||
conf.DetectDeadlocks = opts.DetectDeadlocks
|
||||
conf.Experiments = []string{experiments.VaultExperimentEventsAlpha1}
|
||||
conf.CensusAgent = opts.CensusAgent
|
||||
conf.AdministrativeNamespacePath = opts.AdministrativeNamespacePath
|
||||
|
||||
if opts.Logger != nil {
|
||||
conf.Logger = opts.Logger
|
||||
|
@ -1543,6 +1544,7 @@ func NewTestCluster(t testing.T, base *CoreConfig, opts *TestClusterOptions) *Te
|
|||
coreConfig.DisableSentinelTrace = base.DisableSentinelTrace
|
||||
coreConfig.ClusterName = base.ClusterName
|
||||
coreConfig.DisableAutopilot = base.DisableAutopilot
|
||||
coreConfig.AdministrativeNamespacePath = base.AdministrativeNamespacePath
|
||||
|
||||
if base.BuiltinRegistry != nil {
|
||||
coreConfig.BuiltinRegistry = base.BuiltinRegistry
|
||||
|
|
Loading…
Reference in New Issue