Skip to content

CDH/image-rs | promote error information printing #995

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions confidential-data-hub/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@
Confidential Data Hub (`CDH`) is a service running inside the guest to provide resource related
APIs.

### APIs

The APIs are defined in the [proto file](./hub/protos/).

Note that CDH supports decryption of encrypted images.
To enable this you need to set environment `OCICRYPT_KEYPROVIDER_CONFIG` to point to the [ocicrypt configuration file](./hub/src/image/ocicrypt_config.json) at startup, for example

```shell
OCICRYPT_KEYPROVIDER_CONFIG=<path-to-ocicrypt_config.json> confidential-data-hub
```

### Build

Expand Down
7 changes: 5 additions & 2 deletions confidential-data-hub/example.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
"sigstore_config_uri": "kbs:///default/sigstore-config/test",
"image_security_policy_uri": "kbs:///default/security-policy/test",
"authenticated_registry_credentials_uri": "kbs:///default/credential/test",
"image_pull_proxy": "http://127.0.0.1:5432",
"skip_proxy_ips": "192.168.0.1,localhost",
"image_pull_proxy": {
"https_proxy": "http://127.0.0.1:5432",
"http_proxy": "http://127.0.0.1:5432",
"no_proxy": "192.168.0.1,localhost"
},
"extra_root_certificates": "-----BEGIN CERTIFICATE-----\nMIIFTDCCAvugAwIBAgIBADBGBgkqhkiG9w0BAQowOaAPMA0GCWCGSAFlAwQCAgUA\noRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCATCjAwIBATB7MRQwEgYD\nVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDASBgNVBAcMC1NhbnRhIENs\nYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5jZWQgTWljcm8gRGV2aWNl\nczESMBAGA1UEAwwJU0VWLU1pbGFuMB4XDTIzMDEyNDE3NTgyNloXDTMwMDEyNDE3\nNTgyNlowejEUMBIGA1UECwwLRW5naW5lZXJpbmcxCzAJBgNVBAYTAlVTMRQwEgYD\nVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExHzAdBgNVBAoMFkFkdmFuY2Vk\nIE1pY3JvIERldmljZXMxETAPBgNVBAMMCFNFVi1WQ0VLMHYwEAYHKoZIzj0CAQYF\nK4EEACIDYgAExmG1ZbuoAQK93USRyZQcsyobfbaAEoKEELf/jK39cOVJt1t4s83W\nXM3rqIbS7qHUHQw/FGyOvdaEUs5+wwxpCWfDnmJMAQ+ctgZqgDEKh1NqlOuuKcKq\n2YAWE5cTH7sHo4IBFjCCARIwEAYJKwYBBAGceAEBBAMCAQAwFwYJKwYBBAGceAEC\nBAoWCE1pbGFuLUIwMBEGCisGAQQBnHgBAwEEAwIBAzARBgorBgEEAZx4AQMCBAMC\nAQAwEQYKKwYBBAGceAEDBAQDAgEAMBEGCisGAQQBnHgBAwUEAwIBADARBgorBgEE\nAZx4AQMGBAMCAQAwEQYKKwYBBAGceAEDBwQDAgEAMBEGCisGAQQBnHgBAwMEAwIB\nCDARBgorBgEEAZx4AQMIBAMCAXMwTQYJKwYBBAGceAEEBEDDhCejDUx6+dlvehW5\ncmmCWmTLdqI1L/1dGBFdia1HP46MC82aXZKGYSutSq37RCYgWjueT+qCMBE1oXDk\nd1JOMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0B\nAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBA4ICAQACgCai9x8DAWzX/2IelNWm\nituEBSiq9C9eDnBEckQYikAhPasfagnoWFAtKu/ZWTKHi+BMbhKwswBS8W0G1ywi\ncUWGlzigI4tdxxf1YBJyCoTSNssSbKmIh5jemBfrvIBo1yEd+e56ZJMdhN8e+xWU\nbvovUC2/7Dl76fzAaACLSorZUv5XPJwKXwEOHo7FIcREjoZn+fKjJTnmdXce0LD6\n9RHr+r+ceyE79gmK31bI9DYiJoL4LeGdXZ3gMOVDR1OnDos5lOBcV+quJ6JujpgH\nd9g3Sa7Du7pusD9Fdap98ocZslRfFjFi//2YdVM4MKbq6IwpYNB+2PCEKNC7SfbO\nNgZYJuPZnM/wViES/cP7MZNJ1KUKBI9yh6TmlSsZZOclGJvrOsBZimTXpATjdNMt\ncluKwqAUUzYQmU7bf2TMdOXyA9iH5wIpj1kWGE1VuFADTKILkTc6LzLzOWCofLxf\nonhTtSDtzIv/uel547GZqq+rVRvmIieEuEvDETwuookfV6qu3D/9KuSr9xiznmEg\nxynud/f525jppJMcD/ofbQxUZuGKvb3f3zy+aLxqidoX7gca2Xd9jyUy5Y/83+ZN\nbz4PZx81UJzXVI9ABEh8/xilATh1ZxOePTBJjN7lgr0lXtKYjV/43yyxgUYrXNZS\noLSG2dLCK9mjjraPjau34Q==\n-----END CERTIFICATE-----",
"work_dir": "/run/image-rs"
}
Expand Down
39 changes: 23 additions & 16 deletions confidential-data-hub/example.config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,21 +117,6 @@ image_security_policy_uri = "kbs:///default/security-policy/test"
# By default this value is not set.
authenticated_registry_credentials_uri = "kbs:///default/credential/test"

