refactor(workerauth): consolidate workerAuth retrieval (#2512)

* refactor worker auth
This commit is contained in:
Irena Rindos authored and GitHub committed 2022-10-04 14:08:43 -04:00
1 parent 412e7a2418
commit da885a89c3
3 files changed
+74 -82

No files matched your search

+7
View File
@@ -23,4 +23,11 @@ const (
delete from worker_auth_ca_certificate
where state = @state;
`
getWorkerAuthsByWorkerKeyIdQuery = `
with key_id_to_worker_id as (
select worker_id from worker_auth_authorized where worker_key_identifier = @worker_key_identifier
)
select * from worker_auth_authorized where worker_id in (select * from key_id_to_worker_id)
`
)
+58 -79
View File
@@ -376,17 +376,49 @@ func (r *WorkerAuthRepositoryStorage) loadNodeInformation(ctx context.Context, n
return errors.New(ctx, errors.InvalidParameter, op, "missing NodeInformation")
}
authorizedWorker, err := r.findWorkerAuth(ctx, node)
query := getWorkerAuthsByWorkerKeyIdQuery
rows, err := r.reader.Query(ctx, query, []interface{}{sql.Named("worker_key_identifier", node.Id)})
if err != nil {
return errors.Wrap(ctx, err, op)
}
if authorizedWorker == nil {
defer rows.Close()
var workerAuths []*WorkerAuth
for rows.Next() {
var s WorkerAuth
if err := r.reader.ScanRows(ctx, rows, &s); err != nil {
return errors.Wrap(ctx, err, op, errors.WithMsg("scan row failed"))
}
workerAuths = append(workerAuths, &s)
}
workerAuthorizedSet, err := r.validateWorkerAuths(ctx, workerAuths)
if err != nil {
if errors.IsNotFoundError(err) {
return nodee.ErrNotFound
}
return errors.Wrap(ctx, err, op)
}
if workerAuthorizedSet == nil || workerAuthorizedSet.Current == nil {
return nodee.ErrNotFound
}
node.EncryptionPublicKeyBytes = authorizedWorker.WorkerEncryptionPubKey
node.CertificatePublicKeyPkix = authorizedWorker.WorkerSigningPubKey
node.RegistrationNonce = authorizedWorker.Nonce
if workerAuthorizedSet.Previous != nil {
priorKey := &types.EncryptionKey{
KeyId: workerAuthorizedSet.Previous.WorkerKeyIdentifier,
PrivateKeyPkcs8: workerAuthorizedSet.Previous.ControllerEncryptionPrivKey,
PrivateKeyType: types.KEYTYPE_X25519,
PublicKeyPkix: workerAuthorizedSet.Previous.WorkerEncryptionPubKey,
PublicKeyType: types.KEYTYPE_X25519,
}
node.PreviousEncryptionKey = priorKey
}
node.EncryptionPublicKeyBytes = workerAuthorizedSet.Current.WorkerEncryptionPubKey
node.CertificatePublicKeyPkix = workerAuthorizedSet.Current.WorkerSigningPubKey
node.RegistrationNonce = workerAuthorizedSet.Current.Nonce
// Default values are used for key types
node.EncryptionPublicKeyType = types.KEYTYPE_X25519
@@ -394,16 +426,16 @@ func (r *WorkerAuthRepositoryStorage) loadNodeInformation(ctx context.Context, n
node.ServerEncryptionPrivateKeyType = types.KEYTYPE_X25519
// Decrypt private key
databaseWrapper, err := r.kms.GetWrapper(ctx, scope.Global.String(), kms.KeyPurposeDatabase, kms.WithKeyId(authorizedWorker.KeyId))
databaseWrapper, err := r.kms.GetWrapper(ctx, scope.Global.String(), kms.KeyPurposeDatabase, kms.WithKeyId(workerAuthorizedSet.Current.KeyId))
if err != nil {
return errors.Wrap(ctx, err, op)
}
node.ServerEncryptionPrivateKeyBytes, err = decrypt(ctx, authorizedWorker.ControllerEncryptionPrivKey, databaseWrapper)
node.ServerEncryptionPrivateKeyBytes, err = decrypt(ctx, workerAuthorizedSet.Current.ControllerEncryptionPrivKey, databaseWrapper)
if err != nil {
return errors.Wrap(ctx, err, op)
}
workerIdInfo := workerAuthWorkerId{WorkerId: authorizedWorker.GetWorkerId()}
workerIdInfo := workerAuthWorkerId{WorkerId: workerAuthorizedSet.Current.GetWorkerId()}
s := structs.New(workerIdInfo)
s.TagName = "mapstructure"
state, err := structpb.NewStruct(s.Map())
@@ -419,15 +451,6 @@ func (r *WorkerAuthRepositoryStorage) loadNodeInformation(ctx context.Context, n
}
node.CertificateBundles = certBundles
// Get prior encryption key, if available
priorKey, err := r.findPriorEncryptionKey(ctx, authorizedWorker.GetWorkerId())
if !errors.IsNotFoundError(err) {
if err != nil {
return errors.Wrap(ctx, err, op)
}
node.PreviousEncryptionKey = priorKey
}
return nil
}
@@ -497,56 +520,6 @@ func (r *WorkerAuthRepositoryStorage) findCertBundles(ctx context.Context, worke
return certBundle, nil
}
func (r *WorkerAuthRepositoryStorage) findWorkerAuth(ctx context.Context, node *types.NodeInformation) (*WorkerAuth, error) {
const op = "server.(WorkerAuthRepositoryStorage).findWorkerAuth"
if node == nil {
return nil, errors.New(ctx, errors.InvalidParameter, op, "node is nil")
}
worker := allocWorkerAuth()
worker.WorkerKeyIdentifier = node.Id
err := r.reader.LookupById(ctx, worker)
if err != nil {
if errors.Is(err, dbw.ErrRecordNotFound) {
return nil, nil
}
return nil, errors.Wrap(ctx, err, op)
}
return worker, nil
}
func (r *WorkerAuthRepositoryStorage) findPriorEncryptionKey(ctx context.Context, workerId string) (*types.EncryptionKey, error) {
const op = "server.(WorkerAuthRepositoryStorage).findPriorEncryptionKey"
if workerId == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "empty workerId")
}
workerAuthSet, err := r.FindWorkerAuthByWorkerId(ctx, workerId)
if err != nil {
if errors.IsNotFoundError(err) {
return nil, err
}
return nil, errors.Wrap(ctx, err, op)
}
if workerAuthSet.Previous == nil {
return nil, nil
}
// Create the EncryptionKey using the prior worker auth record
priorKey := &types.EncryptionKey{
KeyId: workerAuthSet.Previous.WorkerKeyIdentifier,
PrivateKeyPkcs8: workerAuthSet.Previous.ControllerEncryptionPrivKey,
PrivateKeyType: types.KEYTYPE_X25519,
PublicKeyPkix: workerAuthSet.Previous.WorkerEncryptionPubKey,
PublicKeyType: types.KEYTYPE_X25519,
}
return priorKey, nil
}
func (r *WorkerAuthRepositoryStorage) loadRootCertificates(ctx context.Context, cert *types.RootCertificates) error {
const op = "server.(WorkerAuthRepositoryStorage).loadRootCertificates"
if cert == nil {
@@ -919,25 +892,16 @@ func decrypt(ctx context.Context, value []byte, wrapper wrapping.Wrapper) ([]byt
return marshaledInfo, nil
}
// FindWorkerAuthByWorkerId takes a workerId and returns the WorkerAuthSet for this worker.
func (r *WorkerAuthRepositoryStorage) FindWorkerAuthByWorkerId(ctx context.Context, workerId string) (*WorkerAuthSet, error) {
const op = "server.(WorkerAuthRepositoryStorage).FindWorkerAuthByWorkerId"
if len(workerId) == 0 {
return nil, errors.New(ctx, errors.InvalidParameter, op, "empty worker ID")
}
func (r *WorkerAuthRepositoryStorage) validateWorkerAuths(ctx context.Context, workerAuths []*WorkerAuth) (*WorkerAuthSet, error) {
const op = "server.(WorkerAuthRepositoryStorage).validateWorkerAuths"
var previousWorkerAuth *WorkerAuth
var currentWorkerAuth *WorkerAuth
var workerAuths []*WorkerAuth
if err := r.reader.SearchWhere(ctx, &workerAuths, "worker_id = ?", []interface{}{workerId}); err != nil {
return nil, errors.Wrap(ctx, err, op)
}
workerAuthsFound := len(workerAuths)
switch {
case workerAuthsFound == 0:
return nil, errors.New(ctx, errors.RecordNotFound, op, fmt.Sprintf("did not find worker auth records for worker %s", workerId))
return nil, errors.New(ctx, errors.RecordNotFound, op, "did not find worker auth records for worker")
case workerAuthsFound == 1:
if workerAuths[0].State != currentWorkerAuthState {
return nil, errors.New(ctx, errors.NotSpecificIntegrity, op,
@@ -972,3 +936,18 @@ func (r *WorkerAuthRepositoryStorage) FindWorkerAuthByWorkerId(ctx context.Conte
return workerAuthSet, nil
}
// FindWorkerAuthByWorkerId takes a workerId and returns the WorkerAuthSet for this worker.
func (r *WorkerAuthRepositoryStorage) FindWorkerAuthByWorkerId(ctx context.Context, workerId string) (*WorkerAuthSet, error) {
const op = "server.(WorkerAuthRepositoryStorage).FindWorkerAuthByWorkerId"
if len(workerId) == 0 {
return nil, errors.New(ctx, errors.InvalidParameter, op, "empty worker ID")
}
var workerAuths []*WorkerAuth
if err := r.reader.SearchWhere(ctx, &workerAuths, "worker_id = ?", []interface{}{workerId}); err != nil {
return nil, errors.Wrap(ctx, err, op)
}
return r.validateWorkerAuths(ctx, workerAuths)
}
@@ -17,6 +17,7 @@ import (
"github.com/hashicorp/boundary/internal/types/scope"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/nodeenrollment"
nodee "github.com/hashicorp/nodeenrollment"
"github.com/hashicorp/nodeenrollment/registration"
"github.com/hashicorp/nodeenrollment/rotation"
"github.com/hashicorp/nodeenrollment/storage/file"
@@ -190,6 +191,13 @@ func TestStoreWorkerAuth(t *testing.T) {
storage, err := NewRepositoryStorage(ctx, rw, rw, kmsCache)
require.NoError(err)
// Look for node info and expect to find nothing
nodeLookup := &types.NodeInformation{
Id: keyId,
}
err = storage.Load(ctx, nodeLookup)
assert.Equal(err, nodee.ErrNotFound)
// The AuthorizeNode request will result in a WorkerAuth record being stored
_, err = registration.AuthorizeNode(ctx, storage, fetchReq, nodeenrollment.WithState(state))
require.NoError(err)
@@ -201,9 +209,6 @@ func TestStoreWorkerAuth(t *testing.T) {
assert.Len(nodeInfos, 1)
// Validate the stored fields match those from the worker
nodeLookup := &types.NodeInformation{
Id: keyId,
}
err = storage.Load(ctx, nodeLookup)
require.NoError(err)
assert.NotEmpty(nodeLookup)
@@ -211,6 +216,7 @@ func TestStoreWorkerAuth(t *testing.T) {
assert.Equal(nodeInfo.RegistrationNonce, nodeLookup.RegistrationNonce)
assert.Equal(nodeInfo.CertificatePublicKeyPkix, nodeLookup.CertificatePublicKeyPkix)
assert.Equal(nodeInfo.State.AsMap(), nodeLookup.State.AsMap())
assert.Empty(nodeInfo.PreviousEncryptionKey)
// Validate that we can find the workerAuth set and key identifier
workerAuthSet, err := storage.FindWorkerAuthByWorkerId(ctx, worker.PublicId)