-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
keyring: E2E testing for KMS/rotation (#23601)
In #23580 we're implementing support for encrypting Nomad's key material with external KMS providers or Vault Transit. This changeset breaks out the E2E infrastructure and testing from that PR to keep the review manageable. Ref: https://hashicorp.atlassian.net/browse/NET-10334 Ref: #14852 Ref: #23580
- Loading branch information
Showing
8 changed files
with
125 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
package keyring | ||
|
||
// This package contains only tests, so this is a placeholder file to | ||
// make sure builds don't fail with "no non-test Go files in" errors |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
package keyring | ||
|
||
import ( | ||
"encoding/json" | ||
"testing" | ||
|
||
"github.com/go-jose/go-jose/v3" | ||
"github.com/hashicorp/nomad/api" | ||
"github.com/hashicorp/nomad/e2e/e2eutil" | ||
"github.com/shoenig/test/must" | ||
) | ||
|
||
func TestKeyringRotation(t *testing.T) { | ||
|
||
nc := e2eutil.NomadClient(t) | ||
|
||
currentKeys, activeKeyID := getKeyMeta(t, nc) | ||
must.NotEq(t, "", activeKeyID, must.Sprint("expected an active key")) | ||
|
||
keyset := getJWKS(t) | ||
|
||
must.Len(t, len(currentKeys), keyset.Keys) | ||
for _, key := range keyset.Keys { | ||
must.MapContainsKey(t, currentKeys, key.KeyID) | ||
} | ||
|
||
out, err := e2eutil.Commandf("nomad operator root keyring rotate -verbose -prepublish 1h") | ||
must.NoError(t, err) | ||
cols, err := e2eutil.ParseColumns(out) | ||
must.NoError(t, err) | ||
must.Greater(t, 0, len(cols)) | ||
newKeyID := cols[0]["Key"] | ||
must.Eq(t, "prepublished", cols[0]["State"], must.Sprint("expected new key to be prepublished")) | ||
|
||
newCurrentKeys, newActiveKeyID := getKeyMeta(t, nc) | ||
must.NotEq(t, "", newActiveKeyID, must.Sprint("expected an active key")) | ||
must.Eq(t, activeKeyID, newActiveKeyID, must.Sprint("active key should not have rotated yet")) | ||
must.Greater(t, len(currentKeys), len(newCurrentKeys), must.Sprint("expected more keys after prepublishing")) | ||
|
||
keyset = getJWKS(t) | ||
must.Len(t, len(newCurrentKeys), keyset.Keys, must.Sprint("number of keys in jwks keyset should match keyring")) | ||
for _, key := range keyset.Keys { | ||
must.MapContainsKey(t, newCurrentKeys, key.KeyID, must.Sprint("jwks keyset contains unexpected key")) | ||
} | ||
must.SliceContainsFunc(t, keyset.Keys, newKeyID, func(a jose.JSONWebKey, b string) bool { | ||
return a.KeyID == b | ||
}, must.Sprint("expected prepublished key to appear in JWKS endpoint")) | ||
} | ||
|
||
func getKeyMeta(t *testing.T, nc *api.Client) (map[string]*api.RootKeyMeta, string) { | ||
t.Helper() | ||
keyMetas, _, err := nc.Keyring().List(nil) | ||
must.NoError(t, err) | ||
|
||
currentKeys := map[string]*api.RootKeyMeta{} | ||
var activeKeyID string | ||
for _, keyMeta := range keyMetas { | ||
currentKeys[keyMeta.KeyID] = keyMeta | ||
if keyMeta.State == api.RootKeyStateActive { | ||
activeKeyID = keyMeta.KeyID | ||
} | ||
} | ||
must.NotEq(t, "", activeKeyID, must.Sprint("expected an active key")) | ||
return currentKeys, activeKeyID | ||
} | ||
|
||
func getJWKS(t *testing.T) *jose.JSONWebKeySet { | ||
t.Helper() | ||
out, err := e2eutil.Commandf("nomad operator api /.well-known/jwks.json") | ||
must.NoError(t, err) | ||
|
||
keyset := &jose.JSONWebKeySet{} | ||
err = json.Unmarshal([]byte(out), keyset) | ||
must.NoError(t, err) | ||
|
||
return keyset | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters