Skip to content

Commit

Permalink
cdh: 'get_secret' support EcsRamRole access for aliyun kms
Browse files Browse the repository at this point in the history
Signed-off-by: 1570005763 <[email protected]>
  • Loading branch information
1570005763 authored and Xynnn007 committed Jan 19, 2024
1 parent 2f8edca commit fb75f9d
Show file tree
Hide file tree
Showing 18 changed files with 962 additions and 264 deletions.
259 changes: 141 additions & 118 deletions Cargo.lock

Large diffs are not rendered by default.

41 changes: 34 additions & 7 deletions confidential-data-hub/docs/kms-providers/alibaba.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,60 @@ The `provider_settings` and `annotations` defined in [Sealed Secret](../SEALED_S

#### annotations

##### encryption/decryption

| Name | Usage |
| ------------------ | -------------------------------------------------------------------- |
| `iv` | The initialization vector used in an encryption/decryption operation |

##### get_secret

| Name | Usage |
| ------------------ | -------------------------------------------------------------------- |
| `version_stage` | (Optional) If this parameter is specified, KMS returns the credentials value of the version that is marked as the specified status. |
| `version_id` | (Optional) If this parameter is specified, KMS returns the credentials value for the specified version number. |

#### provider_settings

`client_type` is used to specify the method of accessing KMS. Only 'client_key' is avaliable for encryption/decryption. While both 'client_key' and 'ecs_ram_role' are avaliable for get_secret.

If `client_type` is set to 'client_key', provider_settings shall be as following:

| Name | Usage |
| ------------------ | -------------------------------------------------------------------- |
| `client_type` | Used to specify the method of accessing KMS. ('client_key' is set here) |
| `client_key_id` | The ID of the client key used to access the KMS instance |
| `kms_instance_id` | The KMS instance ID to be connected |

Else if `client_type` is set to 'ecs_ram_role', provider_settings shall be as following:

| Name | Usage |
| ------------------ | -------------------------------------------------------------------- |
| `client_type` | Used to specify the method of accessing KMS. ('ecs_ram_role' is set here) |

### Credential files

To connect to a KMS instance, a client key is needed. A client key is actually
[an json with encrypted inside](../../kms/src/plugins/aliyun/example_credential/clientKey_KAAP.f4c8____.json)
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/example_credential/password_KAAP.f4c8____.json).
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`.

To connect to a KMS server, [a cert of the KMS server](../../kms/src/plugins/aliyun/example_credential/PrivateKmsCA_kst-shh64702cf2jvc_____.pem)
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`.

For more details please see the [developer document for aliyun](https://www.alibabacloud.com/help/en/key-management-service/latest/api-overview?spm=a2c63.l28256.0.0.bc4f4c6fB82yGa).
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).

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).

## Behavior

The client `AliyunKmsClient` supports both `Encrypter` and `Decrypter` api. When at the
The client `AliyunKmsClient` supports `Encrypter`, `Decrypter`, and `Getter` api. When at the
user side, the credential files can be directly given by the user.

When in Tee, the credential files is supposed to be placed under `/run/confidential-containers/cdh/kms-credential/aliyun` directory.
Expand Down Expand Up @@ -124,6 +150,7 @@ And the output
"iv": "Q/g...",
"provider": "aliyun",
"provider_settings": {
"client_type": "client_key",
"client_key_id": "KAAP.e9...",
"kms_instance_id": "kst-bj..."
},
Expand Down
6 changes: 4 additions & 2 deletions confidential-data-hub/kms/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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, optional = true }
reqwest = { workspace = true, optional = true }
resource_uri = { path = "../../attestation-agent/deps/resource_uri" }
sha2 = { workspace = true, optional = true }
serde.workspace = true
serde_json.workspace = true
sev = { path = "../../attestation-agent/deps/sev", optional = true }
strum.workspace = true
reqwest = { version = "0.11", optional = true }
thiserror.workspace = true
tokio = { workspace = true, features = ["fs"] }
toml.workspace = true
tonic = { workspace = true, optional = true }
url = { workspace = true, optional = true }
uuid = { workspace = true, features = ["serde", "v4"], optional = true }
yasna = { version = "0.5.2", optional = true }
zeroize = { workspace = true, optional = true }
Expand All @@ -47,7 +49,7 @@ tonic-build.workspace = true
[features]
default = ["aliyun", "kbs", "ehsm"]