# Proxy that will be used to pull image
#
# By default this value is not set.
image_pull_proxy = "http://127.0.0.1:5432"

# No proxy env that will be used to pull image.
#
# This will ensure that when we access the image registry with specified
# IPs, the `image_pull_proxy` will not be used.
#
# If `image_pull_proxy` is not set, this field will do nothing.
#
# By default this value is not set.
skip_proxy_ips = "192.168.0.1,localhost"

# To support registries with self signed certs. This config item
# is used to add extra trusted root certifications. The certificates
# must be encoded by PEM.
Expand Down Expand Up @@ -176,4 +161,26 @@ oLSG2dLCK9mjjraPjau34Q==
# The path to store the pulled image layer data.
#
# This value defaults to `/run/image-rs/`.
work_dir = "/run/image-rs"
work_dir = "/run/image-rs"

[image.image_pull_proxy]

# HTTPS proxy that will be used to pull image
#
# By default this value is not set.
https_proxy = "http://127.0.0.1:5432"

# HTTP proxy that will be used to pull image
#
# By default this value is not set.
http_proxy = "http://127.0.0.1:5432"

# No proxy env that will be used to pull image.
#
# This will ensure that when we access the image registry with specified
# IPs, both `https_proxy` and `http_proxy` will not be used.
#
# If neither `https_proxy` nor `http_proxy` is not set, this field will do nothing.
#
# By default this value is not set.
no_proxy = "192.168.0.1,localhost"
10 changes: 5 additions & 5 deletions confidential-data-hub/hub/src/bin/grpc_server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl SealedSecretService for Arc<Cdh> {
.map_err(|e| {
let detailed_error = format_error!(e);
error!("[gRPC CDH] Call CDH to unseal secret failed:\n{detailed_error}");
Status::internal(format!("[ERROR] CDH unseal secret failed: {}", e))
Status::internal(format!("[CDH] [ERROR]: {e}"))
})?;

debug!("[gRPC CDH] Unseal secret successfully!");
Expand All @@ -80,7 +80,7 @@ impl GetResourceService for Arc<Cdh> {
.map_err(|e| {
let detailed_error = format_error!(e);
error!("[gRPC CDH] Call CDH to get resource failed:\n{detailed_error}");
Status::internal(format!("[ERROR] CDH get resource failed: {}", e))
Status::internal(format!("[CDH] [ERROR]: {e}"))
})?;

debug!("[gRPC CDH] Get resource successfully!");
Expand Down Expand Up @@ -109,7 +109,7 @@ impl SecureMountService for Arc<Cdh> {
let mount_path = self.inner.secure_mount(storage).await.map_err(|e| {
let detailed_error = format_error!(e);
error!("[gRPC CDH] Call CDH to secure mount failed:\n{detailed_error}");
Status::internal(format!("[ERROR] CDH secure mount failed: {}", e))
Status::internal(format!("[CDH] [ERROR]: {e}"))
})?;

debug!("[gRPC CDH] Secure mount successfully!");
Expand All @@ -136,7 +136,7 @@ impl ImagePullService for Arc<Cdh> {
.map_err(|e| {
let detailed_error = format_error!(e);
error!("[gRPC CDH] Call CDH to pull image failed:\n{detailed_error}");
Status::internal(format!("[ERROR] CDH image pulling failed: {}", e))
Status::internal(format!("[CDH] [ERROR]: {e}"))
})?;

debug!("[gRPC CDH] Pull image successfully!");
Expand Down Expand Up @@ -185,7 +185,7 @@ impl KeyProviderService for Arc<Cdh> {
.map_err(|e| {
let detailed_error = format_error!(e);
error!("[gRPC CDH] Call CDH to Unwrap Key failed:\n{detailed_error}");
Status::internal(format!("[ERROR] CDH Unwrap Key failed: {}", e))
Status::internal(format!("[CDH] [ERROR]: {e}"))
})?;

// Construct output structure and serialize it as the return value of gRPC
Expand Down
10 changes: 5 additions & 5 deletions confidential-data-hub/hub/src/bin/ttrpc_server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl SealedSecretService for Server {
error!("[ttRPC CDH] UnsealSecret :\n{detailed_error}");
let mut status = Status::new();
status.set_code(Code::INTERNAL);
status.set_message("[CDH] [ERROR]: Unseal Secret failed".into());
status.set_message(format!("[CDH] [ERROR]: {e}"));
Error::RpcStatus(status)
})?;

Expand All @@ -79,7 +79,7 @@ impl GetResourceService for Server {
error!("[ttRPC CDH] GetResource :\n{detailed_error}");
let mut status = Status::new();
status.set_code(Code::INTERNAL);
status.set_message("[CDH] [ERROR]: Get Resource failed".into());
status.set_message(format!("[CDH] [ERROR]: {e}"));
Error::RpcStatus(status)
})?;

Expand Down Expand Up @@ -121,7 +121,7 @@ impl KeyProviderService for Server {
error!("[ttRPC CDH] UnWrapKey :\n{detailed_error}");
let mut status = Status::new();
status.set_code(Code::INTERNAL);
status.set_message("[CDH] [ERROR]: UnwrapKey failed".to_string());
status.set_message(format!("[CDH] [ERROR]: {e}"));
Error::RpcStatus(status)
})?;

Expand Down Expand Up @@ -167,7 +167,7 @@ impl SecureMountService for Server {
error!("[ttRPC CDH] Secure Mount :\n{detailed_error}");
let mut status = Status::new();
status.set_code(Code::INTERNAL);
status.set_message("[CDH] [ERROR]: secure mount failed".to_string());
status.set_message(format!("[CDH] [ERROR]: {e}"));
Error::RpcStatus(status)
})?;

Expand Down Expand Up @@ -195,7 +195,7 @@ impl ImagePullService for Server {
error!("[ttRPC CDH] Pull Image :\n{detailed_error}");
let mut status = Status::new();
status.set_code(Code::INTERNAL);
status.set_message("[CDH] [ERROR]: pull image failed".to_string());
status.set_message(format!("[CDH] [ERROR]: {e}"));
Error::RpcStatus(status)
})?;

