diff --git a/vault/core.go b/vault/core.go index 5c58583cf..9c72c576e 100644 --- a/vault/core.go +++ b/vault/core.go @@ -1179,6 +1179,9 @@ func (c *Core) postUnseal() error { if err := c.barrier.ReloadKeyring(); err != nil { return err } + if err := c.scheduleUpgradeCleanup(); err != nil { + return err + } } if err := c.loadMounts(); err != nil { return err @@ -1387,6 +1390,32 @@ func (c *Core) checkKeyUpgrades() error { return nil } +// scheduleUpgradeCleanup is used to ensure that all the upgrade paths +// are cleaned up in a timely manner if a leader failover takes place +func (c *Core) scheduleUpgradeCleanup() error { + // List the upgrades + upgrades, err := c.barrier.List(keyringUpgradePrefix) + if err != nil { + return fmt.Errorf("failed to list upgrades: %v", err) + } + + // Nothing to do if no upgrades + if len(upgrades) == 0 { + return nil + } + + // Schedule cleanup for all of them + time.AfterFunc(keyRotateGracePeriod, func() { + for _, upgrade := range upgrades { + path := fmt.Sprintf("%s%s", keyringUpgradePrefix, upgrade) + if err := c.barrier.Delete(path); err != nil { + c.logger.Printf("[ERR] core: failed to cleanup upgrade: %s", path) + } + } + }) + return nil +} + // acquireLock blocks until the lock is acquired, returning the leaderCh func (c *Core) acquireLock(lock physical.Lock, stopCh <-chan struct{}) <-chan struct{} { for {