Add nonce to unseal to allow seeing if the operation has reset (#2276)

This commit is contained in:
Jeff Mitchell
2017-01-17 11:47:06 -05:00
committed by GitHub
parent f1c8b772fd
commit ac0f45e45c
7 changed files with 58 additions and 23 deletions

View File

@@ -53,6 +53,7 @@ type SealStatusResponse struct {
T int `json:"t"` T int `json:"t"`
N int `json:"n"` N int `json:"n"`
Progress int `json:"progress"` Progress int `json:"progress"`
Nonce string `json:"nonce"`
Version string `json:"version"` Version string `json:"version"`
ClusterName string `json:"cluster_name,omitempty"` ClusterName string `json:"cluster_name,omitempty"`
ClusterID string `json:"cluster_id,omitempty"` ClusterID string `json:"cluster_id,omitempty"`

View File

@@ -40,11 +40,13 @@ func (c *StatusCommand) Run(args []string) int {
"Key Shares: %d\n"+ "Key Shares: %d\n"+
"Key Threshold: %d\n"+ "Key Threshold: %d\n"+
"Unseal Progress: %d\n"+ "Unseal Progress: %d\n"+
"Unseal Nonce: %v"+
"Version: %s", "Version: %s",
sealStatus.Sealed, sealStatus.Sealed,
sealStatus.N, sealStatus.N,
sealStatus.T, sealStatus.T,
sealStatus.Progress, sealStatus.Progress,
sealStatus.Nonce,
sealStatus.Version) sealStatus.Version)
if sealStatus.ClusterName != "" && sealStatus.ClusterID != "" { if sealStatus.ClusterName != "" && sealStatus.ClusterID != "" {

View File

@@ -84,11 +84,13 @@ func (c *UnsealCommand) Run(args []string) int {
"Sealed: %v\n"+ "Sealed: %v\n"+
"Key Shares: %d\n"+ "Key Shares: %d\n"+
"Key Threshold: %d\n"+ "Key Threshold: %d\n"+
"Unseal Progress: %d", "Unseal Progress: %d\n"+
"Unseal Nonce: %v",
sealStatus.Sealed, sealStatus.Sealed,
sealStatus.N, sealStatus.N,
sealStatus.T, sealStatus.T,
sealStatus.Progress, sealStatus.Progress,
sealStatus.Nonce,
)) ))
return 0 return 0

View File

