diff --git a/.github/workflows/trustee-attester.yml b/.github/workflows/trustee-attester.yml new file mode 100644 index 000000000..a16e042ee --- /dev/null +++ b/.github/workflows/trustee-attester.yml @@ -0,0 +1,93 @@ +name: trustee-attester basic build + +on: + pull_request: + paths: + - 'attestation-agent/**' + - '.github/workflows/trustee-attester.yml' + - 'Cargo.toml' + - 'Cargo.lock' + create: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + trustee_attester_ci: + name: Check + defaults: + run: + working-directory: ./attestation-agent/kbs_protocol/ + strategy: + fail-fast: false + matrix: + rust: + - stable + instance: + - ubuntu-24.04 + - s390x + include: + - instance: ubuntu-24.04 + cargo_test_opts: "-p kbs_protocol --bin trustee-attester --no-default-features --features background_check,passport,openssl,all-attesters,bin" + - instance: s390x + cargo_test_opts: "-p kbs_protocol --bin trustee-attester --no-default-features --features background_check,passport,openssl,se-attester,bin" + runs-on: ${{ matrix.instance }} + steps: + - name: Code checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Install Rust toolchain (${{ matrix.rust }}) + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + components: rustfmt, clippy + + - name: Install protoc + run: | + sudo apt-get update && sudo apt-get install -y protobuf-compiler + + - uses: ./.github/actions/install-intel-dcap + with: + ubuntu-version: noble + if: matrix.instance == 'ubuntu-24.04' + + - name: Install TPM dependencies + run: | + sudo apt-get update + sudo apt-get install -y libtss2-dev + if: matrix.instance == 'ubuntu-24.04' + + - name: Install dm-verity dependencies + run: | + sudo apt-get update + sudo apt-get install -y libdevmapper-dev + + - name: Run cargo build + uses: actions-rs/cargo@v1 + with: + command: build + args: ${{ matrix.cargo_test_opts }} + + - name: Run cargo test + uses: actions-rs/cargo@v1 + with: + command: test + args: ${{ matrix.cargo_test_opts }} + + - name: Run cargo fmt check + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + - name: Run rust clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: ${{ matrix.cargo_test_opts }} diff --git a/attestation-agent/kbs_protocol/Cargo.toml b/attestation-agent/kbs_protocol/Cargo.toml index 5c7cc1ff1..667969a72 100644 --- a/attestation-agent/kbs_protocol/Cargo.toml +++ b/attestation-agent/kbs_protocol/Cargo.toml @@ -10,7 +10,9 @@ anyhow.workspace = true async-trait.workspace = true attester = { path = "../attester", default-features = false } base64.workspace = true +clap = { workspace = true, features = ["derive"], optional = true } crypto = { path = "../deps/crypto", default-features = false } +env_logger = { workspace = true, optional = true } jwt-simple.workspace = true kbs-types.workspace = true log.workspace = true @@ -36,6 +38,10 @@ tokio = { workspace = true, features = [ "rt", "macros", "fs", "process" ]} [build-dependencies] ttrpc-codegen = { workspace = true, optional = true } +[[bin]] +name = "trustee-attester" +required-features = ["bin"] + [features] default = ["background_check", "passport", "rust-crypto", "all-attesters"] @@ -56,3 +62,5 @@ se-attester = ["attester/se-attester"] rust-crypto = ["reqwest/rustls-tls", "crypto/rust-crypto"] openssl = ["reqwest/native-tls-vendored", "crypto/openssl"] + +bin = ["tokio/rt", "tokio/macros", "clap", "env_logger"] diff --git a/attestation-agent/kbs_protocol/src/bin/trustee-attester/README.md b/attestation-agent/kbs_protocol/src/bin/trustee-attester/README.md new file mode 100644 index 000000000..a38b8174d --- /dev/null +++ b/attestation-agent/kbs_protocol/src/bin/trustee-attester/README.md @@ -0,0 +1,33 @@ +# Trustee attester # + +A tool to attest and fetch secrets from Trustee + +Trustee attester 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. + +Trustee attester is using attestation-agent's kbs_protocol client and +attesters to gather hardware-based confidential-computing evidence +and send it over to Trustee. + +A resource with exact same path must be uploaded to Trustee before trustee-attester runs. + + +## Build: ## + +```bash +cargo build -p kbs_protocol --bin trustee-attester --no-default-features +--features "background_check,passport,,bin," +``` + +## Run: ## + +```bash +$ trustee-attester --url [--cert-file ] get-resource --path +``` + +## Example: ## + +```bash +$ trustee-attester --url http://localhost:50000 get-resource --path default/keys/dummy +``` diff --git a/attestation-agent/kbs_protocol/src/bin/trustee-attester/main.rs b/attestation-agent/kbs_protocol/src/bin/trustee-attester/main.rs new file mode 100644 index 000000000..4629e159e --- /dev/null +++ b/attestation-agent/kbs_protocol/src/bin/trustee-attester/main.rs @@ -0,0 +1,90 @@ +// 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 + +//! Attest and fetch confidential resources from Trustee + +use anyhow::Result; +use base64::engine::general_purpose::STANDARD; +use base64::Engine; +use clap::{Parser, Subcommand}; +use log::debug; +use std::fs; +use std::path::PathBuf; + +use kbs_protocol::evidence_provider::NativeEvidenceProvider; +use kbs_protocol::KbsClientBuilder; +use kbs_protocol::KbsClientCapabilities; +use kbs_protocol::ResourceUri; + +#[derive(Parser)] +struct Cli { + /// Trustee URL of format ://: + #[clap(long, value_parser)] + url: String, + + /// Trustee https certificate file path (PEM format) + #[clap(long, value_parser)] + cert_file: Option, + + #[clap(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Get confidential resource + #[clap(arg_required_else_help = true)] + GetResource { + /// KBS Resource path of format // + /// Document: https://github.com/confidential-containers/guest-components/blob/main/attestation-agent/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 url = cli.url; + let cert_file = cli.cert_file; + + debug!("url {}", url); + debug!("cert_file {:?}", cert_file); + + // Native evidence provider + let evidence_provider = Box::new(NativeEvidenceProvider::new()?); + + // 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(cf) = cert_file { + debug!("Reading certificate from cert_file {}", cf.display()); + let cert = fs::read_to_string(cf)?; + client_builder = client_builder.add_kbs_cert(&cert) + } + + // Build the client. This client is used throughout the program + let mut client = client_builder.build()?; + + match cli.command { + Commands::GetResource { path } => { + // resource_path should start with '/' but not with '//' + let resource_path = match path.starts_with('/') { + false => format!("/{}", path), + true => path, + }; + let resource = ResourceUri::new("", &resource_path)?; + let resource_bytes = client.get_resource(resource).await?; + + println!("{}", STANDARD.encode(resource_bytes)); + } + }; + + Ok(()) +}