Skip to content

Commit

Permalink
CDH/KMS/eHSM: read credentials from env
Browse files Browse the repository at this point in the history
Related to confidential-containers#413. Before this commit, we will read credentials from local
filesystem for eHSM KMS plugin. This would make unexpected side effects.
We now read them from the env, which will not spread side effects.

There are two envs that will be used:
- EHSM_API_KEY: API key of the eHSM instance
- EHSM_APP_ID: Application Id to the eHSM instance
- EHSM_ENDPOINT: HTTP/HTTPS address to the eHSM service

Signed-off-by: Xynnn007 <[email protected]>
  • Loading branch information
Xynnn007 committed Jan 20, 2024
1 parent 292ca7c commit 01c9452
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 100 deletions.
5 changes: 4 additions & 1 deletion confidential-data-hub/kms/src/plugins/ehsm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,10 @@ Congratulations! eHSM-KMS service should be ready by now.

# eHSM-KMS Client

eHSM-KMS client requires a credential file to run. The file name of the credential file is `credential.{your_app_id}.json`. The credential file need to be placed in `/run/confidential-containers/cdh/kms-credential/ehsm/`. And the structure of the credential file is shown in `ehsm/example_credential/` folder.
eHSM-KMS client requires credentials to run. In the eHSM plugin, the credentials are delievered by environment variable
- `EHSM_API_KEY`: API key of the eHSM instance
- `EHSM_APP_ID`: Application Id to the eHSM instance
- `EHSM_ENDPOINT`: HTTP/HTTPS address to the eHSM service

To test eHSM-KMS client, run
```bash
Expand Down
13 changes: 0 additions & 13 deletions confidential-data-hub/kms/src/plugins/ehsm/annotations.rs

This file was deleted.

98 changes: 34 additions & 64 deletions confidential-data-hub/kms/src/plugins/ehsm/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,21 @@
// SPDX-License-Identifier: Apache-2.0
//

use std::env;

use ehsm_client::{api::KMS, client::EHSMClient};

use async_trait::async_trait;
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use const_format::concatcp;
use serde_json::Value;
use tokio::fs;

use crate::plugins::_IN_GUEST_DEFAULT_KEY_PATH;
use crate::{Annotations, Decrypter, Encrypter, ProviderSettings};
use crate::{Error, Result};

use super::annotations::EhsmProviderSettings;
use super::credential::Credential;

pub struct EhsmKmsClient {
client: EHSMClient,
}

const EHSM_IN_GUEST_DEFAULT_KEY_PATH: &str = concatcp!(_IN_GUEST_DEFAULT_KEY_PATH, "/ehsm");

impl EhsmKmsClient {
pub fn new(app_id: &str, api_key: &str, endpoint: &str) -> Result<Self> {
Ok(Self {
Expand All @@ -43,51 +36,28 @@ impl EhsmKmsClient {
})
}

/// This new function is used by a in-pod client. The side-effect is to read the
/// [`EHSM_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 provider_settings: EhsmProviderSettings =
serde_json::from_value(Value::Object(provider_settings.clone()))
.map_err(|e| Error::EhsmKmsError(format!("parse provider setting failed: {e}")))?;

let credential_path = format!(
"{EHSM_IN_GUEST_DEFAULT_KEY_PATH}/credential_{}.json",
provider_settings.app_id
);

let api_key = {
let cred = fs::read_to_string(credential_path)
.await
.map_err(|e| Error::EhsmKmsError(format!("read credential failed: {e}")))?;
let cred: Credential = serde_json::from_str(&cred)
.map_err(|e| Error::EhsmKmsError(format!("serialize credential failed: {e}")))?;
cred.api_key
};

Self::new(
&provider_settings.app_id,
&api_key,
&provider_settings.endpoint,
)
/// This new function is used by a in-pod client. It will read environment variables
/// to create the client. The envs are
///
/// - `EHSM_ENDPOINT`: The endpoint of the eHSM instance
/// - `EHSM_API_KEY`: The API key to connect to eHSM
/// - `EHSM_APP_ID`: Application id
pub async fn from_provider_settings(_provider_settings: &ProviderSettings) -> Result<Self> {
let endpoint = env::var("EHSM_ENDPOINT")
.map_err(|_| Error::EhsmKmsError("EHSM_ENDPOINT not set in env".to_string()))?;
let api_key = env::var("EHSM_API_KEY")
.map_err(|_| Error::EhsmKmsError("EHSM_API_KEY not set in env".to_string()))?;
let app_id = env::var("EHSM_APP_ID")
.map_err(|_| Error::EhsmKmsError("EHSM_APP_ID not set in env".to_string()))?;

Self::new(&app_id, &api_key, &endpoint)
}

