Skip to content

Commit

Permalink
Introduce isNonPatchUpdate to distinguish first-unseal-post-upgrade f…
Browse files Browse the repository at this point in the history
…or deprecations
  • Loading branch information
mpalmi committed Dec 6, 2022
1 parent 52790d3 commit 73da5df
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 22 deletions.
8 changes: 2 additions & 6 deletions vault/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -817,12 +817,8 @@ func (c *Core) setupCredentials(ctx context.Context) error {
// don't set the running version to a builtin if it is running as an external plugin
if externaler, ok := backend.(logical.Externaler); !ok || !externaler.IsExternal() {
entry.RunningVersion = versions.GetBuiltinVersion(consts.PluginTypeCredential, entry.Type)
if _, err := c.handleDeprecatedMountEntry(ctx, entry, consts.PluginTypeCredential); err != nil {
c.logger.Error("shutting down core", "error", err)
if shutdownErr := c.Shutdown(); shutdownErr != nil {
c.Logger().Error("failed to shutdown core", "error", shutdownErr)
}
return err
if _, err := c.handleDeprecatedMountEntry(ctx, entry, consts.PluginTypeCredential, isNonPatchUpdate); err != nil {
goto ROUTER_MOUNT
}
}
}
Expand Down
49 changes: 46 additions & 3 deletions vault/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/go-secure-stdlib/tlsutil"
"github.com/hashicorp/go-uuid"
semver "github.com/hashicorp/go-version"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/audit"
"github.com/hashicorp/vault/command/server"
Expand Down Expand Up @@ -101,6 +102,10 @@ const (
// undoLogsAreSafeStoragePath is a storage path that we write once we know undo logs are
// safe, so we don't have to keep checking all the time.
undoLogsAreSafeStoragePath = "core/raft/undo_logs_are_safe"

// lastMountedVersionKey is used to look up the last successfully mounted
// version of Vault from the Version store and cache
lastMountedVersionKey = "last_mounted"
)

var (
Expand Down Expand Up @@ -146,6 +151,7 @@ var (
LicenseInitCheck = func(*Core) error { return nil }
LicenseSummary = func(*Core) (*LicenseState, error) { return nil, nil }
LicenseReload = func(*Core) error { return nil }
isNonPatchUpdate = false
)

// NonFatalError is an error that can be returned during NewCore that should be
Expand Down Expand Up @@ -638,7 +644,9 @@ type Core struct {
// was first run. Note that because perf standbys should be upgraded first, and
// only the active node will actually write the new version timestamp, a perf
// standby shouldn't rely on the stored version timestamps being present.
versionHistory map[string]VaultVersion
versionHistory map[string]VaultVersion
currentVaultVersion *VaultVersion
latestMountedVersion *VaultVersion

// effectiveSDKVersion contains the SDK version that standby nodes should use when
// heartbeating with the active node. Default to the current SDK version.
Expand Down Expand Up @@ -1192,13 +1200,13 @@ func NewCore(conf *CoreConfig) (*Core, error) {
func (c *Core) handleVersionTimeStamps(ctx context.Context) error {
currentTime := time.Now().UTC()

vaultVersion := &VaultVersion{
c.currentVaultVersion = &VaultVersion{
TimestampInstalled: currentTime,
Version: version.Version,
BuildDate: version.BuildDate,
}

isUpdated, err := c.storeVersionEntry(ctx, vaultVersion, false)
isUpdated, err := c.storeVersionEntry(ctx, c.currentVaultVersion, false)
if err != nil {
return fmt.Errorf("error storing vault version: %w", err)
}
Expand All @@ -1210,6 +1218,36 @@ func (c *Core) handleVersionTimeStamps(ctx context.Context) error {
if err != nil {
return err
}

// Inform Vault of a non-patch (major or minor) version update for
// Deprecation handling purposes
if isUpdated {
lastMountedVersion, ok := c.versionHistory[lastMountedVersionKey]
if ok {
// Get versions into comparable form
curr, err := semver.NewSemver(c.currentVaultVersion.Version)
if err != nil {
return fmt.Errorf("could not determine update status: %w", err)
}
prev, err := semver.NewSemver(lastMountedVersion.Version)
if err != nil {
return fmt.Errorf("could not determine update status: %w", err)
}

// Check for major version upgrade
if curr.Segments()[0] > prev.Segments()[0] {
isNonPatchUpdate = true
}

// Check for minor version upgrade
if curr.Segments()[1] > prev.Segments()[1] {
isNonPatchUpdate = true
}
} else {
// First version in history, so technically an update
isNonPatchUpdate = true
}
}
return nil
}

Expand Down Expand Up @@ -2206,6 +2244,11 @@ func (s standardUnsealStrategy) unseal(ctx context.Context, logger log.Logger, c
if err := c.setupCredentials(ctx); err != nil {
return err
}
// After this point, we've mounted all deprecation-dependent mounts. We can
// store the current version as the latest upgrade version.
if err := c.storeMountedVersionEntry(ctx, c.currentVaultVersion); err != nil {
return err
}
if err := c.setupQuotas(ctx, false); err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions vault/logical_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -1188,7 +1188,7 @@ func (b *SystemBackend) handleMount(ctx context.Context, req *logical.Request, d
}

if b.Core.isMountEntryBuiltin(ctx, me, consts.PluginTypeSecrets) {
resp, err = b.Core.handleDeprecatedMountEntry(ctx, me, consts.PluginTypeSecrets)
resp, err = b.Core.handleDeprecatedMountEntry(ctx, me, consts.PluginTypeSecrets, false)
if err != nil {
return handleError(err)
}
Expand Down Expand Up @@ -2619,7 +2619,7 @@ func (b *SystemBackend) handleEnableAuth(ctx context.Context, req *logical.Reque

var resp *logical.Response
if b.Core.isMountEntryBuiltin(ctx, me, consts.PluginTypeCredential) {
resp, err = b.Core.handleDeprecatedMountEntry(ctx, me, consts.PluginTypeCredential)
resp, err = b.Core.handleDeprecatedMountEntry(ctx, me, consts.PluginTypeCredential, false)
if err != nil {
return handleError(err)
}
Expand Down
30 changes: 19 additions & 11 deletions vault/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,7 @@ func (c *Core) taintMountEntry(ctx context.Context, nsID, mountPath string, upda
// * PendingRemoval - log an error about builtin deprecation and return an error
// if VAULT_ALLOW_PENDING_REMOVAL_MOUNTS is unset
// * Removed - log an error about builtin deprecation and return an error
func (c *Core) handleDeprecatedMountEntry(ctx context.Context, entry *MountEntry, pluginType consts.PluginType) (*logical.Response, error) {
func (c *Core) handleDeprecatedMountEntry(ctx context.Context, entry *MountEntry, pluginType consts.PluginType, shutdownOnErr bool) (*logical.Response, error) {
resp := &logical.Response{}

if c.builtinRegistry == nil || entry == nil {
Expand Down Expand Up @@ -1006,10 +1006,23 @@ func (c *Core) handleDeprecatedMountEntry(ctx context.Context, entry *MountEntry
resp.AddWarning(errMountPendingRemoval.Error())
return resp, nil
}
return nil, fmt.Errorf("could not mount %q: %w", t, errMountPendingRemoval)

err := fmt.Errorf("could not mount %q: %w", t, errMountPendingRemoval)
if shutdownOnErr {
c.Logger().Error("shutting down core", "error", err)
if shutdownErr := c.Shutdown(); shutdownErr != nil {
c.Logger().Error("failed to shutdown core", "error", shutdownErr)
}
}
return nil, err
case consts.Removed:
return nil, fmt.Errorf("could not mount %s: %w", t, errMountRemoved)
err := fmt.Errorf("could not mount %q: %w", t, errMountRemoved)
if shutdownOnErr {
c.Logger().Error("shutting down core", "error", err)
if shutdownErr := c.Shutdown(); shutdownErr != nil {
c.Logger().Error("failed to shutdown core", "error", shutdownErr)
}
}
return nil, err
}
}
return nil, nil
Expand Down Expand Up @@ -1483,13 +1496,8 @@ func (c *Core) setupMounts(ctx context.Context) error {
// don't set the running version to a builtin if it is running as an external plugin
if externaler, ok := backend.(logical.Externaler); !ok || !externaler.IsExternal() {
entry.RunningVersion = versions.GetBuiltinVersion(consts.PluginTypeSecrets, entry.Type)
_, err := c.handleDeprecatedMountEntry(ctx, entry, consts.PluginTypeSecrets)
if err != nil {
c.logger.Error("shutting down core", "error", err)
if shutdownErr := c.Shutdown(); shutdownErr != nil {
c.Logger().Error("failed to shutdown core", "error", shutdownErr)
}
return err
if _, err := c.handleDeprecatedMountEntry(ctx, entry, consts.PluginTypeSecrets, isNonPatchUpdate); err != nil {
goto ROUTER_MOUNT
}
}
}
Expand Down
35 changes: 35 additions & 0 deletions vault/version_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,41 @@ func (c *Core) storeVersionEntry(ctx context.Context, vaultVersion *VaultVersion
return true, nil
}

/* LastMountedVaultVersion returns the cached value of the last
func (c *Core) LatestMountedVersionEntry(ctx context.Context) string {
latestMountedVersion, ok := c.versionHistory[lastMountedVersionKey]
if ok {
return latestMountedVersion.Version
}
return ""
}*/

// storeMountedVersionEntry writes the last version of Vault which successfully
// unsealed and mounted to the version store. This is useful for keeping track
// of handling of deprecated mounts. We should only update this after
// successfully unsealing and mounting all entries. Deprecated mounts will fail
// to unseal and will not record the Vaul version.
func (c *Core) storeMountedVersionEntry(ctx context.Context, vaultVersion *VaultVersion) error {
key := vaultVersionPath + lastMountedVersionKey
if vaultVersion.TimestampInstalled.Location() != time.UTC {
vaultVersion.TimestampInstalled = vaultVersion.TimestampInstalled.UTC()
}

marshalledVaultVersion, err := json.Marshal(vaultVersion)
if err != nil {
return err
}
newEntry := &logical.StorageEntry{
Key: key,
Value: marshalledVaultVersion,
}
if err := c.barrier.Put(ctx, newEntry); err != nil {
return fmt.Errorf("could not store latest mounted version: %w", err)
}
return nil
}

// FindOldestVersionTimestamp searches for the vault version with the oldest
// upgrade timestamp from storage. The earliest version this can be is 1.9.0.
func (c *Core) FindOldestVersionTimestamp() (string, time.Time, error) {
Expand Down

0 comments on commit 73da5df

Please sign in to comment.