Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

chore: shorten provisioner key#14017

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
f0ssel merged 7 commits intomainfromf0ssel/shorten-key
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
NextNext commit
chore: shorten provisioner key
  • Loading branch information
@f0ssel
f0ssel committedJul 25, 2024
commitda798f0e7ca34e4260497619374478db0ee8cb73
4 changes: 4 additions & 0 deletionscoderd/database/dbauthz/dbauthz.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1680,6 +1680,10 @@ func (q *querier) GetProvisionerJobsCreatedAfter(ctx context.Context, createdAt
return q.db.GetProvisionerJobsCreatedAfter(ctx, createdAt)
}

func (q *querier) GetProvisionerKeyByHashedSecret(ctx context.Context, hashedSecret []byte) (database.ProvisionerKey, error) {
return fetch(q.log, q.auth, q.db.GetProvisionerKeyByHashedSecret)(ctx, hashedSecret)
}

func (q *querier) GetProvisionerKeyByID(ctx context.Context, id uuid.UUID) (database.ProvisionerKey, error) {
return fetch(q.log, q.auth, q.db.GetProvisionerKeyByID)(ctx, id)
}
Expand Down
13 changes: 13 additions & 0 deletionscoderd/database/dbmem/dbmem.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3240,6 +3240,19 @@ func (q *FakeQuerier) GetProvisionerJobsCreatedAfter(_ context.Context, after ti
return jobs, nil
}

func (q *FakeQuerier) GetProvisionerKeyByHashedSecret(ctx context.Context, hashedSecret []byte) (database.ProvisionerKey, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()

for _, key := range q.provisionerKeys {
if bytes.Equal(key.HashedSecret, hashedSecret) {
return key, nil
}
}

return database.ProvisionerKey{}, sql.ErrNoRows
}

func (q *FakeQuerier) GetProvisionerKeyByID(_ context.Context, id uuid.UUID) (database.ProvisionerKey, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
Expand Down
7 changes: 7 additions & 0 deletionscoderd/database/dbmetrics/dbmetrics.go
View file
Open in desktop

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

15 changes: 15 additions & 0 deletionscoderd/database/dbmock/dbmock.go
View file
Open in desktop

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

1 change: 1 addition & 0 deletionscoderd/database/querier.go
View file
Open in desktop

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

23 changes: 23 additions & 0 deletionscoderd/database/queries.sql.go
View file
Open in desktop

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

8 changes: 8 additions & 0 deletionscoderd/database/queries/provisionerkeys.sql
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -19,6 +19,14 @@ FROM
WHERE
id = $1;

-- name: GetProvisionerKeyByHashedSecret :one
SELECT
*
FROM
provisioner_keys
WHERE
hashed_secret = $1;

-- name: GetProvisionerKeyByName :one
SELECT
*
Expand Down
14 changes: 8 additions & 6 deletionscoderd/httpmw/provisionerdaemon.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,16 +71,17 @@ func ExtractProvisionerDaemonAuthenticated(opts ExtractProvisionerAuthConfig) fu
return
}

