173 lines
6.1 KiB
Go
173 lines
6.1 KiB
Go
package kms
|
|
|
|
import (
|
|
"context"
|
|
stderrors "errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/hashicorp/boundary/internal/db"
|
|
"github.com/hashicorp/boundary/internal/errors"
|
|
wrapping "github.com/hashicorp/go-kms-wrapping"
|
|
"github.com/hashicorp/go-kms-wrapping/wrappers/aead"
|
|
"github.com/hashicorp/go-uuid"
|
|
)
|
|
|
|
// Repository is the iam database repository
|
|
type Repository struct {
|
|
reader db.Reader
|
|
writer db.Writer
|
|
// defaultLimit provides a default for limiting the number of results returned from the repo
|
|
defaultLimit int
|
|
}
|
|
|
|
// NewRepository creates a new kms Repository. Supports the options: WithLimit
|
|
// which sets a default limit on results returned by repo operations.
|
|
func NewRepository(r db.Reader, w db.Writer, opt ...Option) (*Repository, error) {
|
|
if r == nil {
|
|
return nil, stderrors.New("error creating db repository with nil reader")
|
|
}
|
|
if w == nil {
|
|
return nil, stderrors.New("error creating db repository with nil writer")
|
|
}
|
|
opts := getOpts(opt...)
|
|
if opts.withLimit == 0 {
|
|
// zero signals the boundary defaults should be used.
|
|
opts.withLimit = db.DefaultLimit
|
|
}
|
|
return &Repository{
|
|
reader: r,
|
|
writer: w,
|
|
defaultLimit: opts.withLimit,
|
|
}, nil
|
|
}
|
|
|
|
// list will return a listing of resources and honor the WithLimit option or the
|
|
// repo defaultLimit
|
|
func (r *Repository) list(ctx context.Context, resources interface{}, where string, args []interface{}, opt ...Option) error {
|
|
opts := getOpts(opt...)
|
|
limit := r.defaultLimit
|
|
var dbOpts []db.Option
|
|
if opts.withLimit != 0 {
|
|
// non-zero signals an override of the default limit for the repo.
|
|
limit = opts.withLimit
|
|
}
|
|
dbOpts = append(dbOpts, db.WithLimit(limit))
|
|
if opts.withOrder != "" {
|
|
dbOpts = append(dbOpts, db.WithOrder(opts.withOrder))
|
|
}
|
|
return r.reader.SearchWhere(ctx, resources, where, args, dbOpts...)
|
|
}
|
|
|
|
// DefaultLimit returns the default limit for listing as set on the repo
|
|
func (r *Repository) DefaultLimit() int {
|
|
return r.defaultLimit
|
|
}
|
|
|
|
// KeyIder defines a common interface for all keys returned from CreateKeysTx in
|
|
// a Keys map
|
|
type KeyIder interface {
|
|
GetPrivateId() string
|
|
}
|
|
|
|
// Keys defines a return type for CreateKeysTx so the returned keys can be
|
|
// easily accessed via their KeyType
|
|
type Keys map[KeyType]KeyIder
|
|
|
|
// CreateKeysTx creates the root key and DEKs returns a map of the new keys.
|
|
// This function encapsulates all the work required within a db.TxHandler and
|
|
// allows this capability to be shared with the iam repo.
|
|
func CreateKeysTx(ctx context.Context, dbReader db.Reader, dbWriter db.Writer, rootWrapper wrapping.Wrapper, randomReader io.Reader, scopeId string) (Keys, error) {
|
|
if dbReader == nil {
|
|
return nil, fmt.Errorf("create keys: missing db reader: %w", errors.ErrInvalidParameter)
|
|
}
|
|
if dbWriter == nil {
|
|
return nil, fmt.Errorf("create keys: missing db writer: %w", errors.ErrInvalidParameter)
|
|
}
|
|
if rootWrapper == nil {
|
|
return nil, fmt.Errorf("create keys: missing root wrapper: %w", errors.ErrInvalidParameter)
|
|
}
|
|
if randomReader == nil {
|
|
return nil, fmt.Errorf("create keys: missing random reader: %w", errors.ErrInvalidParameter)
|
|
}
|
|
if scopeId == "" {
|
|
return nil, fmt.Errorf("create keys: missing scope id: %w", errors.ErrInvalidParameter)
|
|
}
|
|
k, err := generateKey(randomReader)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create keys: error generating random bytes for root key in scope %s: %w", scopeId, err)
|
|
}
|
|
rootKey, rootKeyVersion, err := createRootKeyTx(ctx, dbWriter, rootWrapper, scopeId, k)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create keys: unable to create root key in scope %s: %w", scopeId, err)
|
|
}
|
|
|
|
rkvWrapper := aead.NewWrapper(nil)
|
|
if _, err := rkvWrapper.SetConfig(map[string]string{
|
|
"key_id": rootKeyVersion.GetPrivateId(),
|
|
}); err != nil {
|
|
return nil, fmt.Errorf("create keys: error setting config on aead root wrapper in scope %s: %w", scopeId, err)
|
|
}
|
|
if err := rkvWrapper.SetAESGCMKeyBytes(rootKeyVersion.GetKey()); err != nil {
|
|
return nil, fmt.Errorf("create keys: error setting key bytes on aead root wrapper in scope %s: %w", scopeId, err)
|
|
}
|
|
|
|
k, err = generateKey(randomReader)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create keys: error generating random bytes for database key in scope %s: %w", scopeId, err)
|
|
}
|
|
dbKey, dbKeyVersion, err := createDatabaseKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create keys: unable to create database key in scope %s: %w", scopeId, err)
|
|
}
|
|
|
|
k, err = generateKey(randomReader)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create keys: error generating random bytes for oplog key in scope %s: %w", scopeId, err)
|
|
}
|
|
oplogKey, oplogKeyVersion, err := createOplogKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create keys: unable to create oplog key in scope %s: %w", scopeId, err)
|
|
}
|
|
|
|
k, err = generateKey(randomReader)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create keys: error generating random bytes for session key in scope %s: %w", scopeId, err)
|
|
}
|
|
sessionKey, sessionKeyVersion, err := createSessionKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create keys: unable to create session key in scope %s: %w", scopeId, err)
|
|
}
|
|
|
|
k, err = generateKey(randomReader)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create keys: error generating random bytes for token key in scope %s: %w", scopeId, err)
|
|
}
|
|
tokenKey, tokenKeyVersion, err := createTokenKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create keys: unable to create token key in scope %s: %w", scopeId, err)
|
|
}
|
|
|
|
keys := Keys{
|
|
KeyTypeRootKey: rootKey,
|
|
KeyTypeRootKeyVersion: rootKeyVersion,
|
|
KeyTypeDatabaseKey: dbKey,
|
|
KeyTypeDatabaseKeyVersion: dbKeyVersion,
|
|
KeyTypeOplogKey: oplogKey,
|
|
KeyTypeOplogKeyVersion: oplogKeyVersion,
|
|
KeyTypeSessionKey: sessionKey,
|
|
KeyTypeSessionKeyVersion: sessionKeyVersion,
|
|
KeyTypeTokenKey: tokenKey,
|
|
KeyTypeTokenKeyVersion: tokenKeyVersion,
|
|
}
|
|
return keys, nil
|
|
}
|
|
|
|
func generateKey(randomReader io.Reader) ([]byte, error) {
|
|
k, err := uuid.GenerateRandomBytesWithReader(32, randomReader)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error generating random bytes for key: %w", err)
|
|
}
|
|
return k, nil
|
|
}
|