214 lines
6.9 KiB
Go
214 lines
6.9 KiB
Go
package servers
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
mathRand "math/rand"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/boundary/internal/db"
|
|
"github.com/hashicorp/boundary/internal/db/timestamp"
|
|
"github.com/hashicorp/boundary/internal/errors"
|
|
"github.com/hashicorp/boundary/internal/iam"
|
|
"github.com/hashicorp/boundary/internal/kms"
|
|
"github.com/hashicorp/boundary/internal/servers/store"
|
|
"github.com/hashicorp/boundary/internal/types/scope"
|
|
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
|
|
"github.com/hashicorp/nodeenrollment"
|
|
"github.com/hashicorp/nodeenrollment/registration"
|
|
"github.com/hashicorp/nodeenrollment/rotation"
|
|
"github.com/hashicorp/nodeenrollment/storage/file"
|
|
"github.com/hashicorp/nodeenrollment/types"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
)
|
|
|
|
const defaultLength = 20
|
|
|
|
// Generate random bytes for byte fields
|
|
func populateBytes(length int) []byte {
|
|
fieldBytes := make([]byte, length)
|
|
rand.Read(fieldBytes)
|
|
return fieldBytes
|
|
}
|
|
|
|
func TestKmsKey(ctx context.Context, t *testing.T, conn *db.DB, wrapper wrapping.Wrapper) string {
|
|
t.Helper()
|
|
org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
|
kmsCache := kms.TestKms(t, conn, wrapper)
|
|
databaseWrapper, err := kmsCache.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
|
|
require.NoError(t, err)
|
|
testKey, err := databaseWrapper.KeyId(ctx)
|
|
require.NoError(t, err)
|
|
|
|
return testKey
|
|
}
|
|
|
|
func TestRootCertificate(ctx context.Context, t *testing.T, conn *db.DB, kmsKey string) *RootCertificate {
|
|
t.Helper()
|
|
rw := db.New(conn)
|
|
|
|
beforeTimestamp := ×tamp.Timestamp{Timestamp: timestamppb.New(time.Now().Add(-1 * time.Hour))}
|
|
afterTimestamp := ×tamp.Timestamp{Timestamp: timestamppb.New(time.Now().Add(1 * time.Hour))}
|
|
|
|
rootCertKeys := RootCertificateKeys{
|
|
publicKey: populateBytes(defaultLength),
|
|
privateKey: populateBytes(defaultLength),
|
|
}
|
|
|
|
cert, err := newRootCertificate(ctx, mathRand.Uint64(), populateBytes(defaultLength), beforeTimestamp, afterTimestamp,
|
|
rootCertKeys, kmsKey, CurrentState)
|
|
err = rw.Create(ctx, cert)
|
|
require.NoError(t, err)
|
|
return cert
|
|
}
|
|
|
|
func TestWorkerAuth(t *testing.T, conn *db.DB, worker *Worker, kmsKey string) *WorkerAuth {
|
|
t.Helper()
|
|
ctx := context.Background()
|
|
rw := db.New(conn)
|
|
wSignPubKey := populateBytes(defaultLength)
|
|
wEncPubKey := populateBytes(defaultLength)
|
|
workerKeys := WorkerKeys{workerSigningPubKey: wSignPubKey, workerEncryptionPubKey: wEncPubKey}
|
|
controllerKey := populateBytes(defaultLength)
|
|
nonce := populateBytes(defaultLength)
|
|
opt := []Option{
|
|
WithKeyId(kmsKey),
|
|
WithWorkerKeys(workerKeys),
|
|
WithControllerEncryptionPrivateKey(controllerKey),
|
|
WithNonce(nonce),
|
|
}
|
|
|
|
workerAuth, err := newWorkerAuth(ctx, "worker-key-identifier", worker.PublicId, opt...)
|
|
require.NoError(t, err)
|
|
err = rw.Create(ctx, workerAuth)
|
|
require.NoError(t, err)
|
|
|
|
return workerAuth
|
|
}
|
|
|
|
// TestKmsWorker inserts a worker into the db to satisfy foreign key constraints.
|
|
// The worker provided fields are auto generated. if WithName is not present a
|
|
// random name will be generated and assigned to the worker.
|
|
func TestKmsWorker(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, opt ...Option) *Worker {
|
|
t.Helper()
|
|
rw := db.New(conn)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
serversRepo, err := NewRepository(rw, rw, kms)
|
|
require.NoError(t, err)
|
|
ctx := context.Background()
|
|
opts := getOpts(opt...)
|
|
|
|
namePart, err := newWorkerId(ctx)
|
|
require.NoError(t, err)
|
|
name := "test-worker-" + strings.ToLower(namePart)
|
|
if opts.withName != "" {
|
|
name = opts.withName
|
|
}
|
|
address := "127.0.0.1"
|
|
if opts.withAddress != "" {
|
|
address = opts.withAddress
|
|
}
|
|
wrk := NewWorker(scope.Global.String(),
|
|
WithName(name),
|
|
WithAddress(address))
|
|
wrk, err = serversRepo.UpsertWorkerStatus(ctx, wrk)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, wrk)
|
|
|
|
if len(opts.withWorkerTags) > 0 {
|
|
var tags []interface{}
|
|
for _, t := range opts.withWorkerTags {
|
|
tags = append(tags, &store.WorkerTag{
|
|
WorkerId: wrk.GetPublicId(),
|
|
Key: t.Key,
|
|
Value: t.Value,
|
|
Source: "configuration",
|
|
})
|
|
}
|
|
require.NoError(t, rw.CreateItems(ctx, tags))
|
|
}
|
|
var mask []string
|
|
if opts.withDescription != "" {
|
|
wrk.Description = opts.withDescription
|
|
mask = append(mask, "description")
|
|
}
|
|
if len(mask) > 0 {
|
|
var n int
|
|
wrk, n, err = serversRepo.UpdateWorker(ctx, wrk, wrk.Version, mask)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, n)
|
|
require.NotNil(t, wrk)
|
|
}
|
|
wrk, err = serversRepo.LookupWorker(ctx, wrk.GetPublicId())
|
|
require.NoError(t, err)
|
|
return wrk
|
|
}
|
|
|
|
// TestPkiWorker inserts a worker into the db to satisfy foreign key constraints.
|
|
// The worker provided fields are auto generated. WithName and WithDescription,
|
|
// are applied to the resource name, description if present. WithTestPkiWorkerAuthorizedKeyId
|
|
// can be used to make the PkiWorker authorized in which case the string pointer
|
|
// passed to WithTestPkiWorkerAuthorizedKeyId is set to the key id.
|
|
func TestPkiWorker(t *testing.T, conn *db.DB, wrapper wrapping.Wrapper, opt ...Option) *Worker {
|
|
t.Helper()
|
|
rw := db.New(conn)
|
|
kmsCache := kms.TestKms(t, conn, wrapper)
|
|
serversRepo, err := NewRepository(rw, rw, kmsCache)
|
|
require.NoError(t, err)
|
|
ctx := context.Background()
|
|
opts := getOpts(opt...)
|
|
|
|
require.NoError(t, err)
|
|
wrk := NewWorker(scope.Global.String(),
|
|
opt...)
|
|
wrk, err = serversRepo.CreateWorker(ctx, wrk, opt...)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, wrk)
|
|
|
|
if len(opts.withWorkerTags) > 0 {
|
|
var tags []interface{}
|
|
for _, t := range opts.withWorkerTags {
|
|
tags = append(tags, &store.WorkerTag{
|
|
WorkerId: wrk.GetPublicId(),
|
|
Key: t.Key,
|
|
Value: t.Value,
|
|
Source: "configuration",
|
|
})
|
|
}
|
|
require.NoError(t, rw.CreateItems(ctx, tags))
|
|
}
|
|
if opts.withTestPkiWorkerAuthorized {
|
|
err = kmsCache.CreateKeys(context.Background(), scope.Global.String(), kms.WithRandomReader(rand.Reader))
|
|
// We always try to create root global scope keys, but if it already exists, just continue...
|
|
require.True(t, err == nil || errors.IsUniqueError(err), err)
|
|
rootStorage, err := NewRepositoryStorage(ctx, rw, rw, kmsCache)
|
|
require.NoError(t, err)
|
|
_, err = rotation.RotateRootCertificates(ctx, rootStorage)
|
|
require.NoError(t, err)
|
|
// Create struct to pass in with workerId that will be passed along to storage
|
|
state, err := AttachWorkerIdToState(ctx, wrk.PublicId)
|
|
require.NoError(t, err)
|
|
|
|
// This happens on the worker
|
|
fileStorage, err := file.New(ctx)
|
|
require.NoError(t, err)
|
|
nodeCreds, err := types.NewNodeCredentials(ctx, fileStorage)
|
|
require.NoError(t, err)
|
|
// Create request using worker id
|
|
fetchReq, err := nodeCreds.CreateFetchNodeCredentialsRequest(ctx)
|
|
require.NoError(t, err)
|
|
registeredNode, err := registration.AuthorizeNode(ctx, rootStorage, fetchReq, nodeenrollment.WithState(state))
|
|
require.NoError(t, err)
|
|
|
|
if opts.withTestPkiWorkerKeyId != nil {
|
|
*opts.withTestPkiWorkerKeyId = registeredNode.Id
|
|
}
|
|
}
|
|
wrk, err = serversRepo.LookupWorker(ctx, wrk.GetPublicId())
|
|
require.NoError(t, err)
|
|
return wrk
|
|
}
|