Skip to content

Commit c793b6f

Browse files
committed
feat: add schema for key rotation
1 parent bfdc29f commit c793b6f

17 files changed

+672
-0
lines changed

coderd/database/dbauthz/dbauthz.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,10 @@ func (q *querier) DeleteCoordinator(ctx context.Context, id uuid.UUID) error {
10411041
return q.db.DeleteCoordinator(ctx, id)
10421042
}
10431043

1044+
func (q *querier) DeleteCryptoKey(ctx context.Context, arg database.DeleteCryptoKeyParams) (database.CryptoKey, error) {
1045+
panic("not implemented")
1046+
}
1047+
10441048
func (q *querier) DeleteCustomRole(ctx context.Context, arg database.DeleteCustomRoleParams) error {
10451049
if arg.OrganizationID.UUID != uuid.Nil {
10461050
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceAssignOrgRole.InOrg(arg.OrganizationID.UUID)); err != nil {
@@ -1383,6 +1387,14 @@ func (q *querier) GetCoordinatorResumeTokenSigningKey(ctx context.Context) (stri
13831387
return q.db.GetCoordinatorResumeTokenSigningKey(ctx)
13841388
}
13851389

1390+
func (q *querier) GetCryptoKeyByFeatureAndSequence(ctx context.Context, arg database.GetCryptoKeyByFeatureAndSequenceParams) (database.CryptoKey, error) {
1391+
panic("not implemented")
1392+
}
1393+
1394+
func (q *querier) GetCryptoKeys(ctx context.Context) ([]database.CryptoKey, error) {
1395+
panic("not implemented")
1396+
}
1397+
13861398
func (q *querier) GetDBCryptKeys(ctx context.Context) ([]database.DBCryptKey, error) {
13871399
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
13881400
return nil, err
@@ -1549,6 +1561,10 @@ func (q *querier) GetLastUpdateCheck(ctx context.Context) (string, error) {
15491561
return q.db.GetLastUpdateCheck(ctx)
15501562
}
15511563

1564+
func (q *querier) GetLatestCryptoKeyByFeature(ctx context.Context, feature database.CryptoKeyFeature) (database.CryptoKey, error) {
1565+
panic("not implemented")
1566+
}
1567+
15521568
func (q *querier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (database.WorkspaceBuild, error) {
15531569
if _, err := q.GetWorkspaceByID(ctx, workspaceID); err != nil {
15541570
return database.WorkspaceBuild{}, err
@@ -2654,6 +2670,10 @@ func (q *querier) InsertAuditLog(ctx context.Context, arg database.InsertAuditLo
26542670
return insert(q.log, q.auth, rbac.ResourceAuditLog, q.db.InsertAuditLog)(ctx, arg)
26552671
}
26562672

2673+
func (q *querier) InsertCryptoKey(ctx context.Context, arg database.InsertCryptoKeyParams) (database.CryptoKey, error) {
2674+
panic("not implemented")
2675+
}
2676+
26572677
func (q *querier) InsertCustomRole(ctx context.Context, arg database.InsertCustomRoleParams) (database.CustomRole, error) {
26582678
// Org and site role upsert share the same query. So switch the assertion based on the org uuid.
26592679
if arg.OrganizationID.UUID != uuid.Nil {
@@ -3157,6 +3177,10 @@ func (q *querier) UpdateAPIKeyByID(ctx context.Context, arg database.UpdateAPIKe
31573177
return update(q.log, q.auth, fetch, q.db.UpdateAPIKeyByID)(ctx, arg)
31583178
}
31593179

3180+
func (q *querier) UpdateCryptoKeyDeletesAt(ctx context.Context, arg database.UpdateCryptoKeyDeletesAtParams) (database.CryptoKey, error) {
3181+
panic("not implemented")
3182+
}
3183+
31603184
func (q *querier) UpdateCustomRole(ctx context.Context, arg database.UpdateCustomRoleParams) (database.CustomRole, error) {
31613185
if arg.OrganizationID.UUID != uuid.Nil {
31623186
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceAssignOrgRole.InOrg(arg.OrganizationID.UUID)); err != nil {

coderd/database/dbgen/dbgen.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dbgen
22

33
import (
44
"context"
5+
"crypto/rand"
56
"crypto/sha256"
67
"database/sql"
78
"encoding/hex"
@@ -893,6 +894,36 @@ func CustomRole(t testing.TB, db database.Store, seed database.CustomRole) datab
893894
return role
894895
}
895896

897+
func CryptoKey(t testing.TB, db database.Store, seed database.CryptoKey) database.CryptoKey {
898+
t.Helper()
899+
900+
b := make([]byte, 96)
901+
_, err := rand.Read(b)
902+
require.NoError(t, err, "generate secret")
903+
904+
key, err := db.InsertCryptoKey(genCtx, database.InsertCryptoKeyParams{
905+
Sequence: takeFirst(seed.Sequence, 123),
906+
Secret: takeFirst(seed.Secret, sql.NullString{
907+
String: hex.EncodeToString(b),
908+
Valid: true,
909+
}),
910+
SecretKeyID: takeFirst(seed.SecretKeyID, sql.NullString{}),
911+
Feature: takeFirst(seed.Feature, database.CryptoKeyFeatureWorkspaceApps),
912+
StartsAt: takeFirst(seed.StartsAt, time.Now()),
913+
})
914+
require.NoError(t, err, "insert crypto key")
915+
916+
if seed.DeletesAt.Valid {
917+
key, err = db.UpdateCryptoKeyDeletesAt(genCtx, database.UpdateCryptoKeyDeletesAtParams{
918+
Feature: key.Feature,
919+
Sequence: key.Sequence,
920+
DeletesAt: sql.NullTime{Time: seed.DeletesAt.Time, Valid: true},
921+
})
922+
require.NoError(t, err, "update crypto key deletes_at")
923+
}
924+
return key
925+
}
926+
896927
func must[V any](v V, err error) V {
897928
if err != nil {
898929
panic(err)

coderd/database/dbmem/dbmem.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ type data struct {
153153
// New tables
154154
workspaceAgentStats []database.WorkspaceAgentStat
155155
auditLogs []database.AuditLog
156+
cryptoKeys []database.CryptoKey
156157
dbcryptKeys []database.DBCryptKey
157158
files []database.File
158159
externalAuthLinks []database.ExternalAuthLink
@@ -1434,6 +1435,15 @@ func (*FakeQuerier) DeleteCoordinator(context.Context, uuid.UUID) error {
14341435
return ErrUnimplemented
14351436
}
14361437

1438+
func (q *FakeQuerier) DeleteCryptoKey(ctx context.Context, arg database.DeleteCryptoKeyParams) (database.CryptoKey, error) {
1439+
err := validateDatabaseType(arg)
1440+
if err != nil {
1441+
return database.CryptoKey{}, err
1442+
}
1443+
1444+
panic("not implemented")
1445+
}
1446+
14371447
func (q *FakeQuerier) DeleteCustomRole(_ context.Context, arg database.DeleteCustomRoleParams) error {
14381448
err := validateDatabaseType(arg)
14391449
if err != nil {
@@ -2309,6 +2319,32 @@ func (q *FakeQuerier) GetCoordinatorResumeTokenSigningKey(_ context.Context) (st
23092319
return q.coordinatorResumeTokenSigningKey, nil
23102320
}
23112321

2322+
func (q *FakeQuerier) GetCryptoKeyByFeatureAndSequence(_ context.Context, arg database.GetCryptoKeyByFeatureAndSequenceParams) (database.CryptoKey, error) {
2323+
err := validateDatabaseType(arg)
2324+
if err != nil {
2325+
return database.CryptoKey{}, err
2326+
}
2327+
2328+
q.mutex.RLock()
2329+
defer q.mutex.RUnlock()
2330+
2331+
for _, key := range q.cryptoKeys {
2332+
if key.Feature == arg.Feature && key.Sequence == arg.Sequence {
2333+
// Keys with NULL secrets are considered deleted.
2334+
if key.Secret.Valid {
2335+
return key, nil
2336+
}
2337+
return database.CryptoKey{}, sql.ErrNoRows
2338+
}
2339+
}
2340+
2341+
return database.CryptoKey{}, sql.ErrNoRows
2342+
}
2343+
2344+
func (q *FakeQuerier) GetCryptoKeys(ctx context.Context) ([]database.CryptoKey, error) {
2345+
panic("not implemented")
2346+
}
2347+
23122348
func (q *FakeQuerier) GetDBCryptKeys(_ context.Context) ([]database.DBCryptKey, error) {
23132349
q.mutex.RLock()
23142350
defer q.mutex.RUnlock()
@@ -2806,6 +2842,10 @@ func (q *FakeQuerier) GetLastUpdateCheck(_ context.Context) (string, error) {
28062842
return string(q.lastUpdateCheck), nil
28072843
}
28082844

2845+
func (q *FakeQuerier) GetLatestCryptoKeyByFeature(ctx context.Context, feature database.CryptoKeyFeature) (database.CryptoKey, error) {
2846+
panic("not implemented")
2847+
}
2848+
28092849
func (q *FakeQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, workspaceID uuid.UUID) (database.WorkspaceBuild, error) {
28102850
q.mutex.RLock()
28112851
defer q.mutex.RUnlock()
@@ -6305,6 +6345,28 @@ func (q *FakeQuerier) InsertAuditLog(_ context.Context, arg database.InsertAudit
63056345
return alog, nil
63066346
}
63076347

6348+
func (q *FakeQuerier) InsertCryptoKey(_ context.Context, arg database.InsertCryptoKeyParams) (database.CryptoKey, error) {
6349+
err := validateDatabaseType(arg)
6350+
if err != nil {
6351+
return database.CryptoKey{}, err
6352+
}
6353+
6354+
q.mutex.Lock()
6355+
defer q.mutex.Unlock()
6356+
6357+
key := database.CryptoKey{
6358+
Feature: arg.Feature,
6359+
Sequence: arg.Sequence,
6360+
Secret: arg.Secret,
6361+
SecretKeyID: arg.SecretKeyID,
6362+
StartsAt: arg.StartsAt,
6363+
}
6364+
6365+
q.cryptoKeys = append(q.cryptoKeys, key)
6366+
6367+
return key, nil
6368+
}
6369+
63086370
func (q *FakeQuerier) InsertCustomRole(_ context.Context, arg database.InsertCustomRoleParams) (database.CustomRole, error) {
63096371
err := validateDatabaseType(arg)
63106372
if err != nil {
@@ -7774,6 +7836,15 @@ func (q *FakeQuerier) UpdateAPIKeyByID(_ context.Context, arg database.UpdateAPI
77747836
return sql.ErrNoRows
77757837
}
77767838

7839+
func (q *FakeQuerier) UpdateCryptoKeyDeletesAt(ctx context.Context, arg database.UpdateCryptoKeyDeletesAtParams) (database.CryptoKey, error) {
7840+
err := validateDatabaseType(arg)
7841+
if err != nil {
7842+
return database.CryptoKey{}, err
7843+
}
7844+
7845+
panic("not implemented")
7846+
}
7847+
77777848
func (q *FakeQuerier) UpdateCustomRole(_ context.Context, arg database.UpdateCustomRoleParams) (database.CustomRole, error) {
77787849
err := validateDatabaseType(arg)
77797850
if err != nil {

coderd/database/dbmetrics/dbmetrics.go

Lines changed: 42 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)