From bcec5486eebd09d6d4312edd6f5319117a370e64 Mon Sep 17 00:00:00 2001 From: Tobin Feldman-Fitzthum Date: Tue, 2 Jan 2024 14:17:27 -0600 Subject: [PATCH 01/18] Makefile: add more platforms to Makefile Adds SNP, AZ-SNP-vTPM, and AZ-TDX-vTPM to the top-level Makefile. Also changes the name of the offline_fs_kbc flag to fs rather than test. Signed-off-by: Tobin Feldman-Fitzthum --- Makefile | 14 +++++++++++--- README.md | 10 +++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 39a42a2ef..44586e391 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -TEE_PLATFORM ?= test +TEE_PLATFORM ?= fs ARCH ?= $(shell uname -m) DESTDIR ?= /usr/local/bin @@ -7,16 +7,24 @@ LIBC ?= musl KBC ?= RESOURCE_PROVIDER ?= kbs -ifeq ($(TEE_PLATFORM), test) +ifeq ($(TEE_PLATFORM), none) + KBC = cc_kbc +else ifeq ($(TEE_PLATFORM), fs) KBC = offline_fs_kbc else ifeq ($(TEE_PLATFORM), tdx) LIBC = gnu KBC = cc_kbc_tdx +else ifeq ($(TEE_PLATFORM), az-tdx-vtpm) + KBC = cc_kbc_az_tdx_vtpm else ifeq ($(TEE_PLATFORM), sev) KBC = online_sev_kbc RESOURCE_PROVIDER = sev +else ifeq ($(TEE_PLATFORM), snp) + KBC = cc_kbc_snp +else ifeq ($(TEE_PLATFORM), az-snp-vtpm) + KBC = cc_kbc_az_snp_vtpm endif -# TODO: Add support for SNP, Az-snp-vtpm, CCA, CSV +# TODO: Add support for CCA and CSV ifeq ($(ARCH), $(filter $(ARCH), s390x powerpc64le)) LIBC = gnu diff --git a/README.md b/README.md index 5386f4742..3f8219347 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ CoCo Keyprovider. Used to encrypt the container images. ## Build -A `Makefile` is provided to quickly build Attestation Agent/Api Server Rest/Confidential Data Hub of a given platform. +A `Makefile` is provided to quickly build Attestation Agent/Api Server Rest/Confidential Data Hub for a given platform. ```shell make build TEE_PLATFORM=$(TEE_PLATFORM) @@ -31,9 +31,13 @@ make install DESTDIR=/usr/local/bin ``` The `TEE_PLATFORM` parameter can be -- `test`: for test +- `none`: for tests with non-confidential guests +- `fs`: for platforms with encrypted root filesystems (i.e. s390x) - `tdx`: for Intel TDX -- `sev`: for AMD SEV +- `az-tdx-vtpm`: for Intel TDX with Azure vTPM +- `sev`: for AMD SEV(-ES) +- `snp`: for AMD SEV-SNP +- `az-snp-vtpm`: for AMD SEV-SNP with Azure vTPM ## License [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fconfidential-containers%2Fimage-rs.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fconfidential-containers%2Fimage-rs?ref=badge_large) From 7ddecc780c1ec03b0ef3ca9e161eea0f75fcaac0 Mon Sep 17 00:00:00 2001 From: Tobin Feldman-Fitzthum Date: Tue, 2 Jan 2024 15:18:40 -0600 Subject: [PATCH 02/18] sample: always enable sample attester Rather than setting an environment variable to enable the sample attester, always enable it as a fallback. Signed-off-by: Tobin Feldman-Fitzthum --- .../attester/src/bin/evidence_getter.rs | 2 +- attestation-agent/attester/src/lib.rs | 23 ++++++++----------- attestation-agent/attester/src/sample/mod.rs | 6 ++--- attestation-agent/kbs_protocol/src/error.rs | 3 --- .../src/evidence_provider/native.rs | 12 ++++------ attestation-agent/lib/src/lib.rs | 4 ++-- 6 files changed, 19 insertions(+), 31 deletions(-) diff --git a/attestation-agent/attester/src/bin/evidence_getter.rs b/attestation-agent/attester/src/bin/evidence_getter.rs index cbdca6138..d5025f43c 100644 --- a/attestation-agent/attester/src/bin/evidence_getter.rs +++ b/attestation-agent/attester/src/bin/evidence_getter.rs @@ -14,7 +14,7 @@ async fn main() { .read(&mut report_data) .expect("read input failed"); - let tee = detect_tee_type().expect("unknown tee type"); + let tee = detect_tee_type(); let attester: BoxedAttester = tee.try_into().expect("create attester failed"); let evidence = attester .get_evidence(report_data) diff --git a/attestation-agent/attester/src/lib.rs b/attestation-agent/attester/src/lib.rs index d1fd146ad..741f18c71 100644 --- a/attestation-agent/attester/src/lib.rs +++ b/attestation-agent/attester/src/lib.rs @@ -77,45 +77,42 @@ pub trait Attester { } // Detect which TEE platform the KBC running environment is. -pub fn detect_tee_type() -> Option { - if sample::detect_platform() { - return Some(Tee::Sample); - } - +pub fn detect_tee_type() -> Tee { #[cfg(feature = "tdx-attester")] if tdx::detect_platform() { - return Some(Tee::Tdx); + return Tee::Tdx; } #[cfg(feature = "sgx-attester")] if sgx_dcap::detect_platform() { - return Some(Tee::Sgx); + return Tee::Sgx; } #[cfg(feature = "az-tdx-vtpm-attester")] if az_tdx_vtpm::detect_platform() { - return Some(Tee::AzTdxVtpm); + return Tee::AzTdxVtpm; } #[cfg(feature = "az-snp-vtpm-attester")] if az_snp_vtpm::detect_platform() { - return Some(Tee::AzSnpVtpm); + return Tee::AzSnpVtpm; } #[cfg(feature = "snp-attester")] if snp::detect_platform() { - return Some(Tee::Snp); + return Tee::Snp; } #[cfg(feature = "csv-attester")] if csv::detect_platform() { - return Some(Tee::Csv); + return Tee::Csv; } #[cfg(feature = "cca-attester")] if cca::detect_platform() { - return Some(Tee::Cca); + return Tee::Cca; } - None + log::warn!("No TEE platform detected. Sample Attester will be used."); + Tee::Sample } diff --git a/attestation-agent/attester/src/sample/mod.rs b/attestation-agent/attester/src/sample/mod.rs index e9a0af29c..1ee6ee63e 100644 --- a/attestation-agent/attester/src/sample/mod.rs +++ b/attestation-agent/attester/src/sample/mod.rs @@ -7,12 +7,10 @@ use super::Attester; use anyhow::*; use base64::Engine; use serde::{Deserialize, Serialize}; -use std::env; -// If the environment variable "AA_SAMPLE_ATTESTER_TEST" is set, -// the TEE platform is considered as "sample". +// Sample attester is always supported pub fn detect_platform() -> bool { - env::var("AA_SAMPLE_ATTESTER_TEST").is_ok() + true } // A simple example of TEE evidence. diff --git a/attestation-agent/kbs_protocol/src/error.rs b/attestation-agent/kbs_protocol/src/error.rs index 933f4bf2a..d46d42889 100644 --- a/attestation-agent/kbs_protocol/src/error.rs +++ b/attestation-agent/kbs_protocol/src/error.rs @@ -24,9 +24,6 @@ pub enum Error { #[error("get token failed: {0}")] GetTokenFailed(String), - #[error("get tee type failed: {0}")] - GetTeeTypeFailed(String), - #[error("http request failed: {0}")] HttpError(String), diff --git a/attestation-agent/kbs_protocol/src/evidence_provider/native.rs b/attestation-agent/kbs_protocol/src/evidence_provider/native.rs index 4e132893c..acad6c691 100644 --- a/attestation-agent/kbs_protocol/src/evidence_provider/native.rs +++ b/attestation-agent/kbs_protocol/src/evidence_provider/native.rs @@ -15,12 +15,9 @@ pub struct NativeEvidenceProvider(BoxedAttester); impl NativeEvidenceProvider { pub fn new() -> Result { - let tee = detect_tee_type() - .ok_or_else(|| Error::GetTeeTypeFailed("no supported Tee type detected.".into()))? - .try_into() - .map_err(|e| { - Error::NativeEvidenceProvider(format!("failed to initialize tee driver: {e}")) - })?; + let tee = detect_tee_type().try_into().map_err(|e| { + Error::NativeEvidenceProvider(format!("failed to initialize tee driver: {e}")) + })?; Ok(Self(tee)) } } @@ -35,7 +32,6 @@ impl EvidenceProvider for NativeEvidenceProvider { } async fn get_tee_type(&self) -> Result { - detect_tee_type() - .ok_or_else(|| Error::GetTeeTypeFailed("no supported Tee type detected.".into())) + Ok(detect_tee_type()) } } diff --git a/attestation-agent/lib/src/lib.rs b/attestation-agent/lib/src/lib.rs index ff0eda218..44258d226 100644 --- a/attestation-agent/lib/src/lib.rs +++ b/attestation-agent/lib/src/lib.rs @@ -195,7 +195,7 @@ impl AttestationAPIs for AttestationAgent { /// Get TEE hardware signed evidence that includes the runtime data. async fn get_evidence(&mut self, runtime_data: &[u8]) -> Result> { - let tee_type = detect_tee_type().ok_or(anyhow!("no supported tee type found!"))?; + let tee_type = detect_tee_type(); let attester = TryInto::::try_into(tee_type)?; let evidence = attester.get_evidence(runtime_data.to_vec()).await?; Ok(evidence.into_bytes()) @@ -207,7 +207,7 @@ impl AttestationAPIs for AttestationAgent { events: Vec>, register_index: Option, ) -> Result<()> { - let tee_type = detect_tee_type().ok_or(anyhow!("no supported tee type found!"))?; + let tee_type = detect_tee_type(); let attester = TryInto::::try_into(tee_type)?; attester .extend_runtime_measurement(events, register_index) From f20d4b59aa62032e82bd8d8107e6874d9618db50 Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Mon, 8 Jan 2024 17:08:33 +0100 Subject: [PATCH 03/18] aa/cdh: make agent-config path configurable by env relates-to: https://github.com/confidential-containers/cloud-api-adaptor/issues/1637 Since peerpods will template the agent-config.toml with aa_kbc_params and /etc might be on a read-only volume, we need to make this path configurable. Signed-off-by: Magnus Kulke --- attestation-agent/lib/src/token.rs | 28 +++++++++----- .../kms/src/plugins/kbs/mod.rs | 37 ++++++++++++------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/attestation-agent/lib/src/token.rs b/attestation-agent/lib/src/token.rs index 0001c57ea..0b206c0ca 100644 --- a/attestation-agent/lib/src/token.rs +++ b/attestation-agent/lib/src/token.rs @@ -3,10 +3,13 @@ // SPDX-License-Identifier: Apache-2.0 // -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, Context, Result}; use kbs_protocol::{evidence_provider::NativeEvidenceProvider, KbsClientBuilder}; +use log::debug; use serde::{Deserialize, Serialize}; +use std::env; use std::path::Path; +use std::sync::OnceLock; use tokio::fs; const PEER_POD_CONFIG_PATH: &str = "/run/peerpod/daemon.json"; @@ -17,6 +20,8 @@ struct Message { tee_keypair: String, } +static KATA_AGENT_CONFIG_PATH: OnceLock = OnceLock::new(); + pub(crate) async fn get_kbs_token() -> Result> { let evidence_provider = Box::new(NativeEvidenceProvider::new()?); @@ -73,15 +78,20 @@ pub(crate) async fn get_kbc_params_from_config_file() -> Result { aa_kbc_params: Option, } - // Hard-code agent config path to "/etc/agent-config.toml" as a workaround - let agent_config_str = fs::read_to_string("/etc/agent-config.toml") + // check env for KATA_AGENT_CONFIG_PATH, fall back to default path + let path: &String = KATA_AGENT_CONFIG_PATH.get_or_init(|| { + env::var("KATA_AGENT_CONFIG_PATH").unwrap_or_else(|_| "/etc/agent-config.toml".into()) + }); + + debug!("reading agent config from {}", path); + let agent_config_str = fs::read_to_string(path) .await - .map_err(|e| anyhow!("Failed to read /etc/agent-config.toml file: {e}"))?; + .context(format!("Failed to read {path}"))?; - let agent_config: AgentConfig = toml::from_str(&agent_config_str) - .map_err(|e| anyhow!("Failed to deserialize /etc/agent-config.toml: {e}"))?; + let agent_config: AgentConfig = + toml::from_str(&agent_config_str).context(format!("Failed to deserialize {path}"))?; - agent_config.aa_kbc_params.ok_or(anyhow!( - "no `aa_kbc_params` found in /etc/agent-config.toml!", - )) + agent_config + .aa_kbc_params + .ok_or(anyhow!("no `aa_kbc_params` found in {path}!")) } diff --git a/confidential-data-hub/kms/src/plugins/kbs/mod.rs b/confidential-data-hub/kms/src/plugins/kbs/mod.rs index 3c7c5e9ec..f25577866 100644 --- a/confidential-data-hub/kms/src/plugins/kbs/mod.rs +++ b/confidential-data-hub/kms/src/plugins/kbs/mod.rs @@ -17,16 +17,20 @@ use std::sync::Arc; use async_trait::async_trait; use lazy_static::lazy_static; +use log::debug; pub use resource_uri::ResourceUri; use serde::Deserialize; -use std::fs; use std::path::Path; +use std::sync::OnceLock; +use std::{env, fs}; use tokio::sync::Mutex; use crate::{Annotations, Error, Getter, Result}; const PEER_POD_CONFIG_PATH: &str = "/run/peerpod/daemon.json"; +static KATA_AGENT_CONFIG_PATH: OnceLock = OnceLock::new(); + enum RealClient { #[cfg(feature = "kbs")] Cc(cc_kbc::CcKbc), @@ -145,25 +149,30 @@ async fn get_aa_params_from_config_file() -> Result<(String, String)> { aa_kbc_params: Option, } - // Hard-code agent config path to "/etc/agent-config.toml" as a workaround - let agent_config_str = fs::read_to_string("/etc/agent-config.toml").map_err(|e| { - Error::KbsClientError(format!("Failed to read /etc/agent-config.toml file: {e}")) - })?; + // check env for KATA_AGENT_CONFIG_PATH, fall back to default path + let path: &String = KATA_AGENT_CONFIG_PATH.get_or_init(|| { + env::var("KATA_AGENT_CONFIG_PATH").unwrap_or_else(|_| "/etc/agent-config.toml".into()) + }); + + debug!("reading agent config from {}", path); + let agent_config_str = fs::read_to_string(path) + .map_err(|e| Error::KbsClientError(format!("Failed to read {path} file: {e}")))?; - let agent_config: AgentConfig = toml::from_str(&agent_config_str).map_err(|e| { - Error::KbsClientError(format!("Failed to deserialize /etc/agent-config.toml: {e}")) - })?; + let agent_config: AgentConfig = toml::from_str(&agent_config_str) + .map_err(|e| Error::KbsClientError(format!("Failed to deserialize {path}: {e}")))?; - let aa_kbc_params = agent_config.aa_kbc_params.ok_or(Error::KbsClientError( - "no `aa_kbc_params` found in /etc/agent-config.toml".into(), - ))?; + let aa_kbc_params = agent_config + .aa_kbc_params + .ok_or(Error::KbsClientError(format!( + "no `aa_kbc_params` found in {path}" + )))?; let aa_kbc_params_vec = aa_kbc_params.split("::").collect::>(); if aa_kbc_params_vec.len() != 2 { - return Err(Error::KbsClientError( - "Illegal `aa_kbc_params` format provided in /etc/agent-config.toml.".to_string(), - )); + return Err(Error::KbsClientError(format!( + "Illegal `aa_kbc_params` format provided in {path}." + ))); } Ok(( From 07ff38067aaaccfda5399bd5626c10f1b2279415 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Fri, 22 Dec 2023 14:32:43 +0800 Subject: [PATCH 04/18] cocokeyprovider: add support for daemonize Fixes #185 Signed-off-by: Xynnn007 --- Cargo.lock | 10 ++++++ attestation-agent/coco_keyprovider/Cargo.toml | 1 + .../coco_keyprovider/src/main.rs | 32 ++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index baab4771f..f798888b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -869,6 +869,7 @@ dependencies = [ "base64 0.21.5", "clap 4.2.7", "ctr", + "daemonize", "env_logger 0.10.1", "futures", "jwt-simple", @@ -1236,6 +1237,15 @@ dependencies = [ "syn 2.0.41", ] +[[package]] +name = "daemonize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8bfdaacb3c887a54d41bdf48d3af8873b3f5566469f8ba21b92057509f116e" +dependencies = [ + "libc", +] + [[package]] name = "darling" version = "0.13.4" diff --git a/attestation-agent/coco_keyprovider/Cargo.toml b/attestation-agent/coco_keyprovider/Cargo.toml index 82f2917ed..8735478f1 100644 --- a/attestation-agent/coco_keyprovider/Cargo.toml +++ b/attestation-agent/coco_keyprovider/Cargo.toml @@ -11,6 +11,7 @@ anyhow.workspace = true base64.workspace = true clap = { workspace = true, features = ["derive"] } ctr.workspace = true +daemonize = "0.5.0" env_logger = "0.10.0" futures = "0.3.5" jwt-simple = "0.11.4" diff --git a/attestation-agent/coco_keyprovider/src/main.rs b/attestation-agent/coco_keyprovider/src/main.rs index 67911032d..a52503b8d 100644 --- a/attestation-agent/coco_keyprovider/src/main.rs +++ b/attestation-agent/coco_keyprovider/src/main.rs @@ -5,8 +5,10 @@ use anyhow::*; use clap::{arg, command, Parser}; +use daemonize::Daemonize; use log::*; -use std::{net::SocketAddr, path::PathBuf}; +use std::{fs::File, net::SocketAddr, path::PathBuf}; +use tokio::fs; pub mod enc_mods; pub mod grpc; @@ -30,6 +32,15 @@ struct Cli { /// will be automatically registered into the KBS. #[arg(long)] kbs: Option, + + /// Whether this process is launched in daemon mode. If it is set to + /// true, the stdio and stderr will be redirected to + /// `/run/confidential-containers/coco_keyprovider.out` and + /// `/run/confidential-containers/coco_keyprovider.err`. + /// The pid will be recorded in + /// `/run/confidential-containers/coco_keyprovider.pid` + #[arg(short, long, default_value = "false")] + daemon: bool, } #[tokio::main] @@ -48,6 +59,25 @@ async fn main() -> Result<()> { ); } + if cli.daemon { + fs::create_dir_all("/run/confidential-containers") + .await + .context("create coco run dir failed.")?; + let stdout = File::create("/run/confidential-containers/coco_keyprovider.out") + .context("create stdout redirect file failed.")?; + let stderr = File::create("/run/confidential-containers/coco_keyprovider.err") + .context("create stderr redirect file failed.")?; + + let daemonize = Daemonize::new() + .pid_file("/run/confidential-containers/coco_keyprovider.pid") + .chown_pid_file(true) + .working_directory("/run/confidential-containers") + .stdout(stdout) + .stderr(stderr); + + daemonize.start().context("daemonize failed")?; + } + grpc::start_service(cli.socket, cli.auth_private_key, cli.kbs).await?; Ok(()) From 15184a52a3171508c91eaf05913dc4289f3dfa3e Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Thu, 11 Jan 2024 16:20:55 +0800 Subject: [PATCH 05/18] Cargo.lock: update az-tdx-vtpm and kbs-types Signed-off-by: Xynnn007 --- Cargo.lock | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f798888b3..b316d3f91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,6 +273,7 @@ dependencies = [ "anyhow", "async-trait", "az-snp-vtpm", + "az-tdx-vtpm", "base64 0.21.5", "codicon", "csv-rs", @@ -354,9 +355,9 @@ dependencies = [ [[package]] name = "az-cvm-vtpm" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6239da1e7629eabf1ee6bf5e7dd78b532c029e2fc477afe846db201c67325233" +checksum = "8810a74cfe3024bdfd6bf13e1829114a3ce5431b7d2ef4e4a718a78ffaf03f79" dependencies = [ "bincode", "jsonwebkey", @@ -388,6 +389,22 @@ dependencies = [ "ureq", ] +[[package]] +name = "az-tdx-vtpm" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42775a99133b9c0edff34fb463713bb197f744b96d74dee5c1f953434721001" +dependencies = [ + "az-cvm-vtpm", + "base64-url", + "bincode", + "serde", + "serde_json", + "thiserror", + "ureq", + "zerocopy", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -431,6 +448,15 @@ dependencies = [ "serde", ] +[[package]] +name = "base64-url" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb9fb9fb058cc3063b5fc88d9a21eefa2735871498a04e1650da76ed511c8569" +dependencies = [ + "base64 0.21.5", +] + [[package]] name = "base64ct" version = "1.6.0" @@ -2815,9 +2841,9 @@ dependencies = [ [[package]] name = "kbs-types" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40d90e19846fb37e6025740825dd10f65320d3e56f8e957b4bba021b85bc79d6" +checksum = "d1f4b0642769e12f56cfc646d8be13668ed48d3caed0e99efb161c407f3ec532" dependencies = [ "serde", "serde_json", From e1fb5a13b027ddff6bc3bb530e019f67d2cd1456 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Thu, 11 Jan 2024 16:22:17 +0800 Subject: [PATCH 06/18] CDH/storage/aliyun: refactor the code of the OSS module The previous parameters of the function is not correct, s.t. using `source` as the target mount path. This commit fixes this. Also, this commit leverages the async lib to handle filesystem and time operations to avoid blocking. The last part is that in the previous version, all mount operations will share a same OSSFS_PASSWD_FILE and GOCRYPTFS_PASSWD_FILE path. This means that the operation cannot be idempotent. This is fixed by create a temp directory under /tmp for every mount operation to store those metadata files. Signed-off-by: Xynnn007 --- Cargo.lock | 1 + confidential-data-hub/storage/Cargo.toml | 13 +- .../src/volume_type/alibaba_cloud_oss/oss.rs | 138 ++++++++++++------ 3 files changed, 101 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b316d3f91..20519287f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5510,6 +5510,7 @@ dependencies = [ "secret", "serde", "serde_json", + "tempfile", "thiserror", "tokio", ] diff --git a/confidential-data-hub/storage/Cargo.toml b/confidential-data-hub/storage/Cargo.toml index fdcd5b685..136bad83f 100644 --- a/confidential-data-hub/storage/Cargo.toml +++ b/confidential-data-hub/storage/Cargo.toml @@ -6,14 +6,15 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = "1" -serde_json = "1" -thiserror.workspace = true -tokio = { workspace = true, features = ["fs"] } anyhow.workspace = true -secret = { path = "../secret" } base64.workspace = true log.workspace = true +secret = { path = "../secret" } +serde.workspace = true +serde_json.workspace = true +tempfile = { workspace = true, optional = true } +thiserror.workspace = true +tokio = { workspace = true, optional = true } [dev-dependencies] rstest.workspace = true @@ -24,4 +25,4 @@ anyhow.workspace = true [features] default = ["aliyun"] -aliyun = [] +aliyun = [ "tempfile", "tokio/fs", "tokio/process", "tokio/io-util", "tokio/time" ] diff --git a/confidential-data-hub/storage/src/volume_type/alibaba_cloud_oss/oss.rs b/confidential-data-hub/storage/src/volume_type/alibaba_cloud_oss/oss.rs index 42cf891d9..1696ebbb3 100644 --- a/confidential-data-hub/storage/src/volume_type/alibaba_cloud_oss/oss.rs +++ b/confidential-data-hub/storage/src/volume_type/alibaba_cloud_oss/oss.rs @@ -3,20 +3,25 @@ // SPDX-License-Identifier: Apache-2.0 // +use std::os::unix::fs::PermissionsExt; + use base64::{engine::general_purpose::STANDARD, Engine}; use secret::secret::Secret; use serde::{Deserialize, Serialize}; -use std::fs; -use std::fs::File; -use std::io::Write; -use std::os::unix::fs::PermissionsExt; -use std::process::Command; +use tokio::{fs, io::AsyncWriteExt, process::Command}; use crate::{Error, Result}; -const OSSFS_PASSWD_FILE: &str = "/tmp/ossfs_passwd"; -const GOCRYPTFS_PASSWD_FILE: &str = "/tmp/gocryptfs_passwd"; +/// Name of the file that contains ossfs password +const OSSFS_PASSWD_FILE: &str = "ossfs_passwd"; + +/// Name of the file that contains gocryptfs password +const GOCRYPTFS_PASSWD_FILE: &str = "gocryptfs_passwd"; + +/// Aliyun OSS filesystem client binary const OSSFS_BIN: &str = "/usr/local/bin/ossfs"; + +/// Gocryptofs binary const GOCRYPTFS_BIN: &str = "/usr/local/bin/gocryptfs"; #[derive(Serialize, Deserialize, PartialEq, Debug)] @@ -88,79 +93,122 @@ async fn get_plaintext_secret(secret: &str) -> Result { } impl Oss { - pub(crate) async fn mount(&self, source: String, mount_point: String) -> Result { + /// Mount the Aliyun OSS storage to the given `mount_point``. + /// + /// The OSS parameters of the mount source are stored inside the `Oss` struct. + /// + /// If `oss.encrypted` is set to `gocryptfs`, the OSS storage is a gocryptofs FUSE. + /// This function will create a temp directory, which is used to mount OSS. Then + /// use gocryptfs to mount the `mount_point` as plaintext and the temp directory + /// as ciphertext. + pub(crate) async fn mount(&self, _source: String, mount_point: String) -> Result { // unseal secret let plain_ak_id = get_plaintext_secret(&self.ak_id).await?; let plain_ak_secret = get_plaintext_secret(&self.ak_secret).await?; + // create temp directory to storage metadata for this mount operation + let tempdir = tempfile::tempdir().map_err(|e| { + Error::FileError(format!( + "create ossfs metadata temp directory failed: {e:?}" + )) + })?; + // create ossfs passwd file - let mut ossfs_passwd = File::create(OSSFS_PASSWD_FILE) - .map_err(|e| Error::FileError(format!("create file failed: {e}")))?; - let metadata = ossfs_passwd + let mut ossfs_passwd_path = tempdir.path().to_owned(); + ossfs_passwd_path.push(OSSFS_PASSWD_FILE); + let ossfs_passwd_path = ossfs_passwd_path.to_string_lossy().to_string(); + let mut ossfs_passwd = fs::File::create(&ossfs_passwd_path) + .await + .map_err(|e| Error::FileError(format!("create ossfs password file failed: {e:?}")))?; + let mut permissions = ossfs_passwd .metadata() - .map_err(|e| Error::FileError(format!("create metadata failed: {e}")))?; - let mut permissions = metadata.permissions(); + .await + .map_err(|e| Error::FileError(format!("create metadata failed: {e}")))? + .permissions(); permissions.set_mode(0o600); ossfs_passwd .set_permissions(permissions) + .await .map_err(|e| Error::FileError(format!("set permissions failed: {e}")))?; ossfs_passwd .write_all(format!("{}:{}:{}", self.bucket, plain_ak_id, plain_ak_secret).as_bytes()) + .await .map_err(|e| Error::FileError(format!("write file failed: {e}")))?; - // generate parameters for ossfs command, and execute + // generate parameters for ossfs command let mut opts = self .other_opts .split_whitespace() .map(str::to_string) .collect(); - let s = if self.encrypted == "gocryptfs" { - fs::create_dir_all("/tmp/oss") - .map_err(|e| Error::FileError(format!("create dir failed: {e}")))?; - "/tmp/oss/".to_string() - } else { - source.clone() - }; - let mut parameters = vec![ - format!("{}:{}", self.bucket, self.path), - s.clone(), - format!("-ourl={}", self.url), - format!("-opasswd_file={}", OSSFS_PASSWD_FILE), - ]; - parameters.append(&mut opts); - - Command::new(OSSFS_BIN) - .args(parameters) - .spawn() - .expect("failed to mount oss"); - std::thread::sleep(std::time::Duration::from_secs(3)); - - // decrypt with gocryptfs if needed + if self.encrypted == "gocryptfs" { - // unseal secret + let gocryptfs_dir = tempfile::tempdir().map_err(|e| { + Error::FileError(format!("create gocryptfs mount dir failed: {e:?}")) + })?; + + let gocryptfs_dir_path = gocryptfs_dir.path().to_string_lossy().to_string(); + let mut parameters = vec![ + format!("{}:{}", self.bucket, self.path), + gocryptfs_dir_path.clone(), + format!("-ourl={}", self.url), + format!("-opasswd_file={ossfs_passwd_path}"), + ]; + + parameters.append(&mut opts); + Command::new(OSSFS_BIN) + .args(parameters) + .spawn() + .map_err(|e| Error::SecureMountFailed(format!("failed to mount oss: {e:?}")))?; + + // get the gocryptfs password let plain_passwd = get_plaintext_secret(&self.enc_passwd).await?; // create gocryptfs passwd file - let mut gocryptfs_passwd = File::create(GOCRYPTFS_PASSWD_FILE) - .map_err(|e| Error::FileError(format!("create file failed: {e}")))?; + let mut gocryptfs_passwd_path = tempdir.path().to_owned(); + gocryptfs_passwd_path.push(GOCRYPTFS_PASSWD_FILE); + let gocryptfs_passwd_path = gocryptfs_passwd_path.to_string_lossy().to_string(); + let mut gocryptfs_passwd = + fs::File::create(&gocryptfs_passwd_path) + .await + .map_err(|e| { + Error::FileError(format!("create gocryptfs password file failed: {e:?}")) + })?; + gocryptfs_passwd .write_all(plain_passwd.as_bytes()) + .await .map_err(|e| Error::FileError(format!("write file failed: {e}")))?; // generate parameters for gocryptfs, and execute let parameters = vec![ - s, - source, + gocryptfs_dir_path, + mount_point.clone(), "-passfile".to_string(), - GOCRYPTFS_PASSWD_FILE.to_string(), + gocryptfs_passwd_path, "-nosyslog".to_string(), ]; Command::new(GOCRYPTFS_BIN) .args(parameters) .spawn() - .expect("failed to decrypt oss"); - std::thread::sleep(std::time::Duration::from_secs(3)); - } + .map_err(|e| Error::SecureMountFailed(format!("failed to decrypt oss: {e:?}")))?; + tokio::time::sleep(std::time::Duration::from_secs(3)).await; + } else { + let mut parameters = vec![ + format!("{}:{}", self.bucket, self.path), + mount_point.clone(), + format!("-ourl={}", self.url), + format!("-opasswd_file={ossfs_passwd_path}"), + ]; + + parameters.append(&mut opts); + Command::new(OSSFS_BIN) + .args(parameters) + .spawn() + .map_err(|e| Error::SecureMountFailed(format!("failed to mount oss: {e:?}")))?; + tokio::time::sleep(std::time::Duration::from_secs(3)).await; + }; + Ok(mount_point) } } From 1b6c702a058df39640d94b1d4cfd3a1b0b6f9701 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Fri, 12 Jan 2024 10:40:00 +0800 Subject: [PATCH 07/18] ocicrypt-rs: fix lint error for useless vec! This is a new clippy check item in cargo nightly. https://rust-lang.github.io/rust-clippy/master/index.html#/useless_vec Signed-off-by: Xynnn007 --- ocicrypt-rs/src/keywrap/jwe.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ocicrypt-rs/src/keywrap/jwe.rs b/ocicrypt-rs/src/keywrap/jwe.rs index 7ae8ececd..388f9313e 100644 --- a/ocicrypt-rs/src/keywrap/jwe.rs +++ b/ocicrypt-rs/src/keywrap/jwe.rs @@ -141,7 +141,7 @@ mod tests { fn test_keywrap_jwe() { let path = load_data_path(); let path = path.display(); - let pub_key_files = vec![ + let pub_key_files = [ format!("{}/{}", path, "public_key.pem"), format!("{}/{}", path, "public_key_ec.der"), format!("{}/{}", path, "RSA_public.jwk"), @@ -167,7 +167,7 @@ mod tests { let json = jwe_key_wrapper.wrap_keys(&ec, &payload).unwrap(); - let priv_key_files = vec![ + let priv_key_files = [ format!("{}/{}", path, "private_key.pem"), format!("{}/{}", path, "private_key.der"), format!("{}/{}", path, "private_key8.pem"), From 0354fd2b966eb7b16958161b0dbdfbc455046464 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Wed, 3 Jan 2024 16:20:33 +0800 Subject: [PATCH 08/18] image-rs: use CDH for GetResource API and abondon AA lib dep As stated in #412, AA will never be used as a component that provides abilities more than attestation. This commit changes the ttrpc socket path from AA to CDH for image-rs to GetResource API. Also, for enclave-cc, the Native resource client will instead use the kbs_protocol crate to do the RCAR handshake and do GetResource. For gRPC, we still use the legacy address, but the API was changed as we do not assume that the API is provided by AA but CDH. Signed-off-by: Xynnn007 --- .github/workflows/image_rs_build.yml | 15 ++-- Cargo.lock | 3 +- image-rs/Cargo.toml | 21 ++--- image-rs/protos/getresource.proto | 2 - image-rs/src/resource/kbs/grpc.rs | 19 ++-- image-rs/src/resource/kbs/mod.rs | 87 ++++++------------- image-rs/src/resource/kbs/native.rs | 53 ++++++++--- image-rs/src/resource/kbs/ttrpc.rs | 11 +-- .../resource/kbs/ttrpc_proto/getresource.rs | 58 +++---------- .../kbs/ttrpc_proto/getresource_ttrpc.rs | 8 +- 10 files changed, 112 insertions(+), 165 deletions(-) diff --git a/.github/workflows/image_rs_build.yml b/.github/workflows/image_rs_build.yml index 305851cc8..d79d9e556 100644 --- a/.github/workflows/image_rs_build.yml +++ b/.github/workflows/image_rs_build.yml @@ -74,9 +74,7 @@ jobs: run: | cargo clippy -p image-rs --all-targets --features=default -- -D warnings cargo clippy -p image-rs --all-targets --features=kata-cc-rustls-tls --no-default-features -- -D warnings - cargo clippy -p image-rs --all-targets --features=enclave-cc-eaakbc-rustls-tls --no-default-features -- -D warnings cargo clippy -p image-rs --all-targets --features=kata-cc-native-tls --no-default-features -- -D warnings - cargo clippy -p image-rs --all-targets --features=enclave-cc-eaakbc-native-tls --no-default-features -- -D warnings cargo clippy -p image-rs --all-targets --features=enclave-cc-cckbc-native-tls --no-default-features -- -D warnings cargo clippy -p image-rs --all-targets --features=kata-cc-native-tls,signature-simple-xrss --no-default-features -- -D warnings @@ -90,13 +88,14 @@ jobs: run: | sudo -E PATH=$PATH -s cargo test -p image-rs --features default - - name: Run cargo test - kata-cc (rust-tls version) with keywrap-grpc + keywrap-jwe - run: | - sudo -E PATH=$PATH -s cargo test -p image-rs --no-default-features --features=encryption-ring,keywrap-grpc,snapshot-overlayfs,signature-cosign-rustls,signature-simple,getresource,oci-distribution/rustls-tls,keywrap-jwe + # TODO: delete the comment after https://github.com/confidential-containers/guest-components/issues/430 + # - name: Run cargo test - kata-cc (rust-tls version) with keywrap-grpc + keywrap-jwe + # run: | + # sudo -E PATH=$PATH -s cargo test -p image-rs --no-default-features --features=encryption-ring,keywrap-grpc,snapshot-overlayfs,signature-cosign-rustls,signature-simple,getresource,oci-distribution/rustls-tls,keywrap-jwe - - name: Run cargo test - kata-cc (native-tls version) with keywrap-grpc + keywrap-jwe - run: | - sudo -E PATH=$PATH -s cargo test -p image-rs --no-default-features --features=encryption-openssl,keywrap-grpc,snapshot-overlayfs,signature-cosign-native,signature-simple,getresource,oci-distribution/native-tls,keywrap-jwe + # - name: Run cargo test - kata-cc (native-tls version) with keywrap-grpc + keywrap-jwe + # run: | + # sudo -E PATH=$PATH -s cargo test -p image-rs --no-default-features --features=encryption-openssl,keywrap-grpc,snapshot-overlayfs,signature-cosign-native,signature-simple,getresource,oci-distribution/native-tls,keywrap-jwe - name: Run cargo test - kata-cc (rust-tls version) with keywrap-ttrpc (default) + keywrap-jwe run: | diff --git a/Cargo.lock b/Cargo.lock index 20519287f..359607d04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2537,7 +2537,6 @@ dependencies = [ "anyhow", "async-compression", "async-trait", - "attestation_agent", "base64 0.21.5", "cfg-if", "devicemapper", @@ -2548,6 +2547,7 @@ dependencies = [ "futures", "futures-util", "hex", + "kbc", "lazy_static", "libc", "log", @@ -2562,6 +2562,7 @@ dependencies = [ "prost 0.11.9", "protobuf 3.3.0", "reqwest", + "resource_uri", "rstest", "sequoia-openpgp", "serde", diff --git a/image-rs/Cargo.toml b/image-rs/Cargo.toml index a22fce6d8..dad7fe75d 100644 --- a/image-rs/Cargo.toml +++ b/image-rs/Cargo.toml @@ -12,7 +12,6 @@ edition = "2021" anyhow.workspace = true async-compression = { version = "0.4.1", features = ["futures-io", "tokio", "gzip", "zstd"] } async-trait.workspace = true -attestation_agent = { path = "../attestation-agent/lib", default-features = false, optional = true } base64.workspace = true cfg-if = { workspace = true, optional = true } devicemapper = { version = "0.33.5", optional = true } @@ -22,6 +21,7 @@ fs_extra = { version = "1.2.0", optional = true } futures = { version = "0.3.28", optional = true } futures-util = "0.3" hex = { workspace = true, optional = true } +kbc = { path = "../attestation-agent/kbc", default-features = false, optional = true } lazy_static = { workspace = true, optional = true } libc = "0.2" log = "0.4.14" @@ -33,6 +33,7 @@ ocicrypt-rs = { path = "../ocicrypt-rs", default-features = false, features = [" prost = { workspace = true, optional = true } protobuf = { workspace = true, optional = true } reqwest = { workspace = true, features = ["json"], optional = true } +resource_uri = { path = "../attestation-agent/deps/resource_uri", optional = true } sequoia-openpgp = { version = "1.7.0", default-features = false, features = ["compression", "crypto-rust", "allow-experimental-crypto", "allow-variable-time-crypto"], optional = true } serde = { workspace = true, features = ["serde_derive", "rc"] } serde_json.workspace = true @@ -82,28 +83,28 @@ default = ["snapshot-overlayfs", "signature-cosign-rustls", "keywrap-grpc", "oci # This will be based on `ring` dependency kata-cc-rustls-tls = ["encryption-ring", "keywrap-ttrpc", "snapshot-overlayfs", "signature-cosign-rustls", "signature-simple", "getresource", "oci-distribution/rustls-tls"] -enclave-cc-eaakbc-rustls-tls = ["encryption-ring", "keywrap-native", "eaa-kbc", "snapshot-unionfs", "signature-simple", "getresource", "signature-cosign-rustls", "oci-distribution-rustls"] -enclave-cc-cckbc-rustls-tls = ["encryption-ring", "keywrap-native", "cc-kbc-sgx", "snapshot-unionfs", "signature-simple", "getresource", "signature-cosign-rustls", "oci-distribution-rustls"] +enclave-cc-cckbc-rustls-tls = ["encryption-ring", "keywrap-native", "snapshot-unionfs", "signature-simple", "getresource", "signature-cosign-rustls", "oci-distribution-rustls"] # This will be based on `openssl` dependency kata-cc-native-tls = ["encryption-openssl", "keywrap-ttrpc", "snapshot-overlayfs", "signature-cosign-native", "signature-simple", "getresource", "oci-distribution/native-tls"] -enclave-cc-eaakbc-native-tls = ["encryption-openssl", "keywrap-native", "eaa-kbc", "snapshot-unionfs", "signature-simple", "getresource", "signature-cosign-native", "oci-distribution-native"] -enclave-cc-cckbc-native-tls = ["encryption-openssl", "keywrap-native", "cc-kbc-sgx", "snapshot-unionfs", "signature-simple", "getresource", "signature-cosign-native", "oci-distribution-native"] +enclave-cc-cckbc-native-tls = ["encryption-openssl", "keywrap-native", "snapshot-unionfs", "signature-simple", "getresource", "signature-cosign-native", "oci-distribution-native"] encryption = ["ocicrypt-rs/block-cipher"] -encryption-ring = ["ocicrypt-rs/block-cipher-ring", "encryption"] -encryption-openssl = ["ocicrypt-rs/block-cipher-openssl", "encryption"] +encryption-ring = ["ocicrypt-rs/block-cipher-ring", "kbc?/rust-crypto", "encryption"] +encryption-openssl = ["ocicrypt-rs/block-cipher-openssl", "kbc?/openssl", "encryption"] keywrap-cmd = ["ocicrypt-rs/keywrap-keyprovider-cmd"] + +# Warning: This feature is not able to compile temporarily +# before https://github.com/confidential-containers/guest-components/issues/430 is fixed. keywrap-grpc = ["ocicrypt-rs/keywrap-keyprovider-grpc", "prost", "tonic", "tonic-build"] -keywrap-native = ["ocicrypt-rs/keywrap-keyprovider-native", "attestation_agent"] +keywrap-native = ["ocicrypt-rs/keywrap-keyprovider-native", "kbc/cc_kbc", "kbc/sample_kbc", "kbc/sgx-attester", "resource_uri"] keywrap-ttrpc = ["ocicrypt-rs/keywrap-keyprovider-ttrpc", "dep:ttrpc", "dep:protobuf", "ttrpc-codegen"] # Enable keywrap-jwe to decrypt image keywrap-jwe = ["ocicrypt-rs/keywrap-jwe"] -eaa-kbc = ["attestation_agent/eaa_kbc", "ocicrypt-rs/eaa_kbc"] -cc-kbc-sgx = ["attestation_agent/cc_kbc", "attestation_agent/sgx-attester", "ocicrypt-rs/cc_kbc_sgx"] +cc-kbc-sgx = ["kbs_protocol/background_check", "kbs_protocol/sgx-attester", "ocicrypt-rs/cc_kbc_sgx", "kbs_protocol/passport"] signature = ["hex"] signature-cosign = ["signature", "futures"] diff --git a/image-rs/protos/getresource.proto b/image-rs/protos/getresource.proto index 8864e01b5..93cd2e4de 100644 --- a/image-rs/protos/getresource.proto +++ b/image-rs/protos/getresource.proto @@ -4,8 +4,6 @@ package getresource; message GetResourceRequest { string ResourcePath = 1; - string KbcName = 2; - string KbsUri = 3; } message GetResourceResponse { diff --git a/image-rs/src/resource/kbs/grpc.rs b/image-rs/src/resource/kbs/grpc.rs index e10abe9b7..e23ddab1c 100644 --- a/image-rs/src/resource/kbs/grpc.rs +++ b/image-rs/src/resource/kbs/grpc.rs @@ -24,7 +24,13 @@ mod get_resource { /// Attestation Agent's GetResource gRPC address. /// It's given -pub const AA_GETRESOURCE_ADDR: &str = "http://127.0.0.1:50001"; +/// +/// We are now using CDH to provide the GetResource gRPC service, +/// while gRPC is still not supported by CDH. So this feature will +/// not work. +/// TODO: Add gRPC support for CDH to leverage the ability of getting +/// resources by image-rs using gRPC. +pub const GETRESOURCE_ADDR: &str = "http://127.0.0.1:50001"; pub struct Grpc { inner: GetResourceServiceClient, @@ -32,23 +38,16 @@ pub struct Grpc { impl Grpc { pub async fn new() -> Result { - let inner = GetResourceServiceClient::connect(AA_GETRESOURCE_ADDR).await?; + let inner = GetResourceServiceClient::connect(GETRESOURCE_ADDR).await?; Ok(Self { inner }) } } #[async_trait] impl Client for Grpc { - async fn get_resource( - &mut self, - kbc_name: &str, - resource_path: &str, - kbs_uri: &str, - ) -> Result> { + async fn get_resource(&mut self, resource_path: &str) -> Result> { let req = tonic::Request::new(GetResourceRequest { - kbc_name: kbc_name.to_string(), resource_path: resource_path.to_string(), - kbs_uri: kbs_uri.to_string(), }); Ok(self.inner.get_resource(req).await?.into_inner().resource) } diff --git a/image-rs/src/resource/kbs/mod.rs b/image-rs/src/resource/kbs/mod.rs index 7a534b3b8..eb565d023 100644 --- a/image-rs/src/resource/kbs/mod.rs +++ b/image-rs/src/resource/kbs/mod.rs @@ -17,7 +17,7 @@ use std::path::Path; #[cfg(not(feature = "keywrap-native"))] use anyhow::Context; -use anyhow::{bail, Result}; +use anyhow::Result; use async_trait::async_trait; use log::info; use sha2::{Digest, Sha256}; @@ -25,6 +25,9 @@ use tokio::fs; use super::Protocol; +#[cfg(feature = "keywrap-grpc")] +compile_error!("`keywrap-grpc` feature is temporarily not supported until https://github.com/confidential-containers/guest-components/issues/430 is closed"); + #[cfg(feature = "keywrap-grpc")] mod grpc; @@ -44,74 +47,43 @@ const STORAGE_PATH: &str = "/run/image-security/kbs/"; pub struct SecureChannel { /// Get Resource Service client. client: Box, - // TODO: now the _kbs_uri from `aa_kbc_params` is not used. Because the - // kbs uri is included in the kbs resource uri. - kbs_uri: String, - kbc_name: String, + /// The path to store downloaded kbs resources pub storage_path: String, } #[async_trait] trait Client: Send + Sync { - async fn get_resource( - &mut self, - kbc_name: &str, - resource_path: &str, - kbs_uri: &str, - ) -> Result>; + async fn get_resource(&mut self, resource_path: &str) -> Result>; } impl SecureChannel { /// Create a new [`SecureChannel`], the input parameter: /// * `aa_kbc_params`: s string with format `::`. - pub async fn new(aa_kbc_params: &str) -> Result { - // unzip here is unstable - if let Some((kbc_name, kbs_uri)) = aa_kbc_params.split_once("::") { - if kbc_name.is_empty() { - bail!("aa_kbc_params: missing KBC name"); + pub async fn new(_aa_kbc_params: &str) -> Result { + let client: Box = { + cfg_if::cfg_if! { + if #[cfg(feature = "keywrap-ttrpc")] { + info!("secure channel uses ttrpc"); + Box::new(ttrpc::Ttrpc::new().context("ttrpc client init failed")?) + } else if #[cfg(feature = "keywrap-native")] { + info!("secure channel uses native-aa"); + Box::new(native::Native::new(_aa_kbc_params)?) + } else if #[cfg(feature = "keywrap-grpc")] { + info!("secure channel uses gRPC"); + Box::new(grpc::Grpc::new().await.context("grpc client init failed")?) + } else { + compile_error!("At last one feature of `keywrap-grpc`, `keywrap-ttrpc`, and `keywrap-native` must be enabled."); + } } + }; - if kbs_uri.is_empty() { - bail!("aa_kbc_params: missing KBS URI"); - } + fs::create_dir_all(STORAGE_PATH).await?; - let client: Box = { - cfg_if::cfg_if! { - if #[cfg(feature = "keywrap-grpc")] { - info!("secure channel uses gRPC"); - Box::new(grpc::Grpc::new().await.context("grpc client init failed")?) - } else if #[cfg(feature = "keywrap-ttrpc")] { - info!("secure channel uses ttrpc"); - Box::new(ttrpc::Ttrpc::new().context("ttrpc client init failed")?) - } else if #[cfg(feature = "keywrap-native")] { - info!("secure channel uses native-aa"); - Box::::default() - } else { - compile_error!("At last one feature of `keywrap-grpc`, `keywrap-ttrpc`, and `keywrap-native` must be enabled."); - } - } - }; - - fs::create_dir_all(STORAGE_PATH).await?; - - let kbs_uri = match kbs_uri { - "null" => { - log::warn!("detected kbs uri `null`, use localhost to be placeholder"); - "http://localhost".into() - } - uri => uri.into(), - }; - - Ok(Self { - client, - kbs_uri, - kbc_name: kbc_name.into(), - storage_path: STORAGE_PATH.into(), - }) - } else { - bail!("aa_kbc_params: KBC/KBS pair not found") - } + Ok(Self { + client, + storage_path: STORAGE_PATH.into(), + }) } /// Check whether the resource of the uri has been downloaded. @@ -159,10 +131,7 @@ impl Protocol for SecureChannel { // `kbs_uri` of [`SecureChannel`]. let resource_path = get_resource_path(resource_uri)?; - let res = self - .client - .get_resource(&self.kbc_name, &resource_path, &self.kbs_uri) - .await?; + let res = self.client.get_resource(&resource_path).await?; let path = self.get_filepath(resource_uri); fs::write(path, &res).await?; diff --git a/image-rs/src/resource/kbs/native.rs b/image-rs/src/resource/kbs/native.rs index c2aebeb9a..59aaf420b 100644 --- a/image-rs/src/resource/kbs/native.rs +++ b/image-rs/src/resource/kbs/native.rs @@ -7,26 +7,53 @@ use anyhow::*; use async_trait::async_trait; -use attestation_agent::AttestationAPIs; -use attestation_agent::AttestationAgent; +use kbc::{cc_kbc::Kbc as CcKbc, sample_kbc::SampleKbc, KbcInterface}; +use resource_uri::ResourceUri; use super::Client; -#[derive(Default)] +enum Kbc { + Sample(SampleKbc), + Cc(CcKbc), +} + pub struct Native { - inner: AttestationAgent, + inner: Kbc, +} + +impl Native { + pub fn new(aa_kbc_params: &str) -> Result { + let Some((kbc_name, kbs_uri)) = aa_kbc_params.split_once("::") else { + bail!("illegal aa_kbc_params : {aa_kbc_params}"); + }; + + if kbc_name.is_empty() { + bail!("aa_kbc_params: missing KBC name"); + } + + if kbs_uri.is_empty() { + bail!("aa_kbc_params: missing KBS URI"); + } + + let inner = match kbc_name { + "cc_kbc" => Kbc::Cc(CcKbc::new(kbs_uri.to_owned())?), + "sample_kbc" => Kbc::Sample(SampleKbc::new(kbs_uri.to_owned())), + other => bail!("Unsupported KBC {other}"), + }; + + Ok(Self { inner }) + } } #[async_trait] impl Client for Native { - async fn get_resource( - &mut self, - kbc_name: &str, - resource_path: &str, - kbs_uri: &str, - ) -> Result> { - self.inner - .download_confidential_resource(kbc_name, resource_path, kbs_uri) - .await + async fn get_resource(&mut self, resource_path: &str) -> Result> { + let url = + ResourceUri::try_from(resource_path).map_err(|e| anyhow!("parse ResourceUri: {e}"))?; + let resource = match &mut self.inner { + Kbc::Sample(ref mut inner) => inner.get_resource(url).await?, + Kbc::Cc(ref mut inner) => inner.get_resource(url).await?, + }; + Ok(resource) } } diff --git a/image-rs/src/resource/kbs/ttrpc.rs b/image-rs/src/resource/kbs/ttrpc.rs index 2cb79eb25..af0d1fcae 100644 --- a/image-rs/src/resource/kbs/ttrpc.rs +++ b/image-rs/src/resource/kbs/ttrpc.rs @@ -14,7 +14,7 @@ use super::Client; use super::ttrpc_proto::getresource::GetResourceRequest; use super::ttrpc_proto::getresource_ttrpc::GetResourceServiceClient; -const SOCKET_ADDR: &str = "unix:///run/confidential-containers/attestation-agent/getresource.sock"; +const SOCKET_ADDR: &str = "unix:///run/confidential-containers/cdh.sock"; pub struct Ttrpc { gtclient: GetResourceServiceClient, @@ -31,16 +31,9 @@ impl Ttrpc { #[async_trait] impl Client for Ttrpc { - async fn get_resource( - &mut self, - kbc_name: &str, - resource_path: &str, - kbs_uri: &str, - ) -> Result> { + async fn get_resource(&mut self, resource_path: &str) -> Result> { let req = GetResourceRequest { - KbcName: kbc_name.to_string(), ResourcePath: resource_path.to_string(), - KbsUri: kbs_uri.to_string(), ..Default::default() }; let res = self diff --git a/image-rs/src/resource/kbs/ttrpc_proto/getresource.rs b/image-rs/src/resource/kbs/ttrpc_proto/getresource.rs index d655b2c8b..0bdf02599 100644 --- a/image-rs/src/resource/kbs/ttrpc_proto/getresource.rs +++ b/image-rs/src/resource/kbs/ttrpc_proto/getresource.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 3.2.0. Do not edit +// This file is generated by rust-protobuf 3.3.0. Do not edit // .proto file is parsed by pure // @generated @@ -23,18 +23,14 @@ /// Generated files are compatible only with the same version /// of protobuf runtime. -const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0; +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_3_0; -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:getresource.GetResourceRequest) +#[derive(PartialEq,Clone,Default,Debug)] pub struct GetResourceRequest { // message fields // @@protoc_insertion_point(field:getresource.GetResourceRequest.ResourcePath) pub ResourcePath: ::std::string::String, - // @@protoc_insertion_point(field:getresource.GetResourceRequest.KbcName) - pub KbcName: ::std::string::String, - // @@protoc_insertion_point(field:getresource.GetResourceRequest.KbsUri) - pub KbsUri: ::std::string::String, // special fields // @@protoc_insertion_point(special_field:getresource.GetResourceRequest.special_fields) pub special_fields: ::protobuf::SpecialFields, @@ -52,23 +48,13 @@ impl GetResourceRequest { } fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { - let mut fields = ::std::vec::Vec::with_capacity(3); + let mut fields = ::std::vec::Vec::with_capacity(1); let mut oneofs = ::std::vec::Vec::with_capacity(0); fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( "ResourcePath", |m: &GetResourceRequest| { &m.ResourcePath }, |m: &mut GetResourceRequest| { &mut m.ResourcePath }, )); - fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( - "KbcName", - |m: &GetResourceRequest| { &m.KbcName }, - |m: &mut GetResourceRequest| { &mut m.KbcName }, - )); - fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( - "KbsUri", - |m: &GetResourceRequest| { &m.KbsUri }, - |m: &mut GetResourceRequest| { &mut m.KbsUri }, - )); ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( "GetResourceRequest", fields, @@ -90,12 +76,6 @@ impl ::protobuf::Message for GetResourceRequest { 10 => { self.ResourcePath = is.read_string()?; }, - 18 => { - self.KbcName = is.read_string()?; - }, - 26 => { - self.KbsUri = is.read_string()?; - }, tag => { ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; }, @@ -111,12 +91,6 @@ impl ::protobuf::Message for GetResourceRequest { if !self.ResourcePath.is_empty() { my_size += ::protobuf::rt::string_size(1, &self.ResourcePath); } - if !self.KbcName.is_empty() { - my_size += ::protobuf::rt::string_size(2, &self.KbcName); - } - if !self.KbsUri.is_empty() { - my_size += ::protobuf::rt::string_size(3, &self.KbsUri); - } my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); self.special_fields.cached_size().set(my_size as u32); my_size @@ -126,12 +100,6 @@ impl ::protobuf::Message for GetResourceRequest { if !self.ResourcePath.is_empty() { os.write_string(1, &self.ResourcePath)?; } - if !self.KbcName.is_empty() { - os.write_string(2, &self.KbcName)?; - } - if !self.KbsUri.is_empty() { - os.write_string(3, &self.KbsUri)?; - } os.write_unknown_fields(self.special_fields.unknown_fields())?; ::std::result::Result::Ok(()) } @@ -150,16 +118,12 @@ impl ::protobuf::Message for GetResourceRequest { fn clear(&mut self) { self.ResourcePath.clear(); - self.KbcName.clear(); - self.KbsUri.clear(); self.special_fields.clear(); } fn default_instance() -> &'static GetResourceRequest { static instance: GetResourceRequest = GetResourceRequest { ResourcePath: ::std::string::String::new(), - KbcName: ::std::string::String::new(), - KbsUri: ::std::string::String::new(), special_fields: ::protobuf::SpecialFields::new(), }; &instance @@ -183,8 +147,8 @@ impl ::protobuf::reflect::ProtobufValue for GetResourceRequest { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:getresource.GetResourceResponse) +#[derive(PartialEq,Clone,Default,Debug)] pub struct GetResourceResponse { // message fields // @@protoc_insertion_point(field:getresource.GetResourceResponse.Resource) @@ -306,13 +270,11 @@ impl ::protobuf::reflect::ProtobufValue for GetResourceResponse { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x11getresource.proto\x12\x0bgetresource\"j\n\x12GetResourceRequest\ - \x12\"\n\x0cResourcePath\x18\x01\x20\x01(\tR\x0cResourcePath\x12\x18\n\ - \x07KbcName\x18\x02\x20\x01(\tR\x07KbcName\x12\x16\n\x06KbsUri\x18\x03\ - \x20\x01(\tR\x06KbsUri\"1\n\x13GetResourceResponse\x12\x1a\n\x08Resource\ - \x18\x01\x20\x01(\x0cR\x08Resource2f\n\x12GetResourceService\x12P\n\x0bG\ - etResource\x12\x1f.getresource.GetResourceRequest\x1a\x20.getresource.Ge\ - tResourceResponseb\x06proto3\ + \n\x11getresource.proto\x12\x0bgetresource\"8\n\x12GetResourceRequest\ + \x12\"\n\x0cResourcePath\x18\x01\x20\x01(\tR\x0cResourcePath\"1\n\x13Get\ + ResourceResponse\x12\x1a\n\x08Resource\x18\x01\x20\x01(\x0cR\x08Resource\ + 2f\n\x12GetResourceService\x12P\n\x0bGetResource\x12\x1f.getresource.Get\ + ResourceRequest\x1a\x20.getresource.GetResourceResponseb\x06proto3\ "; /// `FileDescriptorProto` object which was a source for this generated file diff --git a/image-rs/src/resource/kbs/ttrpc_proto/getresource_ttrpc.rs b/image-rs/src/resource/kbs/ttrpc_proto/getresource_ttrpc.rs index 8f0c6bd9d..40c5e226a 100644 --- a/image-rs/src/resource/kbs/ttrpc_proto/getresource_ttrpc.rs +++ b/image-rs/src/resource/kbs/ttrpc_proto/getresource_ttrpc.rs @@ -1,12 +1,9 @@ -// This file is generated by ttrpc-compiler 0.6.1. Do not edit +// This file is generated by ttrpc-compiler 0.6.2. Do not edit // @generated -// https://github.com/Manishearth/rust-clippy/issues/702 +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unknown_lints)] #![allow(clipto_camel_casepy)] - -#![cfg_attr(rustfmt, rustfmt_skip)] - #![allow(box_pointers)] #![allow(dead_code)] #![allow(missing_docs)] @@ -17,6 +14,7 @@ #![allow(unsafe_code)] #![allow(unused_imports)] #![allow(unused_results)] +#![allow(clippy::all)] use protobuf::{CodedInputStream, CodedOutputStream, Message}; use std::collections::HashMap; use std::sync::Arc; From be554f24a74c67f84e12305abd7a331eb522f8c6 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Wed, 3 Jan 2024 17:19:43 +0800 Subject: [PATCH 09/18] ocicrypt-rs: abondon AA lib dep for UnwrapKey As stated in #412, AA will never be used as a component that provides abilities more than attestation. This commit changes the AA lib calling to decrypt image. This will influence enclave-cc behavior. Signed-off-by: Xynnn007 --- .github/workflows/ocicrypt_rs_build.yml | 12 ---- Cargo.lock | 4 +- image-rs/Cargo.toml | 2 - ocicrypt-rs/Cargo.toml | 21 ++++--- ocicrypt-rs/data/sample_kbc_annotation.json | 2 +- .../{keyprovider.rs => keyprovider/mod.rs} | 19 ++----- ocicrypt-rs/src/keywrap/keyprovider/native.rs | 56 +++++++++++++++++++ 7 files changed, 75 insertions(+), 41 deletions(-) rename ocicrypt-rs/src/keywrap/{keyprovider.rs => keyprovider/mod.rs} (99%) create mode 100644 ocicrypt-rs/src/keywrap/keyprovider/native.rs diff --git a/.github/workflows/ocicrypt_rs_build.yml b/.github/workflows/ocicrypt_rs_build.yml index 3e3272f0c..04aa956bf 100644 --- a/.github/workflows/ocicrypt_rs_build.yml +++ b/.github/workflows/ocicrypt_rs_build.yml @@ -146,18 +146,6 @@ jobs: command: test args: -p ocicrypt-rs --no-default-features --features=keywrap-keyprovider-native - - name: Run cargo test - eaa-kbc - uses: actions-rs/cargo@v1 - with: - command: test - args: -p ocicrypt-rs --no-default-features --features=eaa_kbc - - - name: Run cargo test - cc-kbc-sgx - uses: actions-rs/cargo@v1 - with: - command: test - args: -p ocicrypt-rs --no-default-features --features=cc_kbc_sgx - - name: Run cargo test - default uses: actions-rs/cargo@v1 with: diff --git a/Cargo.lock b/Cargo.lock index 359607d04..70ec80980 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3548,10 +3548,10 @@ dependencies = [ "aes-gcm", "anyhow", "async-trait", - "attestation_agent", "base64 0.21.5", "base64-serde", "cfg-if", + "crypto", "ctr", "hmac 0.12.1", "josekit", @@ -3561,6 +3561,7 @@ dependencies = [ "pin-project-lite", "prost 0.11.9", "protobuf 3.3.0", + "resource_uri", "ring 0.16.20", "serde", "serde_json", @@ -3570,6 +3571,7 @@ dependencies = [ "tonic-build", "ttrpc", "ttrpc-codegen", + "zeroize", ] [[package]] diff --git a/image-rs/Cargo.toml b/image-rs/Cargo.toml index dad7fe75d..090068de5 100644 --- a/image-rs/Cargo.toml +++ b/image-rs/Cargo.toml @@ -104,8 +104,6 @@ keywrap-ttrpc = ["ocicrypt-rs/keywrap-keyprovider-ttrpc", "dep:ttrpc", "dep:prot # Enable keywrap-jwe to decrypt image keywrap-jwe = ["ocicrypt-rs/keywrap-jwe"] -cc-kbc-sgx = ["kbs_protocol/background_check", "kbs_protocol/sgx-attester", "ocicrypt-rs/cc_kbc_sgx", "kbs_protocol/passport"] - signature = ["hex"] signature-cosign = ["signature", "futures"] signature-cosign-rustls = ["signature-cosign", "sigstore/cosign-rustls-tls"] diff --git a/ocicrypt-rs/Cargo.toml b/ocicrypt-rs/Cargo.toml index f473c92e1..d8abeb2a5 100644 --- a/ocicrypt-rs/Cargo.toml +++ b/ocicrypt-rs/Cargo.toml @@ -12,19 +12,20 @@ edition = "2021" anyhow.workspace = true aes = { workspace = true, optional = true } async-trait = { workspace = true, optional = true } -attestation_agent = { path = "../attestation-agent/lib", optional = true } +crypto = { path = "../attestation-agent/deps/crypto", default-features = false, optional = true } base64.workspace = true base64-serde = { workspace = true, optional = true } cfg-if.workspace = true ctr = { workspace = true, optional = true } hmac = { workspace = true, optional = true } josekit = { version = ">=0.7", optional = true } -kbc = { path = "../attestation-agent/kbc", optional = true } +kbc = { path = "../attestation-agent/kbc", default-features = false, optional = true } lazy_static.workspace = true openssl = { workspace = true, features = ["vendored"], optional = true } pin-project-lite = { version = "0.2.9", optional = true } protobuf = { workspace = true, optional = true } prost = { workspace = true, optional = true } +resource_uri = { path = "../attestation-agent/deps/resource_uri", optional = true } ring = { workspace = true, optional = true} serde = { workspace = true, features = ["derive"] } serde_json.workspace = true @@ -32,6 +33,7 @@ sha2 = { workspace = true, optional = true } tokio = { workspace = true, features = ["rt-multi-thread"], optional = true } tonic = { workspace = true, optional = true } ttrpc = { workspace = true, features = ["async"], optional = true } +zeroize = { workspace = true, optional = true } [build-dependencies] tonic-build = { workspace = true, optional = true } @@ -45,25 +47,22 @@ tokio = { workspace = true, features = ["time", "signal"] } [features] default = ["block-cipher-openssl", "keywrap-jwe", "keywrap-keyprovider-cmd"] -# Use eaa kbc to request KEK -eaa_kbc = ["keywrap-keyprovider-native", "attestation_agent/eaa_kbc"] - -# Use cc kbc + SGX to request KEK -cc_kbc_sgx = ["keywrap-keyprovider-native", "attestation_agent/cc_kbc", "attestation_agent/sgx-attester"] - async-io = ["tokio"] block-cipher = [] # Use ring as pseudo random number generator -block-cipher-ring = ["aes", "base64-serde", "ctr", "hmac", "ring", "pin-project-lite", "sha2", "block-cipher"] +block-cipher-ring = ["aes", "base64-serde", "ctr", "hmac", "ring", "pin-project-lite", "sha2", "kbc?/rust-crypto", "block-cipher"] # Use openssl as pseudo random number generator -block-cipher-openssl = ["aes", "base64-serde", "ctr", "hmac", "openssl", "pin-project-lite", "sha2", "block-cipher"] +block-cipher-openssl = ["aes", "base64-serde", "ctr", "hmac", "openssl", "pin-project-lite", "sha2", "kbc?/openssl", "block-cipher"] keywrap-jwe = ["josekit"] keywrap-keyprovider = [] keywrap-keyprovider-cmd = ["keywrap-keyprovider"] keywrap-keyprovider-grpc = ["keywrap-keyprovider", "prost", "tonic", "tokio/net"] keywrap-keyprovider-ttrpc = ["keywrap-keyprovider", "protobuf", "async-trait", "ttrpc", "tokio"] -keywrap-keyprovider-native = ["keywrap-keyprovider", "tokio/net", "tokio/sync", "attestation_agent"] + +# Use KBC to request KEK +keywrap-keyprovider-native = ["keywrap-keyprovider", "tokio/net", "tokio/sync", "crypto/rust-crypto", "zeroize", "kbc/cc_kbc", "kbc/rust-crypto", "kbc/sample_kbc", "kbc/sgx-attester", "resource_uri"] + gen-proto-grpc = ["tonic-build"] gen-proto-ttrpc = ["ttrpc-codegen"] diff --git a/ocicrypt-rs/data/sample_kbc_annotation.json b/ocicrypt-rs/data/sample_kbc_annotation.json index cf426e837..156e882a6 100644 --- a/ocicrypt-rs/data/sample_kbc_annotation.json +++ b/ocicrypt-rs/data/sample_kbc_annotation.json @@ -2,5 +2,5 @@ "kid": "kbs:///default/key/1", "wrapped_data": "KxAFgXwa0y72Xdygub9lF00RVMtSRbYzvakIEASgi3Gvt1wGLkhKPXf0S033Jdi6vAN6zBM7d0xZSDo2JCeew0FeKwTYgdJfdcPhuEpZOpjhwIsidyeiunzp0J/crvI1tSPZJw4DPHZN2eQtg71rDzIbuDM5ATheiDM9/YJv+k+n6Nv6/pRb8qynNzbWFz7Q8wEo1ZZlL6UftOBJ6j9GuEOTM2k/B+5sMA2VhGHSzDsKA1mn0qzcn2HJg4GcmxwDpJwzm5n7B4iIJ3A0umrQAjQ=", "iv": "3PQMqtjbR4hxCr83", - "wrap_type": "aes_256_gcm" + "wrap_type": "A256GCM" } diff --git a/ocicrypt-rs/src/keywrap/keyprovider.rs b/ocicrypt-rs/src/keywrap/keyprovider/mod.rs similarity index 99% rename from ocicrypt-rs/src/keywrap/keyprovider.rs rename to ocicrypt-rs/src/keywrap/keyprovider/mod.rs index 3c6d47012..02279a3b6 100644 --- a/ocicrypt-rs/src/keywrap/keyprovider.rs +++ b/ocicrypt-rs/src/keywrap/keyprovider/mod.rs @@ -13,13 +13,7 @@ use crate::keywrap::KeyWrapper; use crate::utils::{self, CommandExecuter}; #[cfg(feature = "keywrap-keyprovider-native")] -use attestation_agent::{AttestationAPIs, AttestationAgent}; - -#[cfg(feature = "keywrap-keyprovider-native")] -lazy_static! { - pub static ref ATTESTATION_AGENT: std::sync::Arc> = - std::sync::Arc::new(tokio::sync::Mutex::new(AttestationAgent::new())); -} +mod native; #[derive(Debug)] enum OpKey { @@ -201,18 +195,15 @@ impl KeyProviderKeyWrapProtocolOutput { let (kbc, kbs) = pair_str .split_once("::") .ok_or_else(|| anyhow!("keyprovider: invalid kbc::kbs pair"))?; - let kbc = kbc.to_string(); let kbs = kbs.to_string(); + let kbc = kbc.to_string(); let annotation = annotation.to_string(); let handler = std::thread::spawn(move || { create_async_runtime()?.block_on(async { - ATTESTATION_AGENT - .lock() - .await - .decrypt_image_layer_annotation(&kbc, &kbs, &annotation) + native::decrypt_image_layer_annotation(&kbs, &kbc, &annotation) .await - .map_err(|e| format!("{e}")) + .map_err(|e| format!("{e:?}")) }) }); @@ -221,7 +212,7 @@ impl KeyProviderKeyWrapProtocolOutput { key_unwrap_results: Some(KeyUnwrapResults { opts_data: v }), ..Default::default() }), - Ok(Err(e)) => Err(anyhow!("keyprovider: retrieve opts_data failed: {e}")), + Ok(Err(e)) => Err(anyhow!("keyprovider: retrieve opts_data failed: {e:?}")), Err(e) => Err(anyhow!("keyprovider: retrieve opts_data failed: {e:?}")), } } diff --git a/ocicrypt-rs/src/keywrap/keyprovider/native.rs b/ocicrypt-rs/src/keywrap/keyprovider/native.rs new file mode 100644 index 000000000..59f1e3449 --- /dev/null +++ b/ocicrypt-rs/src/keywrap/keyprovider/native.rs @@ -0,0 +1,56 @@ +// Copyright (c) 2024 Alibaba Cloud +// +// SPDX-License-Identifier: Apache-2.0 +// + +use std::sync::Arc; + +use anyhow::*; +use kbc::{cc_kbc::Kbc as CcKbc, sample_kbc::SampleKbc, AnnotationPacket, KbcInterface}; +use tokio::sync::RwLock; + +pub enum Kbc { + Sample(SampleKbc), + Cc(CcKbc), +} + +lazy_static! { + pub static ref CHANNEL: Arc>> = Arc::new(RwLock::new(None)); +} + +async fn initialize_channel(kbs_addr: &str, kbc: &str) -> Result<()> { + let channel = match kbc { + "cc_kbc" => Kbc::Cc(CcKbc::new(kbs_addr.to_owned())?), + "sample_kbc" => Kbc::Sample(SampleKbc::new(kbs_addr.to_owned())), + other => bail!("Unsupported KBC {other}"), + }; + + let mut writer = CHANNEL.write().await; + *writer = Some(channel); + Ok(()) +} + +pub async fn decrypt_image_layer_annotation( + kbs_addr: &str, + kbc: &str, + annotation: &str, +) -> Result> { + let annotation_packet: AnnotationPacket = serde_json::from_str(annotation)?; + + // Sample KBC is still used in enclave-cc legacy e2e test. Native key provider + // will still support this until it is decided to be depreciated. + if CHANNEL.read().await.is_none() { + initialize_channel(kbs_addr, kbc).await?; + } + + let res = { + let mut writer = CHANNEL.write().await; + let writer = writer.as_mut().expect("unexpected uninitialized."); + match writer { + Kbc::Sample(inner) => inner.decrypt_payload(annotation_packet).await, + Kbc::Cc(inner) => inner.decrypt_payload(annotation_packet).await, + } + }?; + + Ok(res) +} From 1956e04595cd3824bf70ef3036724748d1222a21 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Wed, 3 Jan 2024 17:50:24 +0800 Subject: [PATCH 10/18] CDH: fix feature dependencies Signed-off-by: Xynnn007 --- confidential-data-hub/image/Cargo.toml | 4 ++-- .../image/src/annotation_packet/mod.rs | 1 - .../image/src/annotation_packet/v1.rs | 16 ++++++++-------- .../image/src/annotation_packet/v2.rs | 2 -- confidential-data-hub/kms/src/plugins/mod.rs | 1 - 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/confidential-data-hub/image/Cargo.toml b/confidential-data-hub/image/Cargo.toml index 434765df4..1760b86c5 100644 --- a/confidential-data-hub/image/Cargo.toml +++ b/confidential-data-hub/image/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" base64.workspace = true crypto.path = "../../attestation-agent/deps/crypto" kms = { path = "../kms", default-features = false } -resource_uri = { path = "../../attestation-agent/deps/resource_uri", optional = true } +resource_uri.path = "../../attestation-agent/deps/resource_uri" serde.workspace = true serde_json.workspace = true thiserror.workspace = true @@ -23,7 +23,7 @@ rstest.workspace = true default = [] # legacy AnnotationPacket format, s.t. legacy encrypted image format relies on `kbs` feature -kbs = ["kms/kbs", "resource_uri"] +kbs = ["kms/kbs"] aliyun = ["kms/aliyun"] sev = ["kms/sev"] ehsm = ["kms/ehsm"] diff --git a/confidential-data-hub/image/src/annotation_packet/mod.rs b/confidential-data-hub/image/src/annotation_packet/mod.rs index de5317ad1..82d28383b 100644 --- a/confidential-data-hub/image/src/annotation_packet/mod.rs +++ b/confidential-data-hub/image/src/annotation_packet/mod.rs @@ -3,7 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 // -#[cfg(feature = "kbs")] pub mod v1; pub mod v2; diff --git a/confidential-data-hub/image/src/annotation_packet/v1.rs b/confidential-data-hub/image/src/annotation_packet/v1.rs index 69bbecd13..f79f0702b 100644 --- a/confidential-data-hub/image/src/annotation_packet/v1.rs +++ b/confidential-data-hub/image/src/annotation_packet/v1.rs @@ -3,14 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 // -use base64::{engine::general_purpose::STANDARD, Engine}; -use crypto::WrapType; -use kms::{plugins::VaultProvider, Annotations, ProviderSettings}; -use serde::{Deserialize, Serialize}; - use resource_uri::ResourceUri; - -use crate::{Error, Result}; +use serde::{Deserialize, Serialize}; /// `AnnotationPacket` is what a encrypted image layer's /// `org.opencontainers.image.enc.keys.provider.attestation-agent` @@ -30,7 +24,13 @@ pub struct AnnotationPacket { } impl AnnotationPacket { - pub(crate) async fn unwrap_key(&self) -> Result> { + pub(crate) async fn unwrap_key(&self) -> crate::Result> { + use base64::{engine::general_purpose::STANDARD, Engine}; + use crypto::WrapType; + use kms::{plugins::VaultProvider, Annotations, ProviderSettings}; + + use crate::Error; + let wrap_type = WrapType::try_from(&self.wrap_type[..]) .map_err(|e| Error::UnwrapAnnotationV1Failed(format!("parse WrapType failed: {e}")))?; let mut kbs_client = diff --git a/confidential-data-hub/image/src/annotation_packet/v2.rs b/confidential-data-hub/image/src/annotation_packet/v2.rs index 35e36b9d7..df10cbbe6 100644 --- a/confidential-data-hub/image/src/annotation_packet/v2.rs +++ b/confidential-data-hub/image/src/annotation_packet/v2.rs @@ -60,7 +60,6 @@ fn default_provider() -> String { VaultProvider::Kbs.as_ref().to_string() } -#[cfg(feature = "kbs")] impl TryInto for AnnotationPacketV2 { type Error = Error; @@ -107,7 +106,6 @@ impl TryInto for AnnotationPacketV2 { impl AnnotationPacketV2 { pub async fn unwrap_key(&self) -> Result> { let lek = match &self.provider[..] { - #[cfg(feature = "kbs")] "kbs" => { let anno_v1: super::v1::AnnotationPacket = self.clone().try_into()?; anno_v1.unwrap_key().await? diff --git a/confidential-data-hub/kms/src/plugins/mod.rs b/confidential-data-hub/kms/src/plugins/mod.rs index a014433e1..db7e590b6 100644 --- a/confidential-data-hub/kms/src/plugins/mod.rs +++ b/confidential-data-hub/kms/src/plugins/mod.rs @@ -50,7 +50,6 @@ pub async fn new_decryptor( #[derive(AsRefStr, EnumString)] pub enum VaultProvider { - #[cfg(feature = "kbs")] #[strum(ascii_case_insensitive)] Kbs, } From b480263b47ee0ab7d145dc1aa7dbc8d53d9825ea Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Thu, 4 Jan 2024 11:13:43 +0800 Subject: [PATCH 11/18] ci: delete duplicated ocicrypt-rs test cases Signed-off-by: Xynnn007 --- .github/workflows/ocicrypt_rs_build.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/ocicrypt_rs_build.yml b/.github/workflows/ocicrypt_rs_build.yml index 04aa956bf..a97490153 100644 --- a/.github/workflows/ocicrypt_rs_build.yml +++ b/.github/workflows/ocicrypt_rs_build.yml @@ -146,18 +146,6 @@ jobs: command: test args: -p ocicrypt-rs --no-default-features --features=keywrap-keyprovider-native - - name: Run cargo test - default - uses: actions-rs/cargo@v1 - with: - command: test - args: -p ocicrypt-rs --no-default-features - - - name: Run cargo test - all features - uses: actions-rs/cargo@v1 - with: - command: test - args: -p ocicrypt-rs --no-default-features --all-features - - name: Run cargo fmt check uses: actions-rs/cargo@v1 with: From 975ed3e2fdd5e3c102cdfd6dff4fef43bcd7da6e Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Thu, 4 Jan 2024 16:00:57 +0800 Subject: [PATCH 12/18] CDH: add log for launch and requests add logs for every request. Also deletes previous ttrpc socket file every time the CDH launches. Also, create the parent directory tree when given a unix socket path. Signed-off-by: Xynnn007 --- Cargo.lock | 1 + confidential-data-hub/hub/Cargo.toml | 3 +- .../hub/src/bin/confidential-data-hub/main.rs | 39 +++++++++++++++---- confidential-data-hub/hub/src/hub.rs | 5 +++ .../kms/src/plugins/kbs/mod.rs | 2 + 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 70ec80980..871faa174 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -944,6 +944,7 @@ dependencies = [ "async-trait", "base64 0.21.5", "clap 4.2.7", + "env_logger 0.10.1", "image", "kms", "lazy_static", diff --git a/confidential-data-hub/hub/Cargo.toml b/confidential-data-hub/hub/Cargo.toml index 923b675fa..df89c9820 100644 --- a/confidential-data-hub/hub/Cargo.toml +++ b/confidential-data-hub/hub/Cargo.toml @@ -15,6 +15,7 @@ anyhow = { workspace = true, optional = true } async-trait.workspace = true base64.workspace = true clap = { workspace = true, features = [ "derive" ], optional = true } +env_logger = { workspace = true, optional = true } image = { path = "../image", default-features = false } kms = { path = "../kms", default-features = false } lazy_static.workspace = true @@ -47,4 +48,4 @@ sev = ["image/sev", "kms/sev", "dep:sev", "secret/sev"] # support eHSM stacks (KMS, ...) ehsm = ["image/ehsm", "secret/ehsm"] -bin = ["anyhow", "clap", "protobuf", "serde", "tokio/signal", "ttrpc", "ttrpc-codegen"] +bin = ["anyhow", "clap", "env_logger", "protobuf", "serde", "tokio/signal", "ttrpc", "ttrpc-codegen"] diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs index 6455b98b1..3601c8769 100644 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs @@ -5,7 +5,7 @@ use std::{path::Path, sync::Arc}; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use api_ttrpc::{ create_get_resource_service, create_key_provider_service, create_sealed_secret_service, create_secure_mount_service, @@ -23,9 +23,10 @@ mod api; mod api_ttrpc; mod server; -const DEFAULT_UNIX_SOCKET_DIR: &str = "/run/confidential-containers"; const DEFAULT_CDH_SOCKET_ADDR: &str = "unix:///run/confidential-containers/cdh.sock"; +const UNIX_SOCKET_PREFIX: &str = "unix://"; + #[derive(Debug, Parser)] #[command(author, version, about, long_about = None)] struct Cli { @@ -48,13 +49,16 @@ macro_rules! ttrpc_service { #[tokio::main] async fn main() -> Result<()> { + env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); let cli = Cli::parse(); - if !Path::new(DEFAULT_UNIX_SOCKET_DIR).exists() { - fs::create_dir_all(DEFAULT_UNIX_SOCKET_DIR) - .await - .context("create unix socket dir failed")?; - } + let unix_socket_path = cli + .socket + .strip_prefix(UNIX_SOCKET_PREFIX) + .ok_or_else(|| anyhow!("socket address scheme is not expected"))?; + + create_socket_parent_directory(unix_socket_path).await?; + clean_previous_sock_file(unix_socket_path).await?; let sealed_secret_service = ttrpc_service!(create_sealed_secret_service); let get_resource_service = ttrpc_service!(create_get_resource_service); @@ -68,6 +72,10 @@ async fn main() -> Result<()> { .register_service(secure_mount_service) .register_service(key_provider_service); + info!( + "Confidential Data Hub starts to listen to request: {}", + cli.socket + ); server.start().await?; let mut interrupt = signal(SignalKind::interrupt())?; @@ -85,3 +93,20 @@ async fn main() -> Result<()> { Ok(()) } + +async fn clean_previous_sock_file(unix_socket_file: &str) -> Result<()> { + if Path::new(unix_socket_file).exists() { + fs::remove_file(unix_socket_file).await?; + } + + Ok(()) +} + +async fn create_socket_parent_directory(unix_socket_file: &str) -> Result<()> { + let file_path = Path::new(unix_socket_file); + let parent_directory = file_path + .parent() + .ok_or(anyhow!("The file path does not have a parent directory."))?; + fs::create_dir_all(parent_directory).await?; + Ok(()) +} diff --git a/confidential-data-hub/hub/src/hub.rs b/confidential-data-hub/hub/src/hub.rs index a6e95f2d1..f9fb6fe83 100644 --- a/confidential-data-hub/hub/src/hub.rs +++ b/confidential-data-hub/hub/src/hub.rs @@ -7,6 +7,7 @@ use async_trait::async_trait; use base64::{engine::general_purpose::STANDARD, Engine}; use image::AnnotationPacket; use kms::{Annotations, ProviderSettings}; +use log::info; use secret::secret::Secret; use storage::volume_type::Storage; @@ -26,6 +27,7 @@ impl Hub { #[async_trait] impl DataHub for Hub { async fn unseal_secret(&self, secret: Vec) -> Result> { + info!("unseal secret called"); // TODO: verify the jws signature using the key specified by `kid` // in header. Here we directly get the JWS payload let payload = secret @@ -52,6 +54,7 @@ impl DataHub for Hub { } async fn unwrap_key(&self, annotation_packet: &[u8]) -> Result> { + info!("unwrap key called"); let annotation_packet: AnnotationPacket = serde_json::from_slice(annotation_packet) .map_err(|e| Error::ImageDecryption(format!("illegal AnnotationPacket format: {e}")))?; let lek = annotation_packet @@ -62,6 +65,7 @@ impl DataHub for Hub { } async fn get_resource(&self, uri: String) -> Result> { + info!("get resource called: {uri}"); // to initialize a get_resource_provider client we do not need the ProviderSettings. let mut client = kms::new_getter("kbs", ProviderSettings::default()) .await @@ -76,6 +80,7 @@ impl DataHub for Hub { } async fn secure_mount(&self, storage: Storage) -> Result { + info!("secure mount called"); let res = storage .mount() .await diff --git a/confidential-data-hub/kms/src/plugins/kbs/mod.rs b/confidential-data-hub/kms/src/plugins/kbs/mod.rs index f25577866..ac113c522 100644 --- a/confidential-data-hub/kms/src/plugins/kbs/mod.rs +++ b/confidential-data-hub/kms/src/plugins/kbs/mod.rs @@ -119,6 +119,7 @@ impl KbcClient { async fn get_aa_params_from_cmdline() -> Result<(String, String)> { use tokio::fs; + debug!("get aa_kbc_params from kernel cmdline"); let cmdline = fs::read_to_string("/proc/cmdline") .await .map_err(|e| Error::KbsClientError(format!("read kernel cmdline failed: {e}")))?; @@ -143,6 +144,7 @@ async fn get_aa_params_from_cmdline() -> Result<(String, String)> { } async fn get_aa_params_from_config_file() -> Result<(String, String)> { + debug!("get aa_kbc_params from file"); // We only care about the aa_kbc_params value at the moment #[derive(Debug, Deserialize)] struct AgentConfig { From 4996583374345b04a578240867ca664de64649fc Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Thu, 4 Jan 2024 16:03:34 +0800 Subject: [PATCH 13/18] CDH: update ttrpc generated files Signed-off-by: Xynnn007 --- .../hub/src/bin/confidential-data-hub/api.rs | 20 +++++++++---------- .../bin/confidential-data-hub/api_ttrpc.rs | 8 +++----- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs index 302ac804e..81dcf8923 100644 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs @@ -1,4 +1,4 @@ -// This file is generated by rust-protobuf 3.2.0. Do not edit +// This file is generated by rust-protobuf 3.3.0. Do not edit // .proto file is parsed by pure // @generated @@ -23,10 +23,10 @@ /// Generated files are compatible only with the same version /// of protobuf runtime. -const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_2_0; +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_3_0; -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:api.UnsealSecretInput) +#[derive(PartialEq,Clone,Default,Debug)] pub struct UnsealSecretInput { // message fields // @@protoc_insertion_point(field:api.UnsealSecretInput.secret) @@ -147,8 +147,8 @@ impl ::protobuf::reflect::ProtobufValue for UnsealSecretInput { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:api.UnsealSecretOutput) +#[derive(PartialEq,Clone,Default,Debug)] pub struct UnsealSecretOutput { // message fields // @@protoc_insertion_point(field:api.UnsealSecretOutput.plaintext) @@ -269,8 +269,8 @@ impl ::protobuf::reflect::ProtobufValue for UnsealSecretOutput { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:api.GetResourceRequest) +#[derive(PartialEq,Clone,Default,Debug)] pub struct GetResourceRequest { // message fields // @@protoc_insertion_point(field:api.GetResourceRequest.ResourcePath) @@ -391,8 +391,8 @@ impl ::protobuf::reflect::ProtobufValue for GetResourceRequest { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:api.GetResourceResponse) +#[derive(PartialEq,Clone,Default,Debug)] pub struct GetResourceResponse { // message fields // @@protoc_insertion_point(field:api.GetResourceResponse.Resource) @@ -513,8 +513,8 @@ impl ::protobuf::reflect::ProtobufValue for GetResourceResponse { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:api.KeyProviderKeyWrapProtocolInput) +#[derive(PartialEq,Clone,Default,Debug)] pub struct KeyProviderKeyWrapProtocolInput { // message fields // @@protoc_insertion_point(field:api.KeyProviderKeyWrapProtocolInput.KeyProviderKeyWrapProtocolInput) @@ -635,8 +635,8 @@ impl ::protobuf::reflect::ProtobufValue for KeyProviderKeyWrapProtocolInput { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:api.KeyProviderKeyWrapProtocolOutput) +#[derive(PartialEq,Clone,Default,Debug)] pub struct KeyProviderKeyWrapProtocolOutput { // message fields // @@protoc_insertion_point(field:api.KeyProviderKeyWrapProtocolOutput.KeyProviderKeyWrapProtocolOutput) @@ -757,8 +757,8 @@ impl ::protobuf::reflect::ProtobufValue for KeyProviderKeyWrapProtocolOutput { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:api.SecureMountRequest) +#[derive(PartialEq,Clone,Default,Debug)] pub struct SecureMountRequest { // message fields // @@protoc_insertion_point(field:api.SecureMountRequest.driver) @@ -969,8 +969,8 @@ impl ::protobuf::reflect::ProtobufValue for SecureMountRequest { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } -#[derive(PartialEq,Clone,Default,Debug)] // @@protoc_insertion_point(message:api.SecureMountResponse) +#[derive(PartialEq,Clone,Default,Debug)] pub struct SecureMountResponse { // message fields // @@protoc_insertion_point(field:api.SecureMountResponse.mount_path) diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs index 47b16b330..ead9dc17f 100644 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs @@ -1,12 +1,9 @@ -// This file is generated by ttrpc-compiler 0.6.1. Do not edit +// This file is generated by ttrpc-compiler 0.6.2. Do not edit // @generated -// https://github.com/Manishearth/rust-clippy/issues/702 +#![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unknown_lints)] #![allow(clipto_camel_casepy)] - -#![cfg_attr(rustfmt, rustfmt_skip)] - #![allow(box_pointers)] #![allow(dead_code)] #![allow(missing_docs)] @@ -17,6 +14,7 @@ #![allow(unsafe_code)] #![allow(unused_imports)] #![allow(unused_results)] +#![allow(clippy::all)] use protobuf::{CodedInputStream, CodedOutputStream, Message}; use std::collections::HashMap; use std::sync::Arc; From 2ec850921fa46a11f1c8b194a35905dfa5dd6de3 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Thu, 4 Jan 2024 16:04:14 +0800 Subject: [PATCH 14/18] CDH: delete default RESOURCE_PROVIDER in Makefile Before this commit, if we do not specify the RESOURCE_PROVIDER field when make, kbs and sev features will be enabled. This will prevent offline-fs-kbc from being activated. This patch requires programmers that manually provide the RESOURCE_PROVIDER parameter when executing make command. Signed-off-by: Xynnn007 --- .github/workflows/cdh_basic.yml | 4 ++-- Makefile | 15 +++++++++++++-- README.md | 7 +++++++ confidential-data-hub/Makefile | 2 -- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cdh_basic.yml b/.github/workflows/cdh_basic.yml index 1271d8f57..4cce745f5 100644 --- a/.github/workflows/cdh_basic.yml +++ b/.github/workflows/cdh_basic.yml @@ -50,11 +50,11 @@ jobs: - name: Build and install run: | - make && make install + make RESOURCE_PROVIDER=kbs,sev && make install - name: Musl build run: | - make LIBC=musl + make LIBC=musl RESOURCE_PROVIDER=kbs,sev - name: s390x build run: diff --git a/Makefile b/Makefile index 44586e391..e44ed9f1a 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,14 @@ DESTDIR ?= /usr/local/bin LIBC ?= musl KBC ?= -RESOURCE_PROVIDER ?= kbs + +NO_RESOURCE_PROVIDER ?= + +ifeq ($(NO_RESOURCE_PROVIDER), true) + RESOURCE_PROVIDER := +else + RESOURCE_PROVIDER ?= kbs +endif ifeq ($(TEE_PLATFORM), none) KBC = cc_kbc @@ -18,7 +25,11 @@ else ifeq ($(TEE_PLATFORM), az-tdx-vtpm) KBC = cc_kbc_az_tdx_vtpm else ifeq ($(TEE_PLATFORM), sev) KBC = online_sev_kbc - RESOURCE_PROVIDER = sev + ifeq ($(NO_RESOURCE_PROVIDER), true) + RESOURCE_PROVIDER := + else + RESOURCE_PROVIDER = sev + endif else ifeq ($(TEE_PLATFORM), snp) KBC = cc_kbc_snp else ifeq ($(TEE_PLATFORM), az-snp-vtpm) diff --git a/README.md b/README.md index 3f8219347..f0cbf7814 100644 --- a/README.md +++ b/README.md @@ -39,5 +39,12 @@ The `TEE_PLATFORM` parameter can be - `snp`: for AMD SEV-SNP - `az-snp-vtpm`: for AMD SEV-SNP with Azure vTPM +by default, `kbs`/`sev` as a resource provider will be built in Confidential Data Hub. If you do not want enable any +default except for only builtin `offline-fs-kbc`, you can build with `NO_RESOURCE_PROVIDER` flag set to `true`. + +```shell +make build TEE_PLATFORM=$(TEE_PLATFORM) NO_RESOURCE_PROVIDER=true +``` + ## License [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fconfidential-containers%2Fimage-rs.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fconfidential-containers%2Fimage-rs?ref=badge_large) diff --git a/confidential-data-hub/Makefile b/confidential-data-hub/Makefile index 82e331126..e0404994b 100644 --- a/confidential-data-hub/Makefile +++ b/confidential-data-hub/Makefile @@ -31,8 +31,6 @@ endif ifdef RESOURCE_PROVIDER features += $(RESOURCE_PROVIDER) -else - features += kbs,sev endif ifdef PROVIDER From fce13da8d07f84a0ba9cfb5f8a8454afaa324cb4 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Thu, 4 Jan 2024 16:57:23 +0800 Subject: [PATCH 15/18] CDH/hub: fix the KeyProvider Protobuf In protobuf, the `package` matters when a client calls to a server. In ocicrypt-rs, the proto of KeyProvider follows ocicrypt standard, where the package is `keyprovider`. We once use a common name `api` for all apis of CDH, but this does not follow the ocicrypt standard. This patch splits the ocicrypt parts into a separate proto file, whose package is `keyprovider`. Signed-off-by: Xynnn007 --- confidential-data-hub/hub/build.rs | 2 +- confidential-data-hub/hub/protos/api.proto | 12 - .../hub/protos/keyprovider.proto | 16 + .../hub/src/bin/confidential-data-hub/api.rs | 278 +--------------- .../bin/confidential-data-hub/api_ttrpc.rs | 48 --- .../bin/confidential-data-hub/keyprovider.rs | 312 ++++++++++++++++++ .../keyprovider_ttrpc.rs | 91 +++++ .../hub/src/bin/confidential-data-hub/main.rs | 6 +- .../bin/confidential-data-hub/server/mod.rs | 7 +- 9 files changed, 441 insertions(+), 331 deletions(-) create mode 100644 confidential-data-hub/hub/protos/keyprovider.proto create mode 100644 confidential-data-hub/hub/src/bin/confidential-data-hub/keyprovider.rs create mode 100644 confidential-data-hub/hub/src/bin/confidential-data-hub/keyprovider_ttrpc.rs diff --git a/confidential-data-hub/hub/build.rs b/confidential-data-hub/hub/build.rs index df09da21c..aa8b656d3 100644 --- a/confidential-data-hub/hub/build.rs +++ b/confidential-data-hub/hub/build.rs @@ -26,7 +26,7 @@ fn main() { Codegen::new() .out_dir("src/bin/confidential-data-hub") - .inputs(["./protos/api.proto"]) + .inputs(["./protos/api.proto", "./protos/keyprovider.proto"]) .include("./protos") .rust_protobuf() .customize(Customize { diff --git a/confidential-data-hub/hub/protos/api.proto b/confidential-data-hub/hub/protos/api.proto index 8a8ddaf26..97a98660b 100644 --- a/confidential-data-hub/hub/protos/api.proto +++ b/confidential-data-hub/hub/protos/api.proto @@ -18,14 +18,6 @@ message GetResourceResponse { bytes Resource = 1; } -message KeyProviderKeyWrapProtocolInput { - bytes KeyProviderKeyWrapProtocolInput = 1; -} - -message KeyProviderKeyWrapProtocolOutput { - bytes KeyProviderKeyWrapProtocolOutput = 1; -} - message SecureMountRequest { string driver = 1; repeated string driver_options = 2; @@ -47,10 +39,6 @@ service GetResourceService { rpc GetResource(GetResourceRequest) returns (GetResourceResponse) {}; } -service KeyProviderService { - rpc UnWrapKey(KeyProviderKeyWrapProtocolInput) returns (KeyProviderKeyWrapProtocolOutput) {}; -} - service SecureMountService { rpc SecureMount(SecureMountRequest) returns (SecureMountResponse) {}; } diff --git a/confidential-data-hub/hub/protos/keyprovider.proto b/confidential-data-hub/hub/protos/keyprovider.proto new file mode 100644 index 000000000..e8f8f93c1 --- /dev/null +++ b/confidential-data-hub/hub/protos/keyprovider.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package keyprovider; + +message KeyProviderKeyWrapProtocolInput { + bytes KeyProviderKeyWrapProtocolInput = 1; +} + +message KeyProviderKeyWrapProtocolOutput { + bytes KeyProviderKeyWrapProtocolOutput = 1; +} + +service KeyProviderService { + rpc WrapKey(KeyProviderKeyWrapProtocolInput) returns (KeyProviderKeyWrapProtocolOutput) {}; + rpc UnWrapKey(KeyProviderKeyWrapProtocolInput) returns (KeyProviderKeyWrapProtocolOutput) {}; +} diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs index 81dcf8923..cf9934cca 100644 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs @@ -513,250 +513,6 @@ impl ::protobuf::reflect::ProtobufValue for GetResourceResponse { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } -// @@protoc_insertion_point(message:api.KeyProviderKeyWrapProtocolInput) -#[derive(PartialEq,Clone,Default,Debug)] -pub struct KeyProviderKeyWrapProtocolInput { - // message fields - // @@protoc_insertion_point(field:api.KeyProviderKeyWrapProtocolInput.KeyProviderKeyWrapProtocolInput) - pub KeyProviderKeyWrapProtocolInput: ::std::vec::Vec, - // special fields - // @@protoc_insertion_point(special_field:api.KeyProviderKeyWrapProtocolInput.special_fields) - pub special_fields: ::protobuf::SpecialFields, -} - -impl<'a> ::std::default::Default for &'a KeyProviderKeyWrapProtocolInput { - fn default() -> &'a KeyProviderKeyWrapProtocolInput { - ::default_instance() - } -} - -impl KeyProviderKeyWrapProtocolInput { - pub fn new() -> KeyProviderKeyWrapProtocolInput { - ::std::default::Default::default() - } - - fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { - let mut fields = ::std::vec::Vec::with_capacity(1); - let mut oneofs = ::std::vec::Vec::with_capacity(0); - fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( - "KeyProviderKeyWrapProtocolInput", - |m: &KeyProviderKeyWrapProtocolInput| { &m.KeyProviderKeyWrapProtocolInput }, - |m: &mut KeyProviderKeyWrapProtocolInput| { &mut m.KeyProviderKeyWrapProtocolInput }, - )); - ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( - "KeyProviderKeyWrapProtocolInput", - fields, - oneofs, - ) - } -} - -impl ::protobuf::Message for KeyProviderKeyWrapProtocolInput { - const NAME: &'static str = "KeyProviderKeyWrapProtocolInput"; - - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { - while let Some(tag) = is.read_raw_tag_or_eof()? { - match tag { - 10 => { - self.KeyProviderKeyWrapProtocolInput = is.read_bytes()?; - }, - tag => { - ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u64 { - let mut my_size = 0; - if !self.KeyProviderKeyWrapProtocolInput.is_empty() { - my_size += ::protobuf::rt::bytes_size(1, &self.KeyProviderKeyWrapProtocolInput); - } - my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); - self.special_fields.cached_size().set(my_size as u32); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { - if !self.KeyProviderKeyWrapProtocolInput.is_empty() { - os.write_bytes(1, &self.KeyProviderKeyWrapProtocolInput)?; - } - os.write_unknown_fields(self.special_fields.unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn special_fields(&self) -> &::protobuf::SpecialFields { - &self.special_fields - } - - fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { - &mut self.special_fields - } - - fn new() -> KeyProviderKeyWrapProtocolInput { - KeyProviderKeyWrapProtocolInput::new() - } - - fn clear(&mut self) { - self.KeyProviderKeyWrapProtocolInput.clear(); - self.special_fields.clear(); - } - - fn default_instance() -> &'static KeyProviderKeyWrapProtocolInput { - static instance: KeyProviderKeyWrapProtocolInput = KeyProviderKeyWrapProtocolInput { - KeyProviderKeyWrapProtocolInput: ::std::vec::Vec::new(), - special_fields: ::protobuf::SpecialFields::new(), - }; - &instance - } -} - -impl ::protobuf::MessageFull for KeyProviderKeyWrapProtocolInput { - fn descriptor() -> ::protobuf::reflect::MessageDescriptor { - static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); - descriptor.get(|| file_descriptor().message_by_package_relative_name("KeyProviderKeyWrapProtocolInput").unwrap()).clone() - } -} - -impl ::std::fmt::Display for KeyProviderKeyWrapProtocolInput { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for KeyProviderKeyWrapProtocolInput { - type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; -} - -// @@protoc_insertion_point(message:api.KeyProviderKeyWrapProtocolOutput) -#[derive(PartialEq,Clone,Default,Debug)] -pub struct KeyProviderKeyWrapProtocolOutput { - // message fields - // @@protoc_insertion_point(field:api.KeyProviderKeyWrapProtocolOutput.KeyProviderKeyWrapProtocolOutput) - pub KeyProviderKeyWrapProtocolOutput: ::std::vec::Vec, - // special fields - // @@protoc_insertion_point(special_field:api.KeyProviderKeyWrapProtocolOutput.special_fields) - pub special_fields: ::protobuf::SpecialFields, -} - -impl<'a> ::std::default::Default for &'a KeyProviderKeyWrapProtocolOutput { - fn default() -> &'a KeyProviderKeyWrapProtocolOutput { - ::default_instance() - } -} - -impl KeyProviderKeyWrapProtocolOutput { - pub fn new() -> KeyProviderKeyWrapProtocolOutput { - ::std::default::Default::default() - } - - fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { - let mut fields = ::std::vec::Vec::with_capacity(1); - let mut oneofs = ::std::vec::Vec::with_capacity(0); - fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( - "KeyProviderKeyWrapProtocolOutput", - |m: &KeyProviderKeyWrapProtocolOutput| { &m.KeyProviderKeyWrapProtocolOutput }, - |m: &mut KeyProviderKeyWrapProtocolOutput| { &mut m.KeyProviderKeyWrapProtocolOutput }, - )); - ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( - "KeyProviderKeyWrapProtocolOutput", - fields, - oneofs, - ) - } -} - -impl ::protobuf::Message for KeyProviderKeyWrapProtocolOutput { - const NAME: &'static str = "KeyProviderKeyWrapProtocolOutput"; - - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { - while let Some(tag) = is.read_raw_tag_or_eof()? { - match tag { - 10 => { - self.KeyProviderKeyWrapProtocolOutput = is.read_bytes()?; - }, - tag => { - ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u64 { - let mut my_size = 0; - if !self.KeyProviderKeyWrapProtocolOutput.is_empty() { - my_size += ::protobuf::rt::bytes_size(1, &self.KeyProviderKeyWrapProtocolOutput); - } - my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); - self.special_fields.cached_size().set(my_size as u32); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { - if !self.KeyProviderKeyWrapProtocolOutput.is_empty() { - os.write_bytes(1, &self.KeyProviderKeyWrapProtocolOutput)?; - } - os.write_unknown_fields(self.special_fields.unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn special_fields(&self) -> &::protobuf::SpecialFields { - &self.special_fields - } - - fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { - &mut self.special_fields - } - - fn new() -> KeyProviderKeyWrapProtocolOutput { - KeyProviderKeyWrapProtocolOutput::new() - } - - fn clear(&mut self) { - self.KeyProviderKeyWrapProtocolOutput.clear(); - self.special_fields.clear(); - } - - fn default_instance() -> &'static KeyProviderKeyWrapProtocolOutput { - static instance: KeyProviderKeyWrapProtocolOutput = KeyProviderKeyWrapProtocolOutput { - KeyProviderKeyWrapProtocolOutput: ::std::vec::Vec::new(), - special_fields: ::protobuf::SpecialFields::new(), - }; - &instance - } -} - -impl ::protobuf::MessageFull for KeyProviderKeyWrapProtocolOutput { - fn descriptor() -> ::protobuf::reflect::MessageDescriptor { - static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); - descriptor.get(|| file_descriptor().message_by_package_relative_name("KeyProviderKeyWrapProtocolOutput").unwrap()).clone() - } -} - -impl ::std::fmt::Display for KeyProviderKeyWrapProtocolOutput { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for KeyProviderKeyWrapProtocolOutput { - type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; -} - // @@protoc_insertion_point(message:api.SecureMountRequest) #[derive(PartialEq,Clone,Default,Debug)] pub struct SecureMountRequest { @@ -1096,24 +852,18 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x18\x01\x20\x01(\x0cR\x06secret\"2\n\x12UnsealSecretOutput\x12\x1c\n\tp\ laintext\x18\x01\x20\x01(\x0cR\tplaintext\"8\n\x12GetResourceRequest\x12\ \"\n\x0cResourcePath\x18\x01\x20\x01(\tR\x0cResourcePath\"1\n\x13GetReso\ - urceResponse\x12\x1a\n\x08Resource\x18\x01\x20\x01(\x0cR\x08Resource\"k\ - \n\x1fKeyProviderKeyWrapProtocolInput\x12H\n\x1fKeyProviderKeyWrapProtoc\ - olInput\x18\x01\x20\x01(\x0cR\x1fKeyProviderKeyWrapProtocolInput\"n\n\ - \x20KeyProviderKeyWrapProtocolOutput\x12J\n\x20KeyProviderKeyWrapProtoco\ - lOutput\x18\x01\x20\x01(\x0cR\x20KeyProviderKeyWrapProtocolOutput\"\xbe\ - \x01\n\x12SecureMountRequest\x12\x16\n\x06driver\x18\x01\x20\x01(\tR\x06\ - driver\x12%\n\x0edriver_options\x18\x02\x20\x03(\tR\rdriverOptions\x12\ - \x16\n\x06source\x18\x03\x20\x01(\tR\x06source\x12\x16\n\x06fstype\x18\ - \x04\x20\x01(\tR\x06fstype\x12\x18\n\x07options\x18\x05\x20\x03(\tR\x07o\ - ptions\x12\x1f\n\x0bmount_point\x18\x06\x20\x01(\tR\nmountPoint\"4\n\x13\ - SecureMountResponse\x12\x1d\n\nmount_path\x18\x01\x20\x01(\tR\tmountPath\ - 2V\n\x13SealedSecretService\x12?\n\x0cUnsealSecret\x12\x16.api.UnsealSec\ - retInput\x1a\x17.api.UnsealSecretOutput2V\n\x12GetResourceService\x12@\n\ - \x0bGetResource\x12\x17.api.GetResourceRequest\x1a\x18.api.GetResourceRe\ - sponse2n\n\x12KeyProviderService\x12X\n\tUnWrapKey\x12$.api.KeyProviderK\ - eyWrapProtocolInput\x1a%.api.KeyProviderKeyWrapProtocolOutput2V\n\x12Sec\ - ureMountService\x12@\n\x0bSecureMount\x12\x17.api.SecureMountRequest\x1a\ - \x18.api.SecureMountResponseb\x06proto3\ + urceResponse\x12\x1a\n\x08Resource\x18\x01\x20\x01(\x0cR\x08Resource\"\ + \xbe\x01\n\x12SecureMountRequest\x12\x16\n\x06driver\x18\x01\x20\x01(\tR\ + \x06driver\x12%\n\x0edriver_options\x18\x02\x20\x03(\tR\rdriverOptions\ + \x12\x16\n\x06source\x18\x03\x20\x01(\tR\x06source\x12\x16\n\x06fstype\ + \x18\x04\x20\x01(\tR\x06fstype\x12\x18\n\x07options\x18\x05\x20\x03(\tR\ + \x07options\x12\x1f\n\x0bmount_point\x18\x06\x20\x01(\tR\nmountPoint\"4\ + \n\x13SecureMountResponse\x12\x1d\n\nmount_path\x18\x01\x20\x01(\tR\tmou\ + ntPath2V\n\x13SealedSecretService\x12?\n\x0cUnsealSecret\x12\x16.api.Uns\ + ealSecretInput\x1a\x17.api.UnsealSecretOutput2V\n\x12GetResourceService\ + \x12@\n\x0bGetResource\x12\x17.api.GetResourceRequest\x1a\x18.api.GetRes\ + ourceResponse2V\n\x12SecureMountService\x12@\n\x0bSecureMount\x12\x17.ap\ + i.SecureMountRequest\x1a\x18.api.SecureMountResponseb\x06proto3\ "; /// `FileDescriptorProto` object which was a source for this generated file @@ -1131,13 +881,11 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor { file_descriptor.get(|| { let generated_file_descriptor = generated_file_descriptor_lazy.get(|| { let mut deps = ::std::vec::Vec::with_capacity(0); - let mut messages = ::std::vec::Vec::with_capacity(8); + let mut messages = ::std::vec::Vec::with_capacity(6); messages.push(UnsealSecretInput::generated_message_descriptor_data()); messages.push(UnsealSecretOutput::generated_message_descriptor_data()); messages.push(GetResourceRequest::generated_message_descriptor_data()); messages.push(GetResourceResponse::generated_message_descriptor_data()); - messages.push(KeyProviderKeyWrapProtocolInput::generated_message_descriptor_data()); - messages.push(KeyProviderKeyWrapProtocolOutput::generated_message_descriptor_data()); messages.push(SecureMountRequest::generated_message_descriptor_data()); messages.push(SecureMountResponse::generated_message_descriptor_data()); let mut enums = ::std::vec::Vec::with_capacity(0); diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs index ead9dc17f..971ce04e5 100644 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs @@ -116,54 +116,6 @@ pub fn create_get_resource_service(service: Arc Self { - KeyProviderServiceClient { - client, - } - } - - pub async fn un_wrap_key(&self, ctx: ttrpc::context::Context, req: &super::api::KeyProviderKeyWrapProtocolInput) -> ::ttrpc::Result { - let mut cres = super::api::KeyProviderKeyWrapProtocolOutput::new(); - ::ttrpc::async_client_request!(self, ctx, req, "api.KeyProviderService", "UnWrapKey", cres); - } -} - -struct UnWrapKeyMethod { - service: Arc>, -} - -#[async_trait] -impl ::ttrpc::r#async::MethodHandler for UnWrapKeyMethod { - async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { - ::ttrpc::async_request_handler!(self, ctx, req, api, KeyProviderKeyWrapProtocolInput, un_wrap_key); - } -} - -#[async_trait] -pub trait KeyProviderService: Sync { - async fn un_wrap_key(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::api::KeyProviderKeyWrapProtocolInput) -> ::ttrpc::Result { - Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/api.KeyProviderService/UnWrapKey is not supported".to_string()))) - } -} - -pub fn create_key_provider_service(service: Arc>) -> HashMap { - let mut ret = HashMap::new(); - let mut methods = HashMap::new(); - let streams = HashMap::new(); - - methods.insert("UnWrapKey".to_string(), - Box::new(UnWrapKeyMethod{service: service.clone()}) as Box); - - ret.insert("api.KeyProviderService".to_string(), ::ttrpc::r#async::Service{ methods, streams }); - ret -} - #[derive(Clone)] pub struct SecureMountServiceClient { client: ::ttrpc::r#async::Client, diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/keyprovider.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/keyprovider.rs new file mode 100644 index 000000000..3c34f64fa --- /dev/null +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/keyprovider.rs @@ -0,0 +1,312 @@ +// This file is generated by rust-protobuf 3.3.0. Do not edit +// .proto file is parsed by pure +// @generated + +// https://github.com/rust-lang/rust-clippy/issues/702 +#![allow(unknown_lints)] +#![allow(clippy::all)] + +#![allow(unused_attributes)] +#![cfg_attr(rustfmt, rustfmt::skip)] + +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unused_results)] +#![allow(unused_mut)] + +//! Generated file from `keyprovider.proto` + +/// Generated files are compatible only with the same version +/// of protobuf runtime. +const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_3_0; + +// @@protoc_insertion_point(message:keyprovider.KeyProviderKeyWrapProtocolInput) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct KeyProviderKeyWrapProtocolInput { + // message fields + // @@protoc_insertion_point(field:keyprovider.KeyProviderKeyWrapProtocolInput.KeyProviderKeyWrapProtocolInput) + pub KeyProviderKeyWrapProtocolInput: ::std::vec::Vec, + // special fields + // @@protoc_insertion_point(special_field:keyprovider.KeyProviderKeyWrapProtocolInput.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a KeyProviderKeyWrapProtocolInput { + fn default() -> &'a KeyProviderKeyWrapProtocolInput { + ::default_instance() + } +} + +impl KeyProviderKeyWrapProtocolInput { + pub fn new() -> KeyProviderKeyWrapProtocolInput { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "KeyProviderKeyWrapProtocolInput", + |m: &KeyProviderKeyWrapProtocolInput| { &m.KeyProviderKeyWrapProtocolInput }, + |m: &mut KeyProviderKeyWrapProtocolInput| { &mut m.KeyProviderKeyWrapProtocolInput }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "KeyProviderKeyWrapProtocolInput", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for KeyProviderKeyWrapProtocolInput { + const NAME: &'static str = "KeyProviderKeyWrapProtocolInput"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + self.KeyProviderKeyWrapProtocolInput = is.read_bytes()?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if !self.KeyProviderKeyWrapProtocolInput.is_empty() { + my_size += ::protobuf::rt::bytes_size(1, &self.KeyProviderKeyWrapProtocolInput); + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if !self.KeyProviderKeyWrapProtocolInput.is_empty() { + os.write_bytes(1, &self.KeyProviderKeyWrapProtocolInput)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> KeyProviderKeyWrapProtocolInput { + KeyProviderKeyWrapProtocolInput::new() + } + + fn clear(&mut self) { + self.KeyProviderKeyWrapProtocolInput.clear(); + self.special_fields.clear(); + } + + fn default_instance() -> &'static KeyProviderKeyWrapProtocolInput { + static instance: KeyProviderKeyWrapProtocolInput = KeyProviderKeyWrapProtocolInput { + KeyProviderKeyWrapProtocolInput: ::std::vec::Vec::new(), + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for KeyProviderKeyWrapProtocolInput { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("KeyProviderKeyWrapProtocolInput").unwrap()).clone() + } +} + +impl ::std::fmt::Display for KeyProviderKeyWrapProtocolInput { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for KeyProviderKeyWrapProtocolInput { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +// @@protoc_insertion_point(message:keyprovider.KeyProviderKeyWrapProtocolOutput) +#[derive(PartialEq,Clone,Default,Debug)] +pub struct KeyProviderKeyWrapProtocolOutput { + // message fields + // @@protoc_insertion_point(field:keyprovider.KeyProviderKeyWrapProtocolOutput.KeyProviderKeyWrapProtocolOutput) + pub KeyProviderKeyWrapProtocolOutput: ::std::vec::Vec, + // special fields + // @@protoc_insertion_point(special_field:keyprovider.KeyProviderKeyWrapProtocolOutput.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a KeyProviderKeyWrapProtocolOutput { + fn default() -> &'a KeyProviderKeyWrapProtocolOutput { + ::default_instance() + } +} + +impl KeyProviderKeyWrapProtocolOutput { + pub fn new() -> KeyProviderKeyWrapProtocolOutput { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "KeyProviderKeyWrapProtocolOutput", + |m: &KeyProviderKeyWrapProtocolOutput| { &m.KeyProviderKeyWrapProtocolOutput }, + |m: &mut KeyProviderKeyWrapProtocolOutput| { &mut m.KeyProviderKeyWrapProtocolOutput }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "KeyProviderKeyWrapProtocolOutput", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for KeyProviderKeyWrapProtocolOutput { + const NAME: &'static str = "KeyProviderKeyWrapProtocolOutput"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + self.KeyProviderKeyWrapProtocolOutput = is.read_bytes()?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if !self.KeyProviderKeyWrapProtocolOutput.is_empty() { + my_size += ::protobuf::rt::bytes_size(1, &self.KeyProviderKeyWrapProtocolOutput); + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if !self.KeyProviderKeyWrapProtocolOutput.is_empty() { + os.write_bytes(1, &self.KeyProviderKeyWrapProtocolOutput)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> KeyProviderKeyWrapProtocolOutput { + KeyProviderKeyWrapProtocolOutput::new() + } + + fn clear(&mut self) { + self.KeyProviderKeyWrapProtocolOutput.clear(); + self.special_fields.clear(); + } + + fn default_instance() -> &'static KeyProviderKeyWrapProtocolOutput { + static instance: KeyProviderKeyWrapProtocolOutput = KeyProviderKeyWrapProtocolOutput { + KeyProviderKeyWrapProtocolOutput: ::std::vec::Vec::new(), + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for KeyProviderKeyWrapProtocolOutput { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("KeyProviderKeyWrapProtocolOutput").unwrap()).clone() + } +} + +impl ::std::fmt::Display for KeyProviderKeyWrapProtocolOutput { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for KeyProviderKeyWrapProtocolOutput { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +static file_descriptor_proto_data: &'static [u8] = b"\ + \n\x11keyprovider.proto\x12\x0bkeyprovider\"k\n\x1fKeyProviderKeyWrapPro\ + tocolInput\x12H\n\x1fKeyProviderKeyWrapProtocolInput\x18\x01\x20\x01(\ + \x0cR\x1fKeyProviderKeyWrapProtocolInput\"n\n\x20KeyProviderKeyWrapProto\ + colOutput\x12J\n\x20KeyProviderKeyWrapProtocolOutput\x18\x01\x20\x01(\ + \x0cR\x20KeyProviderKeyWrapProtocolOutput2\xe6\x01\n\x12KeyProviderServi\ + ce\x12f\n\x07WrapKey\x12,.keyprovider.KeyProviderKeyWrapProtocolInput\ + \x1a-.keyprovider.KeyProviderKeyWrapProtocolOutput\x12h\n\tUnWrapKey\x12\ + ,.keyprovider.KeyProviderKeyWrapProtocolInput\x1a-.keyprovider.KeyProvid\ + erKeyWrapProtocolOutputb\x06proto3\ +"; + +/// `FileDescriptorProto` object which was a source for this generated file +fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { + static file_descriptor_proto_lazy: ::protobuf::rt::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::Lazy::new(); + file_descriptor_proto_lazy.get(|| { + ::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() + }) +} + +/// `FileDescriptor` object which allows dynamic access to files +pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor { + static generated_file_descriptor_lazy: ::protobuf::rt::Lazy<::protobuf::reflect::GeneratedFileDescriptor> = ::protobuf::rt::Lazy::new(); + static file_descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::FileDescriptor> = ::protobuf::rt::Lazy::new(); + file_descriptor.get(|| { + let generated_file_descriptor = generated_file_descriptor_lazy.get(|| { + let mut deps = ::std::vec::Vec::with_capacity(0); + let mut messages = ::std::vec::Vec::with_capacity(2); + messages.push(KeyProviderKeyWrapProtocolInput::generated_message_descriptor_data()); + messages.push(KeyProviderKeyWrapProtocolOutput::generated_message_descriptor_data()); + let mut enums = ::std::vec::Vec::with_capacity(0); + ::protobuf::reflect::GeneratedFileDescriptor::new_generated( + file_descriptor_proto(), + deps, + messages, + enums, + ) + }); + ::protobuf::reflect::FileDescriptor::new_generated_2(generated_file_descriptor) + }) +} diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/keyprovider_ttrpc.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/keyprovider_ttrpc.rs new file mode 100644 index 000000000..52b823b60 --- /dev/null +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/keyprovider_ttrpc.rs @@ -0,0 +1,91 @@ +// This file is generated by ttrpc-compiler 0.6.2. Do not edit +// @generated + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unknown_lints)] +#![allow(clipto_camel_casepy)] +#![allow(box_pointers)] +#![allow(dead_code)] +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] +#![allow(trivial_casts)] +#![allow(unsafe_code)] +#![allow(unused_imports)] +#![allow(unused_results)] +#![allow(clippy::all)] +use protobuf::{CodedInputStream, CodedOutputStream, Message}; +use std::collections::HashMap; +use std::sync::Arc; +use async_trait::async_trait; + +#[derive(Clone)] +pub struct KeyProviderServiceClient { + client: ::ttrpc::r#async::Client, +} + +impl KeyProviderServiceClient { + pub fn new(client: ::ttrpc::r#async::Client) -> Self { + KeyProviderServiceClient { + client: client, + } + } + + pub async fn wrap_key(&self, ctx: ttrpc::context::Context, req: &super::keyprovider::KeyProviderKeyWrapProtocolInput) -> ::ttrpc::Result { + let mut cres = super::keyprovider::KeyProviderKeyWrapProtocolOutput::new(); + ::ttrpc::async_client_request!(self, ctx, req, "keyprovider.KeyProviderService", "WrapKey", cres); + } + + pub async fn un_wrap_key(&self, ctx: ttrpc::context::Context, req: &super::keyprovider::KeyProviderKeyWrapProtocolInput) -> ::ttrpc::Result { + let mut cres = super::keyprovider::KeyProviderKeyWrapProtocolOutput::new(); + ::ttrpc::async_client_request!(self, ctx, req, "keyprovider.KeyProviderService", "UnWrapKey", cres); + } +} + +struct WrapKeyMethod { + service: Arc>, +} + +#[async_trait] +impl ::ttrpc::r#async::MethodHandler for WrapKeyMethod { + async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { + ::ttrpc::async_request_handler!(self, ctx, req, keyprovider, KeyProviderKeyWrapProtocolInput, wrap_key); + } +} + +struct UnWrapKeyMethod { + service: Arc>, +} + +#[async_trait] +impl ::ttrpc::r#async::MethodHandler for UnWrapKeyMethod { + async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { + ::ttrpc::async_request_handler!(self, ctx, req, keyprovider, KeyProviderKeyWrapProtocolInput, un_wrap_key); + } +} + +#[async_trait] +pub trait KeyProviderService: Sync { + async fn wrap_key(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::keyprovider::KeyProviderKeyWrapProtocolInput) -> ::ttrpc::Result { + Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/keyprovider.KeyProviderService/WrapKey is not supported".to_string()))) + } + async fn un_wrap_key(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::keyprovider::KeyProviderKeyWrapProtocolInput) -> ::ttrpc::Result { + Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/keyprovider.KeyProviderService/UnWrapKey is not supported".to_string()))) + } +} + +pub fn create_key_provider_service(service: Arc>) -> HashMap { + let mut ret = HashMap::new(); + let mut methods = HashMap::new(); + let streams = HashMap::new(); + + methods.insert("WrapKey".to_string(), + Box::new(WrapKeyMethod{service: service.clone()}) as Box); + + methods.insert("UnWrapKey".to_string(), + Box::new(UnWrapKeyMethod{service: service.clone()}) as Box); + + ret.insert("keyprovider.KeyProviderService".to_string(), ::ttrpc::r#async::Service{ methods, streams }); + ret +} diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs index 3601c8769..4b647bdd8 100644 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs @@ -7,10 +7,10 @@ use std::{path::Path, sync::Arc}; use anyhow::{anyhow, Context, Result}; use api_ttrpc::{ - create_get_resource_service, create_key_provider_service, create_sealed_secret_service, - create_secure_mount_service, + create_get_resource_service, create_sealed_secret_service, create_secure_mount_service, }; use clap::Parser; +use keyprovider_ttrpc::create_key_provider_service; use log::info; use server::Server; use tokio::{ @@ -21,6 +21,8 @@ use ttrpc::r#async::Server as TtrpcServer; mod api; mod api_ttrpc; +mod keyprovider; +mod keyprovider_ttrpc; mod server; const DEFAULT_CDH_SOCKET_ADDR: &str = "unix:///run/confidential-containers/cdh.sock"; diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/server/mod.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/server/mod.rs index 501f0850f..3b15ab379 100644 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/server/mod.rs +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/server/mod.rs @@ -16,11 +16,12 @@ use ttrpc::{asynchronous::TtrpcContext, Code, Error, Status}; use crate::{ api::{ - GetResourceRequest, GetResourceResponse, KeyProviderKeyWrapProtocolInput, - KeyProviderKeyWrapProtocolOutput, SecureMountRequest, SecureMountResponse, + GetResourceRequest, GetResourceResponse, SecureMountRequest, SecureMountResponse, UnsealSecretInput, UnsealSecretOutput, }, - api_ttrpc::{GetResourceService, KeyProviderService, SealedSecretService, SecureMountService}, + api_ttrpc::{GetResourceService, SealedSecretService, SecureMountService}, + keyprovider::{KeyProviderKeyWrapProtocolInput, KeyProviderKeyWrapProtocolOutput}, + keyprovider_ttrpc::KeyProviderService, server::message::{KeyProviderInput, KeyUnwrapOutput, KeyUnwrapResults}, }; From 85ad504736547c6aa037ca58d484d355aae29824 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Thu, 4 Jan 2024 17:03:44 +0800 Subject: [PATCH 16/18] CDH/image: fix unwrap key logic 1. Fix the place of AnnotationPacket. The old code points to a wrong place that was never test so we never found that. 2. Fix the provider comparation logic. The scheme of KBS should be `kbs` rather than `Kbs`. Signed-off-by: Xynnn007 --- .../hub/src/bin/confidential-data-hub/server/message.rs | 6 +----- confidential-data-hub/image/src/annotation_packet/v2.rs | 4 ++-- confidential-data-hub/kms/src/plugins/mod.rs | 4 +++- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/server/message.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/server/message.rs index 196450ea0..806b2c539 100644 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/server/message.rs +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/server/message.rs @@ -10,8 +10,6 @@ use std::collections::HashMap; use std::str; use std::vec::Vec; -const ANNOTATION_KEY_NAME: &str = "attestation-agent"; - #[derive(Serialize, Deserialize, Debug, PartialEq, Default, Clone)] pub struct KeyProviderInput { // Operation is either "keywrap" or "keyunwrap" @@ -26,10 +24,8 @@ impl KeyProviderInput { pub fn get_annotation(&self) -> Result> { let annotation_base64 = self .keyunwrapparams - .dc + .annotation .as_ref() - .and_then(|dc| dc.parameters.get(ANNOTATION_KEY_NAME)) - .and_then(|paras| paras.get(0)) .ok_or_else(|| anyhow!("Illegal UnwrapKey request: no AnnotationPacket given."))?; let engine = base64::engine::general_purpose::STANDARD; diff --git a/confidential-data-hub/image/src/annotation_packet/v2.rs b/confidential-data-hub/image/src/annotation_packet/v2.rs index df10cbbe6..541a65c87 100644 --- a/confidential-data-hub/image/src/annotation_packet/v2.rs +++ b/confidential-data-hub/image/src/annotation_packet/v2.rs @@ -57,7 +57,7 @@ fn default_version() -> String { } fn default_provider() -> String { - VaultProvider::Kbs.as_ref().to_string() + VaultProvider::Kbs.as_ref().to_lowercase().to_string() } impl TryInto for AnnotationPacketV2 { @@ -70,7 +70,7 @@ impl TryInto for AnnotationPacketV2 { ))); } - if self.provider != VaultProvider::Kbs.as_ref() { + if self.provider != VaultProvider::Kbs.as_ref().to_lowercase() { return Err(Error::ConvertAnnotationPacketFailed(String::from( "Provider must be `kbs`.", ))); diff --git a/confidential-data-hub/kms/src/plugins/mod.rs b/confidential-data-hub/kms/src/plugins/mod.rs index db7e590b6..698d838ee 100644 --- a/confidential-data-hub/kms/src/plugins/mod.rs +++ b/confidential-data-hub/kms/src/plugins/mod.rs @@ -3,6 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 // +use std::str::FromStr; + use strum::{AsRefStr, EnumString}; use crate::{Decrypter, Error, Getter, ProviderSettings, Result}; @@ -59,7 +61,7 @@ pub async fn new_getter( provider_name: &str, _provider_settings: ProviderSettings, ) -> Result> { - let provider = VaultProvider::try_from(provider_name) + let provider = VaultProvider::from_str(provider_name) .map_err(|_| Error::UnsupportedProvider(provider_name.to_string()))?; match provider { VaultProvider::Kbs => Ok(Box::new(kbs::KbcClient::new().await?) as Box), From ee6306cc96f40c7488f2e3d22b6de4b39b377ad5 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Thu, 4 Jan 2024 17:09:29 +0800 Subject: [PATCH 17/18] image-rs: fix integration test We used to request AA for image decryption keys and public keys, etc. Now we are using CDH for these non-attestation APIs. This patch brings a workaround that make the test environment look like it is a "peer pod" environment, then the CDH will read aa_kbc_params from a file rather than kernel cmdline. In future, we will define a launch configuration file for CDH. After that, this workaround can be depreciated. Signed-off-by: Xynnn007 --- image-rs/protos/getresource.proto | 2 +- ...gent.sh => build_confidential_data_hub.sh} | 11 ++-- .../scripts/install_offline_fs_kbc_files.sh | 10 +++- image-rs/src/resource/kbs/grpc.rs | 2 +- image-rs/src/resource/kbs/mod.rs | 19 +----- .../resource/kbs/ttrpc_proto/getresource.rs | 22 +++---- .../kbs/ttrpc_proto/getresource_ttrpc.rs | 6 +- .../test_data/ocicrypt_keyprovider_ttrpc.conf | 2 +- image-rs/tests/common/mod.rs | 59 ++++++++----------- image-rs/tests/credential.rs | 27 +++++---- image-rs/tests/image_decryption.rs | 44 +++++++++----- image-rs/tests/signature_verification.rs | 26 ++++---- ocicrypt-rs/src/keywrap/keyprovider/mod.rs | 8 +-- 13 files changed, 120 insertions(+), 118 deletions(-) rename image-rs/scripts/{build_attestation_agent.sh => build_confidential_data_hub.sh} (69%) diff --git a/image-rs/protos/getresource.proto b/image-rs/protos/getresource.proto index 93cd2e4de..97faf9344 100644 --- a/image-rs/protos/getresource.proto +++ b/image-rs/protos/getresource.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package getresource; +package api; message GetResourceRequest { string ResourcePath = 1; diff --git a/image-rs/scripts/build_attestation_agent.sh b/image-rs/scripts/build_confidential_data_hub.sh similarity index 69% rename from image-rs/scripts/build_attestation_agent.sh rename to image-rs/scripts/build_confidential_data_hub.sh index 4d073604b..d499baf72 100755 --- a/image-rs/scripts/build_attestation_agent.sh +++ b/image-rs/scripts/build_confidential_data_hub.sh @@ -9,12 +9,9 @@ set -o errexit set -o nounset set -o pipefail -parameters=("KBC=offline_fs_kbc") - [ -n "${BASH_VERSION:-}" ] && set -o errtrace [ -n "${DEBUG:-}" ] && set -o xtrace if [[ -n "${TTRPC:-}" ]]; then - parameters+=("ttrpc=true") dest_dir_suffix="ttrpc" else dest_dir_suffix="grpc" @@ -23,12 +20,12 @@ fi source $HOME/.cargo/env SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) -AA_DIR=$SCRIPT_DIR/../../attestation-agent +CDH_DIR=$SCRIPT_DIR/../../confidential-data-hub -pushd $AA_DIR +pushd $CDH_DIR -make "${parameters[@]}" +make make DESTDIR="${SCRIPT_DIR}/${dest_dir_suffix}" install -file "${SCRIPT_DIR}/${dest_dir_suffix}/attestation-agent" +file "${SCRIPT_DIR}/${dest_dir_suffix}/confidential-data-hub" popd diff --git a/image-rs/scripts/install_offline_fs_kbc_files.sh b/image-rs/scripts/install_offline_fs_kbc_files.sh index cdf5bfc24..62597bd6f 100755 --- a/image-rs/scripts/install_offline_fs_kbc_files.sh +++ b/image-rs/scripts/install_offline_fs_kbc_files.sh @@ -25,11 +25,19 @@ if [ "${1:-}" = "install" ]; then sudo install --owner=root --group=root --mode=0640 "${test_resource_record}" "${target_resource_record_path}" sudo install --owner=root --group=root --mode=0640 "${test_keys}" "${target_keys_path}" + # This is a workaround for CDH to read the aa_kbc_params from a + # file rather than kernel commandline. This makes a fake environment + # that CDH will recognize as it is in "peer pod", so aa_kbc param will + # be read from a file. + # TODO: when CDH has its own configuration launch file, we can + # promote this way. + mkdir -p /run/peerpod + touch /run/peerpod/daemon.json + echo "aa_kbc_params = \"offline_fs_kbc::null\"" > /etc/agent-config.toml elif [ "${1:-}" = "clean" ]; then sudo rm "${target_resource_record_path}" sudo rm "${target_keys_path}" else echo >&2 "ERROR: Wrong or missing argument: '${1:-}'" - fi diff --git a/image-rs/src/resource/kbs/grpc.rs b/image-rs/src/resource/kbs/grpc.rs index e23ddab1c..d44b28c4a 100644 --- a/image-rs/src/resource/kbs/grpc.rs +++ b/image-rs/src/resource/kbs/grpc.rs @@ -19,7 +19,7 @@ mod get_resource { #![allow(unknown_lints)] #![allow(clippy::derive_partial_eq_without_eq)] #![allow(clippy::redundant_async_block)] - tonic::include_proto!("getresource"); + tonic::include_proto!("api"); } /// Attestation Agent's GetResource gRPC address. diff --git a/image-rs/src/resource/kbs/mod.rs b/image-rs/src/resource/kbs/mod.rs index eb565d023..7d7990696 100644 --- a/image-rs/src/resource/kbs/mod.rs +++ b/image-rs/src/resource/kbs/mod.rs @@ -119,27 +119,10 @@ impl Protocol for SecureChannel { return Ok(res); } - // Related issue: https://github.com/confidential-containers/attestation-agent/issues/130 - // - // Now we use `aa_kbc_params` to specify the KBC and KBS URI - // used in CoCo System. Different KBCs are initialized in AA lazily due - // to the kbs uri information included in a `download_confidential_resource` or - // `decrypt_image_layer_annotation`. The kbs uri input to the two APIs - // are from `aa_kbc_params` but not the kbs uri in a resource uri. - // Thus as a temporary solution, we need to overwrite the - // kbs uri field using the one included in `aa_kbc_params`, s.t. - // `kbs_uri` of [`SecureChannel`]. - let resource_path = get_resource_path(resource_uri)?; - - let res = self.client.get_resource(&resource_path).await?; + let res = self.client.get_resource(resource_uri).await?; let path = self.get_filepath(resource_uri); fs::write(path, &res).await?; Ok(res) } } - -fn get_resource_path(uri: &str) -> Result { - let path = url::Url::parse(uri)?; - Ok(path.path().to_string()) -} diff --git a/image-rs/src/resource/kbs/ttrpc_proto/getresource.rs b/image-rs/src/resource/kbs/ttrpc_proto/getresource.rs index 0bdf02599..7cfe2fefa 100644 --- a/image-rs/src/resource/kbs/ttrpc_proto/getresource.rs +++ b/image-rs/src/resource/kbs/ttrpc_proto/getresource.rs @@ -25,14 +25,14 @@ /// of protobuf runtime. const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_3_0; -// @@protoc_insertion_point(message:getresource.GetResourceRequest) +// @@protoc_insertion_point(message:api.GetResourceRequest) #[derive(PartialEq,Clone,Default,Debug)] pub struct GetResourceRequest { // message fields - // @@protoc_insertion_point(field:getresource.GetResourceRequest.ResourcePath) + // @@protoc_insertion_point(field:api.GetResourceRequest.ResourcePath) pub ResourcePath: ::std::string::String, // special fields - // @@protoc_insertion_point(special_field:getresource.GetResourceRequest.special_fields) + // @@protoc_insertion_point(special_field:api.GetResourceRequest.special_fields) pub special_fields: ::protobuf::SpecialFields, } @@ -147,14 +147,14 @@ impl ::protobuf::reflect::ProtobufValue for GetResourceRequest { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } -// @@protoc_insertion_point(message:getresource.GetResourceResponse) +// @@protoc_insertion_point(message:api.GetResourceResponse) #[derive(PartialEq,Clone,Default,Debug)] pub struct GetResourceResponse { // message fields - // @@protoc_insertion_point(field:getresource.GetResourceResponse.Resource) + // @@protoc_insertion_point(field:api.GetResourceResponse.Resource) pub Resource: ::std::vec::Vec, // special fields - // @@protoc_insertion_point(special_field:getresource.GetResourceResponse.special_fields) + // @@protoc_insertion_point(special_field:api.GetResourceResponse.special_fields) pub special_fields: ::protobuf::SpecialFields, } @@ -270,11 +270,11 @@ impl ::protobuf::reflect::ProtobufValue for GetResourceResponse { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x11getresource.proto\x12\x0bgetresource\"8\n\x12GetResourceRequest\ - \x12\"\n\x0cResourcePath\x18\x01\x20\x01(\tR\x0cResourcePath\"1\n\x13Get\ - ResourceResponse\x12\x1a\n\x08Resource\x18\x01\x20\x01(\x0cR\x08Resource\ - 2f\n\x12GetResourceService\x12P\n\x0bGetResource\x12\x1f.getresource.Get\ - ResourceRequest\x1a\x20.getresource.GetResourceResponseb\x06proto3\ + \n\x11getresource.proto\x12\x03api\"8\n\x12GetResourceRequest\x12\"\n\ + \x0cResourcePath\x18\x01\x20\x01(\tR\x0cResourcePath\"1\n\x13GetResource\ + Response\x12\x1a\n\x08Resource\x18\x01\x20\x01(\x0cR\x08Resource2V\n\x12\ + GetResourceService\x12@\n\x0bGetResource\x12\x17.api.GetResourceRequest\ + \x1a\x18.api.GetResourceResponseb\x06proto3\ "; /// `FileDescriptorProto` object which was a source for this generated file diff --git a/image-rs/src/resource/kbs/ttrpc_proto/getresource_ttrpc.rs b/image-rs/src/resource/kbs/ttrpc_proto/getresource_ttrpc.rs index 40c5e226a..f412ded9b 100644 --- a/image-rs/src/resource/kbs/ttrpc_proto/getresource_ttrpc.rs +++ b/image-rs/src/resource/kbs/ttrpc_proto/getresource_ttrpc.rs @@ -34,7 +34,7 @@ impl GetResourceServiceClient { pub async fn get_resource(&self, ctx: ttrpc::context::Context, req: &super::getresource::GetResourceRequest) -> ::ttrpc::Result { let mut cres = super::getresource::GetResourceResponse::new(); - ::ttrpc::async_client_request!(self, ctx, req, "getresource.GetResourceService", "GetResource", cres); + ::ttrpc::async_client_request!(self, ctx, req, "api.GetResourceService", "GetResource", cres); } } @@ -52,7 +52,7 @@ impl ::ttrpc::r#async::MethodHandler for GetResourceMethod { #[async_trait] pub trait GetResourceService: Sync { async fn get_resource(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::getresource::GetResourceRequest) -> ::ttrpc::Result { - Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/getresource.GetResourceService/GetResource is not supported".to_string()))) + Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/api.GetResourceService/GetResource is not supported".to_string()))) } } @@ -64,6 +64,6 @@ pub fn create_get_resource_service(service: Arc); - ret.insert("getresource.GetResourceService".to_string(), ::ttrpc::r#async::Service{ methods, streams }); + ret.insert("api.GetResourceService".to_string(), ::ttrpc::r#async::Service{ methods, streams }); ret } diff --git a/image-rs/test_data/ocicrypt_keyprovider_ttrpc.conf b/image-rs/test_data/ocicrypt_keyprovider_ttrpc.conf index 016c4385c..75df218b6 100644 --- a/image-rs/test_data/ocicrypt_keyprovider_ttrpc.conf +++ b/image-rs/test_data/ocicrypt_keyprovider_ttrpc.conf @@ -1,7 +1,7 @@ { "key-providers": { "attestation-agent": { - "ttrpc": "unix:///run/confidential-containers/attestation-agent/keyprovider.sock" + "ttrpc": "unix:///run/confidential-containers/cdh.sock" } } } diff --git a/image-rs/tests/common/mod.rs b/image-rs/tests/common/mod.rs index ef75572e3..61d02089a 100644 --- a/image-rs/tests/common/mod.rs +++ b/image-rs/tests/common/mod.rs @@ -19,7 +19,7 @@ const OFFLINE_FS_KBC_RESOURCE_SCRIPT: &str = "scripts/install_offline_fs_kbc_fil pub const AA_PARAMETER: &str = "provider:attestation-agent:offline_fs_kbc::null"; /// Attestation Agent Offline Filesystem KBC resources file for general tests that use images stored in the quay.io registry -pub const AA_OFFLINE_FS_KBC_RESOURCES_FILE: &str = "aa-offline_fs_kbc-resources.json"; +pub const OFFLINE_FS_KBC_RESOURCES_FILE: &str = "aa-offline_fs_kbc-resources.json"; /// Attestation Agent Offline Filesystem KBC resources file for XRSS tests #[cfg(feature = "signature-simple-xrss")] @@ -62,70 +62,61 @@ pub async fn clean() { .expect("Clean GPG signature file failed."); } -pub async fn start_attestation_agent() -> Result { +pub async fn start_confidential_data_hub() -> Result { let script_dir = format!("{}/{}", std::env!("CARGO_MANIFEST_DIR"), "scripts"); cfg_if::cfg_if! { if #[cfg(feature = "keywrap-ttrpc")] { - let aa_path = format!("{}/ttrpc/{}", script_dir, "attestation-agent"); + let cdh_path = format!("{}/ttrpc/{}", script_dir, "confidential-data-hub"); } else { - let aa_path = format!("{}/grpc/{}", script_dir, "attestation-agent"); + let cdh_path = format!("{}/grpc/{}", script_dir, "confidential-data-hub"); } }; - println!("aa_path: {}", aa_path); + println!("cdh_path: {}", cdh_path); println!("script_dir: {}", script_dir); - if !Path::new(&aa_path).exists() { - let script_path = format!("{}/{}", script_dir, "build_attestation_agent.sh"); + if !Path::new(&cdh_path).exists() { + let script_path = format!("{}/{}", script_dir, "build_confidential_data_hub.sh"); cfg_if::cfg_if! { if #[cfg(feature = "keywrap-ttrpc")] { let output = Command::new(script_path) .env("TTRPC", "1") .output() .await - .expect("Failed to build attestation-agent"); - println!("build ttrpc attestation-agent: {:?}", output); + .expect("Failed to build confidential-data-hub"); + println!("build ttrpc confidential-data-hub: {:?}", output); } else { let output = Command::new(script_path) .output() .await - .expect("Failed to build attestation-agent"); - println!("build grpc attestation-agent: {:?}", output); + .expect("Failed to build confidential-data-hub"); + println!("build grpc confidential-data-hub: {:?}", output); } } } cfg_if::cfg_if! { if #[cfg(feature = "keywrap-ttrpc")] { - let mut aa = Command::new(aa_path) - .kill_on_drop(true) - .args([ - "--keyprovider_sock", - "unix:///run/confidential-containers/attestation-agent/keyprovider.sock", - "--getresource_sock", - "unix:///run/confidential-containers/attestation-agent/getresource.sock" - ]) - .spawn() - .expect("Failed to start ttrpc attestation-agent"); + let mut cdh = Command::new(cdh_path) + .kill_on_drop(true) + .args(["-s", "unix:///run/confidential-containers/cdh.sock"]) + .spawn() + .expect("Failed to start confidential-data-hub"); } else { - let mut aa = Command::new(aa_path) - .kill_on_drop(true) - .args([ - "--keyprovider_sock", - "127.0.0.1:50000", - "--getresource_sock", - "127.0.0.1:50001" - ]) - .spawn() - .expect("Failed to start grpc attestation-agent"); + // TODO: implement this after CDH supports gRPC + let mut cdh = Command::new(cdh_path) + .kill_on_drop(true) + .args(["-s", "unix:///run/confidential-containers/cdh.sock"]) + .spawn() + .expect("Failed to start confidential-data-hub"); } }; // Leave some time to let fork-ed AA process to be ready tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - if (aa.try_wait()?).is_some() { - panic!("Attestation Agent failed to start"); + if (cdh.try_wait()?).is_some() { + panic!("Confidential Data Hub failed to start"); } - Ok(aa) + Ok(cdh) } pub fn umount_bundle(bundle_dir: &tempfile::TempDir) { diff --git a/image-rs/tests/credential.rs b/image-rs/tests/credential.rs index 55360ceb5..2075c5157 100644 --- a/image-rs/tests/credential.rs +++ b/image-rs/tests/credential.rs @@ -3,31 +3,29 @@ // SPDX-License-Identifier: Apache-2.0 // -#[cfg(feature = "getresource")] +#[cfg(all(feature = "getresource", feature = "keywrap-ttrpc"))] use image_rs::image::ImageClient; -#[cfg(feature = "getresource")] +#[cfg(all(feature = "getresource", feature = "keywrap-ttrpc"))] use rstest::rstest; -#[cfg(feature = "getresource")] +#[cfg(all(feature = "getresource", feature = "keywrap-ttrpc"))] use serial_test::serial; pub mod common; -#[cfg(feature = "getresource")] +// TODO: add `keywrap-grpc` integration test after CDH supports grpc mode +#[cfg(all(feature = "getresource", feature = "keywrap-ttrpc"))] #[rstest] #[case("liudalibj/private-busy-box", "kbs:///default/credential/test")] #[case("quay.io/liudalibj/private-busy-box", "kbs:///default/credential/test")] #[tokio::test] #[serial] async fn test_use_credential(#[case] image_ref: &str, #[case] auth_file_uri: &str) { - common::prepare_test(common::AA_OFFLINE_FS_KBC_RESOURCES_FILE).await; + common::prepare_test(common::OFFLINE_FS_KBC_RESOURCES_FILE).await; - // Init AA - let _aa = common::start_attestation_agent() + // // Init CDH + let _cdh = common::start_confidential_data_hub() .await - .expect("Failed to start attestation agent!"); - - // AA parameter - let aa_parameters = common::AA_PARAMETER; + .expect("Failed to start confidential data hub!"); // clean former test files, which is needed to prevent // lint from warning dead code. @@ -50,7 +48,12 @@ async fn test_use_credential(#[case] image_ref: &str, #[case] auth_file_uri: &st let bundle_dir = tempfile::tempdir().unwrap(); let res = image_client - .pull_image(image_ref, bundle_dir.path(), &None, &Some(aa_parameters)) + .pull_image( + image_ref, + bundle_dir.path(), + &None, + &Some(common::AA_PARAMETER), + ) .await; if cfg!(all(feature = "snapshot-overlayfs",)) { assert!(res.is_ok(), "{:?}", res); diff --git a/image-rs/tests/image_decryption.rs b/image-rs/tests/image_decryption.rs index 3c59d1a8d..d9e92a552 100644 --- a/image-rs/tests/image_decryption.rs +++ b/image-rs/tests/image_decryption.rs @@ -6,38 +6,54 @@ //! Test for decryption of image layers. -#[cfg(all(feature = "getresource", feature = "encryption"))] +#[cfg(all( + feature = "getresource", + feature = "encryption", + feature = "keywrap-ttrpc" +))] use image_rs::image::ImageClient; -#[cfg(all(feature = "getresource", feature = "encryption"))] +#[cfg(all( + feature = "getresource", + feature = "encryption", + feature = "keywrap-ttrpc" +))] use serial_test::serial; pub mod common; -/// Ocicrypt-rs config for grpc -#[cfg(all(feature = "getresource", feature = "encryption"))] -#[cfg(not(feature = "keywrap-ttrpc"))] -const OCICRYPT_CONFIG: &str = "test_data/ocicrypt_keyprovider_grpc.conf"; +// TODO: add `keywrap-grpc` integration test after CDH supports grpc mode +// /// Ocicrypt-rs config for grpc +// #[cfg(all(feature = "getresource", feature = "encryption"))] +// #[cfg(not(feature = "keywrap-ttrpc"))] +// const OCICRYPT_CONFIG: &str = "test_data/ocicrypt_keyprovider_grpc.conf"; /// Ocicrypt-rs config for ttrpc -#[cfg(all(feature = "getresource", feature = "encryption"))] -#[cfg(feature = "keywrap-ttrpc")] +#[cfg(all( + feature = "getresource", + feature = "encryption", + feature = "keywrap-ttrpc" +))] const OCICRYPT_CONFIG: &str = "test_data/ocicrypt_keyprovider_ttrpc.conf"; -#[cfg(all(feature = "getresource", feature = "encryption"))] +#[cfg(all( + feature = "getresource", + feature = "encryption", + feature = "keywrap-ttrpc" +))] #[rstest::rstest] #[case("ghcr.io/confidential-containers/test-container:unencrypted")] #[case("ghcr.io/confidential-containers/test-container:encrypted")] #[tokio::test] #[serial] async fn test_decrypt_layers(#[case] image: &str) { - common::prepare_test(common::AA_OFFLINE_FS_KBC_RESOURCES_FILE).await; - // Init AA - let _aa = common::start_attestation_agent() + common::prepare_test(common::OFFLINE_FS_KBC_RESOURCES_FILE).await; + // Init CDH + let _cdh = common::start_confidential_data_hub() .await - .expect("Failed to start attestation agent!"); + .expect("Failed to start confidential data hub!"); // Set env for ocicrypt-rs. The env is needed by ocicrypt-rs - // to communicate with AA + // to communicate with CDH let manifest_dir = std::env!("CARGO_MANIFEST_DIR"); let keyprovider_config = format!("{}/{}", manifest_dir, OCICRYPT_CONFIG); std::env::set_var("OCICRYPT_KEYPROVIDER_CONFIG", keyprovider_config); diff --git a/image-rs/tests/signature_verification.rs b/image-rs/tests/signature_verification.rs index 223c6bc51..9a2149797 100644 --- a/image-rs/tests/signature_verification.rs +++ b/image-rs/tests/signature_verification.rs @@ -6,9 +6,9 @@ //! Test for signature verification. -#[cfg(feature = "getresource")] +#[cfg(all(feature = "getresource", feature = "keywrap-ttrpc"))] use image_rs::image::ImageClient; -#[cfg(feature = "getresource")] +#[cfg(all(feature = "getresource", feature = "keywrap-ttrpc"))] use serial_test::serial; use strum_macros::{Display, EnumString}; @@ -105,23 +105,27 @@ const _TESTS_XRSS: [_TestItem; _TEST_ITEMS_XRSS] = [ }, ]; -#[cfg(feature = "getresource")] +#[cfg(all(feature = "getresource", feature = "keywrap-ttrpc"))] const POLICY_URI: &str = "kbs:///default/security-policy/test"; -#[cfg(feature = "getresource")] +#[cfg(all(feature = "getresource", feature = "keywrap-ttrpc"))] const SIGSTORE_CONFIG_URI: &str = "kbs:///default/sigstore-config/test"; /// image-rs built without support for cosign image signing cannot use a policy that includes a type that /// uses cosign (type: sigstoreSigned), even if the image being pulled is not signed using cosign. /// https://github.com/confidential-containers/guest-components/blob/main/attestation-agent/kbc/src/sample_kbc/policy.json -#[cfg(feature = "getresource")] +#[cfg(all(feature = "getresource", feature = "keywrap-ttrpc"))] #[tokio::test] #[serial] async fn signature_verification() { - do_signature_verification_tests(&_TESTS, common::AA_OFFLINE_FS_KBC_RESOURCES_FILE, &None).await; + do_signature_verification_tests(&_TESTS, common::OFFLINE_FS_KBC_RESOURCES_FILE, &None).await; } -#[cfg(all(feature = "signature-simple-xrss", feature = "getresource"))] +#[cfg(all( + feature = "signature-simple-xrss", + feature = "getresource", + feature = "keywrap-ttrpc" +))] #[tokio::test] #[serial] async fn signature_verification_xrss() { @@ -147,17 +151,17 @@ async fn signature_verification_xrss() { } } -#[cfg(feature = "getresource")] +#[cfg(all(feature = "getresource", feature = "keywrap-ttrpc"))] async fn do_signature_verification_tests( tests: &[_TestItem<'_, '_>], offline_fs_kbc_resources: &str, auth_info: &Option<&str>, ) { common::prepare_test(offline_fs_kbc_resources).await; - // Init AA - let _aa = common::start_attestation_agent() + // Init CDH + let _cdh = common::start_confidential_data_hub() .await - .expect("Failed to start attestation agent!"); + .expect("Failed to start confidential data hub!"); for test in tests { let mut test_auth_info = auth_info; diff --git a/ocicrypt-rs/src/keywrap/keyprovider/mod.rs b/ocicrypt-rs/src/keywrap/keyprovider/mod.rs index 02279a3b6..9f5b31f6a 100644 --- a/ocicrypt-rs/src/keywrap/keyprovider/mod.rs +++ b/ocicrypt-rs/src/keywrap/keyprovider/mod.rs @@ -150,9 +150,9 @@ impl KeyProviderKeyWrapProtocolOutput { OpKey::Unwrap => kc1 .un_wrap_key(ttrpc::context::with_timeout(50 * 1000 * 1000 * 1000), &req) .await - .map_err(|_| { + .map_err(|e| { anyhow!( - "keyprovider: Error from ttrpc server for {:?} operation", + "keyprovider: Error from ttrpc server for {:?} operation: {e:?}", OpKey::Unwrap.to_string() ) })?, @@ -440,8 +440,8 @@ impl KeyProviderKeyWrapper { }); match handler.join() { Ok(Ok(v)) => Ok(v), - Ok(Err(e)) => bail!("failed to unwrap key by gRPC, {e}"), - Err(e) => bail!("failed to unwrap key by gRPC, {e:?}"), + Ok(Err(e)) => bail!("failed to unwrap key by ttrpc, {e}"), + Err(e) => bail!("failed to unwrap key by ttrpc, {e:?}"), } } } From cf5716d833e801d4557760610ec5ea40d0f0b4af Mon Sep 17 00:00:00 2001 From: Pradipta Banerjee Date: Wed, 17 Jan 2024 13:23:30 +0530 Subject: [PATCH 18/18] build: Rename the feature flag and set default Rename the feature flag to align with the feature and provide for build time customisations of the options Fixes: #435 Signed-off-by: Pradipta Banerjee --- confidential-data-hub/Makefile | 17 ++++++---------- confidential-data-hub/README.md | 36 +++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/confidential-data-hub/Makefile b/confidential-data-hub/Makefile index e0404994b..0d7857d35 100644 --- a/confidential-data-hub/Makefile +++ b/confidential-data-hub/Makefile @@ -19,8 +19,8 @@ SOURCE_ARCH := $(shell uname -m) ARCH ?= $(shell uname -m) DEBUG ?= LIBC ?= gnu -RESOURCE_PROVIDER ?= -PROVIDER ?= +RESOURCE_PROVIDER ?= kbs,sev +KMS_PROVIDER ?= aliyun,ehsm DESTDIR ?= $(PREFIX)/bin RUSTFLAGS_ARGS ?= features ?= @@ -29,17 +29,12 @@ ifeq ($(SOURCE_ARCH), ppc64le) ARCH=powerpc64le endif -ifdef RESOURCE_PROVIDER +ifneq ($(RESOURCE_PROVIDER), none) features += $(RESOURCE_PROVIDER) endif -ifdef PROVIDER - features += $(PROVIDER) -else - ifneq ($(ARCH), s390x) - $(info INFO: All plugins will be built in by default) - features += aliyun,ehsm - endif +ifneq ($(KMS_PROVIDER), none) + features += $(KMS_PROVIDER) endif ifeq ($(LIBC), musl) @@ -105,5 +100,5 @@ clean: help: @echo "==========================Help=========================================" - @echo "build: make [DEBUG=1] [LIBC=(musl)] [ARCH=(x86_64/s390x/ppc64le)] [RESOURCE_PROVIDER=(kbs/sev)] [PROVIDER=aliyun]" + @echo "build: make [DEBUG=1] [LIBC=(musl)] [ARCH=(x86_64/s390x/ppc64le)] [RESOURCE_PROVIDER=(kbs/sev)] [KMS_PROVIDER=aliyun/ehsm]" @echo "install: make install [DESTDIR=/path/to/target] [LIBC=(musl)]" diff --git a/confidential-data-hub/README.md b/confidential-data-hub/README.md index 2d1b1b1cf..71c2e2131 100644 --- a/confidential-data-hub/README.md +++ b/confidential-data-hub/README.md @@ -1,27 +1,40 @@ # Confidential Data Hub -Confidential Data Hub is a service running inside guest to provide resource related +Confidential Data Hub (`CDH`) is a service running inside the guest to provide resource related APIs. ### Build -Build and install with default KBC modules: +Build and install with default features: ```shell git clone https://github.com/confidential-containers/guest-components cd guest-components/confidential-data-hub make ``` +This will build CDH with `RESOURCE_PROVIDER=kbs,sev` and `KMS_PROVIDER=aliyun,ehsm` -or explicitly specify the confidential resource provider and KMS plugin, please refer to -[Supported Features](#supported-features) +You can explicitly specify the confidential resource provider and KMS_PROVIDER plugin during the build. +For example if you only want to include `aliyun` KMS_PROVIDER: ```shell -make RESOURCE_PROVIDER=kbs PROVIDER=aliyun +make KMS_PROVIDER=aliyun ``` +If you don't want to include any KMS_PROVIDER(s) and want to use only `kbs` as the resource provider: +```shell +make RESOURCE_PROVIDER=kbs KMS_PROVIDER=none +``` + +If you don't want to include any RESOURCE_PROVIDER(s): +```shell +make RESOURCE_PROVIDER=none +``` + +Please refer to [Supported Features](#supported-features) for the options. + ### Supported Features Confidential resource providers (flag `RESOURCE_PROVIDER`) @@ -31,14 +44,15 @@ Confidential resource providers (flag `RESOURCE_PROVIDER`) | kbs | For TDX/SNP/Azure-SNP-vTPM based on KBS Attestation Protocol | | sev | For SEV based on efi secret pre-attestation | -Note: `offline-fs` is built-in, we do not need to manually enable. If no `RESOURCE_PROVIDER` -is given, all features will be enabled. +Note: +- If no `RESOURCE_PROVIDER` flag is given, then all the resource providers will be enabled by default -KMS plugins (flag `PROVIDER`) +KMS_PROVIDER plugins (flag `KMS_PROVIDER`) | Feature name | Note | | ------------------- | ----------------------------------------------------------------- | -| aliyun | Use aliyun KMS suites to unseal secrets, etc. | -| ehsm | Use Intel eHSM KMS suites to unseal secrets, etc. | +| aliyun | Use aliyun KMS_PROVIDER suites to unseal secrets, etc. | +| ehsm | Use Intel eHSM KMS_PROVIDER suites to unseal secrets, etc. | -Note: If no `PROVIDER` is given, all features will be enabled. +Note: +- If no `KMS_PROVIDER` flag is given, then all the KMS providers will be enabled by default.