-
Notifications
You must be signed in to change notification settings - Fork 474
Password auth #32131
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
Password auth #32131
Conversation
a80a26b
to
39260a0
Compare
return; | ||
} | ||
let password = password.expect("a password, we don't support other auth modes for now"); | ||
if let Some(role) = self.catalog().try_get_role_by_name(role_name.as_str()) { |
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.
holy nesting, batman!
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.
You could reduce some of the nesting by using let else with an early return.
src/auth/src/hash.rs
Outdated
|
||
fn hash_password_inner(opts: &HashOpts, password: &[u8]) -> [u8; SHA256_OUTPUT_LEN] { | ||
let mut salted_password = [0u8; SHA256_OUTPUT_LEN]; | ||
pbkdf2::derive( |
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.
Not technically constant time, but I don't think we are really subject to timing attacks here
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.
is there another document where we outline the set of attacks we are defending against? I can't see anything in the design
src/auth/src/hash.rs
Outdated
use ring::hmac::{self, Key, HMAC_SHA256}; | ||
use ring::pbkdf2::{self, PBKDF2_HMAC_SHA256 as SHA256}; | ||
use ring::rand::SecureRandom; |
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.
we are using BoringSSL here or a repackaging of it[1]. BoringSSL is not FIPS certified[2]. in past positions we have declined to use ring/BoringSSL. it's worth noting that neither ring nor BoringSSL recommend the usage of their code. in past positions we have declined to use both these libraries. what security guarantees are we planning to give to our customers?
[1] https://crates.io/crates/ring
[2] https://boringssl.googlesource.com/boringssl/+/master/crypto/fipsmodule/FIPS.md
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.
I retract part of this as it looks like the algorithms in boringssl are FIPS certified. so I guess this is fine?
see: https://boringssl.googlesource.com/boringssl/+/master/crypto/fipsmodule/FIPS.md
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.
spoke offline with @DAlperin we are migrating to aws-lc-rs which has passed FIPs certification with an approved lab at least for a specific branch of the repo.
it has not been approved by NIST as of 04/10/2025 for current status, see: https://csrc.nist.gov/Projects/cryptographic-module-validation-program/modules-in-process/Modules-In-Process-List
having said that it seems to be far and away the best option. good find @DAlperin.
|
||
/// The default iteration count as suggested by | ||
/// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html | ||
const DEFAULT_ITERATIONS: NonZeroU32 = NonZeroU32::new(600_000).unwrap(); |
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 we're going for 600,000 then we should update the technical design to reflect the new value as last I checked we were planning to use 400,000. there should also be a test showing that we meet that bench criteria of 0.1 seconds per hash.
see: https://github.com/MaterializeInc/materialize/pull/32005/files#r2025880535
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.
I'm still reading through NIST and references in that website to try to understand why they picked that value.
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.
Overall looks good to me! Don't forget to "Squash and Merge" :)
A few comments that would be nice to address but aren't blocking. The only thing we need to do is remove "OpenSSL" from our list of approved licenses, once I see that I'll approve!!
deny.toml
Outdated
@@ -296,6 +297,7 @@ allow = [ | |||
"Zlib", | |||
"Unicode-3.0", | |||
"Unicode-DFS-2016", | |||
"OpenSSL", |
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.
Before merging this we need legal's approval. Have you reached out to #operations
? If so, can you copy the Slack thread here?
I'm curious where this additional license requirement comes from?
src/adapter/src/error.rs
Outdated
@@ -175,6 +175,11 @@ pub enum AdapterError { | |||
Unstructured(anyhow::Error), | |||
/// The named feature is not supported and will (probably) not be. | |||
Unsupported(&'static str), | |||
/// Some |
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.
Left behind comment?
src/adapter/src/error.rs
Outdated
/// Authentication error. | ||
AuthenticationError, |
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.
Can you include some more context, like what kind of authentication error? Is this from Frontegg or something else?
If you're new to the code and trying to track down why this error is being returned, what would be helpful for you to see here?
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Arbitrary)] | ||
pub struct Password(String); | ||
|
||
assert_not_impl_all!(Password: Display); |
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.
Probably want to assert it doesn't impl Debug
as well?
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.
It does impl Debug, but we implement it manually so it always shows Password(****)
. This is due to the fact that Password
gets carried around in lots of structs with #[derive(Debug)]
src/auth/src/password.rs
Outdated
|
||
///Password is a String wrapper type that does not implement Display or Debug | ||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Arbitrary)] | ||
pub struct Password(String); |
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.
Nice!! Thanks for adding this!
/// Self hosted auth | ||
#[clap(long, env = "ENABLE_SELF_HOSTED_AUTH")] | ||
enable_self_hosted_auth: bool, | ||
/// Self hosted auth over internal port | ||
#[clap(long, env = "ENABLE_SELF_HOSTED_AUTH_INTERNAL")] | ||
enable_self_hosted_auth_internal: bool, |
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.
Mind tossing a TODO(auth)
here so we can track the follow-up?
// No frontegg check, so auth session lasts indefinitely. | ||
let auth_session = pending().right_future(); |
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.
Thanks for checking!
@@ -47,11 +47,14 @@ COMPLETE 0 | |||
statement error non inherit roles not yet supported | |||
CREATE ROLE foo NOINHERIT | |||
|
|||
statement error LOGIN attribute is not supported, for more information consult the documentation at | |||
statement error db error: ERROR: SUPERUSER, PASSWORD, and LOGIN attributes is not supported in this environment. For more information consult the documentation at https://materialize.com/docs/sql/create-role/#details |
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.
Very slick! 💯
# You might think to yourself "why is creating a role with PASSWORD NULL | ||
# allowed? Especially when self hosted auth isn't enabled?" | ||
# The answer is unsatisfying: it's a legacy behavior from Postgres. | ||
# Creating a role with a null password is the same as not specifying a password at all. | ||
# So, uh, sure... |
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.
Honestly I was wondering, so thanks for adding this comment!
Follow-up to MaterializeInc#32131 Failures seen in https://buildkite.com/materialize/nightly/builds/11825
This is the bones of self managed password auth. This is missing integration tests and documentation which will come next. You can test this locally like so:
This begins implementing #32005
Motivation
Tips for reviewer
Checklist
$T ⇔ Proto$T
mapping (possibly in a backwards-incompatible way), then it is tagged with aT-proto
label.