Add ability to migrate autoseal to autoseal (#5930)

* Add ability to migrate autoseal to autoseal

This adds the ability to migrate from shamir to autoseal, autoseal to
shamir, or autoseal to autoseal, by allowing multiple seal stanzas. A
disabled stanza will be used as the config being migrated from; this can
also be used to provide an unwrap seal on ent over multiple unseals.

A new test is added to ensure that autoseal to autoseal works as
expected.

* Fix test

* Provide default shamir info if not given in config

* Linting feedback

* Remove context var that isn't used

* Don't run auto unseal watcher when in migration, and move SetCores to SetSealsForMigration func

* Slight logic cleanup

* Fix test build and fix bug

* Updates

* remove GetRecoveryKey function
This commit is contained in:
Jeff Mitchell
2019-03-04 17:11:56 -05:00
committed by Brian Kassouf
parent facbc4cc60
commit 213da13264
13 changed files with 351 additions and 245 deletions

View File

@@ -6,7 +6,6 @@ import (
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/hashicorp/vault/helper/metricsutil"
"io"
"io/ioutil"
"net"
@@ -21,6 +20,8 @@ import (
"sync"
"time"
"github.com/hashicorp/vault/helper/metricsutil"
metrics "github.com/armon/go-metrics"
"github.com/armon/go-metrics/circonus"
"github.com/armon/go-metrics/datadog"
@@ -501,44 +502,61 @@ func (c *ServerCommand) Run(args []string) int {
info["log level"] = logLevelString
infoKeys = append(infoKeys, "log level")
sealType := vaultseal.Shamir
if config.Seal != nil || os.Getenv("VAULT_SEAL_TYPE") != "" {
if config.Seal == nil {
sealType = os.Getenv("VAULT_SEAL_TYPE")
} else {
sealType = config.Seal.Type
}
}
var barrierSeal vault.Seal
var unwrapSeal vault.Seal
var seal vault.Seal
var sealConfigError error
if c.flagDevAutoSeal {
seal = vault.NewAutoSeal(vaultseal.NewTestSeal(nil))
barrierSeal = vault.NewAutoSeal(vaultseal.NewTestSeal(nil))
} else {
sealLogger := c.logger.Named(sealType)
allLoggers = append(allLoggers, sealLogger)
seal, sealConfigError = serverseal.ConfigureSeal(config, &infoKeys, &info, sealLogger, vault.NewDefaultSeal())
if sealConfigError != nil {
if !errwrap.ContainsType(sealConfigError, new(logical.KeyNotFoundError)) {
// Handle the case where no seal is provided
if len(config.Seals) == 0 {
config.Seals = append(config.Seals, &server.Seal{Type: vaultseal.Shamir})
}
for _, configSeal := range config.Seals {
sealType := vaultseal.Shamir
if !configSeal.Disabled && os.Getenv("VAULT_SEAL_TYPE") != "" {
sealType = os.Getenv("VAULT_SEAL_TYPE")
} else {
sealType = configSeal.Type
}
var seal vault.Seal
sealLogger := c.logger.Named(sealType)
allLoggers = append(allLoggers, sealLogger)
seal, sealConfigError = serverseal.ConfigureSeal(configSeal, &infoKeys, &info, sealLogger, vault.NewDefaultSeal())
if sealConfigError != nil {
if !errwrap.ContainsType(sealConfigError, new(logical.KeyNotFoundError)) {
c.UI.Error(fmt.Sprintf(
"Error parsing Seal configuration: %s", sealConfigError))
return 1
}
}
if seal == nil {
c.UI.Error(fmt.Sprintf(
"Error parsing Seal configuration: %s", sealConfigError))
"After configuring seal nil returned, seal type was %s", sealType))
return 1
}
if configSeal.Disabled {
unwrapSeal = seal
} else {
barrierSeal = seal
}
// Ensure that the seal finalizer is called, even if using verify-only
defer func() {
err = seal.Finalize(context.Background())
if err != nil {
c.UI.Error(fmt.Sprintf("Error finalizing seals: %v", err))
}
}()
}
}
// Ensure that the seal finalizer is called, even if using verify-only
defer func() {
if seal != nil {
err = seal.Finalize(context.Background())
if err != nil {
c.UI.Error(fmt.Sprintf("Error finalizing seals: %v", err))
}
}
}()
if seal == nil {
c.UI.Error(fmt.Sprintf("Could not create seal! Most likely proper Seal configuration information was not set, but no error was generated."))
if barrierSeal == nil {
c.UI.Error(fmt.Sprintf("Could not create barrier seal! Most likely proper Seal configuration information was not set, but no error was generated."))
return 1
}
@@ -546,7 +564,7 @@ func (c *ServerCommand) Run(args []string) int {
Physical: backend,
RedirectAddr: config.Storage.RedirectAddr,
HAPhysical: nil,
Seal: seal,
Seal: barrierSeal,
AuditBackends: c.AuditBackends,
CredentialBackends: c.CredentialBackends,
LogicalBackends: c.LogicalBackends,
@@ -937,7 +955,7 @@ CLUSTER_SYNTHESIS_COMPLETE:
}))
// Before unsealing with stored keys, setup seal migration if needed
if err := adjustCoreForSealMigration(context.Background(), core, coreConfig, seal, config); err != nil {
if err := adjustCoreForSealMigration(core, barrierSeal, unwrapSeal); err != nil {
c.UI.Error(err.Error())
return 1
}
@@ -946,27 +964,29 @@ CLUSTER_SYNTHESIS_COMPLETE:
// Vault cluster with multiple servers is configured with auto-unseal but is
// uninitialized. Once one server initializes the storage backend, this
// goroutine will pick up the unseal keys and unseal this instance.
go func() {
for {
err := core.UnsealWithStoredKeys(context.Background())
if err == nil {
return
}
if !core.IsInSealMigration() {
go func() {
for {
err := core.UnsealWithStoredKeys(context.Background())
if err == nil {
return
}
if vault.IsFatalError(err) {
c.logger.Error("error unsealing core", "error", err)
return
} else {
c.logger.Warn("failed to unseal core", "error", err)
}
if vault.IsFatalError(err) {
c.logger.Error("error unsealing core", "error", err)
return
} else {
c.logger.Warn("failed to unseal core", "error", err)
}
select {
case <-c.ShutdownCh:
return
case <-time.After(5 * time.Second):
select {
case <-c.ShutdownCh:
return
case <-time.After(5 * time.Second):
}
}
}
}()
}()
}
// Perform service discovery registrations and initialization of
// HTTP server after the verifyOnly check.
@@ -1366,9 +1386,8 @@ func (c *ServerCommand) enableDev(core *vault.Core, coreConfig *vault.CoreConfig
return nil, err
}
// Upgrade the default K/V store
kvVer := "2"
if c.flagDevKVV1 {
if c.flagDevKVV1 || c.flagDevLeasedKV {
kvVer = "1"
}
req := &logical.Request{