package vault import ( "encoding/hex" "fmt" "github.com/hashicorp/vault/helper/pgpkeys" "github.com/hashicorp/vault/shamir" ) // InitResult is used to provide the key parts back after // they are generated as part of the initialization. type InitResult struct { SecretShares [][]byte RecoveryShares [][]byte RootToken string } // Initialized checks if the Vault is already initialized func (c *Core) Initialized() (bool, error) { // Check the barrier first init, err := c.barrier.Initialized() if err != nil { c.logger.Printf("[ERR] core: barrier init check failed: %v", err) return false, err } if !init { c.logger.Printf("[INFO] core: security barrier not initialized") return false, nil } // Verify the seal configuration sealConf, err := c.seal.BarrierConfig() if err != nil { return false, err } if sealConf == nil { return false, fmt.Errorf("[ERR] core: barrier reports initialized but no seal configuration found") } return true, nil } func (c *Core) generateShares(sc *SealConfig) ([]byte, [][]byte, error) { // Generate a master key masterKey, err := c.barrier.GenerateKey() if err != nil { return nil, nil, fmt.Errorf("key generation failed: %v", err) } // Return the master key if only a single key part is used var unsealKeys [][]byte if sc.SecretShares == 1 { unsealKeys = append(unsealKeys, masterKey) } else { // Split the master key using the Shamir algorithm shares, err := shamir.Split(masterKey, sc.SecretShares, sc.SecretThreshold) if err != nil { return nil, nil, fmt.Errorf("failed to generate shares: %v", err) } unsealKeys = shares } // If we have PGP keys, perform the encryption if len(sc.PGPKeys) > 0 { hexEncodedShares := make([][]byte, len(unsealKeys)) for i, _ := range unsealKeys { hexEncodedShares[i] = []byte(hex.EncodeToString(unsealKeys[i])) } _, encryptedShares, err := pgpkeys.EncryptShares(hexEncodedShares, sc.PGPKeys) if err != nil { return nil, nil, err } unsealKeys = encryptedShares } return masterKey, unsealKeys, nil } // Initialize is used to initialize the Vault with the given // configurations. func (c *Core) Initialize(barrierConfig, recoveryConfig *SealConfig) (*InitResult, error) { if c.seal.RecoveryKeySupported() { if recoveryConfig == nil { return nil, fmt.Errorf("recovery configuration must be supplied") } if recoveryConfig.SecretShares == 0 { return nil, fmt.Errorf("recovery configuration must specify a positive number of shares, or a negative number to disable") } if recoveryConfig.SecretShares > 0 { // Check if the seal configuraiton is valid if err := recoveryConfig.Validate(); err != nil { c.logger.Printf("[ERR] core: invalid recovery configuration: %v", err) return nil, fmt.Errorf("invalid recovery configuration: %v", err) } } } if c.seal.StoredKeysSupported() { if barrierConfig.SecretShares != 1 { return nil, fmt.Errorf("secret shares must be 1") } if barrierConfig.SecretThreshold != barrierConfig.SecretShares { return nil, fmt.Errorf("secret threshold must be same as secret shares") } if barrierConfig.StoredShares != barrierConfig.SecretShares { return nil, fmt.Errorf("stored shares must be same as secret shares") } if barrierConfig.PGPKeys != nil && len(barrierConfig.PGPKeys) > 0 { return nil, fmt.Errorf("PGP keys not supported when storing shares") } } else { if barrierConfig.StoredShares > 0 { return nil, fmt.Errorf("stored keys are not supported") } } // Check if the seal configuraiton is valid if err := barrierConfig.Validate(); err != nil { c.logger.Printf("[ERR] core: invalid seal configuration: %v", err) return nil, fmt.Errorf("invalid seal configuration: %v", err) } // Avoid an initialization race c.stateLock.Lock() defer c.stateLock.Unlock() // Check if we are initialized init, err := c.Initialized() if err != nil { return nil, err } if init { return nil, ErrAlreadyInit } err = c.seal.Init() if err != nil { c.logger.Printf("[ERR] core: failed to initialize seal: %v", err) return nil, fmt.Errorf("error initializing seal: %v", err) } err = c.seal.SetBarrierConfig(barrierConfig) if err != nil { c.logger.Printf("[ERR] core: failed to save barrier configuration: %v", err) return nil, fmt.Errorf("barrier configuration saving failed: %v", err) } barrierKey, barrierUnsealKeys, err := c.generateShares(barrierConfig) if err != nil { c.logger.Printf("[ERR] core: %v", err) return nil, err } // If we are storing shares, pop them out of the returned results and push // them through the seal if barrierConfig.StoredShares > 0 { var keysToStore [][]byte for i := 0; i < barrierConfig.StoredShares; i++ { keysToStore = append(keysToStore, barrierUnsealKeys[0]) barrierUnsealKeys = barrierUnsealKeys[1:] } if err := c.seal.SetStoredKeys(keysToStore); err != nil { c.logger.Printf("[ERR] core: failed to store keys: %v", err) return nil, fmt.Errorf("failed to store keys: %v", err) } } results := &InitResult{ SecretShares: barrierUnsealKeys, } // Save the configuration regardless, but only generate a key if it's not // disabled if c.seal.RecoveryKeySupported() { err = c.seal.SetRecoveryConfig(recoveryConfig) if err != nil { c.logger.Printf("[ERR] core: failed to save recovery configuration: %v", err) return nil, fmt.Errorf("recovery configuration saving failed: %v", err) } if recoveryConfig.SecretShares > 0 { recoveryKey, recoveryUnsealKeys, err := c.generateShares(recoveryConfig) if err != nil { c.logger.Printf("[ERR] core: %v", err) return nil, err } err = c.seal.SetRecoveryKey(recoveryKey) if err != nil { return nil, err } results.RecoveryShares = recoveryUnsealKeys } } // Initialize the barrier if err := c.barrier.Initialize(barrierKey); err != nil { c.logger.Printf("[ERR] core: failed to initialize barrier: %v", err) return nil, fmt.Errorf("failed to initialize barrier: %v", err) } c.logger.Printf("[INFO] core: security barrier initialized (shares: %d, threshold %d)", barrierConfig.SecretShares, barrierConfig.SecretThreshold) // Unseal the barrier if err := c.barrier.Unseal(barrierKey); err != nil { c.logger.Printf("[ERR] core: failed to unseal barrier: %v", err) return nil, fmt.Errorf("failed to unseal barrier: %v", err) } // Ensure the barrier is re-sealed defer func() { if err := c.barrier.Seal(); err != nil { c.logger.Printf("[ERR] core: failed to seal barrier: %v", err) } }() // Perform initial setup if err := c.postUnseal(); err != nil { c.logger.Printf("[ERR] core: post-unseal setup failed: %v", err) return nil, err } // Generate a new root token rootToken, err := c.tokenStore.rootToken() if err != nil { c.logger.Printf("[ERR] core: root token generation failed: %v", err) return nil, err } results.RootToken = rootToken.ID c.logger.Printf("[INFO] core: root token generated") // Prepare to re-seal if err := c.preSeal(); err != nil { c.logger.Printf("[ERR] core: pre-seal teardown failed: %v", err) return nil, err } return results, nil } func (c *Core) UnsealWithStoredKeys() error { if !c.seal.StoredKeysSupported() { return nil } sealed, err := c.Sealed() if err != nil { c.logger.Printf("[ERR] core: error checking sealed status in auto-unseal: %s", err) return fmt.Errorf("error checking sealed status in auto-unseal: %s", err) } if !sealed { return nil } c.logger.Printf("[INFO] core: stored unseal keys supported, attempting fetch") keys, err := c.seal.GetStoredKeys() if err != nil { c.logger.Printf("[ERR] core: fetching stored unseal keys failed: %v", err) return &NonFatalError{Err: fmt.Errorf("fetching stored unseal keys failed: %v", err)} } if len(keys) == 0 { c.logger.Printf("[WARN] core: stored unseal key(s) supported but none found") } else { unsealed := false keysUsed := 0 for _, key := range keys { unsealed, err = c.Unseal(key) if err != nil { c.logger.Printf("[ERR] core: unseal with stored unseal key failed: %v", err) return &NonFatalError{Err: fmt.Errorf("unseal with stored key failed: %v", err)} } keysUsed += 1 if unsealed { break } } if !unsealed { c.logger.Printf("[WARN] core: %d stored unseal key(s) used but Vault not unsealed yet", keysUsed) } else { c.logger.Printf("[INFO] core: successfully unsealed with %d stored key(s)", keysUsed) } } return nil }