The old logic made it impossible for the caller to set the release version with WithReleaseVersion. Only set the release version when it's not explicitly set already.
212 lines
7.1 KiB
Go
212 lines
7.1 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package server
|
|
|
|
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/server/store"
|
|
"github.com/hashicorp/boundary/internal/types/scope"
|
|
"github.com/hashicorp/boundary/version"
|
|
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, wrapping.Wrapper) {
|
|
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, databaseWrapper
|
|
}
|
|
|
|
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, kmsWrapper wrapping.Wrapper) *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{
|
|
WithWorkerKeys(workerKeys),
|
|
WithControllerEncryptionPrivateKey(controllerKey),
|
|
WithNonce(nonce),
|
|
}
|
|
|
|
workerAuth, err := newWorkerAuth(ctx, "worker-key-identifier", worker.PublicId, opt...)
|
|
require.NoError(t, err)
|
|
require.NoError(t, workerAuth.encrypt(ctx, kmsWrapper))
|
|
require.NoError(t, rw.Create(ctx, workerAuth))
|
|
|
|
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()
|
|
ctx := context.Background()
|
|
rw := db.New(conn)
|
|
kms := kms.TestKms(t, conn, wrapper)
|
|
serversRepo, err := NewRepository(ctx, rw, rw, kms)
|
|
require.NoError(t, err)
|
|
opts := GetOpts(opt...)
|
|
|
|
if opts.withName == "" {
|
|
namePart, err := newWorkerId(ctx)
|
|
require.NoError(t, err)
|
|
name := "test-worker-" + strings.ToLower(namePart)
|
|
opt = append(opt, WithName(name))
|
|
}
|
|
if opts.withAddress == "" {
|
|
address := "127.0.0.1"
|
|
opt = append(opt, WithAddress(address))
|
|
}
|
|
if opts.withReleaseVersion == "" {
|
|
// Only set the release version if it isn't already set
|
|
versionInfo := version.Get()
|
|
relVer := versionInfo.FullVersionNumber(false)
|
|
opt = append(opt, WithReleaseVersion(relVer))
|
|
}
|
|
|
|
wrk := NewWorker(scope.Global.String(), opt...)
|
|
wrk, err = serversRepo.UpsertWorkerStatus(ctx, wrk)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, wrk)
|
|
require.Equal(t, "kms", wrk.Type)
|
|
|
|
if len(opts.withWorkerTags) > 0 {
|
|
var tags []any
|
|
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))
|
|
}
|
|
|
|
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()
|
|
ctx := context.Background()
|
|
rw := db.New(conn)
|
|
kmsCache := kms.TestKms(t, conn, wrapper)
|
|
serversRepo, err := NewRepository(ctx, rw, rw, kmsCache)
|
|
require.NoError(t, err)
|
|
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 []any
|
|
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
|
|
}
|