id, keyValue,err := provisionerkey.Parse(key)
err := provisionerkey.Validate(key)
if err != nil {
handleOptional(http.StatusUnauthorized, codersdk.Response{
handleOptional(http.StatusBadGateway, codersdk.Response{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

http.StatusBadGateway? This should be unauthorized, no?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This error has a detail that specifies the length must be 64, and I thought it felt more like a 400 in that regard.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

omg I meantStatusBadRequest...

Message: "provisioner daemon key invalid",
Detail: err.Error(),
})
return
}

hashedKey := provisionerkey.HashSecret(key)
// nolint:gocritic // System must check if the provisioner key is valid.
pk, err := opts.DB.GetProvisionerKeyByID(dbauthz.AsSystemRestricted(ctx),id)
pk, err := opts.DB.GetProvisionerKeyByHashedSecret(dbauthz.AsSystemRestricted(ctx),hashedKey)
if err != nil {
if httpapi.Is404Error(err) {
handleOptional(http.StatusUnauthorized, codersdk.Response{
Expand All@@ -90,12 +91,13 @@ func ExtractProvisionerDaemonAuthenticated(opts ExtractProvisionerAuthConfig) fu
}

handleOptional(http.StatusInternalServerError, codersdk.Response{
Message: "get provisioner daemon key: " + err.Error(),
Message: "get provisioner daemon key",
Detail: err.Error(),
})
return
}

if provisionerkey.Compare(pk.HashedSecret,provisionerkey.HashSecret(keyValue)) {
if provisionerkey.Compare(pk.HashedSecret,hashedKey) {
handleOptional(http.StatusUnauthorized, codersdk.Response{
Message: "provisioner daemon key invalid",
})
Expand Down
29 changes: 9 additions & 20 deletionscoderd/provisionerkey/provisionerkey.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,8 +3,6 @@ package provisionerkey
import (
"crypto/sha256"
"crypto/subtle"
"fmt"
"strings"

"github.com/google/uuid"
"golang.org/x/xerrors"
Expand All@@ -15,40 +13,31 @@ import (
)

func New(organizationID uuid.UUID, name string, tags map[string]string) (database.InsertProvisionerKeyParams, string, error) {
id := uuid.New()
secret, err := cryptorand.HexString(64)
secret, err := cryptorand.String(64)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

64 is probably longer than we need if we are using alpha (lower & upper) + numbers. When we using hex strings, technically they are case insensitive, so you only get 16 options vs the now 62 (26 lower, 26 upper, 10 numeric)

You only need ~43 characters to match the same search space as 64 hex characters. We only use22 characters for our api keys (I bet we copied someone else here).

It does not really matter, but if we are shortening our keys, we can at least shorten them to 43 and keep the same level of security as 64 hex characters. Which is super common.

16^64 = 1.157920e+7762^43 = 1.182613e+77log(16^64)/log(62) = 42.9948 <-- basically 43

Thoughts on going even shorter? 64 is such an excessive level of security.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Of course, I was leaning on better safe than sorry but let's go short - 32 sound good?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

32 is ~190 bits of entropy. 43 gets us to 256, which is common in symmetric key encryption.

At the end of the day, 32 vs 43 feels completely arbitrary and probably sufficient, but 43 feels like "random" than "32" in the fact it lines up with 256bit. 🤷‍♂️

I don't think 43 looks too bad. That's just my 2c.

43 characters long

RrMe58fCjqyf7A8uRivKq3hQDcC3y5N5rnUWSRz5QA1KH5y6hAUAJjymG8Xrjia4NY3yz3crenkmuEkT4T3N3TEiuE7aDvUZyG1TqAtiikKR5rW6WkmG2RuEjCLXi3z2B0ZRpbhZibWFfdDjRbb6fQzqy7baCBq2JQFKjDeA

32

VB3StT1Uj0CvP6LX2iMzX3eDACKPEBzFjaDjJSPNLygpKLUELrUU5m5fuNbTfvV73QvMTSuRLwn7x0hbX4YJQKf2GMcL3TA5G6LkDZdw1rumSZuLyMLGUYi15hvR38jA

64

qySKB6Zi6XLmahApVJLM5GMYP9TGy6BEyCYUC7KbVH0AE5h07W0eWg2Cqmjw7gCFpSngALfmYcVmMETAAcntnp2bzZkRC90pYRa2fC5MmvHMuQHZ7hwg5eGMnWfnbCUut5gFjyTD3iy8J9emR6B7TSCwCYrcwJGLQXBw4zPMM0AS9E89DMXy4bK4V4FtJ1qwv4C06YWqALYBpMScm7AuVYwzun0iEb5iCpQyg2fEWgfreNL2W6itRfzeS1cic1XY537TcRdc3McvbTKtN4uZRfRp68hrnYJieHHtJp4d9tNWbFFxvrECv0umzig7UUk9

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

43 it is 😄

if err != nil {
return database.InsertProvisionerKeyParams{}, "", xerrors.Errorf("generatetoken: %w", err)
return database.InsertProvisionerKeyParams{}, "", xerrors.Errorf("generatesecret: %w", err)
}
hashedSecret := HashSecret(secret)
token := fmt.Sprintf("%s:%s", id, secret)

if tags == nil {
tags = map[string]string{}
}

return database.InsertProvisionerKeyParams{
ID:id,
ID:uuid.New(),
CreatedAt: dbtime.Now(),
OrganizationID: organizationID,
Name: name,
HashedSecret:hashedSecret,
HashedSecret:HashSecret(secret),
Tags: tags,
},token, nil
},secret, nil
}

func Parse(token string) (uuid.UUID, string, error) {
parts := strings.Split(token, ":")
if len(parts) != 2 {
return uuid.UUID{}, "", xerrors.Errorf("invalid token format")
func Validate(token string) error {
if len(token) != 64 {
return xerrors.Errorf("must be 64 characters")
}

id, err := uuid.Parse(parts[0])
if err != nil {
return uuid.UUID{}, "", xerrors.Errorf("parse id: %w", err)
}

return id, parts[1], nil
return nil
}

func HashSecret(secret string) []byte {
Expand Down
4 changes: 2 additions & 2 deletionsenterprise/cli/provisionerdaemonstart.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -122,9 +122,9 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command {
if len(rawTags) > 0 {
return xerrors.New("cannot provide tags when using provisioner key")
}
_, _,err:= provisionerkey.Parse(provisionerKey)
err = provisionerkey.Validate(provisionerKey)
if err != nil {
return xerrors.Errorf("parse provisioner key: %w", err)
return xerrors.Errorf("validate provisioner key: %w", err)
}
}

Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp