-
Notifications
You must be signed in to change notification settings - Fork 590
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
feat: create secret catalog #16288
feat: create secret catalog #16288
Conversation
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.
license-eye has totally checked 5070 files.
Valid | Invalid | Ignored | Fixed |
---|---|---|---|
2171 | 1 | 2898 | 0 |
Click to see the invalid file list
- src/frontend/src/handler/create_secret.rs
|
GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
---|---|---|---|---|---|
9425213 | Triggered | Generic Password | 8e4637f | e2e_test/source/cdc/cdc.validate.postgres.slt | View secret |
9425213 | Triggered | Generic Password | 1a75e35 | e2e_test/source/cdc/cdc.validate.postgres.slt | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secrets safely. Learn here the best practices.
- Revoke and rotate these secrets.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
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 PR is too large, can we separate it into two parts, like meta and frontend. Btw, we need to add some e2e to check if it works.
Btw, the backup and migration from etcd to sql backend are still missing, we need to add them as well. It's acceptable for me to add them in some other PRs.
secret_by_name: HashMap<String, Arc<SecretCatalog>>, | ||
secret_by_id: HashMap<SecretId, Arc<SecretCatalog>>, | ||
|
||
secret_source_ref: HashMap<SecretId, Vec<SourceId>>, |
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.
Do we have any usage of these two fields? We need to update them when issuing create/drop
source/sink
.
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 believe they're necessary for command like show secrets
.
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.
Do we have any usage of these two fields? We need to update them when issuing create/drop source/sink.
I am planning to impl this in the next pr. It is more intuitive to do it with ref secret
syntax.
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 believe they're necessary for command like show secrets.
Yes, show secrets
will be in this pr.
src/meta/model_v2/src/sink.rs
Outdated
@@ -127,6 +129,13 @@ impl From<PbSink> for ActiveModel { | |||
sink_from_name: Set(pb_sink.sink_from_name), | |||
sink_format_desc: Set(pb_sink.format_desc.as_ref().map(|x| x.into())), | |||
target_table: Set(pb_sink.target_table.map(|x| x as _)), | |||
secret_ref: Set({ |
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.
Better to define this column as json_binary
in migration, then you can define a struct wrapping the map and use it here. Check examples that are using derive_from_json_struct
for more details.
src/meta/src/manager/catalog/mod.rs
Outdated
let user_core = &mut core.user; | ||
let mut secrets = BTreeMapTransaction::new(&mut database_core.secrets); | ||
|
||
match database_core.relation_ref_count.get(&secret_id) { |
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.
Ditto, secret referring count is never updated when create/drop sink and source.
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 resolved, you can remove the check and leave a TODO
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.
Overall LGTM
let session = handler_args.session.clone(); | ||
let db_name = session.database(); | ||
let (schema_name, connection_name) = | ||
Binder::resolve_schema_qualified_name(db_name, stmt.secret_name.clone())?; |
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.
Do we follow the same rule of identifiers for secrets? That is,
foo
will be converted to lower-case, so thatFoo
andfoo
will be the same"foo"
will be interpreted as case-sensitive, i.e."foo"
and"Foo"
are different
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.
For the secret name, yes. The impl leverages the existing funds and tries best to keep the same as other catalogs.
secret.schema_id, | ||
SecretId::new(secret.id), | ||
), | ||
Operation::Update => unimplemented!(), |
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.
Considering key rotation, I think it makes sense to provide an "update secret" command
@@ -184,6 +203,14 @@ impl MetaClient { | |||
Ok(resp.version) | |||
} | |||
|
|||
pub async fn drop_secret(&self, secret_id: SecretId) -> Result<CatalogVersion> { |
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 a big deal but why not placing it with create_secret()
together
Signed-off-by: tabVersion <[email protected]>
Signed-off-by: tabVersion <[email protected]>
Signed-off-by: tabVersion <[email protected]>
src/meta/src/rpc/ddl_controller.rs
Outdated
let encrypted_payload = simplestcrypt::encrypt_and_serialize( | ||
self.env.opts.secret_store_private_key.as_slice(), | ||
secret.get_value().as_slice(), | ||
) |
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 do the encryption and the secret key here.
@yuhao-su
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.
Why not using the implementation in our built-in function encrypt(bytea, bytea, varchar) -> bytea
?
risingwave/src/expr/impl/src/scalar/encrypt.rs
Lines 141 to 157 in 1cc36e1
fn eval_inner( | |
&self, | |
input: &[u8], | |
operation: CipherMode, | |
) -> std::result::Result<Box<[u8]>, ErrorStack> { | |
let mut decrypter = Crypter::new(self.cipher, operation, self.crypt_key.as_ref(), None)?; | |
let enable_padding = match self.padding { | |
Padding::Pkcs => true, | |
Padding::None => false, | |
}; | |
decrypter.pad(enable_padding); | |
let mut decrypt = vec![0; input.len() + self.cipher.block_size()]; | |
let count = decrypter.update(input, &mut decrypt)?; | |
let rest = decrypter.finalize(&mut decrypt[count..])?; | |
decrypt.truncate(count + rest); | |
Ok(decrypt.into()) | |
} |
Benefits include
- Avoid duplicates in dependencies
- Easy to encrypt & decrypt with SQL interface when debugging
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.
Agree with #16288 (comment)
Better to consider a more popular encryption lib
Such as openssl
directly.
It's a bit risky to use a 3rd-party unpopular lib for decryption & encryption here. Considering the possibility that the lib author may discontinue its maintenance, we should either use ourselves's implementation, or ensure we know 100% how the lib works so that we can write an exactly same one. The former one is easier, I think.
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.
Why not using the implementation in our built-in function encrypt(bytea, bytea, varchar) -> bytea?
Good point! Let me fix it.
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.
risingwave/src/meta/src/rpc/ddl_controller.rs
Lines 633 to 660 in af892fa
let encrypted_payload = { | |
let data = secret.get_value().as_slice(); | |
let key = self.env.opts.secret_store_private_key.as_slice(); | |
let encrypt_key = { | |
let mut k = key[..(std::cmp::min(key.len(), 32))].to_vec(); | |
k.resize_with(32, || 0); | |
k | |
}; | |
let mut rng = rand::thread_rng(); | |
let mut nonce: [u8; 16] = [0; 16]; | |
rng.fill_bytes(&mut nonce); | |
let nonce_array = GenericArray::from_slice(&nonce); | |
let cipher = Aes128SivAead::new(encrypt_key.as_slice().into()); | |
let ciphertext = cipher.encrypt(nonce_array, data).map_err(|e| { | |
MetaError::from(MetaErrorInner::InvalidParameter(format!( | |
"failed to encrypt secret {}: {:?}", | |
secret.name, e | |
))) | |
})?; | |
bincode::serialize(&SecretEncryption { nonce, ciphertext }).map_err(|e| { | |
MetaError::from(MetaErrorInner::InvalidParameter(format!( | |
"failed to serialize secret {}: {:?}", | |
secret.name, e | |
))) | |
})? | |
}; |
Impl the encryption myself :-)
src/meta/Cargo.toml
Outdated
@@ -64,6 +64,7 @@ scopeguard = "1.2.0" | |||
sea-orm = { workspace = true } | |||
serde = { version = "1.0.196", features = ["derive"] } | |||
serde_json = "1.0.113" | |||
simplestcrypt = "0.1" |
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.
Better to consider a more popular encryption lib
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.
https://github.com/TotalKrill/simplestcrypt/blob/master/src/lib.rs
Took a rough look at the crate, the owner just wrapped a basic usage of an audited encryption crate, instead of writing the real "encryption" part. Seems not that vital. What do you think?
Signed-off-by: tabVersion <[email protected]>
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.
Rest generally LGTM. This PR is so large, rubber stamp for it. We need to add more e2e and secret usage support for it. After this PR, we also need to support it in migration script from etcd to sql backend.
src/sqlparser/src/ast/mod.rs
Outdated
@@ -1861,6 +1868,7 @@ impl fmt::Display for Statement { | |||
Statement::DeclareCursor { stmt } => write!(f, "DECLARE {}", stmt,), | |||
Statement::FetchCursor { stmt } => write!(f, "FETCH {}", stmt), | |||
Statement::CloseCursor { stmt } => write!(f, "CLOSE {}", stmt), | |||
Statement::CreateSecret { stmt } => write!(f, "CREATE SECRET {}", stmt, ), |
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.
Statement::CreateSecret { stmt } => write!(f, "CREATE SECRET {}", stmt, ), | |
Statement::CreateSecret { stmt } => write!(f, "CREATE SECRET {}", stmt), |
src/meta/src/manager/catalog/mod.rs
Outdated
let user_core = &mut core.user; | ||
let mut secrets = BTreeMapTransaction::new(&mut database_core.secrets); | ||
|
||
match database_core.relation_ref_count.get(&secret_id) { |
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 resolved, you can remove the check and leave a TODO
here.
@@ -24,6 +25,7 @@ impl MigratorTrait for Migrator { | |||
Box::new(m20240410_154406_session_params::Migration), | |||
Box::new(m20240417_062305_subscription_internal_table_name::Migration), | |||
Box::new(m20240418_142249_function_runtime::Migration), | |||
Box::new(m20240422_090457_secret::Migration), |
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 not sure whether a smaller date naming for this migration can be applied when upgrade from the version before this PR. Didn't check, if not work you can rename to a larger date for it.
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.
fixed
Signed-off-by: tabVersion <[email protected]>
Signed-off-by: tabVersion <[email protected]>
Signed-off-by: tabVersion <[email protected]>
Signed-off-by: tabVersion <[email protected]>
Signed-off-by: tabVersion <[email protected]>
Signed-off-by: tabVersion <[email protected]>
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.
Generally LGTM, thx for the PR.
Co-authored-by: August <[email protected]>
Bump up #16288 (comment). Seems to be overlooked. The rest LGTM |
Signed-off-by: tabVersion <[email protected]>
Signed-off-by: tabVersion <[email protected]>
Not sure if it is ok to dep |
Signed-off-by: tabVersion <[email protected]>
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 rest LGTM
Co-authored-by: Eric Fu <[email protected]>
Signed-off-by: tabVersion <[email protected]>
I hereby agree to the terms of the RisingWave Labs, Inc. Contributor License Agreement.
What's changed and what's your intention?
Checklist
./risedev check
(or alias,./risedev c
)Documentation
Release note
If this PR includes changes that directly affect users or other significant modifications relevant to the community, kindly draft a release note to provide a concise summary of these changes. Please prioritize highlighting the impact these changes will have on users.