Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Track barrier encryptions and rotate when an operation threshold or time limit is reached. #10774

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
08f260d
wip
sgmiller Jan 21, 2021
2bee1bf
Add a barrier stanza, with options for configuring automatic barrier …
sgmiller Jan 22, 2021
f5fd587
Track and persist local encryptions
sgmiller Jan 22, 2021
a1da4ab
wip
sgmiller Jan 25, 2021
18d8425
Merge remote-tracking branch 'origin/master' into barrier_aes_encrypt…
sgmiller Jan 25, 2021
ab32e7e
Basic unit tests
sgmiller Jan 25, 2021
6f6e482
Add a unit test around encryption count persistence
sgmiller Jan 25, 2021
fced04f
Documentation
sgmiller Jan 26, 2021
34e78e4
Merge remote-tracking branch 'origin/master' into barrier_aes_rotatio…
sgmiller Jan 26, 2021
19f100f
Switch to storing config in persistence via API rather than Vault hcl
sgmiller Jan 26, 2021
174ad75
Store rotation config in the keyring, and update via sys/rotate/config
sgmiller Jan 27, 2021
4ebcee4
Remove cruft
sgmiller Jan 27, 2021
3437ce2
Remove more cruft
sgmiller Jan 27, 2021
9110e92
remove docs cruft
sgmiller Jan 27, 2021
1c3a650
Merge branch 'barrier_aes_rotation_config' into barrier_aes_encryptio…
sgmiller Jan 28, 2021
7e2083c
Fix merge errors
sgmiller Jan 28, 2021
d23b32d
Address review feedback
sgmiller Feb 1, 2021
9779f47
Merge branch 'barrier_aes_rotation_config' into barrier_aes_encryptio…
sgmiller Feb 1, 2021
5680128
Merge remote-tracking branch 'origin/master' into barrier_aes_encrypt…
sgmiller Feb 1, 2021
71bdd0d
Bring ENT changes over to OSS
sgmiller Feb 1, 2021
dddbddc
Cleanup Check function signature/usage
sgmiller Feb 1, 2021
579acb6
unused import
sgmiller Feb 1, 2021
bfb620f
Fix unit tests
sgmiller Feb 1, 2021
2c81acd
Expose encryption counts to key status
sgmiller Feb 1, 2021
59b470a
Add to the CLI output
sgmiller Feb 1, 2021
af177c5
Add local encryptions to key status to facilitate unit testing
sgmiller Feb 2, 2021
d2cf5d9
Skip the rotation check if the keyring isn't yet initialized. This c…
sgmiller Feb 2, 2021
ee942a4
Wire local_encryptions
sgmiller Feb 2, 2021
cfd6bfd
Only add to totalLocalEncryptions via encryptTracked
sgmiller Feb 2, 2021
07330dd
Add a new method to the request forwarding client for barrier enc tra…
sgmiller Feb 2, 2021
10faee7
Sync OSS portions of enc tracking back
sgmiller Feb 4, 2021
5d239b7
Cleanup
sgmiller Feb 4, 2021
53a3a0a
Add stubs
sgmiller Feb 4, 2021
9aed87c
Fix some affected unit tests, remove more debugging
sgmiller Feb 4, 2021
8ddac03
Fix sys_rotate better
sgmiller Feb 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions api/sys_rotate.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,41 @@ func (c *Sys) KeyStatus() (*KeyStatus, error) {
}
result.InstallTime = installTime

encryptionsRaw, ok := secret.Data["encryptions"]
if !ok {
return nil, errors.New("encryptions not found in response")
}
encryptions, ok := encryptionsRaw.(json.Number)
if !ok {
return nil, errors.New("could not convert encryptions to a number")
}
encryptions64, err := encryptions.Int64()
if err != nil {
return nil, err
}
result.Encryptions = int(encryptions64)

localEncryptionsRaw, ok := secret.Data["local_encryptions"]
if !ok {
return nil, errors.New("local encryptions not found in response")
}
localEncryptions, ok := localEncryptionsRaw.(json.Number)
if !ok {
return nil, errors.New("could not convert local_encryptions to a number")
}

localEncryptions64, err := localEncryptions.Int64()
if err != nil {
return nil, err
}
result.LocalEncryptions = int(localEncryptions64)

return &result, err
}

type KeyStatus struct {
Term int `json:"term"`
InstallTime time.Time `json:"install_time"`
Term int `json:"term"`
InstallTime time.Time `json:"install_time"`
Encryptions int `json:"encryptions"`
LocalEncryptions int `json:"local_encryptions"`
}
1 change: 1 addition & 0 deletions command/base_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ func printKeyStatus(ks *api.KeyStatus) string {
return columnOutput([]string{
fmt.Sprintf("Key Term | %d", ks.Term),
fmt.Sprintf("Install Time | %s", ks.InstallTime.UTC().Format(time.RFC822)),
fmt.Sprintf("Encryption Count | %d", ks.Encryptions),
}, nil)
}

Expand Down
13 changes: 7 additions & 6 deletions http/sys_rotate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,16 @@ func TestSysRotate(t *testing.T) {
testResponseStatus(t, resp, 200)
testResponseBody(t, resp, &actual)

actualInstallTime, ok := actual["data"].(map[string]interface{})["install_time"]
if !ok || actualInstallTime == "" {
t.Fatal("install_time missing in data")
for _, field := range []string{"install_time", "encryptions", "local_encryptions"} {
actualVal, ok := actual["data"].(map[string]interface{})[field]
if !ok || actualVal == "" {
t.Fatal(field, " missing in data")
}
expected["data"].(map[string]interface{})[field] = actualVal
expected[field] = actualVal
}
expected["data"].(map[string]interface{})["install_time"] = actualInstallTime
expected["install_time"] = actualInstallTime

expected["request_id"] = actual["request_id"]

if diff := deep.Equal(actual, expected); diff != nil {
t.Fatal(diff)
}
Expand Down
29 changes: 29 additions & 0 deletions internalshared/configutil/barrier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package configutil

import (
"time"
)

// 10% shy of the NIST recommended maximum, leaving a buffer to account for
// tracking losses.
const AbsoluteOperationMaximum = int64(3865470566)

var DefaultRotationConfig = KeyRotationConfig{
MaxOperations: AbsoluteOperationMaximum,
}

type KeyRotationConfig struct {
MaxOperations int64
Interval time.Duration
nextRotation time.Time
}

func (c *KeyRotationConfig) Sanitize() {
if c.MaxOperations == 0 || c.MaxOperations > AbsoluteOperationMaximum {
c.MaxOperations = AbsoluteOperationMaximum
}
}

func (c *KeyRotationConfig) Equals(config KeyRotationConfig) bool {
return c.MaxOperations == config.MaxOperations && c.Interval == config.Interval
}
2 changes: 1 addition & 1 deletion vault/activity/activity_log.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 21 additions & 2 deletions vault/barrier.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io"
"time"

"github.com/hashicorp/vault/internalshared/configutil"
"github.com/hashicorp/vault/sdk/logical"
)

Expand Down Expand Up @@ -136,12 +137,28 @@ type SecurityBarrier interface {
// ActiveKeyInfo is used to inform details about the active key
ActiveKeyInfo() (*KeyInfo, error)

// RotationConfig returns the auto-rotation config for the barrier key
RotationConfig() (configutil.KeyRotationConfig, error)

// SetRotationConfig updates the auto-rotation config for the barrier key
SetRotationConfig(ctx context.Context, config configutil.KeyRotationConfig) error

// Rekey is used to change the master key used to protect the keyring
Rekey(context.Context, []byte) error

// For replication we must send over the keyring, so this must be available
Keyring() (*Keyring, error)

// For encryption count shipping, a function which handles updating local encryption counts if the consumer succeeds.
// This isolates the barrier code from the replication system
ConsumeEncryptionCount(consumer func(int64) error) error

// Add encryption counts from a remote source (downstream cluster node)
AddRemoteEncryptions(encryptions int64)

// Check whether an automatic rotation is due
CheckBarrierAutoRotate(ctx context.Context, rand io.Reader) error

// SecurityBarrier must provide the storage APIs
logical.Storage

Expand Down Expand Up @@ -175,6 +192,8 @@ type BarrierEncryptor interface {

// KeyInfo is used to convey information about the encryption key
type KeyInfo struct {
Term int
InstallTime time.Time
Term int
InstallTime time.Time
Encryptions int64
LocalEncryptions int64
}
Loading