From 93704992c59fc9bf39de2b0393fbe49058930298 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Fri, 19 Jan 2024 17:38:03 +0800 Subject: [PATCH] CDH/KMS/Aliyun: read credentials from env Related to #413. Before this commit, we will read credentials from local filesystem for aliyun KMS plugin. This would make unexpected side effects. We now read them from the env, which will not spread side effects. There are some envs that will be used. If the `client_type` is `client_key`: - `ALIYUN_CLIENT_KEY`: Aliyun KMS client key - `ALIYUN_PASSWORD`: The password of Aliyun KMS client key - `ALIYUN_KMS_INSTANCE_CERT`: The public key cert to KMS instance if the `client_type` is `ecs_ram_role` - `ALIYUN_ECS_RAM_ROLE`: The ECS RAM Role name on Aliyun - `ALIYUN_REGION_ID`: ECS Instance region id Signed-off-by: Xynnn007 --- .../docs/kms-providers/alibaba.md | 32 +++++++---- .../PrivateKmsCA_kst-shh64702cf2jvc_____.pem | 2 +- .../alibaba/clientKey_KAAP.f4c8____.json | 4 ++ .../alibaba/password_KAAP.f4c8____.json | 0 .../clientKey_KAAP.f4c8____.json | 4 -- .../password_KAAP.f4c8____.json | 3 - .../aliyun/client/client_key_client/mod.rs | 35 ++++-------- .../example_credential/ecsRamRole.json | 4 -- .../aliyun/client/ecs_ram_role_client/mod.rs | 57 +++---------------- .../kms/src/plugins/aliyun/client/mod.rs | 29 ++++++---- 10 files changed, 62 insertions(+), 108 deletions(-) rename confidential-data-hub/{kms/src/plugins/aliyun/client/client_key_client/example_credential => docs/kms-providers/alibaba}/PrivateKmsCA_kst-shh64702cf2jvc_____.pem (99%) create mode 100644 confidential-data-hub/docs/kms-providers/alibaba/clientKey_KAAP.f4c8____.json create mode 100644 confidential-data-hub/docs/kms-providers/alibaba/password_KAAP.f4c8____.json delete mode 100644 confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/example_credential/clientKey_KAAP.f4c8____.json delete mode 100644 confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/example_credential/password_KAAP.f4c8____.json delete mode 100644 confidential-data-hub/kms/src/plugins/aliyun/client/ecs_ram_role_client/example_credential/ecsRamRole.json diff --git a/confidential-data-hub/docs/kms-providers/alibaba.md b/confidential-data-hub/docs/kms-providers/alibaba.md index 4a9eb3e66..48cd0725c 100644 --- a/confidential-data-hub/docs/kms-providers/alibaba.md +++ b/confidential-data-hub/docs/kms-providers/alibaba.md @@ -47,21 +47,29 @@ Else if `client_type` is set to 'ecs_ram_role', provider_settings shall be as fo ### Credential files -To connect to a KMS instance with `client_type` set to 'client_key', a client key is needed. A client key is actually -[an json with encrypted inside](../../kms/src/plugins/aliyun/client/client_key_client/example_credential/clientKey_KAAP.f4c8____.json) -private key. The name of the client key is always derived from the client key id. Suppose the -client key ID is `xxx`, then the client key file has name `clientKey_xxx.json`. The key to encrypt -the private key is derived from a password that is also saved in [a file](../../kms/src/plugins/aliyun/client/client_key_client/example_credential/password_KAAP.f4c8____.json). -Suppose the client key ID is `xxx`, then the password file has name `password_xxx.json`. -Besides, [a cert of the KMS server](../../kms/src/plugins/aliyun/client/client_key_client/example_credential/PrivateKmsCA_kst-shh64702cf2jvc_____.pem) -is also needed. Suppose the kms instance id is `xxx`, then the cert of the KMS server has name `PrivateKmsCA_xxx.pem`. +There are two ways to connect to a KMS instance. + +#### With Client Key + +In this case, 'client_type' is set to `client_key`. + +To leverage the client key way to connect to a KMS instance, the following files should be provided. +- A client key file, like [the example](./alibaba/clientKey_KAAP.f4c8____.json), which is actually +an json with encrypted inside private key. +- A password file, like [the example](./alibaba/password_KAAP.f4c8____.json). This will be derived +into a symmetric key to decrypt the client key. +- A cert of the KMS server, [like the example](./alibaba/PrivateKmsCA_kst-shh64702cf2jvc_____.pem). This is +the public key cert of the KMS server. For more details please see the [developer document for aliyun](https://www.alibabacloud.com/help/en/key-management-service/latest/api-overview). -To connect to a KMS instance with `client_type` set to 'ecs_ram_role', a [ecsRamRole.json](../../kms/src/plugins/aliyun/client/ecs_ram_role_client/example_credential/ecsRamRole.json) file is needed. -In the json file, `ecs_ram_role_name` and `region_id` is set in order to get access to Dedicated KMS. -Among them,`ecs_ram_role_name` refer to RAM role for ECS instances in a VPC network, where CDH runs. Can be set on Aliyun Console. -And `region_id` refers to region id of Dedicated KMS, to which more details can be refered [here](https://www.alibabacloud.com/help/en/kms/product-overview/supported-regions). +#### With ECS RAM Role + +In this case, 'client_type' is set to `ecs_ram_role`. + +To leverage the ecs ram role way to connect to a KMS instance, the following files should be provided. +- `eca_ram_role_name`: refer to RAM role for ECS instances in a VPC network, where CDH runs. Can be set on Aliyun Console. +- `region_id`: refers to region id of Dedicated KMS, to which more details can be refered [here](https://www.alibabacloud.com/help/en/kms/product-overview/supported-regions). More details about accessing via EcsRamRole can be seen at [Access KMS from an ECS instance in a secure manner](https://www.alibabacloud.com/help/en/kms/use-cases/access-kms-from-an-ecs-instance-in-a-secure-manner). diff --git a/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/example_credential/PrivateKmsCA_kst-shh64702cf2jvc_____.pem b/confidential-data-hub/docs/kms-providers/alibaba/PrivateKmsCA_kst-shh64702cf2jvc_____.pem similarity index 99% rename from confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/example_credential/PrivateKmsCA_kst-shh64702cf2jvc_____.pem rename to confidential-data-hub/docs/kms-providers/alibaba/PrivateKmsCA_kst-shh64702cf2jvc_____.pem index b2b42280b..22d721e80 100644 --- a/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/example_credential/PrivateKmsCA_kst-shh64702cf2jvc_____.pem +++ b/confidential-data-hub/docs/kms-providers/alibaba/PrivateKmsCA_kst-shh64702cf2jvc_____.pem @@ -42,4 +42,4 @@ F6TFaabuFbw/42mjB3IB5RtR/+fz5je5WykII/ST4xQdKCU3reU6zZ3jU9erhHVP FwLb4ltDYHMNlN1HCj31Z8NxWUtnIH7Xv1c93FTCFoeOc9fssNDgsy5FFXy0XIkm 1xrT6gQcxRKoDCC4LwEmLwV3S1OfrNXhgJzx1R65pahAzjJR0vgWU8NbkmY8ZZS8 i6LVVFDar9z0K/8UN1n+nl6saJSUuVFdWzHBRX4wYuUxQI+P ------END CERTIFICATE----- +-----END CERTIFICATE----- \ No newline at end of file diff --git a/confidential-data-hub/docs/kms-providers/alibaba/clientKey_KAAP.f4c8____.json b/confidential-data-hub/docs/kms-providers/alibaba/clientKey_KAAP.f4c8____.json new file mode 100644 index 000000000..4c0b645c6 --- /dev/null +++ b/confidential-data-hub/docs/kms-providers/alibaba/clientKey_KAAP.f4c8____.json @@ -0,0 +1,4 @@ +{ + "KeyId": "KAAP.f4c8****", + "PrivateKeyData": "MIIJ****" + } \ No newline at end of file diff --git a/confidential-data-hub/docs/kms-providers/alibaba/password_KAAP.f4c8____.json b/confidential-data-hub/docs/kms-providers/alibaba/password_KAAP.f4c8____.json new file mode 100644 index 000000000..e69de29bb diff --git a/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/example_credential/clientKey_KAAP.f4c8____.json b/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/example_credential/clientKey_KAAP.f4c8____.json deleted file mode 100644 index 005ea13ff..000000000 --- a/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/example_credential/clientKey_KAAP.f4c8____.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "KeyId": "KAAP.f4c8****", - "PrivateKeyData": "MIIJ****" -} \ No newline at end of file diff --git a/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/example_credential/password_KAAP.f4c8____.json b/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/example_credential/password_KAAP.f4c8____.json deleted file mode 100644 index 01150d9e0..000000000 --- a/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/example_credential/password_KAAP.f4c8____.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "ClientKeyPassword": "fa79****" -} \ No newline at end of file diff --git a/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/mod.rs b/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/mod.rs index ac567de48..0a79fec50 100644 --- a/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/mod.rs +++ b/confidential-data-hub/kms/src/plugins/aliyun/client/client_key_client/mod.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::collections::BTreeMap; +use std::{collections::BTreeMap, env}; use async_trait::async_trait; use base64::{engine::general_purpose::STANDARD, Engine}; @@ -14,7 +14,6 @@ use reqwest::{header::HeaderMap, Certificate, ClientBuilder}; use serde::{Deserialize, Serialize}; use serde_json::Value; use sha2::{Digest, Sha256}; -use tokio::fs; mod config; mod credential; @@ -23,7 +22,6 @@ use crate::{Annotations, Decrypter, Encrypter, Getter, ProviderSettings}; use crate::{Error, Result}; use super::super::annotations::*; -use super::ALIYUN_IN_GUEST_DEFAULT_KEY_PATH; use config::*; use credential::*; @@ -82,34 +80,23 @@ impl ClientKeyClient { } /// This new function is used by a in-pod client. The side-effect is to read the - /// [`ALIYUN_IN_GUEST_DEFAULT_KEY_PATH`] which is the by default path where the credential - /// to access kms is saved. + /// environment variable to get parameters, s.t. + /// - `ALIYUN_CLIENT_KEY`: Aliyun KMS client key + /// - `ALIYUN_PASSWORD`: The password of Aliyun KMS client key + /// - `ALIYUN_KMS_INSTANCE_CERT`: The public key cert to KMS instance pub async fn from_provider_settings(provider_settings: &ProviderSettings) -> Result { let provider_settings: AliClientKeyProviderSettings = serde_json::from_value(Value::Object(provider_settings.clone())).map_err(|e| { Error::AliyunKmsError(format!("parse client_key provider setting failed: {e}")) })?; - let cert_path = format!( - "{ALIYUN_IN_GUEST_DEFAULT_KEY_PATH}/PrivateKmsCA_{}.pem", - provider_settings.kms_instance_id - ); - let pswd_path = format!( - "{ALIYUN_IN_GUEST_DEFAULT_KEY_PATH}/password_{}.json", - provider_settings.client_key_id - ); - let client_key_path = format!( - "{ALIYUN_IN_GUEST_DEFAULT_KEY_PATH}/clientKey_{}.json", - provider_settings.client_key_id - ); - let cert_pem = fs::read_to_string(cert_path).await.map_err(|e| { - Error::AliyunKmsError(format!("read kms instance pem cert failed: {e}")) - })?; - let pswd = fs::read_to_string(pswd_path).await.map_err(|e| { - Error::AliyunKmsError(format!("read password of the credential failed: {e}")) + let client_key = env::var("ALIYUN_CLIENT_KEY") + .map_err(|_| Error::AliyunKmsError("ALIYUN_CLIENT_KEY not set in env".to_string()))?; + let pswd = env::var("ALIYUN_PASSWORD").map_err(|_| { + Error::AliyunKmsError("ALIYUN_CLIENT_KEY_PASSWORD not set in env".to_string()) })?; - let client_key = fs::read_to_string(client_key_path).await.map_err(|e| { - Error::AliyunKmsError(format!("read client key of the credential failed: {e}")) + let cert_pem = env::var("ALIYUN_KMS_INSTANCE_CERT").map_err(|_| { + Error::AliyunKmsError("ALIYUN_KMS_INSTANCE_CERT not set in env".to_string()) })?; Self::new( diff --git a/confidential-data-hub/kms/src/plugins/aliyun/client/ecs_ram_role_client/example_credential/ecsRamRole.json b/confidential-data-hub/kms/src/plugins/aliyun/client/ecs_ram_role_client/example_credential/ecsRamRole.json deleted file mode 100644 index 752b30941..000000000 --- a/confidential-data-hub/kms/src/plugins/aliyun/client/ecs_ram_role_client/example_credential/ecsRamRole.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "ecs_ram_role_name": "EcsRamRoleTest", - "region_id": "cn-beijing" -} \ No newline at end of file diff --git a/confidential-data-hub/kms/src/plugins/aliyun/client/ecs_ram_role_client/mod.rs b/confidential-data-hub/kms/src/plugins/aliyun/client/ecs_ram_role_client/mod.rs index 733ff2698..ea82014f9 100644 --- a/confidential-data-hub/kms/src/plugins/aliyun/client/ecs_ram_role_client/mod.rs +++ b/confidential-data-hub/kms/src/plugins/aliyun/client/ecs_ram_role_client/mod.rs @@ -5,6 +5,7 @@ use std::{ collections::{BTreeMap, HashMap}, + env, fmt::Write, }; @@ -14,7 +15,6 @@ use log::error; use rand::{distributions::Alphanumeric, Rng}; use reqwest::{header::HeaderMap, ClientBuilder}; use serde_json::Value; -use tokio::fs; mod config; mod credential; @@ -23,7 +23,6 @@ use crate::{Annotations, Getter, ProviderSettings}; use crate::{Error, Result}; use super::super::annotations::*; -use super::ALIYUN_IN_GUEST_DEFAULT_KEY_PATH; use config::*; use credential::*; @@ -55,54 +54,16 @@ impl EcsRamRoleClient { } /// This new function is used by a in-pod client. The side-effect is to read the - /// [`ALIYUN_IN_GUEST_DEFAULT_KEY_PATH`] which is the by default path where the credential - /// to access kms is saved. + /// environment variable to get parameters, s.t. + /// - `ALIYUN_ECS_RAM_ROLE`: The ECS RAM Role name on Aliyun + /// - `ALIYUN_REGION_ID`: ECS Instance region id pub async fn from_provider_settings(_provider_settings: &ProviderSettings) -> Result { - let ecs_ram_role_path = format!("{ALIYUN_IN_GUEST_DEFAULT_KEY_PATH}/ecsRamRole.json"); + let ecs_ram_role_name = env::var("ALIYUN_ECS_RAM_ROLE") + .map_err(|_| Error::AliyunKmsError("ALIYUN_ECS_RAM_ROLE not set in env".to_string()))?; + let region_id = env::var("ALIYUN_REGION_ID") + .map_err(|_| Error::AliyunKmsError("ALIYUN_REGION_ID not set in env".to_string()))?; - let ecs_ram_role_str = fs::read_to_string(ecs_ram_role_path).await.map_err(|e| { - Error::AliyunKmsError(format!( - "read ecs_ram_role with `fs::read_to_string()` failed: {e}" - )) - })?; - - let ecs_ram_role_json: serde_json::Value = serde_json::from_str(&ecs_ram_role_str) - .map_err(|e| { - Error::AliyunKmsError(format!( - "read ecs_ram_role with `serde_json::from_str()` failed: {e}" - )) - })?; - - let ecs_ram_role_name = - if let Some(ecs_ram_role_name_value) = ecs_ram_role_json.get("ecs_ram_role_name") { - match ecs_ram_role_name_value.as_str() { - Some(ecs_ram_role_name) => ecs_ram_role_name, - None => { - return Err(Error::AliyunKmsError( - "ecs ram role name value is not str.".to_string(), - )) - } - } - } else { - return Err(Error::AliyunKmsError( - "ecs ram role name not exist.".to_string(), - )); - }; - - let region_id = if let Some(region_id_value) = ecs_ram_role_json.get("region_id") { - match region_id_value.as_str() { - Some(region_id) => region_id, - None => { - return Err(Error::AliyunKmsError( - "region id value is not str.".to_string(), - )) - } - } - } else { - return Err(Error::AliyunKmsError("region id not exist.".to_string())); - }; - - Self::new(ecs_ram_role_name, region_id) + Self::new(&ecs_ram_role_name, ®ion_id) } /// Export the [`ProviderSettings`] of the current client. This function is to be used diff --git a/confidential-data-hub/kms/src/plugins/aliyun/client/mod.rs b/confidential-data-hub/kms/src/plugins/aliyun/client/mod.rs index 3ea30e9c5..42641ffe6 100644 --- a/confidential-data-hub/kms/src/plugins/aliyun/client/mod.rs +++ b/confidential-data-hub/kms/src/plugins/aliyun/client/mod.rs @@ -4,13 +4,11 @@ // use async_trait::async_trait; -use const_format::concatcp; use serde_json::json; mod client_key_client; mod ecs_ram_role_client; -use crate::plugins::_IN_GUEST_DEFAULT_KEY_PATH; use crate::{Annotations, Decrypter, Encrypter, Getter, ProviderSettings}; use crate::{Error, Result}; @@ -31,8 +29,6 @@ pub struct AliyunKmsClient { inner_client: Client, } -const ALIYUN_IN_GUEST_DEFAULT_KEY_PATH: &str = concatcp!(_IN_GUEST_DEFAULT_KEY_PATH, "/aliyun"); - impl AliyunKmsClient { pub fn new( client_key: &str, @@ -70,8 +66,15 @@ impl AliyunKmsClient { } /// This new function is used by a in-pod client. The side-effect is to read the - /// [`ALIYUN_IN_GUEST_DEFAULT_KEY_PATH`] which is the by default path where the credential - /// to access kms is saved. + /// environment variable to get parameters. If the `client_type` is `client_key`, + /// will read the following env keys + /// - `ALIYUN_CLIENT_KEY`: Aliyun KMS client key + /// - `ALIYUN_PASSWORD`: The password of Aliyun KMS client key + /// - `ALIYUN_KMS_INSTANCE_CERT`: The public key cert to KMS instance + /// + /// if the `client_type` is `ecs_ram_role`, will read the following env keys + /// - `ALIYUN_ECS_RAM_ROLE`: The ECS RAM Role name on Aliyun + /// - `ALIYUN_REGION_ID`: ECS Instance region id pub async fn from_provider_settings(provider_settings: &ProviderSettings) -> Result { let client_type = if let Some(client_type_value) = provider_settings.get("client_type") { match client_type_value.as_str() { @@ -209,10 +212,11 @@ mod tests { #[tokio::test] async fn key_lifetime(#[case] plaintext: &[u8]) { let kid = "alias/test_key_id"; + std::env::set_var("ALIYUN_CLIENT_KEY", "KAAP.f4c8****"); + std::env::set_var("ALIYUN_KMS_INSTANCE_CERT", "kst-shh6****"); + std::env::set_var("ALIYUN_PASSWORD", "xxx"); let provider_settings = json!({ - "client_type": "client_key", - "client_key_id": "KAAP.f4c8****", - "kms_instance_id": "kst-shh6****", + "client_type": "client_key" }); // init encrypter at user side let provider_settings = provider_settings.as_object().unwrap().to_owned(); @@ -247,10 +251,11 @@ mod tests { #[tokio::test] async fn get_secret(#[case] client_type: &str) { let secret_name = "test_secret"; + std::env::set_var("ALIYUN_CLIENT_KEY", "KAAP.f4c8****"); + std::env::set_var("ALIYUN_KMS_INSTANCE_CERT", "kst-shh6****"); + std::env::set_var("ALIYUN_PASSWORD", "xxx"); let provider_settings = json!({ - "client_type": client_type, - "client_key_id": "KAAP.f4c8****", - "kms_instance_id": "kst-shh6****", + "client_type": client_type }); // init getter at user side let provider_settings = provider_settings.as_object().unwrap().to_owned();