-
Notifications
You must be signed in to change notification settings - Fork 99
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
CDH: add get_secret support for Aliyun KMS #423
CDH: add get_secret support for Aliyun KMS #423
Conversation
2a84202
to
90a64d4
Compare
The basic build check failure is irrelevant to this PR. I'll open another PR to fix it. |
The basic build check failure is fixed in #424. |
90a64d4
to
bf96b6e
Compare
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 @1570005763 for this patch. Here are some comments
@@ -18,12 +18,12 @@ use serde_json::Value; | |||
use sha2::{Digest, Sha256}; | |||
use tokio::fs; | |||
|
|||
use crate::plugins::aliyun::client::dkms_api::{DecryptRequest, EncryptRequest}; | |||
// use crate::plugins::aliyun::client::dkms_api; |
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 the note //
here for debug?
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.
Deleted.
"client_key_id": "KAAP.2bc431c0-416f-4ccb-8638-e71245fd60c1", | ||
"kms_instance_id": "kst-bjj65794c36xm0v9aeujs", | ||
}); | ||
// init encrypter at user side |
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.
encrypter -> getter
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.
Modified.
#[ignore] | ||
#[tokio::test] | ||
async fn get_secret_with_client_key() { | ||
let secret_name = "test_secret"; |
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.
Could you use rstest
like https://github.com/confidential-containers/guest-components/blob/main/confidential-data-hub/kms/src/plugins/aliyun/client.rs#L320-L326 for test cases?
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.
Sure, rtest
looks better.
confidential-data-hub/kms/Cargo.toml
Outdated
@@ -21,17 +21,19 @@ log.workspace = true | |||
openssl = { workspace = true, optional = true } | |||
p12 = { version = "0.6.3", optional = true } | |||
prost = { workspace = true, optional = true } | |||
rand.workspace = true | |||
reqwest = { version = "0.11", optional = true } |
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.
as we already imported request in the workspace's Cargo.toml, here can be
reqwest = { workspace = true, optional = true }
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.
Modified.
// use base64::{engine::general_purpose::STANDARD, Engine}; | ||
// use log::debug; | ||
// use openssl::{ | ||
// pkey::{PKey, Private}, | ||
// sign::Signer, | ||
// }; | ||
// use p12::{CertBag, ContentInfo, MacData, SafeBagKind, PFX}; | ||
// use serde::Deserialize; | ||
// use yasna::ASN1Result; |
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.
Are these left by debug?
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.
Deleted.
return Err(anyhow!( | ||
"Request session_credential failed with status: {}", | ||
response.status() | ||
)); |
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.
return Err(anyhow!( | |
"Request session_credential failed with status: {}", | |
response.status() | |
)); | |
bail!( | |
"Request session_credential failed with status: {}", | |
response.status() | |
); |
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.
Modified.
let session_ak = body_json["AccessKeyId"].as_str().unwrap().to_string(); | ||
let session_sk = body_json["AccessKeySecret"].as_str().unwrap().to_string(); | ||
let token = body_json["SecurityToken"].as_str().unwrap().to_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.
Can you please avoid using unwrap()
but an error handling like ok_or
to prevent the process from panic?
Also, if directly use ["SecurityToken"]
to index the field in a JSON, it might also panic if no field named SecurityToken
exists. Please try to use .get("..")
instead.
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.
Helpful suggestion! Has been modified.
} | ||
} | ||
|
||
pub(crate) fn urlencode_openapi(&self, s: &String) -> 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.
pub(crate) fn urlencode_openapi(&self, s: &String) -> String { | |
pub(crate) fn urlencode_openapi(&self, s: &str) -> String { |
When use a reference to a String, &str
is preferred.
BTW, is this function actually used?
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.
Yeah, it's used in both build_params()
and do_request()
functions.
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.
Modified.
bf96b6e
to
83b0b9a
Compare
client_key_id: ck.key_id.clone(), | ||
private_key, | ||
}; | ||
|
||
Ok(credential) | ||
} | ||
|
||
pub(crate) fn generate_bear_auth(&self, str_to_sign: &str) -> Result<String> { | ||
pub(crate) fn sign(&self, str_to_sign: &str) -> Result<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.
This function actually generates bear auth string. Do we need to change the name?
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 was originally hoping to unify the function names for obtaining signatures in clientKey access and ecsRamRole access. It seems that the sign()
might be confusing. What do you think about changing it to get_signature()
?
9ce601d
to
921ed51
Compare
I have reorganized the code structure to make it easier to understand. Please take another look. @Xynnn007 |
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.
Some more comments
})?; | ||
|
||
let ecs_ram_role_name = | ||
if let Some(ecs_ram_role_name) = ecs_ram_role_json["ecs_ram_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.
Please check the existance of ecs_ram_role_json["ecs_ram_role_name"]
before using that
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.
modified.
.join("&"); | ||
let urlencoded_canonicalized_params: String = | ||
credential.urlencode_openapi(&canonicalized_params); | ||
let string_to_sign = format!("POST&%2F&{}", urlencoded_canonicalized_params,); |
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.
let string_to_sign = format!("POST&%2F&{}", urlencoded_canonicalized_params,); | |
let string_to_sign = format!("POST&%2F&{}", urlencoded_canonicalized_params); |
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.
deleted.
confidential-data-hub/kms/Cargo.toml
Outdated
thiserror.workspace = true | ||
tokio = { workspace = true, features = ["fs"] } | ||
toml.workspace = true | ||
tonic = { workspace = true, optional = true } | ||
url.workspace = true |
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 might need to make url
as optional
to aliyun
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.
modified.
confidential-data-hub/kms/Cargo.toml
Outdated
@@ -21,17 +21,19 @@ log.workspace = true | |||
openssl = { workspace = true, optional = true } | |||
p12 = { version = "0.6.3", optional = true } | |||
prost = { workspace = true, optional = true } | |||
rand.workspace = true |
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 might need to make this optional
to aliyun
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.
modified.
|
||
// implement ConfigClientKey related function | ||
impl ConfigClientKey { | ||
pub(crate) fn new(kms_instance_id: &str, endpoint: &str) -> Result<Self> { |
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 do not return any Error
, usually we do not use Result<Self>
but directly Self
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.
Result<_>
removed.
@@ -0,0 +1,29 @@ | |||
// Copyright (c) 2023 Alibaba Cloud |
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.
2023 -> 2024
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.
updated.
|
||
// implement ConfigEcsRamRole related function | ||
impl ConfigEcsRamRole { | ||
pub(crate) fn new(region_id: &str, endpoint: &str, vpc: &str) -> Result<Self> { |
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 same issue upon Result<_>
usage
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.
Result<_>
removed.
/// Export the [`ProviderSettings`] of the current client. This function is to be used | ||
/// in the encryptor side. The [`ProviderSettings`] will be used to initial a client | ||
/// in the decryptor side. | ||
pub fn export_provider_settings(&self) -> Result<ProviderSettings> { |
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 same issue upon Result<_>
usage.
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.
Result<_>
removed.
let inner_client = if provider_settings.contains_key("client_type") | ||
&& provider_settings["client_type"] == "client_key" | ||
{ | ||
Client::ClientKey { | ||
client_key_client: ClientKeyClient::from_provider_settings(provider_settings) | ||
.await | ||
.map_err(|e| { | ||
Error::AliyunKmsError(format!( | ||
"build ClientKeyClient with `from_provider_settings()` failed: {e}" | ||
)) | ||
})?, | ||
} | ||
} else if provider_settings.contains_key("client_type") | ||
&& provider_settings["client_type"] == "ecs_ram_role" | ||
{ | ||
Client::EcsRamRole { | ||
ecs_ram_role_client: EcsRamRoleClient::from_provider_settings(provider_settings) | ||
.await | ||
.map_err(|e| { | ||
Error::AliyunKmsError(format!( | ||
"build EcsRamRoleClient with `from_provider_settings()` failed: {e}" | ||
)) | ||
})?, | ||
} | ||
} else { | ||
return Err(Error::AliyunKmsError( | ||
"client type invalid or not exist.".to_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.
Could you do some refactoring like the following to make the logic clearer
let inner_client = if provider_settings.contains_key("client_type") | |
&& provider_settings["client_type"] == "client_key" | |
{ | |
Client::ClientKey { | |
client_key_client: ClientKeyClient::from_provider_settings(provider_settings) | |
.await | |
.map_err(|e| { | |
Error::AliyunKmsError(format!( | |
"build ClientKeyClient with `from_provider_settings()` failed: {e}" | |
)) | |
})?, | |
} | |
} else if provider_settings.contains_key("client_type") | |
&& provider_settings["client_type"] == "ecs_ram_role" | |
{ | |
Client::EcsRamRole { | |
ecs_ram_role_client: EcsRamRoleClient::from_provider_settings(provider_settings) | |
.await | |
.map_err(|e| { | |
Error::AliyunKmsError(format!( | |
"build EcsRamRoleClient with `from_provider_settings()` failed: {e}" | |
)) | |
})?, | |
} | |
} else { | |
return Err(Error::AliyunKmsError( | |
"client type invalid or not exist.".to_string(), | |
)); | |
}; | |
let Some(client_type) = provider_settings.get("client_type") else { | |
return Err(Error::AliyunKmsError( | |
"client type invalid or not exist.".to_string(), | |
)); | |
}; | |
let inner_client = match client_type { | |
"client_key" => ... | |
"ecs_ram_role" => ... | |
} |
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.
Great! It does look clearer.
eb4df0d
to
2237a86
Compare
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.
LGTM.
/// [`ALIYUN_IN_GUEST_DEFAULT_KEY_PATH`] which is the by default path where the credential | ||
/// to access kms is saved. | ||
pub async fn from_provider_settings(_provider_settings: &ProviderSettings) -> Result<Self> { | ||
let ecs_ram_role_path = format!("{ALIYUN_IN_GUEST_DEFAULT_KEY_PATH}/ecsRamRole.json"); |
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 can use concatcp!
to declare this as a const.
Signed-off-by: 1570005763 <[email protected]>
Signed-off-by: 1570005763 <[email protected]>
Signed-off-by: 1570005763 <[email protected]>
2237a86
to
99b1fbf
Compare
Apply
get_secret()
function forGetter
trait.And two methods of accessing Aliyun KMS is offered. One is through ClientKey, the same as encrypt/decrypt function, the other is through EcsRamRole, which can only be used on Aliyun ECS. More information is updated to the doc file.
Again it is hard to test code on CI. I can only test them on my machine, this is a screenshot of the test results.