-
Notifications
You must be signed in to change notification settings - Fork 95
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
Add trustee-client - a simple client for Trustee #755
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[package] | ||
name = "trustee-client" | ||
version = "0.10.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
anyhow.workspace = true | ||
base64.workspace = true | ||
clap = { workspace = true, features = ["derive"] } | ||
config.workspace = true | ||
tokio = { workspace = true, features = ["macros", "rt"] } | ||
env_logger.workspace = true | ||
log.workspace = true | ||
kbs_protocol = { path = "../attestation-agent/kbs_protocol", features=["openssl", "all-attesters", "background_check", "passport" ] } | ||
rstest.workspace = true | ||
serde = { workspace = true, features = ["derive"] } | ||
serde_json.workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
Trustee client -- a simple tool to attest and fetch secrets from Trustee | ||
|
||
Trustee client is using attestation-agent's kbs_protocol client and | ||
attesters to gather hardware-based confidential-computing evidence | ||
and send it over to Trustee. | ||
|
||
Trustee client is a part of [confidential-containers](https://github.com/confidential-containers) | ||
[guest-components](https://github.com/confidential-containers/guest-components) | ||
project but can be used for confidential VMs as well. | ||
|
||
|
||
|
||
Build with: | ||
cargo build [--no-default-features] | ||
|
||
|
||
Configuration file: | ||
trustee-client configuration must contain the trustee (server) URL. | ||
Possibly it can also contain the trustee https certificate, either | ||
as a string in the configuration file or in another file (but not both). | ||
|
||
A configuration file path is an optional argument to trustee-client | ||
If no configuration file path is provided /etc/trustee-client.conf is used. | ||
|
||
Run: | ||
$ trustee-client [--config-file <path>] get-resource --path <resource-path> | ||
|
||
Example: | ||
$ trustee-client get-resource --path default/keys/dummy |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// Copyright (c) 2023 by Alibaba. | ||
// Copyright (c) 2024 Red Hat, Inc | ||
// Licensed under the Apache License, Version 2.0, see LICENSE for details. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
//! A simple client for fetching resources from Trustee. | ||
|
||
use anyhow::Result; | ||
use base64::engine::general_purpose::STANDARD; | ||
use base64::Engine; | ||
use clap::{Parser, Subcommand}; | ||
use log::debug; | ||
|
||
use kbs_protocol::evidence_provider::NativeEvidenceProvider; | ||
use kbs_protocol::KbsClientBuilder; | ||
use kbs_protocol::KbsClientCapabilities; | ||
|
||
pub mod tcconfig; | ||
use tcconfig::TrusteeClientConfig; | ||
|
||
#[derive(Parser)] | ||
struct Cli { | ||
/// A configuration file for trustee-client (default is /etc/trustee-client.conf) | ||
#[clap(long, value_parser)] | ||
config_file: Option<String>, | ||
|
||
#[clap(subcommand)] | ||
command: Commands, | ||
} | ||
|
||
#[derive(Subcommand)] | ||
enum Commands { | ||
/// Get confidential resource | ||
#[clap(arg_required_else_help = true)] | ||
GetResource { | ||
/// KBS Resource path, e.g my_repo/resource_type/123abc | ||
/// Document: https://github.com/confidential-containers/attestation-agent/blob/main/docs/KBS_URI.md | ||
#[clap(long, value_parser)] | ||
path: String, | ||
}, | ||
} | ||
|
||
#[tokio::main(flavor = "current_thread")] | ||
async fn main() -> Result<()> { | ||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); | ||
|
||
let cli = Cli::parse(); | ||
|
||
let tcc = TrusteeClientConfig::new(cli.config_file)?; | ||
|
||
let url = tcc.url.clone(); | ||
let cert = tcc.get_cert(); | ||
|
||
debug!("url {}", url); | ||
debug!("cert {:?}", cert); | ||
|
||
let evidence_provider = Box::new(NativeEvidenceProvider::new()?); | ||
|
||
// build a kbs_protocol client with evidence_provider | ||
let mut client_builder = KbsClientBuilder::with_evidence_provider(evidence_provider, &url); | ||
|
||
// if a certificate is given, use it | ||
if let Some(c) = cert { | ||
client_builder = client_builder.add_kbs_cert(&c) | ||
} | ||
|
||
// Build the client. This client is used throughout the program | ||
let mut client = client_builder.build()?; | ||
|
||
match cli.command { | ||
Commands::GetResource { path } => { | ||
// get resource | ||
let resource_uri = format!("kbs:///{}", path); | ||
let resource_bytes = client | ||
.get_resource(serde_json::from_str(&format!("\"{resource_uri}\""))?) | ||
.await?; | ||
|
||
println!("{}", STANDARD.encode(resource_bytes)); | ||
} | ||
}; | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// Copyright (c) 2024 Alibaba Cloud | ||
// Copyright (c) 2024 Red Hat, Inc | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
use anyhow::{bail, Context, Result}; | ||
use config::{Config, File, FileFormat}; | ||
use log::{debug, info}; | ||
use serde::Deserialize; | ||
use std::fs; | ||
use std::path::Path; | ||
|
||
const DEFAULT_TCCONFIG_FILE_PATH: &str = "/etc/trustee-client.conf"; | ||
#[derive(Deserialize, Debug, PartialEq)] | ||
pub struct TrusteeClientConfig { | ||
/// URL Address of Trustee. | ||
pub url: String, | ||
|
||
/// https:// certificate for Trustee as a string | ||
pub cert: Option<String>, | ||
|
||
/// https:// certificate for Trustee in a cert_file | ||
pub cert_file: Option<String>, | ||
} | ||
|
||
impl TrusteeClientConfig { | ||
pub fn new(path_arg: Option<String>) -> Result<Self> { | ||
let path = match path_arg { | ||
Some(f) => f, | ||
None => DEFAULT_TCCONFIG_FILE_PATH.to_string(), | ||
}; | ||
|
||
debug!("Using configuration file {path}"); | ||
if !Path::new(&path).exists() { | ||
bail!("Config file {path} not found.") | ||
} | ||
|
||
let c = Config::builder() | ||
.add_source(File::new(&path as &str, FileFormat::Toml)) | ||
.build()?; | ||
|
||
let tcc: TrusteeClientConfig = | ||
c.try_deserialize().context("failed to parse config_file")?; | ||
|
||
Ok(tcc) | ||
} | ||
|
||
// get the certificate from the configuration file, if exists | ||
// If cert does not exists but cert_file does, read cert from cert_file | ||
pub fn get_cert(&self) -> Option<String> { | ||
debug!( | ||
"cert={:?} cert_file={:?}", | ||
self.cert.clone(), | ||
self.cert_file.clone() | ||
); | ||
if let Some(c) = &self.cert { | ||
debug!("Some cert {}", c.clone()); | ||
return Some(c.clone()); | ||
} | ||
|
||
if let Some(cf) = &self.cert_file { | ||
debug!("Some cert_file {}", cf.clone()); | ||
let newcert = fs::read_to_string(cf.clone()).ok()?; | ||
return Some(newcert); | ||
} | ||
None | ||
} | ||
|
||
pub fn is_valid(&self) -> Result<()> { | ||
if self.cert.is_some() && self.cert_file.is_some() { | ||
bail!("Please provide only one of 'cert' and 'cert_file'"); | ||
} | ||
if self.url.starts_with("https://") && self.cert.is_none() { | ||
info!("An https:// URL is used but no certificate is provided"); | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::TrusteeClientConfig; | ||
use rstest::rstest; | ||
use std::fs::File as fsfile; | ||
use std::io::Write; | ||
|
||
#[rstest] | ||
#[case::good_http( | ||
1, | ||
r#" | ||
url = "http://localhost:50000" | ||
"#, | ||
Some(TrusteeClientConfig { | ||
url : "http://localhost:50000".to_string(), | ||
cert : None, | ||
cert_file: None, | ||
}))] | ||
#[case::good_https_with_cert( | ||
2, | ||
r#" | ||
url = "https://localhost:50000" | ||
cert = "Trustee Certificate" | ||
"#, | ||
Some(TrusteeClientConfig { | ||
url : "https://localhost:50000".to_string(), | ||
cert : Some("Trustee Certificate".to_string()), | ||
cert_file: None, | ||
}) | ||
)] | ||
#[case::good_https_with_cert_file( | ||
3, | ||
r#" | ||
url = "https://localhost:50000" | ||
cert_file = "/tmp/test_cert_file.conf" | ||
"#, | ||
Some(TrusteeClientConfig { | ||
url : "https://localhost:50000".to_string(), | ||
cert : None, | ||
cert_file: Some("/tmp/test_cert_file.conf".to_string()), | ||
}) | ||
)] | ||
#[case::bad_empty(4, r#""#, None)] | ||
#[case::bad_nourl_only_cert_file( | ||
5, | ||
r#" | ||
cert_file = "/tmp/test_cert_file" | ||
"#, | ||
None | ||
)] | ||
fn check_trustee_config_file( | ||
#[case] n: i32, | ||
#[case] config: &str, | ||
#[case] expected: Option<TrusteeClientConfig>, | ||
) { | ||
let testfilename = format!("/tmp/tccconfigtest{n}.conf"); | ||
{ | ||
let mut f = fsfile::create(testfilename.clone()).unwrap(); | ||
f.write_all(config.as_bytes()).unwrap(); | ||
f.sync_all().unwrap(); | ||
} // close f | ||
let tcc = TrusteeClientConfig::new(Some(testfilename)); | ||
match expected { | ||
Some(cfg) => assert_eq!(cfg, tcc.unwrap()), | ||
None => assert!(tcc.is_err()), | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this name might be too general. This tool only exercises a subset of the Trustee APIs. Btw see this proposal which might end up with a similar name.
Maybe this could be called
cc-kbc-resource-getter
ortrustee-resource-getter
ortrustee-resource-client
or something elseThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I'll take a look at that proposal and think of names.