Expand Down
15 changes: 9 additions & 6 deletions confidential-data-hub/hub/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ mod tests {
use std::{env, io::Write};

use anyhow::anyhow;
use image_rs::config::ImageConfig;
use image_rs::config::{ImageConfig, ProxyConfig};
use rstest::rstest;

use crate::{config::DEFAULT_CDH_SOCKET_ADDR, CdhConfig, KbsConfig};
Expand All @@ -188,7 +188,9 @@ sigstore_config_uri = "kbs:///default/sigstore-config/test"
image_security_policy_uri = "kbs:///default/security-policy/test"
authenticated_registry_credentials_uri = "kbs:///default/credential/test"
extra_root_certificates = ["cert1", "cert2"]
image_pull_proxy = "http://127.0.0.1:8080"

[image.image_pull_proxy]
https_proxy = "http://127.0.0.1:8080"
"#,
Some(CdhConfig {
kbc: KbsConfig {
Expand All @@ -202,8 +204,11 @@ image_pull_proxy = "http://127.0.0.1:8080"
sigstore_config_uri: Some("kbs:///default/sigstore-config/test".to_string()),
image_security_policy_uri: Some("kbs:///default/security-policy/test".to_string()),
authenticated_registry_credentials_uri: Some("kbs:///default/credential/test".to_string()),
image_pull_proxy: Some("http://127.0.0.1:8080".into()),
skip_proxy_ips: None,
image_pull_proxy: Some(ProxyConfig {
https_proxy: Some("http://127.0.0.1:8080".into()),
http_proxy: None,
no_proxy: None,
}),
extra_root_certificates: vec!["cert1".into(), "cert2".into()],
..Default::default()
},
Expand Down Expand Up @@ -240,7 +245,6 @@ name = "offline_fs_kbc"
image_security_policy_uri: None,
authenticated_registry_credentials_uri: None,
image_pull_proxy: None,
skip_proxy_ips: None,
..Default::default()
},
socket: DEFAULT_CDH_SOCKET_ADDR.to_string(),
Expand All @@ -266,7 +270,6 @@ some_undefined_field = "unknown value"
image_security_policy_uri: None,
authenticated_registry_credentials_uri: None,
image_pull_proxy: None,
skip_proxy_ips: None,
..Default::default()
},
socket: DEFAULT_CDH_SOCKET_ADDR.to_string(),
Expand Down
44 changes: 35 additions & 9 deletions confidential-data-hub/hub/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,53 @@ pub enum Error {
source: kms::Error,
},

#[error("get resource failed")]
#[error("Get Resource failed")]
GetResource {
#[source]
source: kms::Error,
},

#[error("decrypt image (unwrap key) failed")]
#[error("Decrypt Image (UnwrapKey) failed")]
ImageDecryption(#[from] image::Error),

#[error("init Hub failed: {0}")]
InitializationFailed(String),

#[error("unseal secret failed")]
#[error("Unseal Secret failed")]
UnsealSecret(#[from] secret::SecretError),

#[error("secure mount failed")]
#[error("Secure Mount failed")]
SecureMount(#[from] storage::Error),

#[error("image pull failed")]
ImagePull {
#[source]
source: anyhow::Error,
},
#[error("Image Pull error: {0}")]
ImagePull(#[from] image_rs::image::PullImageError),

#[error("Image Client error: {0}")]
ImageClient(#[from] image_rs::builder::BuilderError),
}
#[cfg(test)]
mod tests {
use super::*;
use anyhow::anyhow;
use image_rs::signature::SignatureError;
use rstest::rstest;

#[rstest]
#[case(Error::KbsClient { source: kms::Error::KbsClientError("details".into()) }, "kbs client initialization failed")]
#[case(Error::GetResource { source: kms::Error::KbsClientError("details".into()) }, "Get Resource failed")]
#[case(
Error::UnsealSecret(secret::SecretError::VersionError),
"Unseal Secret failed"
)]
#[case(
Error::SecureMount(storage::Error::StorageTypeNotRecognized(
strum::ParseError::VariantNotFound
)),
"Secure Mount failed"
)]
#[case(Error::ImagePull(image_rs::image::PullImageError::SignatureValidationFailed(SignatureError::DeniedByPolicy { source: anyhow!("some details")})), "Image Pull error: Image policy rejected: Denied by policy: some details")]
fn test_brief_message(#[case] error: Error, #[case] expected: &str) {
let brief_message = error.to_string();
assert_eq!(brief_message, expected);
}
}
10 changes: 2 additions & 8 deletions confidential-data-hub/hub/src/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,21 +90,15 @@ impl DataHub for Hub {
.lock()
.await
.pull_image(image_url, Path::new(bundle_path), &None, &None)
.await
.map_err(|e| Error::ImagePull { source: e })?;
.await?;
Ok(manifest_digest)
}
}

