diff --git a/changelog/26878.txt b/changelog/26878.txt new file mode 100644 index 0000000000..a8cfc57648 --- /dev/null +++ b/changelog/26878.txt @@ -0,0 +1,3 @@ +```release-note:bug +core/metrics: store cluster name in unencrypted storage to prevent blank cluster name +``` diff --git a/command/server.go b/command/server.go index dd3aea605b..c25f028543 100644 --- a/command/server.go +++ b/command/server.go @@ -1182,20 +1182,6 @@ func (c *ServerCommand) Run(args []string) int { "in a Docker container, provide the IPC_LOCK cap to the container.")) } - inmemMetrics, metricSink, prometheusEnabled, err := configutil.SetupTelemetry(&configutil.SetupTelemetryOpts{ - Config: config.Telemetry, - Ui: c.UI, - ServiceName: "vault", - DisplayName: "Vault", - UserAgent: useragent.String(), - ClusterName: config.ClusterName, - }) - if err != nil { - c.UI.Error(fmt.Sprintf("Error initializing telemetry: %s", err)) - return 1 - } - metricsHelper := metricsutil.NewMetricsHelper(inmemMetrics, prometheusEnabled) - // Initialize the storage backend var backend physical.Backend if !c.flagDev || config.Storage != nil { @@ -1211,6 +1197,27 @@ func (c *ServerCommand) Run(args []string) int { } } + clusterName := config.ClusterName + + // Attempt to retrieve cluster name from insecure storage + if clusterName == "" { + clusterName, err = c.readClusterNameFromInsecureStorage(backend) + } + + inmemMetrics, metricSink, prometheusEnabled, err := configutil.SetupTelemetry(&configutil.SetupTelemetryOpts{ + Config: config.Telemetry, + Ui: c.UI, + ServiceName: "vault", + DisplayName: "Vault", + UserAgent: useragent.String(), + ClusterName: clusterName, + }) + if err != nil { + c.UI.Error(fmt.Sprintf("Error initializing telemetry: %s", err)) + return 1 + } + metricsHelper := metricsutil.NewMetricsHelper(inmemMetrics, prometheusEnabled) + // Initialize the Service Discovery, if there is one var configSR sr.ServiceRegistration if config.ServiceRegistration != nil { @@ -3530,6 +3537,32 @@ func (c *ServerCommand) reloadSeals(ctx context.Context, grabStateLock bool, cor return true, nil } +// Attempt to read the cluster name from the insecure storage. +func (c *ServerCommand) readClusterNameFromInsecureStorage(b physical.Backend) (string, error) { + ctx := context.Background() + entry, err := b.Get(ctx, "core/cluster/local/name") + if err != nil { + return "", err + } + + var result map[string]interface{} + // Decode JSON data into the map + + if entry != nil { + if err := jsonutil.DecodeJSON(entry.Value, &result); err != nil { + return "", fmt.Errorf("failed to decode JSON data: %w", err) + } + } + + // Retrieve the value of the "name" field from the map + name, ok := result["name"].(string) + if !ok { + return "", fmt.Errorf("failed to extract name field from decoded JSON") + } + + return name, nil +} + func SetStorageMigration(b physical.Backend, active bool) error { if !active { return b.Delete(context.Background(), storageMigrationLock) diff --git a/vault/cluster.go b/vault/cluster.go index 903b36c5cf..67a7793558 100644 --- a/vault/cluster.go +++ b/vault/cluster.go @@ -23,12 +23,14 @@ import ( uuid "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/sdk/helper/jsonutil" "github.com/hashicorp/vault/sdk/logical" + "github.com/hashicorp/vault/sdk/physical" "github.com/hashicorp/vault/vault/cluster" ) const ( // Storage path where the local cluster name and identifier are stored coreLocalClusterInfoPath = "core/cluster/local/info" + coreLocalClusterNamePath = "core/cluster/local/name" corePrivateKeyTypeP521 = "p521" corePrivateKeyTypeED25519 = "ed25519" @@ -61,18 +63,30 @@ type Cluster struct { // when Vault is sealed. func (c *Core) Cluster(ctx context.Context) (*Cluster, error) { var cluster Cluster + var logicalEntry *logical.StorageEntry + var physicalEntry *physical.Entry // Fetch the storage entry. This call fails when Vault is sealed. - entry, err := c.barrier.Get(ctx, coreLocalClusterInfoPath) + logicalEntry, err := c.barrier.Get(ctx, coreLocalClusterInfoPath) if err != nil { - return nil, err + // Vault is sealed, pull cluster name from unencrypted storage + physicalEntry, err = c.physical.Get(ctx, coreLocalClusterNamePath) + if err != nil { + return nil, err + } } - if entry == nil { + if logicalEntry == nil && physicalEntry == nil { return &cluster, nil } // Decode the cluster information - if err = jsonutil.DecodeJSON(entry.Value, &cluster); err != nil { + var value []byte + if logicalEntry != nil { + value = logicalEntry.Value + } else { + value = physicalEntry.Value + } + if err = jsonutil.DecodeJSON(value, &cluster); err != nil { return nil, fmt.Errorf("failed to decode cluster details: %w", err) } @@ -162,6 +176,7 @@ func (c *Core) setupCluster(ctx context.Context) error { } var modified bool + var generatedClusterName bool if cluster == nil { cluster = &Cluster{} @@ -178,6 +193,7 @@ func (c *Core) setupCluster(ctx context.Context) error { } c.clusterName = fmt.Sprintf("vault-cluster-%08x", clusterNameBytes) + generatedClusterName = true } cluster.Name = c.clusterName @@ -270,7 +286,7 @@ func (c *Core) setupCluster(ctx context.Context) error { return err } - // Store it + // Store cluster information in logical storage err = c.barrier.Put(ctx, &logical.StorageEntry{ Key: coreLocalClusterInfoPath, Value: rawCluster, @@ -279,6 +295,32 @@ func (c *Core) setupCluster(ctx context.Context) error { c.logger.Error("failed to store cluster details", "error", err) return err } + + // Store only cluster name in physical storage, but only if name isn't provided in config + if generatedClusterName { + rawCluster, err = json.Marshal(&Cluster{Name: cluster.Name}) + if err != nil { + c.logger.Error("failed to marshal cluster name", "error", err) + return err + } + + err = c.physical.Put(ctx, &physical.Entry{ + Key: coreLocalClusterNamePath, + Value: rawCluster, + }) + if err != nil { + c.logger.Error("failed to store cluster name", "error", err) + return err + } + } else { + // check to ensure there is no entry at coreLocalClusterNamePath + err = c.physical.Delete(ctx, coreLocalClusterNamePath) + if err != nil { + c.logger.Error("failed to clear cluster name", "error", err) + return err + } + + } } c.clusterID.Store(cluster.ID)