Skip to content

pgwire: auto-upgrade password authentication with SCRAM hashes (scram 9/10)#74849

Merged
craig[bot] merged 3 commits intomasterfrom
20211228-scram9
Jan 21, 2022
Merged

pgwire: auto-upgrade password authentication with SCRAM hashes (scram 9/10)#74849
craig[bot] merged 3 commits intomasterfrom
20211228-scram9

Conversation

@knz
Copy link
Copy Markdown
Contributor

@knz knz commented Jan 14, 2022

(PR peeled away from #74301; previous PR in series #74848; next PR in series: #74850)
Epic CRDB-5349

Release note (security update): When using the HBA authentication
method cert-password (the default) for SQL client connections, and
the SQL client does not present a TLS client certificate to the
server, CockroachDB now automatically upgrades the password handshake
protocol to use SCRAM-SHA-256 if the user's stored password uses the
SCRAM encoding.

The previous behavior of requesting a cleartext password is still used
if the stored password is encoded using the CRDB-BCRYPT format.

An operator can force to always request SCRAM-SHA-256 when a TLS
client cert is not provided (so as to guarantee the various
security benefits of SCRAM) using the authentication methods
cert-scram-sha-256 (either TLS client cert or SCRAM-SHA-256); and
scram-sha-256 (only SCRAM-SHA-256).

(As previously, mandatory cleartext password authentication
can be requested, e.g. for debugging purposes, by using the HBA
method password.)

This automatic protocol upgrade can be manually disabled
using the new cluster setting
server.user_login.cert_password_method.auto_scram_promotion.enable (by
setting it to false), for example if certain client drivers
are found to not support SCRAM-SHA-256 authentication properly.

Release note (sql change): When possible, CockroachDB will now
automatically require the PostgreSQL-compatible SCRAM-SHA-256 protocol
when performing password validation when SQL client log in. (Reminder:
this mechanism is not used when SQL clients use TLS client certs,
which is the recommended approach.)

This assumes support for SCRAM-SHA-256 in client drivers.
As of 2020, we have found this to be prevalent in the pg driver
ecosystem. However, users should be mindful of the following possible
behavior changes:

  • an application that tries to detect whether password verification
    has failed by checking server error messages, might observe
    different error messages with SCRAM-SHA-256. Those checks, if
    present, need to be updated.

  • if a client driver simply does not support SCRAM-SHA-256 at all,
    the operator retains the option to set the cluster setting
    server.user_login.cert_password_method.auto_scram_promotion.enable
    to false to force the previous password verification method instead.

@cockroach-teamcity
Copy link
Copy Markdown
Member

This change is Reviewable

@knz knz force-pushed the 20211228-scram8 branch from 238624a to 31d18cd Compare January 14, 2022 10:53
@knz knz force-pushed the 20211228-scram9 branch from dfec195 to c4c92a2 Compare January 14, 2022 10:56
@knz knz changed the title wip9 pgwire: auto-upgrade password authentication with SCRAM hashes Jan 14, 2022
@knz knz requested review from a team, bdarnell and rafiss January 14, 2022 10:57
@knz knz marked this pull request as ready for review January 14, 2022 10:57
@knz knz requested a review from a team as a January 14, 2022 10:57
@knz knz force-pushed the 20211228-scram8 branch from 31d18cd to 41b29ed Compare January 14, 2022 11:13
@knz knz requested a review from a team January 14, 2022 11:13
@knz knz force-pushed the 20211228-scram9 branch from c4c92a2 to 2f3e89b Compare January 14, 2022 11:13
@knz knz force-pushed the 20211228-scram8 branch from 41b29ed to cc70947 Compare January 14, 2022 11:18
@knz knz force-pushed the 20211228-scram9 branch from 2f3e89b to ddc00c8 Compare January 14, 2022 11:19
@knz knz changed the title pgwire: auto-upgrade password authentication with SCRAM hashes pgwire: auto-upgrade password authentication with SCRAM hashes (scram 9/10) Jan 14, 2022
@knz knz force-pushed the 20211228-scram8 branch from cc70947 to ccf130c Compare January 14, 2022 15:10
@knz knz force-pushed the 20211228-scram9 branch from ddc00c8 to 1362b23 Compare January 14, 2022 15:11
@knz knz force-pushed the 20211228-scram8 branch from ccf130c to c7f918c Compare January 14, 2022 19:18
@knz knz force-pushed the 20211228-scram9 branch from 1362b23 to 9c44b2c Compare January 14, 2022 19:18
@knz knz force-pushed the 20211228-scram8 branch from c7f918c to 606d0a7 Compare January 14, 2022 19:44
@knz knz force-pushed the 20211228-scram9 branch from 9c44b2c to 212f044 Compare January 14, 2022 19:44
@knz knz force-pushed the 20211228-scram8 branch from 606d0a7 to 7fd3c05 Compare January 14, 2022 19:46
@knz knz force-pushed the 20211228-scram9 branch from 212f044 to 3cf870e Compare January 14, 2022 19:47
@knz knz force-pushed the 20211228-scram8 branch from 7fd3c05 to 2fb6482 Compare January 15, 2022 12:12
@knz knz force-pushed the 20211228-scram9 branch from 3cf870e to 5fa5820 Compare January 15, 2022 12:12
@knz knz force-pushed the 20211228-scram8 branch from 2fb6482 to cb4687d Compare January 15, 2022 12:39
@knz knz requested a review from a team January 15, 2022 12:39
@knz knz force-pushed the 20211228-scram9 branch from 5fa5820 to 0d4ff57 Compare January 15, 2022 12:39
Copy link
Copy Markdown
Collaborator

@rafiss rafiss left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @bdarnell and @knz)


pkg/sql/pgwire/auth_methods.go, line 233 at r3 (raw file):

}

// passwordAuthenticator is the authenticator function for the

nit: passwordAuthenticator -> scramAuthenticator


pkg/sql/pgwire/auth_methods.go, line 494 at r3 (raw file):

		// The authenticator function needs a closure to retrieve the same information.
		// Memoize it.
		newpwfn := func(ctx context.Context) (bool, security.PasswordHash, error) { return expired, hashedPassword, err }

so just to confirm, both expired and err are checked later when newpwfn is called? perhaps a comment here that reiterates that would help


pkg/sql/pgwire/auth_methods.go, line 499 at r3 (raw file):

		if err == nil && hashedPassword.Method() == security.HashSCRAMSHA256 {
			// Yes: use a SCRAM-SHA-256 exchange.
			c.LogAuthInfof(ctx, "no client cert but SCRAM credentials found, proceeding with SCRAM-SHA-256")

i wonder if the logging here assumes too much. currently this is only called in the cert-password mode, but if the code is refactored and this gets used elsewhere, the "no client cert" part of the message might be confusing.

in other words, can we have c.LogAuthInfof(no client cert ...) in the authCertPassword function, and keep c.LogAuthInfof(proceeding with SCRAM ...) in this function? (ditto for c.LogAuthInfof(requesting cleartext ...)

Copy link
Copy Markdown
Contributor Author

@knz knz left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @bdarnell and @rafiss)


pkg/sql/pgwire/auth_methods.go, line 233 at r3 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

nit: passwordAuthenticator -> scramAuthenticator

Fixed.


pkg/sql/pgwire/auth_methods.go, line 494 at r3 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

so just to confirm, both expired and err are checked later when newpwfn is called? perhaps a comment here that reiterates that would help

Good call. Done.


pkg/sql/pgwire/auth_methods.go, line 499 at r3 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

i wonder if the logging here assumes too much. currently this is only called in the cert-password mode, but if the code is refactored and this gets used elsewhere, the "no client cert" part of the message might be confusing.

in other words, can we have c.LogAuthInfof(no client cert ...) in the authCertPassword function, and keep c.LogAuthInfof(proceeding with SCRAM ...) in this function? (ditto for c.LogAuthInfof(requesting cleartext ...)

Great idea. Done.

@knz knz force-pushed the 20211228-scram9 branch 2 times, most recently from fdff4d7 to 7ca14c9 Compare January 19, 2022 14:10
Copy link
Copy Markdown
Collaborator

@rafiss rafiss left a comment

Choose a reason for hiding this comment

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

lgtm!

Reviewed 8 of 8 files at r6, all commit messages.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @bdarnell and @rafiss)

@knz
Copy link
Copy Markdown
Contributor Author

knz commented Jan 20, 2022

NB: I'm holding off merging this PR until all the PRs in the sequence are ready (otherwise, the entire chain will be auto-closed by github).

knz added 3 commits January 21, 2022 00:59
This just lifts the closures into named functions and gives them
explicit argument lists.

Release note: None
Release note (security update): When using the HBA authentication
method `cert-password` (the default) for SQL client connections, and
the SQL client does not present a TLS client certificate to the
server, CockroachDB now automatically upgrades the password handshake
protocol to use SCRAM-SHA-256 if the user's stored password uses the
SCRAM encoding.

The previous behavior of requesting a cleartext password is still used
if the stored password is encoded using the CRDB-BCRYPT format.

An operator can force to _always_ request SCRAM-SHA-256 when a TLS
client cert is not provided (so as to guarantee the various
security benefits of SCRAM) using the authentication methods
`cert-scram-sha-256` (either TLS client cert _or_ SCRAM-SHA-256); and
`scram-sha-256` (only SCRAM-SHA-256).

(As previously, mandatory cleartext password authentication
can be requested, e.g. for debugging purposes, by using the HBA
method `password`.)

This automatic protocol upgrade can be manually disabled
using the new cluster setting
`server.user_login.cert_password_method.auto_scram_promotion.enable` (by
setting it to `false`), for example if certain client drivers
are found to not support SCRAM-SHA-256 authentication properly.

Release note (sql change): When possible, CockroachDB will now
automatically require the PostgreSQL-compatible SCRAM-SHA-256 protocol
when performing password validation when SQL client log in. (Reminder:
this mechanism is not used when SQL clients use TLS client certs,
which is the recommended approach.)

This assumes support for SCRAM-SHA-256 in client drivers.
As of 2020, we have found this to be prevalent in the pg driver
ecosystem. However, users should be mindful of the following possible
behavior changes:

- an application that tries to detect whether password verification
  has failed by checking server error messages, might observe
  different error messages with SCRAM-SHA-256. Those checks, if
  present, need to be updated.

- if a client driver simply does not support SCRAM-SHA-256 at all,
  the operator retains the option to set the cluster setting
  `server.user_login.cert_password_method.auto_scram_promotion.enable`
  to `false` to force the previous password verification method instead.
@knz knz force-pushed the 20211228-scram8 branch from 16db78a to 0a71168 Compare January 21, 2022 00:01
@knz knz force-pushed the 20211228-scram9 branch from 40f9bf8 to 50ca9f9 Compare January 21, 2022 00:01
craig bot pushed a commit that referenced this pull request Jan 21, 2022
74301: sql,server: support SCRAM authentication for SQL sessions r=rafiss,JeffSwenson,bdarnell,aaron-crl,kpatron-cockroachlabs a=knz

Fixes #42519.
Fixes #74511.
Informs #65117.
Epic CRDB-5349

**tldr:** this PR adds support for the SCRAM-SHA-256 authentication method, as defined by IETF RFCs [5802](https://datatracker.ietf.org/doc/html/rfc5802) and [7677](https://datatracker.ietf.org/doc/html/rfc7677) and as supported by PostgreSQL. This offers [multiple security benefits](#scram-benefits) over CockroachDB's current use of cleartext password authentication. To use this feature,
1) the stored password hashes must use the SCRAM encoding (this requires a migration away from crdb's bcrypt-based hashes); and
2) one of the SCRAM authentication methods must be enabled explictly via the HBA configuration (cluster setting `server.host_based_authentication.configuration`).

### How to review this work

The addition of the feature goes as follows:

1. adding HBA syntax and authentication method hooks for `scram-sha-256` and `cert-scram-sha-256`. These are gated behind a new cluster version, so that previous-version nodes do not get confused by the new syntax.

   Split into separate PR: #74842

2. extending ALTER/CREATE USER/ROLE WITH PASSWORD to recognize SCRAM hashes. This allows operators to use these SQL statements to populate SCRAM hashes.
    (This should also be seen as the more desirable way to configure SQL user accounts: it ensures that the CockroachDB node never ever sees the cleartext password of an account. Even if we later support computing the SCRAM hash server-side, pre-computing the hash client-side should be seen and documented as the superior approach.)

   Split into separate PR: #74843

3. extending the existing cleartext methods inside CockroachDB (used for the HTTP interface and the `password`-based methods in SQL) to compare a cleartext password to a pre-computed SCRAM hash. This ensures that the existing password mechanisms that are cleartext-based continue to work even after the stored credentials start using the SCRAM encoding.

   Split into separate PRs: #74844 and #74845

4. extending the code created at step 1 to actually use the stored SCRAM credentials for client authentication. This achieves the main goal.

   Split into separate PRs: #74846 and #74847

5. making the hash method used to encode cleartext passwords passed to ALTER/CREATE USER/ROLE WITH PASSWORD configurable, using a new cluster setting `server.user_login.password_encryption`, and exposing its value via the pg-compatible session variable `password_encryption`.
   This is a convenience feature - properly secured deployments should not need this, as they should use pre-hashing client-side instead (see note at point 2 above).

   Split into separate PR: #74848

6. making crdb auto-select SCRAM authn if the stored password uses SCRAM. This is one step to ensuring that previous-version clusters are automatically opted into SCRAM.

   Split into separate PR: #74849

7. Auto-upgrade the stored credentials from bcrypt to SCRAM, when enabled and possible.

   Split into separate PR: #74850

The reviewer is invited to consider each PR in turn, read its commit message(s) to understand the goal of that PR, then review the PR to ascertain that the implementation (and relevant tests) match the goals announced in the commit message.


Co-authored-by: Raphael 'kena' Poss <knz@thaumogen.net>
Base automatically changed from 20211228-scram8 to master January 21, 2022 09:12
@craig craig bot merged commit 50ca9f9 into master Jan 21, 2022
@craig craig bot deleted the 20211228-scram9 branch January 21, 2022 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants