-
Notifications
You must be signed in to change notification settings - Fork 278
/
repository.go
189 lines (171 loc) · 6.88 KB
/
repository.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package kms
import (
"context"
"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) {
const op = "kms.NewRepository"
if r == nil {
return nil, errors.New(errors.InvalidParameter, op, "nil reader")
}
if w == nil {
return nil, errors.New(errors.InvalidParameter, op, "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))
switch opts.withOrderByVersion {
case db.AscendingOrderBy:
dbOpts = append(dbOpts, db.WithOrder("version asc"))
case db.DescendingOrderBy:
dbOpts = append(dbOpts, db.WithOrder("version desc"))
}
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) {
const op = "kms.CreateKeysTx"
if dbReader == nil {
return nil, errors.New(errors.InvalidParameter, op, "missing db reader")
}
if dbWriter == nil {
return nil, errors.New(errors.InvalidParameter, op, "missing db writer")
}
if rootWrapper == nil {
return nil, errors.New(errors.InvalidParameter, op, "missing root wrapper")
}
if randomReader == nil {
return nil, errors.New(errors.InvalidParameter, op, "missing random reader")
}
if scopeId == "" {
return nil, errors.New(errors.InvalidParameter, op, "missing scope id")
}
k, err := generateKey(randomReader)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for root key in scope %s", scopeId)))
}
rootKey, rootKeyVersion, err := createRootKeyTx(ctx, dbWriter, rootWrapper, scopeId, k)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to create root key in scope %s", scopeId)))
}
rkvWrapper := aead.NewWrapper(nil)
if _, err := rkvWrapper.SetConfig(map[string]string{
"key_id": rootKeyVersion.GetPrivateId(),
}); err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error setting config on aead root wrapper in scope %s", scopeId)))
}
if err := rkvWrapper.SetAESGCMKeyBytes(rootKeyVersion.GetKey()); err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error setting key bytes on aead root wrapper in scope %s", scopeId)))
}
k, err = generateKey(randomReader)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for database key in scope %s", scopeId)))
}
dbKey, dbKeyVersion, err := createDatabaseKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to create database key in scope %s", scopeId)))
}
k, err = generateKey(randomReader)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for oplog key in scope %s", scopeId)))
}
oplogKey, oplogKeyVersion, err := createOplogKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to create oplog key in scope %s", scopeId)))
}
k, err = generateKey(randomReader)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for session key in scope %s", scopeId)))
}
sessionKey, sessionKeyVersion, err := createSessionKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to create session key in scope %s", scopeId)))
}
k, err = generateKey(randomReader)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for token key in scope %s", scopeId)))
}
tokenKey, tokenKeyVersion, err := createTokenKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to create token key in scope %s", scopeId)))
}
k, err = generateKey(randomReader)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("error generating random bytes for oidc key in scope %s", scopeId)))
}
oidcKey, oidcKeyVersion, err := createOidcKeyTx(ctx, dbReader, dbWriter, rkvWrapper, k)
if err != nil {
return nil, errors.Wrap(err, op, errors.WithMsg(fmt.Sprintf("unable to create oidc key in scope %s", scopeId)))
}
keys := Keys{
KeyTypeRootKey: rootKey,
KeyTypeRootKeyVersion: rootKeyVersion,
KeyTypeDatabaseKey: dbKey,
KeyTypeDatabaseKeyVersion: dbKeyVersion,
KeyTypeOplogKey: oplogKey,
KeyTypeOplogKeyVersion: oplogKeyVersion,
KeyTypeSessionKey: sessionKey,
KeyTypeSessionKeyVersion: sessionKeyVersion,
KeyTypeTokenKey: tokenKey,
KeyTypeTokenKeyVersion: tokenKeyVersion,
KeyTypeOidcKey: oidcKey,
KeyTypeOidcKeyVersion: oidcKeyVersion,
}
return keys, nil
}
func generateKey(randomReader io.Reader) ([]byte, error) {
const op = "kms.generateKey"
k, err := uuid.GenerateRandomBytesWithReader(32, randomReader)
if err != nil {
return nil, errors.Wrap(err, op)
}
return k, nil
}