Files
threshold/internal/server/worker_auth.go
T
Jeff MitchellandIrena Rindos 01fb949d0b Add controller-led worker auth flow (#2413)
This adds an action to the API that allows pulling out an activation
token that can be given to a worker in its config (directly or via env
or file). The worker can pass this along with its normal request in
place of its normal nonce and the server will automatically accept it.

Co-authored-by: Irena Rindos <irenarindos@users.noreply.github.com>
2022-09-02 14:32:41 -04:00

184 lines
5.3 KiB
Go

package server
import (
"context"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/server/store"
"google.golang.org/protobuf/proto"
)
// WorkerAuth contains all fields related to an authorized Worker resource
// This includes worker public keys, the controller encryption key,
// and certificate bundles issued by the Boundary CA
type WorkerAuth struct {
*store.WorkerAuth
tableName string `gorm:"-"`
}
// WorkerKeys contain the signing and encryption keys for a WorkerAuth resource
type WorkerKeys struct {
workerSigningPubKey []byte
workerEncryptionPubKey []byte
}
func newWorkerAuth(ctx context.Context, workerKeyIdentifier, workerId string, opt ...Option) (*WorkerAuth, error) {
const op = "server.newWorkerAuth"
opts := GetOpts(opt...)
if workerKeyIdentifier == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no workerKeyIdentifier")
}
if workerId == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no workerId")
}
l := &WorkerAuth{
WorkerAuth: &store.WorkerAuth{
WorkerKeyIdentifier: workerKeyIdentifier,
WorkerId: workerId,
},
}
if &opts.withWorkerKeys != nil {
l.WorkerSigningPubKey = opts.withWorkerKeys.workerSigningPubKey
l.WorkerEncryptionPubKey = opts.withWorkerKeys.workerEncryptionPubKey
}
if &opts.withControllerEncryptionPrivateKey != nil {
l.ControllerEncryptionPrivKey = opts.withControllerEncryptionPrivateKey
}
if opts.withKeyId != "" {
l.KeyId = opts.withKeyId
}
if opts.withNonce != nil {
l.Nonce = opts.withNonce
}
return l, nil
}
func allocWorkerAuth() *WorkerAuth {
return &WorkerAuth{
WorkerAuth: &store.WorkerAuth{},
}
}
func (w *WorkerAuth) clone() *WorkerAuth {
cp := proto.Clone(w.WorkerAuth)
return &WorkerAuth{
WorkerAuth: cp.(*store.WorkerAuth),
}
}
// Validate is called before storing a WorkerAuth in the db
func (w *WorkerAuth) ValidateNewWorkerAuth(ctx context.Context) error {
const op = "server.(WorkerAuth).validateNewWorkerAuth"
if w.WorkerKeyIdentifier == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing WorkerKeyIdentifier")
}
if w.WorkerId == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing WorkerId")
}
if w.WorkerSigningPubKey == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing WorkerSigningPubKey")
}
if w.WorkerEncryptionPubKey == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing WorkerEncryptionPubKey")
}
if w.ControllerEncryptionPrivKey == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing ControllerEncryptionPrivKey")
}
if w.KeyId == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing KeyId")
}
if w.Nonce == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing Nonce")
}
return nil
}
// TableName returns the table name.
func (w *WorkerAuth) TableName() string {
if w.tableName != "" {
return w.tableName
}
return "worker_auth_authorized"
}
// SetTableName sets the table name.
func (w *WorkerAuth) SetTableName(n string) {
w.tableName = n
}
// WorkerCertBundle contains all fields related to a WorkerCertBundle resource
// This includes the serial number of the issuing CA, the worker id, and the certificate bundles issued by the CA
type WorkerCertBundle struct {
*store.WorkerCertBundle
tableName string `gorm:"-"`
}
func newWorkerCertBundle(ctx context.Context, certificatePublicKey []byte, workerKeyIdentifier string, certBundle []byte) (*WorkerCertBundle, error) {
const op = "server.newWorkerCertBundle"
if certificatePublicKey == nil {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no certificatePublicKey")
}
if workerKeyIdentifier == "" {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no workerKeyIdentifier")
}
if certBundle == nil || len(certBundle) == 0 {
return nil, errors.New(ctx, errors.InvalidParameter, op, "empty certBundle")
}
l := &WorkerCertBundle{
WorkerCertBundle: &store.WorkerCertBundle{
RootCertificatePublicKey: certificatePublicKey,
WorkerKeyIdentifier: workerKeyIdentifier,
CertBundle: certBundle,
},
}
return l, nil
}
func allocWorkerCertBundle() *WorkerCertBundle {
return &WorkerCertBundle{
WorkerCertBundle: &store.WorkerCertBundle{},
}
}
func (w *WorkerCertBundle) clone() *WorkerCertBundle {
cp := proto.Clone(w.WorkerCertBundle)
return &WorkerCertBundle{
WorkerCertBundle: cp.(*store.WorkerCertBundle),
}
}
// Validate is called before storing a WorkerCertBundle in the db
func (w *WorkerCertBundle) ValidateNewWorkerCertBundle(ctx context.Context) error {
const op = "server.(WorkerAuth).validateNewWorkerCertBundle"
if w.RootCertificatePublicKey == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing CertificatePublicKey")
}
if w.WorkerKeyIdentifier == "" {
return errors.New(ctx, errors.InvalidParameter, op, "missing WorkerKeyIdentifier")
}
if w.CertBundle == nil {
return errors.New(ctx, errors.InvalidParameter, op, "missing certificate bundle")
}
return nil
}
// TableName returns the table name.
func (w *WorkerCertBundle) TableName() string {
if w.tableName != "" {
return w.tableName
}
return "worker_auth_certificate_bundle"
}
// SetTableName sets the table name.
func (w *WorkerCertBundle) SetTableName(n string) {
w.tableName = n
}