-
Notifications
You must be signed in to change notification settings - Fork 887
feat: encrypt oidc and git auth tokens in the database #7959
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
Conversation
does this resolve #7640? |
Yup! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem to support upgrading non-encrypted secrets to encrypted on startup, and it doesn't support rotating the encryption key.
@@ -0,0 +1,48 @@ | |||
package cryptorand |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this doesn't belong in cryptorand package because it's not random, it should go in the dbcrypt
package or it's own package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Will move
|
||
// CipherAES256 returns a new AES-256 cipher. | ||
func CipherAES256(key []byte) (Cipher, error) { | ||
block, err := aes.NewCipher(key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the key should be verified to ensure it's 32 bytes for AES-256
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aes.NewCipher throws an error if it's not
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aes.NewCipher accepts smaller key sizes for less secure AES variants, we should just enforce 32 bytes for AES-256 which is the most secure algo supported
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, good catch
if err != nil { | ||
return nil, err | ||
} | ||
return a.aead.Seal(nonce, nonce, plaintext, nil), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should write to a new buffer instead of reusing the nonce buffer, and the nonce should be copied
"github.com/coder/coder/cryptorand" | ||
) | ||
|
||
func TestCipherAES256(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should add a test to ensure a unique nonce is being generated each time we encrypt something new, and another to ensure that changing the nonce causes decryption to fail
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should add another test to ensure that the format doesn't change in a backwards incompatible way. Hardcode a key, encrypt something once and then hardcode the encrypted result to ensure it gets decrypted successfully and matches the same input string.
|
||
{ | ||
Name: "External Token Encryption Key", | ||
Description: "Encrypt OIDC and Git authentication tokens with AES-256-GCM in the database. The value must be a base64-encoded key.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should mention that it needs to be 32 bytes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And should provide a bash one liner to generate a secure random key with e.g. openssl or just plain /dev/random
@@ -229,6 +229,12 @@ func ExtractAPIKey(rw http.ResponseWriter, r *http.Request, cfg ExtractAPIKeyCon | |||
UserID: key.UserID, | |||
LoginType: key.LoginType, | |||
}) | |||
if errors.Is(err, sql.ErrNoRows) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if errors.Is(err, sql.ErrNoRows) { | |
if xerrors.Is(err, sql.ErrNoRows) { |
@@ -27,3 +27,6 @@ UPDATE git_auth_links SET | |||
oauth_refresh_token = $5, | |||
oauth_expiry = $6 | |||
WHERE provider_id = $1 AND user_id = $2 RETURNING *; | |||
|
|||
-- name: DeleteGitAuthLink :exec | |||
DELETE FROM git_auth_links WHERE provider_id = $1 AND user_id = $2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DELETE FROM git_auth_links WHERE provider_id = $1 AND user_id = $2; | |
DELETE FROM | |
git_auth_links | |
WHERE | |
provider_id = $1 AND | |
user_id = $2; |
// If we have a magic prefix but encryption is disabled, | ||
// we should delete the row. | ||
return delete("encryption disabled") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens when the key is accidentally not specified during coder startup? All rows will start being deleted when they're queried? This seems like a really bad idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All data encrypted at rest is intentionally temporary. We will not do this for any data that must persist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be written in a very prominent comment at the top of the file or something then, because I can definitely see this being used for e.g. gitauth by another engineer who doesn't know about this limitation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed will add
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All data encrypted at rest is intentionally temporary. We will not do this for any data that must persist.
What about ssh keys that should use encryption at rest ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Adphi that isn't in this PR yet, but I'm not sure what we should do in that case. Maybe stop the server from starting with a warning that is dismissable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I may, perhaps when the encryption key is wrong, the program should crash loudly to preserve the integrity of the secrets.
And maybe add a command line flag or environment variable to allow all encrypted data to be erased, recovery style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed!
This commit builds upon the previous work in #7959: - Moved dbcrypt package to enterprise/dbcrypt - Modified original dbcrypt behaviour to not delete un-decryptable rows. - Added a table dbcrypt_sentinel used to determine database encryption status NOTE: This is part 1 of a 2-part PR. This PR focuses mainly on the dbcrypt and database packages. A separate PR will add the required plumbing to integrate this into enterprise/coderd properly. Co-authored-by: Kyle Carberry <kyle@coder.com>
This commit builds upon the previous work in #7959: - Moved dbcrypt package to enterprise/dbcrypt - Modified original dbcrypt behaviour to not delete un-decryptable rows. - Added a table dbcrypt_sentinel used to determine database encryption status. - Added support for multiple encryption keys in dbcrypt. NOTE: This is part 1 of a 2-part PR. This PR focuses mainly on the dbcrypt and database packages. A separate PR will add the required plumbing to integrate this into enterprise/coderd properly. Co-authored-by: Kyle Carberry <kyle@coder.com>
No description provided.