mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-03 20:17:59 +00:00
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:
committed by
Brian Kassouf
parent
facbc4cc60
commit
213da13264
@@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
hclog "github.com/hashicorp/go-hclog"
|
hclog "github.com/hashicorp/go-hclog"
|
||||||
"github.com/hashicorp/vault/api"
|
"github.com/hashicorp/vault/api"
|
||||||
"github.com/hashicorp/vault/command/server"
|
|
||||||
"github.com/hashicorp/vault/helper/logging"
|
"github.com/hashicorp/vault/helper/logging"
|
||||||
vaulthttp "github.com/hashicorp/vault/http"
|
vaulthttp "github.com/hashicorp/vault/http"
|
||||||
"github.com/hashicorp/vault/physical"
|
"github.com/hashicorp/vault/physical"
|
||||||
@@ -114,11 +113,7 @@ func TestSealMigration(t *testing.T) {
|
|||||||
newSeal := vault.NewAutoSeal(seal.NewTestSeal(nil))
|
newSeal := vault.NewAutoSeal(seal.NewTestSeal(nil))
|
||||||
newSeal.SetCore(core)
|
newSeal.SetCore(core)
|
||||||
autoSeal = newSeal
|
autoSeal = newSeal
|
||||||
if err := adjustCoreForSealMigration(ctx, core, coreConfig, newSeal, &server.Config{
|
if err := adjustCoreForSealMigration(core, newSeal, nil); err != nil {
|
||||||
Seal: &server.Seal{
|
|
||||||
Type: "test-auto",
|
|
||||||
},
|
|
||||||
}); err != nil {
|
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,13 +192,16 @@ func TestSealMigration(t *testing.T) {
|
|||||||
cluster.Cores = nil
|
cluster.Cores = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should see stored barrier keys; after the next stanza, we shouldn't
|
// We should see stored barrier keys; after the sixth test, we shouldn't
|
||||||
if entry, err := phys.Get(ctx, vault.StoredBarrierKeysPath); err != nil || entry == nil {
|
if entry, err := phys.Get(ctx, vault.StoredBarrierKeysPath); err != nil || entry == nil {
|
||||||
t.Fatalf("expected nil error and non-nil entry, got error %#v and entry %#v", err, entry)
|
t.Fatalf("expected nil error and non-nil entry, got error %#v and entry %#v", err, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fifth: create an autoseal and activate migration. Verify it doesn't work
|
altTestSeal := seal.NewTestSeal(nil)
|
||||||
// if disabled isn't set.
|
altTestSeal.Type = "test-alternate"
|
||||||
|
altSeal := vault.NewAutoSeal(altTestSeal)
|
||||||
|
|
||||||
|
// Fifth: migrate from auto-seal to auto-seal
|
||||||
{
|
{
|
||||||
coreConfig.Seal = autoSeal
|
coreConfig.Seal = autoSeal
|
||||||
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
||||||
@@ -212,17 +210,45 @@ func TestSealMigration(t *testing.T) {
|
|||||||
|
|
||||||
core := cluster.Cores[0].Core
|
core := cluster.Cores[0].Core
|
||||||
|
|
||||||
serverConf := &server.Config{
|
if err := adjustCoreForSealMigration(core, altSeal, autoSeal); err != nil {
|
||||||
Seal: &server.Seal{
|
t.Fatal(err)
|
||||||
Type: "test-auto",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := adjustCoreForSealMigration(ctx, core, coreConfig, shamirSeal, serverConf); err == nil {
|
client := cluster.Cores[0].Client
|
||||||
t.Fatal("expected error since disabled isn't set true")
|
client.SetToken(rootToken)
|
||||||
|
|
||||||
|
var resp *api.SealStatusResponse
|
||||||
|
unsealOpts := &api.UnsealOpts{}
|
||||||
|
for _, key := range keys {
|
||||||
|
unsealOpts.Key = key
|
||||||
|
unsealOpts.Migrate = true
|
||||||
|
resp, err = client.Sys().UnsealWithOptions(unsealOpts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
serverConf.Seal.Disabled = true
|
if resp == nil {
|
||||||
if err := adjustCoreForSealMigration(ctx, core, coreConfig, shamirSeal, serverConf); err != nil {
|
t.Fatal("expected response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp.Sealed {
|
||||||
|
t.Fatalf("expected unsealed state; got %#v", *resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster.Cleanup()
|
||||||
|
cluster.Cores = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sixth: create an Shamir seal and activate migration. Verify it doesn't work
|
||||||
|
// if disabled isn't set.
|
||||||
|
{
|
||||||
|
coreConfig.Seal = altSeal
|
||||||
|
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
||||||
|
cluster.Start()
|
||||||
|
defer cluster.Cleanup()
|
||||||
|
|
||||||
|
core := cluster.Cores[0].Core
|
||||||
|
|
||||||
|
if err := adjustCoreForSealMigration(core, shamirSeal, altSeal); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +285,7 @@ func TestSealMigration(t *testing.T) {
|
|||||||
t.Fatalf("expected nil error and nil entry, got error %#v and entry %#v", err, entry)
|
t.Fatalf("expected nil error and nil entry, got error %#v and entry %#v", err, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sixth: verify autoseal is off and the expected key shares work
|
// Seventh: verify autoseal is off and the expected key shares work
|
||||||
{
|
{
|
||||||
coreConfig.Seal = shamirSeal
|
coreConfig.Seal = shamirSeal
|
||||||
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
cluster := vault.NewTestCluster(t, coreConfig, clusterConfig)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hashicorp/vault/helper/metricsutil"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
@@ -21,6 +20,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/helper/metricsutil"
|
||||||
|
|
||||||
metrics "github.com/armon/go-metrics"
|
metrics "github.com/armon/go-metrics"
|
||||||
"github.com/armon/go-metrics/circonus"
|
"github.com/armon/go-metrics/circonus"
|
||||||
"github.com/armon/go-metrics/datadog"
|
"github.com/armon/go-metrics/datadog"
|
||||||
@@ -501,23 +502,29 @@ func (c *ServerCommand) Run(args []string) int {
|
|||||||
info["log level"] = logLevelString
|
info["log level"] = logLevelString
|
||||||
infoKeys = append(infoKeys, "log level")
|
infoKeys = append(infoKeys, "log level")
|
||||||
|
|
||||||
|
var barrierSeal vault.Seal
|
||||||
|
var unwrapSeal vault.Seal
|
||||||
|
|
||||||
|
var sealConfigError error
|
||||||
|
if c.flagDevAutoSeal {
|
||||||
|
barrierSeal = vault.NewAutoSeal(vaultseal.NewTestSeal(nil))
|
||||||
|
} else {
|
||||||
|
// 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
|
sealType := vaultseal.Shamir
|
||||||
if config.Seal != nil || os.Getenv("VAULT_SEAL_TYPE") != "" {
|
if !configSeal.Disabled && os.Getenv("VAULT_SEAL_TYPE") != "" {
|
||||||
if config.Seal == nil {
|
|
||||||
sealType = os.Getenv("VAULT_SEAL_TYPE")
|
sealType = os.Getenv("VAULT_SEAL_TYPE")
|
||||||
} else {
|
} else {
|
||||||
sealType = config.Seal.Type
|
sealType = configSeal.Type
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var seal vault.Seal
|
var seal vault.Seal
|
||||||
var sealConfigError error
|
|
||||||
if c.flagDevAutoSeal {
|
|
||||||
seal = vault.NewAutoSeal(vaultseal.NewTestSeal(nil))
|
|
||||||
} else {
|
|
||||||
sealLogger := c.logger.Named(sealType)
|
sealLogger := c.logger.Named(sealType)
|
||||||
allLoggers = append(allLoggers, sealLogger)
|
allLoggers = append(allLoggers, sealLogger)
|
||||||
seal, sealConfigError = serverseal.ConfigureSeal(config, &infoKeys, &info, sealLogger, vault.NewDefaultSeal())
|
seal, sealConfigError = serverseal.ConfigureSeal(configSeal, &infoKeys, &info, sealLogger, vault.NewDefaultSeal())
|
||||||
if sealConfigError != nil {
|
if sealConfigError != nil {
|
||||||
if !errwrap.ContainsType(sealConfigError, new(logical.KeyNotFoundError)) {
|
if !errwrap.ContainsType(sealConfigError, new(logical.KeyNotFoundError)) {
|
||||||
c.UI.Error(fmt.Sprintf(
|
c.UI.Error(fmt.Sprintf(
|
||||||
@@ -525,20 +532,31 @@ func (c *ServerCommand) Run(args []string) int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if seal == nil {
|
||||||
|
c.UI.Error(fmt.Sprintf(
|
||||||
|
"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
|
// Ensure that the seal finalizer is called, even if using verify-only
|
||||||
defer func() {
|
defer func() {
|
||||||
if seal != nil {
|
|
||||||
err = seal.Finalize(context.Background())
|
err = seal.Finalize(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.UI.Error(fmt.Sprintf("Error finalizing seals: %v", err))
|
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
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,7 +564,7 @@ func (c *ServerCommand) Run(args []string) int {
|
|||||||
Physical: backend,
|
Physical: backend,
|
||||||
RedirectAddr: config.Storage.RedirectAddr,
|
RedirectAddr: config.Storage.RedirectAddr,
|
||||||
HAPhysical: nil,
|
HAPhysical: nil,
|
||||||
Seal: seal,
|
Seal: barrierSeal,
|
||||||
AuditBackends: c.AuditBackends,
|
AuditBackends: c.AuditBackends,
|
||||||
CredentialBackends: c.CredentialBackends,
|
CredentialBackends: c.CredentialBackends,
|
||||||
LogicalBackends: c.LogicalBackends,
|
LogicalBackends: c.LogicalBackends,
|
||||||
@@ -937,7 +955,7 @@ CLUSTER_SYNTHESIS_COMPLETE:
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
// Before unsealing with stored keys, setup seal migration if needed
|
// 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())
|
c.UI.Error(err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -946,6 +964,7 @@ CLUSTER_SYNTHESIS_COMPLETE:
|
|||||||
// Vault cluster with multiple servers is configured with auto-unseal but is
|
// Vault cluster with multiple servers is configured with auto-unseal but is
|
||||||
// uninitialized. Once one server initializes the storage backend, this
|
// uninitialized. Once one server initializes the storage backend, this
|
||||||
// goroutine will pick up the unseal keys and unseal this instance.
|
// goroutine will pick up the unseal keys and unseal this instance.
|
||||||
|
if !core.IsInSealMigration() {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
err := core.UnsealWithStoredKeys(context.Background())
|
err := core.UnsealWithStoredKeys(context.Background())
|
||||||
@@ -967,6 +986,7 @@ CLUSTER_SYNTHESIS_COMPLETE:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
// Perform service discovery registrations and initialization of
|
// Perform service discovery registrations and initialization of
|
||||||
// HTTP server after the verifyOnly check.
|
// HTTP server after the verifyOnly check.
|
||||||
@@ -1366,9 +1386,8 @@ func (c *ServerCommand) enableDev(core *vault.Core, coreConfig *vault.CoreConfig
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upgrade the default K/V store
|
|
||||||
kvVer := "2"
|
kvVer := "2"
|
||||||
if c.flagDevKVV1 {
|
if c.flagDevKVV1 || c.flagDevLeasedKV {
|
||||||
kvVer = "1"
|
kvVer = "1"
|
||||||
}
|
}
|
||||||
req := &logical.Request{
|
req := &logical.Request{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -29,7 +30,7 @@ type Config struct {
|
|||||||
Storage *Storage `hcl:"-"`
|
Storage *Storage `hcl:"-"`
|
||||||
HAStorage *Storage `hcl:"-"`
|
HAStorage *Storage `hcl:"-"`
|
||||||
|
|
||||||
Seal *Seal `hcl:"-"`
|
Seals []*Seal `hcl:"-"`
|
||||||
|
|
||||||
CacheSize int `hcl:"cache_size"`
|
CacheSize int `hcl:"cache_size"`
|
||||||
DisableCache bool `hcl:"-"`
|
DisableCache bool `hcl:"-"`
|
||||||
@@ -276,9 +277,11 @@ func (c *Config) Merge(c2 *Config) *Config {
|
|||||||
result.HAStorage = c2.HAStorage
|
result.HAStorage = c2.HAStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Seal = c.Seal
|
for _, s := range c.Seals {
|
||||||
if c2.Seal != nil {
|
result.Seals = append(result.Seals, s)
|
||||||
result.Seal = c2.Seal
|
}
|
||||||
|
for _, s := range c2.Seals {
|
||||||
|
result.Seals = append(result.Seals, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Telemetry = c.Telemetry
|
result.Telemetry = c.Telemetry
|
||||||
@@ -558,13 +561,13 @@ func ParseConfig(d string, logger log.Logger) (*Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if o := list.Filter("hsm"); len(o.Items) > 0 {
|
if o := list.Filter("hsm"); len(o.Items) > 0 {
|
||||||
if err := parseSeal(&result, o, "hsm"); err != nil {
|
if err := parseSeals(&result, o, "hsm"); err != nil {
|
||||||
return nil, errwrap.Wrapf("error parsing 'hsm': {{err}}", err)
|
return nil, errwrap.Wrapf("error parsing 'hsm': {{err}}", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if o := list.Filter("seal"); len(o.Items) > 0 {
|
if o := list.Filter("seal"); len(o.Items) > 0 {
|
||||||
if err := parseSeal(&result, o, "seal"); err != nil {
|
if err := parseSeals(&result, o, "seal"); err != nil {
|
||||||
return nil, errwrap.Wrapf("error parsing 'seal': {{err}}", err)
|
return nil, errwrap.Wrapf("error parsing 'seal': {{err}}", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -795,22 +798,21 @@ func parseHAStorage(result *Config, list *ast.ObjectList, name string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSeal(result *Config, list *ast.ObjectList, blockName string) error {
|
func parseSeals(result *Config, list *ast.ObjectList, blockName string) error {
|
||||||
if len(list.Items) > 1 {
|
if len(list.Items) > 2 {
|
||||||
return fmt.Errorf("only one %q block is permitted", blockName)
|
return fmt.Errorf("only two or less %q blocks are permitted", blockName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get our item
|
seals := make([]*Seal, 0, len(list.Items))
|
||||||
item := list.Items[0]
|
for _, item := range list.Items {
|
||||||
|
key := "seal"
|
||||||
key := blockName
|
|
||||||
if len(item.Keys) > 0 {
|
if len(item.Keys) > 0 {
|
||||||
key = item.Keys[0].Token.Value().(string)
|
key = item.Keys[0].Token.Value().(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
var m map[string]string
|
var m map[string]string
|
||||||
if err := hcl.DecodeObject(&m, item.Val); err != nil {
|
if err := hcl.DecodeObject(&m, item.Val); err != nil {
|
||||||
return multierror.Prefix(err, fmt.Sprintf("%s.%s:", blockName, key))
|
return multierror.Prefix(err, fmt.Sprintf("seal.%s:", key))
|
||||||
}
|
}
|
||||||
|
|
||||||
var disabled bool
|
var disabled bool
|
||||||
@@ -822,13 +824,20 @@ func parseSeal(result *Config, list *ast.ObjectList, blockName string) error {
|
|||||||
}
|
}
|
||||||
delete(m, "disabled")
|
delete(m, "disabled")
|
||||||
}
|
}
|
||||||
|
seals = append(seals, &Seal{
|
||||||
result.Seal = &Seal{
|
|
||||||
Type: strings.ToLower(key),
|
Type: strings.ToLower(key),
|
||||||
Disabled: disabled,
|
Disabled: disabled,
|
||||||
Config: m,
|
Config: m,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(seals) == 2 &&
|
||||||
|
(seals[0].Disabled && seals[1].Disabled || !seals[0].Disabled && !seals[1].Disabled) {
|
||||||
|
return errors.New("seals: two seals provided but both are disabled or neither are disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Seals = seals
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package seal
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
|
|
||||||
log "github.com/hashicorp/go-hclog"
|
log "github.com/hashicorp/go-hclog"
|
||||||
"github.com/hashicorp/vault/command/server"
|
"github.com/hashicorp/vault/command/server"
|
||||||
@@ -11,39 +10,33 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ConfigureSeal func(*server.Config, *[]string, *map[string]string, log.Logger, vault.Seal) (vault.Seal, error) = configureSeal
|
ConfigureSeal = configureSeal
|
||||||
)
|
)
|
||||||
|
|
||||||
func configureSeal(config *server.Config, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (outseal vault.Seal, err error) {
|
func configureSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (outseal vault.Seal, err error) {
|
||||||
if config.Seal != nil || os.Getenv("VAULT_SEAL_TYPE") != "" {
|
switch configSeal.Type {
|
||||||
if config.Seal == nil {
|
|
||||||
config.Seal = &server.Seal{
|
|
||||||
Type: os.Getenv("VAULT_SEAL_TYPE"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch config.Seal.Type {
|
|
||||||
case seal.AliCloudKMS:
|
case seal.AliCloudKMS:
|
||||||
return configureAliCloudKMSSeal(config, infoKeys, info, logger, inseal)
|
return configureAliCloudKMSSeal(configSeal, infoKeys, info, logger, inseal)
|
||||||
|
|
||||||
case seal.AWSKMS:
|
case seal.AWSKMS:
|
||||||
return configureAWSKMSSeal(config, infoKeys, info, logger, inseal)
|
return configureAWSKMSSeal(configSeal, infoKeys, info, logger, inseal)
|
||||||
|
|
||||||
case seal.GCPCKMS:
|
case seal.GCPCKMS:
|
||||||
return configureGCPCKMSSeal(config, infoKeys, info, logger, inseal)
|
return configureGCPCKMSSeal(configSeal, infoKeys, info, logger, inseal)
|
||||||
|
|
||||||
case seal.AzureKeyVault:
|
case seal.AzureKeyVault:
|
||||||
return configureAzureKeyVaultSeal(config, infoKeys, info, logger, inseal)
|
return configureAzureKeyVaultSeal(configSeal, infoKeys, info, logger, inseal)
|
||||||
|
|
||||||
case seal.Transit:
|
case seal.Transit:
|
||||||
return configureTransitSeal(config, infoKeys, info, logger, inseal)
|
return configureTransitSeal(configSeal, infoKeys, info, logger, inseal)
|
||||||
|
|
||||||
case seal.PKCS11:
|
case seal.PKCS11:
|
||||||
return nil, fmt.Errorf("Seal type 'pkcs11' requires the Vault Enterprise HSM binary")
|
return nil, fmt.Errorf("Seal type 'pkcs11' requires the Vault Enterprise HSM binary")
|
||||||
|
|
||||||
default:
|
case seal.Shamir:
|
||||||
return nil, fmt.Errorf("Unknown seal type %q", config.Seal.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return inseal, nil
|
return inseal, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Unknown seal type %q", configSeal.Type)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"github.com/hashicorp/vault/vault/seal/alicloudkms"
|
"github.com/hashicorp/vault/vault/seal/alicloudkms"
|
||||||
)
|
)
|
||||||
|
|
||||||
func configureAliCloudKMSSeal(config *server.Config, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) {
|
func configureAliCloudKMSSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) {
|
||||||
kms := alicloudkms.NewSeal(logger)
|
kms := alicloudkms.NewSeal(logger)
|
||||||
kmsInfo, err := kms.SetConfig(config.Seal.Config)
|
kmsInfo, err := kms.SetConfig(configSeal.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If the error is any other than logical.KeyNotFoundError, return the error
|
// If the error is any other than logical.KeyNotFoundError, return the error
|
||||||
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
||||||
@@ -21,7 +21,7 @@ func configureAliCloudKMSSeal(config *server.Config, infoKeys *[]string, info *m
|
|||||||
autoseal := vault.NewAutoSeal(kms)
|
autoseal := vault.NewAutoSeal(kms)
|
||||||
if kmsInfo != nil {
|
if kmsInfo != nil {
|
||||||
*infoKeys = append(*infoKeys, "Seal Type", "AliCloud KMS Region", "AliCloud KMS KeyID")
|
*infoKeys = append(*infoKeys, "Seal Type", "AliCloud KMS Region", "AliCloud KMS KeyID")
|
||||||
(*info)["Seal Type"] = config.Seal.Type
|
(*info)["Seal Type"] = configSeal.Type
|
||||||
(*info)["AliCloud KMS Region"] = kmsInfo["region"]
|
(*info)["AliCloud KMS Region"] = kmsInfo["region"]
|
||||||
(*info)["AliCloud KMS KeyID"] = kmsInfo["kms_key_id"]
|
(*info)["AliCloud KMS KeyID"] = kmsInfo["kms_key_id"]
|
||||||
if domain, ok := kmsInfo["domain"]; ok {
|
if domain, ok := kmsInfo["domain"]; ok {
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"github.com/hashicorp/vault/vault/seal/awskms"
|
"github.com/hashicorp/vault/vault/seal/awskms"
|
||||||
)
|
)
|
||||||
|
|
||||||
func configureAWSKMSSeal(config *server.Config, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) {
|
func configureAWSKMSSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) {
|
||||||
kms := awskms.NewSeal(logger)
|
kms := awskms.NewSeal(logger)
|
||||||
kmsInfo, err := kms.SetConfig(config.Seal.Config)
|
kmsInfo, err := kms.SetConfig(configSeal.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If the error is any other than logical.KeyNotFoundError, return the error
|
// If the error is any other than logical.KeyNotFoundError, return the error
|
||||||
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
||||||
@@ -21,7 +21,7 @@ func configureAWSKMSSeal(config *server.Config, infoKeys *[]string, info *map[st
|
|||||||
autoseal := vault.NewAutoSeal(kms)
|
autoseal := vault.NewAutoSeal(kms)
|
||||||
if kmsInfo != nil {
|
if kmsInfo != nil {
|
||||||
*infoKeys = append(*infoKeys, "Seal Type", "AWS KMS Region", "AWS KMS KeyID")
|
*infoKeys = append(*infoKeys, "Seal Type", "AWS KMS Region", "AWS KMS KeyID")
|
||||||
(*info)["Seal Type"] = config.Seal.Type
|
(*info)["Seal Type"] = configSeal.Type
|
||||||
(*info)["AWS KMS Region"] = kmsInfo["region"]
|
(*info)["AWS KMS Region"] = kmsInfo["region"]
|
||||||
(*info)["AWS KMS KeyID"] = kmsInfo["kms_key_id"]
|
(*info)["AWS KMS KeyID"] = kmsInfo["kms_key_id"]
|
||||||
if endpoint, ok := kmsInfo["endpoint"]; ok {
|
if endpoint, ok := kmsInfo["endpoint"]; ok {
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"github.com/hashicorp/vault/vault/seal/azurekeyvault"
|
"github.com/hashicorp/vault/vault/seal/azurekeyvault"
|
||||||
)
|
)
|
||||||
|
|
||||||
func configureAzureKeyVaultSeal(config *server.Config, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) {
|
func configureAzureKeyVaultSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) {
|
||||||
kv := azurekeyvault.NewSeal(logger)
|
kv := azurekeyvault.NewSeal(logger)
|
||||||
kvInfo, err := kv.SetConfig(config.Seal.Config)
|
kvInfo, err := kv.SetConfig(configSeal.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If the error is any other than logical.KeyNotFoundError, return the error
|
// If the error is any other than logical.KeyNotFoundError, return the error
|
||||||
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
||||||
@@ -21,7 +21,7 @@ func configureAzureKeyVaultSeal(config *server.Config, infoKeys *[]string, info
|
|||||||
autoseal := vault.NewAutoSeal(kv)
|
autoseal := vault.NewAutoSeal(kv)
|
||||||
if kvInfo != nil {
|
if kvInfo != nil {
|
||||||
*infoKeys = append(*infoKeys, "Seal Type", "Azure Environment", "Azure Vault Name", "Azure Key Name")
|
*infoKeys = append(*infoKeys, "Seal Type", "Azure Environment", "Azure Vault Name", "Azure Key Name")
|
||||||
(*info)["Seal Type"] = config.Seal.Type
|
(*info)["Seal Type"] = configSeal.Type
|
||||||
(*info)["Azure Environment"] = kvInfo["environment"]
|
(*info)["Azure Environment"] = kvInfo["environment"]
|
||||||
(*info)["Azure Vault Name"] = kvInfo["vault_name"]
|
(*info)["Azure Vault Name"] = kvInfo["vault_name"]
|
||||||
(*info)["Azure Key Name"] = kvInfo["key_name"]
|
(*info)["Azure Key Name"] = kvInfo["key_name"]
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"github.com/hashicorp/vault/vault/seal/gcpckms"
|
"github.com/hashicorp/vault/vault/seal/gcpckms"
|
||||||
)
|
)
|
||||||
|
|
||||||
func configureGCPCKMSSeal(config *server.Config, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) {
|
func configureGCPCKMSSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) {
|
||||||
kms := gcpckms.NewSeal(logger)
|
kms := gcpckms.NewSeal(logger)
|
||||||
kmsInfo, err := kms.SetConfig(config.Seal.Config)
|
kmsInfo, err := kms.SetConfig(configSeal.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If the error is any other than logical.KeyNotFoundError, return the error
|
// If the error is any other than logical.KeyNotFoundError, return the error
|
||||||
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
||||||
@@ -21,7 +21,7 @@ func configureGCPCKMSSeal(config *server.Config, infoKeys *[]string, info *map[s
|
|||||||
autoseal := vault.NewAutoSeal(kms)
|
autoseal := vault.NewAutoSeal(kms)
|
||||||
if kmsInfo != nil {
|
if kmsInfo != nil {
|
||||||
*infoKeys = append(*infoKeys, "Seal Type", "GCP KMS Project", "GCP KMS Region", "GCP KMS Key Ring", "GCP KMS Crypto Key")
|
*infoKeys = append(*infoKeys, "Seal Type", "GCP KMS Project", "GCP KMS Region", "GCP KMS Key Ring", "GCP KMS Crypto Key")
|
||||||
(*info)["Seal Type"] = config.Seal.Type
|
(*info)["Seal Type"] = configSeal.Type
|
||||||
(*info)["GCP KMS Project"] = kmsInfo["project"]
|
(*info)["GCP KMS Project"] = kmsInfo["project"]
|
||||||
(*info)["GCP KMS Region"] = kmsInfo["region"]
|
(*info)["GCP KMS Region"] = kmsInfo["region"]
|
||||||
(*info)["GCP KMS Key Ring"] = kmsInfo["key_ring"]
|
(*info)["GCP KMS Key Ring"] = kmsInfo["key_ring"]
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"github.com/hashicorp/vault/vault/seal/transit"
|
"github.com/hashicorp/vault/vault/seal/transit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func configureTransitSeal(config *server.Config, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) {
|
func configureTransitSeal(configSeal *server.Seal, infoKeys *[]string, info *map[string]string, logger log.Logger, inseal vault.Seal) (vault.Seal, error) {
|
||||||
transitSeal := transit.NewSeal(logger)
|
transitSeal := transit.NewSeal(logger)
|
||||||
sealInfo, err := transitSeal.SetConfig(config.Seal.Config)
|
sealInfo, err := transitSeal.SetConfig(configSeal.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If the error is any other than logical.KeyNotFoundError, return the error
|
// If the error is any other than logical.KeyNotFoundError, return the error
|
||||||
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
|
||||||
@@ -21,7 +21,7 @@ func configureTransitSeal(config *server.Config, infoKeys *[]string, info *map[s
|
|||||||
autoseal := vault.NewAutoSeal(transitSeal)
|
autoseal := vault.NewAutoSeal(transitSeal)
|
||||||
if sealInfo != nil {
|
if sealInfo != nil {
|
||||||
*infoKeys = append(*infoKeys, "Seal Type", "Transit Address", "Transit Mount Path", "Transit Key Name")
|
*infoKeys = append(*infoKeys, "Seal Type", "Transit Address", "Transit Mount Path", "Transit Key Name")
|
||||||
(*info)["Seal Type"] = config.Seal.Type
|
(*info)["Seal Type"] = configSeal.Type
|
||||||
(*info)["Transit Address"] = sealInfo["address"]
|
(*info)["Transit Address"] = sealInfo["address"]
|
||||||
(*info)["Transit Mount Path"] = sealInfo["mount_path"]
|
(*info)["Transit Mount Path"] = sealInfo["mount_path"]
|
||||||
(*info)["Transit Key Name"] = sealInfo["key_name"]
|
(*info)["Transit Key Name"] = sealInfo["key_name"]
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/command/server"
|
|
||||||
"github.com/hashicorp/vault/vault"
|
"github.com/hashicorp/vault/vault"
|
||||||
vaultseal "github.com/hashicorp/vault/vault/seal"
|
vaultseal "github.com/hashicorp/vault/vault/seal"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -14,27 +13,44 @@ var (
|
|||||||
onEnterprise = false
|
onEnterprise = false
|
||||||
)
|
)
|
||||||
|
|
||||||
func adjustCoreForSealMigration(ctx context.Context, core *vault.Core, coreConfig *vault.CoreConfig, seal vault.Seal, config *server.Config) error {
|
func adjustCoreForSealMigration(core *vault.Core, barrierSeal, unwrapSeal vault.Seal) error {
|
||||||
existBarrierSealConfig, existRecoverySealConfig, err := core.PhysicalSealConfigs(context.Background())
|
existBarrierSealConfig, existRecoverySealConfig, err := core.PhysicalSealConfigs(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error checking for existing seal: %s", err)
|
return fmt.Errorf("Error checking for existing seal: %s", err)
|
||||||
}
|
}
|
||||||
var existSeal vault.Seal
|
|
||||||
var newSeal vault.Seal
|
// If we don't have an existing config or if it's the deprecated auto seal
|
||||||
if existBarrierSealConfig != nil && existBarrierSealConfig.Type != vaultseal.HSMAutoDeprecated &&
|
// which needs an upgrade, skip out
|
||||||
(existBarrierSealConfig.Type != seal.BarrierType() ||
|
if existBarrierSealConfig == nil || existBarrierSealConfig.Type == vaultseal.HSMAutoDeprecated {
|
||||||
config.Seal != nil && config.Seal.Disabled) {
|
return nil
|
||||||
// If the existing seal is not Shamir, we're going to Shamir, which
|
|
||||||
// means we require them setting "disabled" to true in their
|
|
||||||
// configuration as a sanity check.
|
|
||||||
if (config.Seal == nil || !config.Seal.Disabled) && existBarrierSealConfig.Type != vaultseal.Shamir {
|
|
||||||
return errors.New(`Seal migration requires specifying "disabled" as "true" in the "seal" block of Vault's configuration file"`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conversely, if they are going from Shamir to auto, we want to
|
if unwrapSeal == nil {
|
||||||
// ensure disabled is *not* set
|
// We have the same barrier type and the unwrap seal is nil so we're not
|
||||||
if existBarrierSealConfig.Type == vaultseal.Shamir && config.Seal != nil && config.Seal.Disabled {
|
// migrating from same to same, IOW we assume it's not a migration
|
||||||
coreConfig.Logger.Warn(`when not migrating, Vault's config should not specify "disabled" as "true" in the "seal" block of Vault's configuration file`)
|
if existBarrierSealConfig.Type == barrierSeal.BarrierType() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're not coming from Shamir, and the existing type doesn't match
|
||||||
|
// the barrier type, we need both the migration seal and the new seal
|
||||||
|
if existBarrierSealConfig.Type != vaultseal.Shamir && barrierSeal.BarrierType() != vaultseal.Shamir {
|
||||||
|
return errors.New(`Trying to migrate from auto-seal to auto-seal but no "disabled" seal stanza found`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if unwrapSeal.BarrierType() == vaultseal.Shamir {
|
||||||
|
return errors.New("Shamir seals cannot be set disabled (they should simply not be set)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var existSeal vault.Seal
|
||||||
|
var newSeal vault.Seal
|
||||||
|
|
||||||
|
if existBarrierSealConfig.Type == barrierSeal.BarrierType() {
|
||||||
|
// In this case our migration seal is set so we are using it
|
||||||
|
// (potentially) for unwrapping. Set it on core for that purpose then
|
||||||
|
// exit.
|
||||||
|
core.SetSealsForMigration(nil, nil, unwrapSeal)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,8 +62,7 @@ func adjustCoreForSealMigration(ctx context.Context, core *vault.Core, coreConfi
|
|||||||
case vaultseal.Shamir:
|
case vaultseal.Shamir:
|
||||||
// The value reflected in config is what we're going to
|
// The value reflected in config is what we're going to
|
||||||
existSeal = vault.NewDefaultSeal()
|
existSeal = vault.NewDefaultSeal()
|
||||||
existSeal.SetCore(core)
|
newSeal = barrierSeal
|
||||||
newSeal = seal
|
|
||||||
newBarrierSealConfig := &vault.SealConfig{
|
newBarrierSealConfig := &vault.SealConfig{
|
||||||
Type: newSeal.BarrierType(),
|
Type: newSeal.BarrierType(),
|
||||||
SecretShares: 1,
|
SecretShares: 1,
|
||||||
@@ -58,19 +73,18 @@ func adjustCoreForSealMigration(ctx context.Context, core *vault.Core, coreConfi
|
|||||||
newSeal.SetCachedRecoveryConfig(existBarrierSealConfig)
|
newSeal.SetCachedRecoveryConfig(existBarrierSealConfig)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if onEnterprise {
|
if onEnterprise && barrierSeal.BarrierType() == vaultseal.Shamir {
|
||||||
return errors.New("Migrating from autoseal to Shamir seal is not supported on Vault Enterprise")
|
return errors.New("Migrating from autoseal to Shamir seal is not currently supported on Vault Enterprise")
|
||||||
}
|
}
|
||||||
|
|
||||||
// The disabled value reflected in config is what we're going from
|
// If we're not cominng from Shamir we expect the previous seal to be
|
||||||
existSeal = coreConfig.Seal
|
// in the config and disabled.
|
||||||
newSeal = vault.NewDefaultSeal()
|
existSeal = unwrapSeal
|
||||||
newSeal.SetCore(core)
|
newSeal = barrierSeal
|
||||||
newSeal.SetCachedBarrierConfig(existRecoverySealConfig)
|
newSeal.SetCachedBarrierConfig(existRecoverySealConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
core.SetSealsForMigration(existSeal, newSeal)
|
core.SetSealsForMigration(existSeal, newSeal, unwrapSeal)
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,6 +179,10 @@ type Core struct {
|
|||||||
// seal we're migrating *from*.
|
// seal we're migrating *from*.
|
||||||
migrationSeal Seal
|
migrationSeal Seal
|
||||||
|
|
||||||
|
// unwrapSeal is the seal to use on Enterprise to unwrap values wrapped
|
||||||
|
// with the previous seal.
|
||||||
|
unwrapSeal Seal
|
||||||
|
|
||||||
// barrier is the security barrier wrapping the physical backend
|
// barrier is the security barrier wrapping the physical backend
|
||||||
barrier SecurityBarrier
|
barrier SecurityBarrier
|
||||||
|
|
||||||
@@ -921,9 +925,12 @@ func (c *Core) unsealPart(ctx context.Context, seal Seal, key []byte, useRecover
|
|||||||
return nil, errwrap.Wrapf("unable to retrieve stored keys: {{err}}", err)
|
return nil, errwrap.Wrapf("unable to retrieve stored keys: {{err}}", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(masterKeyShares) == 1 {
|
switch len(masterKeyShares) {
|
||||||
|
case 0:
|
||||||
|
return nil, errors.New("seal returned no master key shares")
|
||||||
|
case 1:
|
||||||
masterKey = masterKeyShares[0]
|
masterKey = masterKeyShares[0]
|
||||||
} else {
|
default:
|
||||||
masterKey, err = shamir.Combine(masterKeyShares)
|
masterKey, err = shamir.Combine(masterKeyShares)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errwrap.Wrapf("failed to compute master key: {{err}}", err)
|
return nil, errwrap.Wrapf("failed to compute master key: {{err}}", err)
|
||||||
@@ -942,10 +949,50 @@ func (c *Core) unsealPart(ctx context.Context, seal Seal, key []byte, useRecover
|
|||||||
}
|
}
|
||||||
defer c.barrier.Seal()
|
defer c.barrier.Seal()
|
||||||
|
|
||||||
// The seal used in this function will have been the migration seal,
|
switch {
|
||||||
// and c.seal will be the opposite type, so there are two
|
case c.migrationSeal.RecoveryKeySupported() && c.seal.RecoveryKeySupported():
|
||||||
// possibilities: Shamir to auto, and auto to Shamir.
|
// Set the recovery and barrier keys to be the same.
|
||||||
if !seal.RecoveryKeySupported() {
|
recoveryKey, err := c.migrationSeal.RecoveryKey(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf("error getting recovery key to set on new seal: {{err}}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.seal.SetRecoveryKey(ctx, recoveryKey); err != nil {
|
||||||
|
return nil, errwrap.Wrapf("error setting new recovery key information during migrate: {{err}}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
barrierKeys, err := c.migrationSeal.GetStoredKeys(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf("error getting stored keys to set on new seal: {{err}}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.seal.SetStoredKeys(ctx, barrierKeys); err != nil {
|
||||||
|
return nil, errwrap.Wrapf("error setting new barrier key information during migrate: {{err}}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case c.migrationSeal.RecoveryKeySupported():
|
||||||
|
// Auto to Shamir, since recovery key isn't supported on new seal
|
||||||
|
|
||||||
|
// In this case we have to ensure that the recovery information was
|
||||||
|
// set properly.
|
||||||
|
if recoveryKey == nil {
|
||||||
|
return nil, errors.New("did not get expected recovery information to set new seal during migration")
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have recovery keys; we're going to use them as the new
|
||||||
|
// barrier key.
|
||||||
|
if err := c.barrier.Rekey(ctx, recoveryKey); err != nil {
|
||||||
|
return nil, errwrap.Wrapf("error rekeying barrier during migration: {{err}}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.barrier.Delete(ctx, StoredBarrierKeysPath); err != nil {
|
||||||
|
// Don't actually exit here as successful deletion isn't critical
|
||||||
|
c.logger.Error("error deleting stored barrier keys after migration; continuing anyways", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
masterKey = recoveryKey
|
||||||
|
|
||||||
|
case c.seal.RecoveryKeySupported():
|
||||||
// The new seal will have recovery keys; we set it to the existing
|
// The new seal will have recovery keys; we set it to the existing
|
||||||
// master key, so barrier key shares -> recovery key shares
|
// master key, so barrier key shares -> recovery key shares
|
||||||
if err := c.seal.SetRecoveryKey(ctx, masterKey); err != nil {
|
if err := c.seal.SetRecoveryKey(ctx, masterKey); err != nil {
|
||||||
@@ -970,25 +1017,9 @@ func (c *Core) unsealPart(ctx context.Context, seal Seal, key []byte, useRecover
|
|||||||
|
|
||||||
// Return the new key so it can be used to unlock the barrier
|
// Return the new key so it can be used to unlock the barrier
|
||||||
masterKey = newMasterKey
|
masterKey = newMasterKey
|
||||||
} else {
|
|
||||||
// In this case we have to ensure that the recovery information was
|
|
||||||
// set properly.
|
|
||||||
if recoveryKey == nil {
|
|
||||||
return nil, errors.New("did not get expected recovery information to set new seal during migration")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto to Shamir. We have recovery keys; we're going to use them
|
default:
|
||||||
// as the new barrier key
|
return nil, errors.New("unhandled migration case (shamir to shamir)")
|
||||||
if err := c.barrier.Rekey(ctx, recoveryKey); err != nil {
|
|
||||||
return nil, errwrap.Wrapf("error rekeying barrier during migration: {{err}}", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.barrier.Delete(ctx, StoredBarrierKeysPath); err != nil {
|
|
||||||
// Don't actually exit here as successful deletion isn't critical
|
|
||||||
c.logger.Error("error deleting stored barrier keys after migration; continuing anyways", "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
masterKey = recoveryKey
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point we've swapped things around and need to ensure we
|
// At this point we've swapped things around and need to ensure we
|
||||||
@@ -1700,12 +1731,20 @@ func (c *Core) PhysicalSealConfigs(ctx context.Context) (*SealConfig, *SealConfi
|
|||||||
return barrierConf, recoveryConf, nil
|
return barrierConf, recoveryConf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) SetSealsForMigration(migrationSeal, newSeal Seal) {
|
func (c *Core) SetSealsForMigration(migrationSeal, newSeal, unwrapSeal Seal) {
|
||||||
c.stateLock.Lock()
|
c.stateLock.Lock()
|
||||||
defer c.stateLock.Unlock()
|
defer c.stateLock.Unlock()
|
||||||
|
c.unwrapSeal = unwrapSeal
|
||||||
|
if c.unwrapSeal != nil {
|
||||||
|
c.unwrapSeal.SetCore(c)
|
||||||
|
}
|
||||||
|
if newSeal != nil && migrationSeal != nil {
|
||||||
c.migrationSeal = migrationSeal
|
c.migrationSeal = migrationSeal
|
||||||
|
c.migrationSeal.SetCore(c)
|
||||||
c.seal = newSeal
|
c.seal = newSeal
|
||||||
c.logger.Warn("entering seal migration mode; Vault will not automatically unseal even if using an autoseal")
|
c.seal.SetCore(c)
|
||||||
|
c.logger.Warn("entering seal migration mode; Vault will not automatically unseal even if using an autoseal", "from_barrier_type", c.migrationSeal.BarrierType(), "to_barrier_type", c.seal.BarrierType())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) IsInSealMigration() bool {
|
func (c *Core) IsInSealMigration() bool {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type TestSeal struct {
|
type TestSeal struct {
|
||||||
|
Type string
|
||||||
secret []byte
|
secret []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ var _ Access = (*TestSeal)(nil)
|
|||||||
|
|
||||||
func NewTestSeal(secret []byte) *TestSeal {
|
func NewTestSeal(secret []byte) *TestSeal {
|
||||||
return &TestSeal{
|
return &TestSeal{
|
||||||
|
Type: Test,
|
||||||
secret: secret,
|
secret: secret,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,7 +30,7 @@ func (t *TestSeal) Finalize(_ context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TestSeal) SealType() string {
|
func (t *TestSeal) SealType() string {
|
||||||
return Test
|
return t.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TestSeal) KeyID() string {
|
func (t *TestSeal) KeyID() string {
|
||||||
|
|||||||
@@ -303,30 +303,6 @@ func (d *autoSeal) RecoveryConfig(ctx context.Context) (*SealConfig, error) {
|
|||||||
return conf.Clone(), nil
|
return conf.Clone(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *autoSeal) RecoveryKey(ctx context.Context) ([]byte, error) {
|
|
||||||
pe, err := d.core.physical.Get(ctx, recoveryKeyPath)
|
|
||||||
if err != nil {
|
|
||||||
d.core.logger.Error("autoseal: failed to read recovery key", "error", err)
|
|
||||||
return nil, errwrap.Wrapf("failed to read recovery key: {{err}}", err)
|
|
||||||
}
|
|
||||||
if pe == nil {
|
|
||||||
d.core.logger.Warn("autoseal: no recovery key found")
|
|
||||||
return nil, fmt.Errorf("no recovery key found")
|
|
||||||
}
|
|
||||||
|
|
||||||
blobInfo := &physical.EncryptedBlobInfo{}
|
|
||||||
if err := proto.Unmarshal(pe.Value, blobInfo); err != nil {
|
|
||||||
return nil, errwrap.Wrapf("failed to proto decode recovery keys: {{err}}", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pt, err := d.Decrypt(ctx, blobInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errwrap.Wrapf("failed to decrypt encrypted recovery keys: {{err}}", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetRecoveryConfig writes the recovery configuration to the physical storage
|
// SetRecoveryConfig writes the recovery configuration to the physical storage
|
||||||
// and sets it as the seal's recoveryConfig.
|
// and sets it as the seal's recoveryConfig.
|
||||||
func (d *autoSeal) SetRecoveryConfig(ctx context.Context, conf *SealConfig) error {
|
func (d *autoSeal) SetRecoveryConfig(ctx context.Context, conf *SealConfig) error {
|
||||||
@@ -377,7 +353,7 @@ func (d *autoSeal) VerifyRecoveryKey(ctx context.Context, key []byte) error {
|
|||||||
return fmt.Errorf("recovery key to verify is nil")
|
return fmt.Errorf("recovery key to verify is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
pt, err := d.RecoveryKey(ctx)
|
pt, err := d.getRecoveryKeyInternal(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -422,6 +398,34 @@ func (d *autoSeal) SetRecoveryKey(ctx context.Context, key []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *autoSeal) RecoveryKey(ctx context.Context) ([]byte, error) {
|
||||||
|
return d.getRecoveryKeyInternal(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *autoSeal) getRecoveryKeyInternal(ctx context.Context) ([]byte, error) {
|
||||||
|
pe, err := d.core.physical.Get(ctx, recoveryKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
d.core.logger.Error("autoseal: failed to read recovery key", "error", err)
|
||||||
|
return nil, errwrap.Wrapf("failed to read recovery key: {{err}}", err)
|
||||||
|
}
|
||||||
|
if pe == nil {
|
||||||
|
d.core.logger.Warn("autoseal: no recovery key found")
|
||||||
|
return nil, fmt.Errorf("no recovery key found")
|
||||||
|
}
|
||||||
|
|
||||||
|
blobInfo := &physical.EncryptedBlobInfo{}
|
||||||
|
if err := proto.Unmarshal(pe.Value, blobInfo); err != nil {
|
||||||
|
return nil, errwrap.Wrapf("failed to proto decode stored keys: {{err}}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pt, err := d.Decrypt(ctx, blobInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf("failed to decrypt encrypted stored keys: {{err}}", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pt, nil
|
||||||
|
}
|
||||||
|
|
||||||
// migrateRecoveryConfig is a helper func to migrate the recovery config to
|
// migrateRecoveryConfig is a helper func to migrate the recovery config to
|
||||||
// live outside the barrier. This is called from SetRecoveryConfig which is
|
// live outside the barrier. This is called from SetRecoveryConfig which is
|
||||||
// always called with the stateLock.
|
// always called with the stateLock.
|
||||||
|
|||||||
Reference in New Issue
Block a user