/// 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> {
let provider_settings = EhsmProviderSettings {
app_id: self.client.appid.clone(),
endpoint: self.client.base_url.clone(),
};

let provider_settings = serde_json::to_value(provider_settings)
.map_err(|e| Error::EhsmKmsError(format!("serialize ProviderSettings failed: {e}")))?
.as_object()
.expect("must be an object")
.to_owned();

Ok(provider_settings)
pub fn export_provider_settings(&self) -> ProviderSettings {
ProviderSettings::default()
}
}

Expand Down Expand Up @@ -149,23 +119,24 @@ impl EhsmKmsClient {

#[cfg(test)]
mod tests {
use std::env;

use rstest::rstest;
use serde_json::json;
use serde_json::Map;

use crate::{plugins::ehsm::client::EhsmKmsClient, Decrypter, Encrypter};

#[ignore]
#[tokio::test]
async fn test_create_key() {
let key_spec = "EH_AES_GCM_256";
let provider_settings = json!({
"app_id": "86f0e9fe-****-a224ddee1233",
"endpoint": "https://172.0.0.1:9000",
});

env::set_var("EHSM_ENDPOINT", "https://172.0.0.1:9000");
env::set_var("EHSM_APP_ID", "86f0e9fe-****-a224ddee1233");
env::set_var("EHSM_API_KEY", "xxx");

// init client at user side
let provider_settings = provider_settings.as_object().unwrap().to_owned();
let mut client = EhsmKmsClient::from_provider_settings(&provider_settings)
let mut client = EhsmKmsClient::from_provider_settings(&Map::new())
.await
.unwrap();

Expand All @@ -183,21 +154,20 @@ mod tests {
#[tokio::test]
async fn key_lifetime(#[case] plaintext: &[u8]) {
let key_spec = "EH_AES_GCM_256";
let provider_settings = json!({
"app_id": "86f0e9fe-7f05-4110-9f65-a224ddee1233",
"endpoint": "https://172.16.1.1:9002",
});

env::set_var("EHSM_ENDPOINT", "https://172.16.1.1:9002");
env::set_var("EHSM_APP_ID", "86f0e9fe-****-a224ddee1233");
env::set_var("EHSM_API_KEY", "xxx");

// init client at user side
let provider_settings = provider_settings.as_object().unwrap().to_owned();
let mut client = EhsmKmsClient::from_provider_settings(&provider_settings)
let mut client = EhsmKmsClient::from_provider_settings(&Map::new())
.await
.unwrap();

// create key
let key_id = client.create_key(key_spec).await.unwrap();

let mut encryptor = EhsmKmsClient::from_provider_settings(&provider_settings)
let mut encryptor = EhsmKmsClient::from_provider_settings(&Map::new())
.await
.unwrap();

Expand All @@ -208,7 +178,7 @@ mod tests {
.encrypt(plaintext, &key_id)
.await
.expect("encrypt");
let provider_settings = encryptor.export_provider_settings().unwrap();
let provider_settings = encryptor.export_provider_settings();

// init decrypter in a guest
let mut decryptor = EhsmKmsClient::from_provider_settings(&provider_settings)
Expand Down
16 changes: 0 additions & 16 deletions confidential-data-hub/kms/src/plugins/ehsm/credential.rs

This file was deleted.

This file was deleted.

2 changes: 0 additions & 2 deletions confidential-data-hub/kms/src/plugins/ehsm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
//! eHSM KMS uses eHSM-KMS to support all functions.
//! The project detail can be found here: <https://github.com/intel/ehsm>.
mod annotations;
mod client;
mod credential;

pub use client::EhsmKmsClient;

0 comments on commit 01c9452

Please sign in to comment.