@@ -186,11 +186,14 @@ func handleSysSealStatusRaw(core *vault.Core, w http.ResponseWriter, r *http.Req
clusterID = cluster.ID clusterID = cluster.ID
} }
progress, nonce := core.SecretProgress()
respondOk(w, &SealStatusResponse{ respondOk(w, &SealStatusResponse{
Sealed: sealed, Sealed: sealed,
T: sealConfig.SecretThreshold, T: sealConfig.SecretThreshold,
N: sealConfig.SecretShares, N: sealConfig.SecretShares,
Progress: core.SecretProgress(), Progress: progress,
Nonce: nonce,
Version: version.GetVersion().VersionNumber(), Version: version.GetVersion().VersionNumber(),
ClusterName: clusterName, ClusterName: clusterName,
ClusterID: clusterID, ClusterID: clusterID,
@@ -202,6 +205,7 @@ type SealStatusResponse struct {
T int `json:"t"` T int `json:"t"`
N int `json:"n"` N int `json:"n"`
Progress int `json:"progress"` Progress int `json:"progress"`
Nonce string `json:"nonce"`
Version string `json:"version"` Version string `json:"version"`
ClusterName string `json:"cluster_name,omitempty"` ClusterName string `json:"cluster_name,omitempty"`
ClusterID string `json:"cluster_id,omitempty"` ClusterID string `json:"cluster_id,omitempty"`

View File

@@ -29,6 +29,7 @@ func TestSysSealStatus(t *testing.T) {
"t": json.Number("1"), "t": json.Number("1"),
"n": json.Number("1"), "n": json.Number("1"),
"progress": json.Number("0"), "progress": json.Number("0"),
"nonce": "",
} }
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
@@ -115,6 +116,7 @@ func TestSysUnseal(t *testing.T) {
"t": json.Number("1"), "t": json.Number("1"),
"n": json.Number("1"), "n": json.Number("1"),
"progress": json.Number("0"), "progress": json.Number("0"),
"nonce": "",
} }
testResponseStatus(t, resp, 200) testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual) testResponseBody(t, resp, &actual)
@@ -189,6 +191,10 @@ func TestSysUnseal_Reset(t *testing.T) {
t.Fatalf("expected version information") t.Fatalf("expected version information")
} }
expected["version"] = actual["version"] expected["version"] = actual["version"]
if actual["nonce"] == "" && expected["sealed"].(bool) {
t.Fatalf("expected a nonce")
}
expected["nonce"] = actual["nonce"]
if actual["cluster_name"] == nil { if actual["cluster_name"] == nil {
delete(expected, "cluster_name") delete(expected, "cluster_name")
} else { } else {
@@ -221,6 +227,7 @@ func TestSysUnseal_Reset(t *testing.T) {
t.Fatalf("expected version information") t.Fatalf("expected version information")
} }
expected["version"] = actual["version"] expected["version"] = actual["version"]
expected["nonce"] = actual["nonce"]
if actual["cluster_name"] == nil { if actual["cluster_name"] == nil {
delete(expected, "cluster_name") delete(expected, "cluster_name")
} else { } else {

View File

@@ -124,6 +124,11 @@ type activeAdvertisement struct {
ClusterKeyParams *clusterKeyParams `json:"cluster_key_params,omitempty"` ClusterKeyParams *clusterKeyParams `json:"cluster_key_params,omitempty"`
} }
type unlockInformation struct {
Parts [][]byte
Nonce string
}
// Core is used as the central manager of Vault activity. It is the primary point of // Core is used as the central manager of Vault activity. It is the primary point of
// interface for API handlers and is responsible for managing the logical and physical // interface for API handlers and is responsible for managing the logical and physical
// backends, router, security barrier, and audit trails. // backends, router, security barrier, and audit trails.
@@ -167,9 +172,8 @@ type Core struct {
standbyStopCh chan struct{} standbyStopCh chan struct{}
manualStepDownCh chan struct{} manualStepDownCh chan struct{}
// unlockParts has the keys provided to Unseal until // unlockInfo has the keys provided to Unseal until the threshold number of parts is available, as well as the operation nonce
// the threshold number of parts is available. unlockInfo *unlockInformation
unlockParts [][]byte
// generateRootProgress holds the shares until we reach enough // generateRootProgress holds the shares until we reach enough
// to verify the master key // to verify the master key
@@ -735,10 +739,15 @@ func (c *Core) Leader() (isLeader bool, leaderAddr string, err error) {
} }
// SecretProgress returns the number of keys provided so far // SecretProgress returns the number of keys provided so far
func (c *Core) SecretProgress() int { func (c *Core) SecretProgress() (int, string) {
c.stateLock.RLock() c.stateLock.RLock()
defer c.stateLock.RUnlock() defer c.stateLock.RUnlock()
return len(c.unlockParts) switch c.unlockInfo {
case nil:
return 0, ""
default:
return len(c.unlockInfo.Parts), c.unlockInfo.Nonce
}
} }
// ResetUnsealProcess removes the current unlock parts from memory, to reset // ResetUnsealProcess removes the current unlock parts from memory, to reset
@@ -749,7 +758,7 @@ func (c *Core) ResetUnsealProcess() {
if !c.sealed { if !c.sealed {
return return
} }
c.unlockParts = nil c.unlockInfo = nil
} }
// Unseal is used to provide one of the key parts to unseal the Vault. // Unseal is used to provide one of the key parts to unseal the Vault.
@@ -790,19 +799,29 @@ func (c *Core) Unseal(key []byte) (bool, error) {
} }
// Check if we already have this piece // Check if we already have this piece
for _, existing := range c.unlockParts { if c.unlockInfo != nil {
if bytes.Equal(existing, key) { for _, existing := range c.unlockInfo.Parts {
return false, nil if bytes.Equal(existing, key) {
return false, nil
}
}
} else {
uuid, err := uuid.GenerateUUID()
if err != nil {
return false, err
}
c.unlockInfo = &unlockInformation{
Nonce: uuid,
} }
} }
// Store this key // Store this key
c.unlockParts = append(c.unlockParts, key) c.unlockInfo.Parts = append(c.unlockInfo.Parts, key)
// Check if we don't have enough keys to unlock // Check if we don't have enough keys to unlock
if len(c.unlockParts) < config.SecretThreshold { if len(c.unlockInfo.Parts) < config.SecretThreshold {
if c.logger.IsDebug() { if c.logger.IsDebug() {
c.logger.Debug("core: cannot unseal, not enough keys", "keys", len(c.unlockParts), "threshold", config.SecretThreshold) c.logger.Debug("core: cannot unseal, not enough keys", "keys", len(c.unlockInfo.Parts), "threshold", config.SecretThreshold, "nonce", c.unlockInfo.Nonce)
} }
return false, nil return false, nil
} }
@@ -810,11 +829,11 @@ func (c *Core) Unseal(key []byte) (bool, error) {
// Recover the master key // Recover the master key
var masterKey []byte var masterKey []byte
if config.SecretThreshold == 1 { if config.SecretThreshold == 1 {
masterKey = c.unlockParts[0] masterKey = c.unlockInfo.Parts[0]
c.unlockParts = nil c.unlockInfo = nil
} else { } else {
masterKey, err = shamir.Combine(c.unlockParts) masterKey, err = shamir.Combine(c.unlockInfo.Parts)
c.unlockParts = nil c.unlockInfo = nil
if err != nil { if err != nil {
return false, fmt.Errorf("failed to compute master key: %v", err) return false, fmt.Errorf("failed to compute master key: %v", err)
} }

View File

@@ -72,7 +72,7 @@ func TestCore_Unseal_MultiShare(t *testing.T) {
t.Fatalf("should be sealed") t.Fatalf("should be sealed")
} }
if prog := c.SecretProgress(); prog != 0 { if prog, _ := c.SecretProgress(); prog != 0 {
t.Fatalf("bad progress: %d", prog) t.Fatalf("bad progress: %d", prog)
} }
@@ -91,14 +91,14 @@ func TestCore_Unseal_MultiShare(t *testing.T) {
if !unseal { if !unseal {
t.Fatalf("should be unsealed") t.Fatalf("should be unsealed")
} }
if prog := c.SecretProgress(); prog != 0 { if prog, _ := c.SecretProgress(); prog != 0 {
t.Fatalf("bad progress: %d", prog) t.Fatalf("bad progress: %d", prog)
} }
} else { } else {
if unseal { if unseal {
t.Fatalf("should not be unsealed") t.Fatalf("should not be unsealed")
} }
if prog := c.SecretProgress(); prog != i+1 { if prog, _ := c.SecretProgress(); prog != i+1 {
t.Fatalf("bad progress: %d", prog) t.Fatalf("bad progress: %d", prog)
} }
} }
@@ -160,7 +160,7 @@ func TestCore_Unseal_Single(t *testing.T) {
t.Fatalf("should be sealed") t.Fatalf("should be sealed")
} }
if prog := c.SecretProgress(); prog != 0 { if prog, _ := c.SecretProgress(); prog != 0 {
t.Fatalf("bad progress: %d", prog) t.Fatalf("bad progress: %d", prog)
} }
@@ -172,7 +172,7 @@ func TestCore_Unseal_Single(t *testing.T) {
if !unseal { if !unseal {
t.Fatalf("should be unsealed") t.Fatalf("should be unsealed")
} }
if prog := c.SecretProgress(); prog != 0 { if prog, _ := c.SecretProgress(); prog != 0 {
t.Fatalf("bad progress: %d", prog) t.Fatalf("bad progress: %d", prog)
} }