aliyun = ["chrono", "hex", "openssl", "p12", "prost", "reqwest/rustls-tls", "sha2", "tonic", "yasna"]
aliyun = ["chrono", "hex", "openssl", "p12", "prost", "rand", "reqwest/rustls-tls", "sha2", "tonic", "url", "yasna"]
kbs = ["kbs_protocol"]
ehsm = ["ehsm_client"]
sev = ["bincode", "crypto", "dep:sev", "prost", "tonic", "uuid", "zeroize"]
4 changes: 3 additions & 1 deletion confidential-data-hub/kms/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use anyhow::*;

fn main() -> Result<()> {
#[cfg(feature = "aliyun")]
tonic_build::compile_protos("./src/plugins/aliyun/protobuf/dkms_api.proto")?;
tonic_build::compile_protos(
"./src/plugins/aliyun/client/client_key_client/protobuf/dkms_api.proto",
)?;

#[cfg(feature = "sev")]
tonic_build::configure()
Expand Down
9 changes: 1 addition & 8 deletions confidential-data-hub/kms/src/plugins/aliyun/annotations.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2023 Alibaba Cloud
// Copyright (c) 2024 Alibaba Cloud
//
// SPDX-License-Identifier: Apache-2.0
//
Expand All @@ -17,10 +17,3 @@ pub struct AliSecretAnnotations {
pub version_stage: String,
pub version_id: String,
}

/// Serialized [`crate::ProviderSettings`]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AliProviderSettings {
pub client_key_id: String,
pub kms_instance_id: String,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) 2024 Alibaba Cloud
//
// SPDX-License-Identifier: Apache-2.0
//

//! Configs to access aliyun KMS
#[derive(Clone, Debug)]
pub(crate) struct ConfigClientKey {
pub kms_instance_id: String,
pub endpoint: String,
}

// implement ConfigClientKey related function
impl ConfigClientKey {
pub(crate) fn new(kms_instance_id: &str, endpoint: &str) -> Self {
ConfigClientKey {
kms_instance_id: kms_instance_id.to_string(),
endpoint: endpoint.to_string(),
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2023 Alibaba Cloud
// Copyright (c) 2024 Alibaba Cloud
//
// SPDX-License-Identifier: Apache-2.0
//
Expand All @@ -17,8 +17,8 @@ use serde::Deserialize;
use yasna::ASN1Result;

#[derive(Clone, Debug)]
pub(crate) struct Credential {
pub(crate) client_key_id: String,
pub(crate) struct CredentialClientKey {
pub client_key_id: String,
private_key: PKey<Private>,
}

Expand All @@ -35,30 +35,30 @@ struct Password {
client_key_password: String,
}

impl Credential {
// implement CredentialClientKey related function
impl CredentialClientKey {
pub(crate) fn new(client_key: &str, pswd: &str) -> Result<Self> {
let ck: ClientKey = serde_json::from_str(client_key)?;

let password: Password = serde_json::from_str(pswd)?;

let private_key =
Self::parse_private_key(ck.private_key_data, password.client_key_password)?;

let private_key = PKey::private_key_from_der(&private_key)?;
let credential = Credential {

let credential = CredentialClientKey {
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> {
let mut signer = Signer::new(openssl::hash::MessageDigest::sha256(), &self.private_key)?;
signer.update(str_to_sign.as_bytes())?;
let signature = signer.sign_to_vec()?;

Ok(format!("Bearer {}", STANDARD.encode(signature)))
Ok(STANDARD.encode(signature))
}

pub(crate) fn parse_private_key(private_key_data: String, password: String) -> Result<Vec<u8>> {
Expand Down
Loading

0 comments on commit fb75f9d

Please sign in to comment.