async fn initialize_image_client(config: ImageConfig) -> Result<Mutex<ImageClient>> {
debug!("Image client lazy initializing...");

let image_client = Into::<ClientBuilder>::into(config)
.build()
.await
.map_err(|e| {
Error::InitializationFailed(format!("failed to initialize image pull client :{e:?}"))
})?;
let image_client = Into::<ClientBuilder>::into(config).build().await?;

Ok(Mutex::new(image_client))
}
7 changes: 7 additions & 0 deletions confidential-data-hub/hub/src/image/ocicrypt_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"key-providers": {
"attestation-agent": {
"ttrpc": "unix:///run/confidential-containers/cdh.sock"
}
}
}
3 changes: 2 additions & 1 deletion image-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ serde = { workspace = true, features = ["serde_derive", "rc"] }
serde_json.workspace = true
serde_yaml = { version = "0.9", optional = true }
sha2.workspace = true
sigstore = { git = "https://github.com/sigstore/sigstore-rs.git", rev = "5df33d6b7d0590a534948a2b9b415cd6e13bafdc", default-features = false, optional = true }
sigstore = { version = "0.12.1", default-features = false, optional = true }
strum.workspace = true
strum_macros = "0.27"
astral-tokio-tar = "0.5.1"
thiserror.workspace = true
tokio.workspace = true
tokio-util = "0.7.15"
toml.workspace = true
Expand Down
4 changes: 2 additions & 2 deletions image-rs/libs/test-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ macro_rules! assert_result {
assert!($actual_result.is_err(), "{}", $msg);

let expected_error = $expected_result.as_ref().unwrap_err();
let expected_error_msg = format!("{:?}", expected_error);
let expected_error_msg = format!("{}", expected_error);

let actual_error_msg = format!("{:?}", $actual_result.unwrap_err());
let actual_error_msg = format!("{}", $actual_result.unwrap_err());

assert!(expected_error_msg == actual_error_msg, "{}", $msg);
}
Expand Down
Loading
Loading