Skip to content

fix(enterprise/dbcrypt): do not skip deleted users when encrypting or deleting #9694

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 15, 2023
Prev Previous commit
Next Next commit
make AllUserIDs a fully-fledged query citizen
  • Loading branch information
johnstcn committed Sep 15, 2023
commit 11f85bff7436a1006a91bc47a5bcf447c727f159
9 changes: 9 additions & 0 deletions coderd/database/dbauthz/dbauthz.go
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,15 @@ func (q *querier) ActivityBumpWorkspace(ctx context.Context, arg uuid.UUID) erro
return update(q.log, q.auth, fetch, q.db.ActivityBumpWorkspace)(ctx, arg)
}

func (q *querier) AllUserIDs(ctx context.Context) ([]uuid.UUID, error) {
// Although this technically only reads users, only system-related functions should be
// allowed to call this.
if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceSystem); err != nil {
return nil, err
}
return q.db.AllUserIDs(ctx)
}

func (q *querier) CleanTailnetCoordinators(ctx context.Context) error {
if err := q.authorizeContext(ctx, rbac.ActionDelete, rbac.ResourceTailnetCoordinator); err != nil {
return err
Expand Down
8 changes: 8 additions & 0 deletions coderd/database/dbfake/dbfake.go
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,14 @@ func (q *FakeQuerier) ActivityBumpWorkspace(ctx context.Context, workspaceID uui
return sql.ErrNoRows
}

func (q *FakeQuerier) AllUserIDs(ctx context.Context) ([]uuid.UUID, error) {
userIDs := make([]uuid.UUID, 0, len(q.users))
for idx := range q.users {
userIDs[idx] = q.users[idx].ID
}
return userIDs, nil
}

func (*FakeQuerier) CleanTailnetCoordinators(_ context.Context) error {
return ErrUnimplemented
}
Expand Down
7 changes: 7 additions & 0 deletions coderd/database/dbmetrics/dbmetrics.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions coderd/database/dbmock/dbmock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions coderd/database/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions coderd/database/queries/dbcrypt.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ AND
INSERT INTO dbcrypt_keys
(number, active_key_digest, created_at, test)
VALUES (@number::int, @active_key_digest::text, CURRENT_TIMESTAMP, @test::text);

5 changes: 5 additions & 0 deletions coderd/database/queries/users.sql
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,8 @@ WHERE
last_seen_at < @last_seen_after :: timestamp
AND status = 'active'::user_status
RETURNING id, email, last_seen_at;

-- AllUserIDs returns all UserIDs regardless of user status or deletion.
-- name: AllUserIDs :many
SELECT DISTINCT id FROM USERS;

28 changes: 2 additions & 26 deletions enterprise/dbcrypt/cliutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (

"golang.org/x/xerrors"

"github.com/google/uuid"

"cdr.dev/slog"
"github.com/coder/coder/v2/coderd/database"
)
Expand All @@ -21,7 +19,7 @@ func Rotate(ctx context.Context, log slog.Logger, sqlDB *sql.DB, ciphers []Ciphe
return xerrors.Errorf("create cryptdb: %w", err)
}

userIDs, err := allUserIDs(ctx, sqlDB)
userIDs, err := db.AllUserIDs(ctx)
if err != nil {
return xerrors.Errorf("get users: %w", err)
}
Expand Down Expand Up @@ -105,7 +103,7 @@ func Decrypt(ctx context.Context, log slog.Logger, sqlDB *sql.DB, ciphers []Ciph
}
cryptDB.primaryCipherDigest = ""

userIDs, err := allUserIDs(ctx, sqlDB)
userIDs, err := db.AllUserIDs(ctx)
if err != nil {
return xerrors.Errorf("get users: %w", err)
}
Expand Down Expand Up @@ -214,25 +212,3 @@ func Delete(ctx context.Context, log slog.Logger, sqlDB *sql.DB) error {

return nil
}

// allUserIDs returns _all_ user IDs we know about, regardless of status or deletion.
// We need to encrypt / decrypt tokens regardless of user status or deletion as they
// may still be valid. While we could check the expiry, we also don't know if the
// provider is lying about expiry.
// This function will likely only ever be used here, so keeping it here instead
// of exposing it in all of our database-related interfaces.
func allUserIDs(ctx context.Context, sqlDB *sql.DB) ([]uuid.UUID, error) {
var id uuid.UUID
userIDs := make([]uuid.UUID, 0)
rows, err := sqlDB.QueryContext(ctx, `SELECT DISTINCT id FROM users`)
if err != nil {
return nil, xerrors.Errorf("failed to query all user ids: %w", err)
}
for rows.Next() {
if err := rows.Scan(&id); err != nil {
return nil, xerrors.Errorf("failed to scan user_id: %w", err)
}
userIDs = append(userIDs, id)
}
return userIDs, nil
}