diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 53bd89bc..1a1e28fb 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -73,6 +73,7 @@ jobs: - { nixpackage: 'container-self-attestation-test-sgx-azure' } - { nixpackage: 'container-verify-attestation-sgx' } - { nixpackage: 'container-verify-era-proof-attestation-sgx' } + - { nixpackage: 'container-test-tdx' } steps: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@v30 diff --git a/Cargo.lock b/Cargo.lock index b770552e..2d4b5b5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -337,9 +337,9 @@ checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "argon2" @@ -1927,8 +1927,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -1999,6 +2001,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "google-metadata" +version = "0.3.0" +dependencies = [ + "anyhow", + "reqwest 0.12.9", + "reqwest-middleware", + "reqwest-retry", + "serde_json", + "tokio", +] + [[package]] name = "gpt" version = "4.0.0" @@ -2596,6 +2610,18 @@ dependencies = [ "generic-array", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "intel-tee-quote-verification-sys" version = "0.2.1" @@ -3575,6 +3601,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -3582,7 +3619,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -3593,7 +3644,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.8", "smallvec", "windows-targets 0.52.6", ] @@ -3905,7 +3956,7 @@ checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", - "parking_lot", + "parking_lot 0.12.3", "prometheus-client-derive-encode", ] @@ -4099,6 +4150,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.8" @@ -4242,6 +4302,52 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "reqwest-middleware" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1ccd3b55e711f91a9885a2fa6fbbb2e39db1776420b062efc058c6410f7e5e3" +dependencies = [ + "anyhow", + "async-trait", + "http 1.2.0", + "reqwest 0.12.9", + "serde", + "thiserror", + "tower-service", +] + +[[package]] +name = "reqwest-retry" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c73e4195a6bfbcb174b790d9b3407ab90646976c55de58a6515da25d851178" +dependencies = [ + "anyhow", + "async-trait", + "futures", + "getrandom", + "http 1.2.0", + "hyper 1.5.2", + "parking_lot 0.11.2", + "reqwest 0.12.9", + "reqwest-middleware", + "retry-policies", + "thiserror", + "tokio", + "tracing", + "wasm-timer", +] + +[[package]] +name = "retry-policies" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5875471e6cab2871bc150ecb8c727db5113c9338cc3354dc5ee3425b6aa40a1c" +dependencies = [ + "rand", +] + [[package]] name = "rfc6979" version = "0.3.1" @@ -5543,7 +5649,7 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", @@ -6200,6 +6306,21 @@ version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.76" diff --git a/assets/config.json b/assets/config.json new file mode 100644 index 00000000..a69a474a --- /dev/null +++ b/assets/config.json @@ -0,0 +1,4 @@ +{ + "foo": "bar", + "bar": "baz" +} diff --git a/assets/gcloud-deploy.sh b/assets/gcloud-deploy.sh index b2f8a226..7eeaa06a 100755 --- a/assets/gcloud-deploy.sh +++ b/assets/gcloud-deploy.sh @@ -7,8 +7,12 @@ set -ex +BASE_DIR=${0%/*} + NO=${NO:-1} +ZONE=${ZONE:-us-central1-c} + nix build -L .#tdx_google gsutil cp result/tdx_base_1.vmdk gs://tdx_vms/ @@ -21,8 +25,8 @@ gcloud migration vms image-imports create \ --source-file=gs://tdx_vms/tdx_base_1.vmdk \ tdx-img-pre-"${NO}" -gcloud compute instances stop tdx-pilot --zone us-central1-c --project tdx-pilot || : -gcloud compute instances delete tdx-pilot --zone us-central1-c --project tdx-pilot || : +gcloud compute instances stop tdx-pilot --zone ${ZONE} --project tdx-pilot || : +gcloud compute instances delete tdx-pilot --zone ${ZONE} --project tdx-pilot || : while gcloud migration vms image-imports list --location=us-central1 --project=tdx-pilot | grep -F RUNNING; do sleep 1 @@ -36,10 +40,11 @@ gcloud compute images create \ tdx-img-f-"${NO}" gcloud compute instances create tdx-pilot \ - --machine-type c3-standard-4 --zone us-central1-c \ + --machine-type c3-standard-4 --zone ${ZONE} \ --confidential-compute-type=TDX \ --maintenance-policy=TERMINATE \ --image-project=tdx-pilot \ --project tdx-pilot \ - --metadata=container_hub="docker.io",container_image="amd64/hello-world@sha256:e2fc4e5012d16e7fe466f5291c476431beaa1f9b90a5c2125b493ed28e2aba57" \ + --metadata=container_hub="docker.io",container_image="matterlabsrobot/test-tdx:117p5y281limw0w7b03v802ij00c5gzw" \ + --metadata-from-file=container_config=$BASE_DIR/config.json \ --image tdx-img-f-"${NO}" diff --git a/bin/google-metadata/Cargo.toml b/bin/google-metadata/Cargo.toml new file mode 100644 index 00000000..e51aba6d --- /dev/null +++ b/bin/google-metadata/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "google-metadata" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true + +[dependencies] +anyhow.workspace = true +reqwest.workspace = true +serde_json.workspace = true +tokio.workspace = true +reqwest-middleware = "0.4.0" +reqwest-retry = "0.7.0" diff --git a/bin/google-metadata/src/main.rs b/bin/google-metadata/src/main.rs new file mode 100644 index 00000000..33bdc66f --- /dev/null +++ b/bin/google-metadata/src/main.rs @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2025 Matter Labs + +use anyhow::{bail, Result}; +use reqwest::Client; +use reqwest_middleware::{ClientBuilder, ClientWithMiddleware}; +use reqwest_retry::{policies::ExponentialBackoff, Jitter, RetryTransientMiddleware}; +use serde_json::Value; +use std::time::Duration; + +const DEFAULT_INSTANCE_METADATA_BASE_URL: &str = + "http://metadata.google.internal/computeMetadata/v1/instance/attributes"; + +async fn fetch_gcp_metadata( + http_client: &ClientWithMiddleware, + metadata_key: &str, +) -> Result { + // Validate the metadata key: + if metadata_key.is_empty() { + bail!("Empty metadata_key"); + } + + let url = format!("{DEFAULT_INSTANCE_METADATA_BASE_URL}/{metadata_key}"); + + // Make an HTTP GET request: + let response = http_client + .get(url) + .header("Metadata-Flavor", "Google") + .send() + .await?; + + // Handle response: + if response.status().is_success() { + let metadata_text = response.text().await?; + serde_json::from_str(&metadata_text) + .map_err(|e| anyhow::format_err!("Failed to parse metadata JSON: {}", e)) + } else { + let status = response.status(); + let error_body = response + .text() + .await + .unwrap_or_else(|_| "".to_string()); + bail!( + "Failed to fetch metadata: {}, Response body: {}", + status, + error_body + ); + } +} + +#[tokio::main] +async fn main() -> Result<()> { + // Build the client with retry middleware and exponential backoff: + let retry_policy = ExponentialBackoff::builder() + .retry_bounds(Duration::from_secs(1), Duration::from_secs(32)) + .jitter(Jitter::Bounded) + .base(2) + .build_with_total_retry_duration(Duration::from_secs(60)); + let client = ClientBuilder::new(Client::builder().build()?) // Underlying reqwest client + .with(RetryTransientMiddleware::new_with_policy(retry_policy)) // Add retry middleware + .build(); + + // Fetch and display metadata: + match fetch_gcp_metadata(&client, "container_config").await { + Ok(container_config) => { + println!("Container config:\n{:#?}", container_config); + } + Err(e) => { + eprintln!("Error fetching container config: {}", e); + } + } + + Ok(()) +} diff --git a/checks/cargoClippy/default.nix b/checks/cargoClippy/default.nix new file mode 100644 index 00000000..2b16ef74 --- /dev/null +++ b/checks/cargoClippy/default.nix @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Matter Labs +{ teepot }: teepot.teepot.passthru.craneLib.cargoClippy ( + teepot.teepot.passthru.commonArgs // { + pname = "teepot"; + inherit (teepot.teepot.passthru) cargoArtifacts; + } +) diff --git a/packages/cargoFmt/default.nix b/checks/cargoDeny/default.nix similarity index 50% rename from packages/cargoFmt/default.nix rename to checks/cargoDeny/default.nix index cc8e631c..7f3cb736 100644 --- a/packages/cargoFmt/default.nix +++ b/checks/cargoDeny/default.nix @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs -{ teepotCrate }: teepotCrate.craneLib.cargoFmt ( - teepotCrate.commonArgs // { +{ teepot }: teepot.teepot.passthru.craneLib.cargoDeny ( + teepot.teepot.passthru.commonArgs // { pname = "teepot"; } ) diff --git a/packages/cargoDeny/default.nix b/checks/cargoFmt/default.nix similarity index 50% rename from packages/cargoDeny/default.nix rename to checks/cargoFmt/default.nix index e4c400a0..4f60a7f8 100644 --- a/packages/cargoDeny/default.nix +++ b/checks/cargoFmt/default.nix @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs -{ teepotCrate }: teepotCrate.craneLib.cargoDeny ( - teepotCrate.commonArgs // { +{ teepot }: teepot.teepot.passthru.craneLib.cargoFmt ( + teepot.teepot.passthru.commonArgs // { pname = "teepot"; } ) diff --git a/flake.nix b/flake.nix index 0512524a..d4c56edb 100644 --- a/flake.nix +++ b/flake.nix @@ -25,12 +25,9 @@ }; outputs = inputs: - let - src = ./.; - in inputs.snowfall-lib.mkFlake { inherit inputs; - inherit src; + src = ./.; snowfall.namespace = "teepot"; @@ -42,8 +39,6 @@ nixsgx-flake.overlays.default vault-auth-tee-flake.overlays.default rust-overlay.overlays.default - # somehow the original `src` is not available anymore - (final: prev: { teepotCrate = prev.pkgs.callPackage ./teepot-crate.nix { inherit inputs; inherit src; }; }) ]; alias = { @@ -59,16 +54,7 @@ }; outputs-builder = channels: { - formatter = channels.nixpkgs.nixpkgs-fmt; - - checks = { - inherit - (channels.nixpkgs.teepot) cargoFmt; - inherit - (channels.nixpkgs.teepot) cargoClippy; - inherit - (channels.nixpkgs.teepot) cargoDeny; - }; + formatter = channels.nixpkgs.nixfmt-rfc-style; }; }; } diff --git a/packages/cargoClippy/default.nix b/packages/cargoClippy/default.nix deleted file mode 100644 index f356dce1..00000000 --- a/packages/cargoClippy/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# Copyright (c) 2024 Matter Labs -{ teepotCrate }: teepotCrate.craneLib.cargoClippy ( - teepotCrate.commonArgs // { - pname = "teepot"; - inherit (teepotCrate) cargoArtifacts; - } -) diff --git a/packages/container-test-tdx/default.nix b/packages/container-test-tdx/default.nix new file mode 100644 index 00000000..fd32c492 --- /dev/null +++ b/packages/container-test-tdx/default.nix @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Matter Labs +{ dockerTools +, buildEnv +, teepot +}: +dockerTools.buildLayeredImage { + name = "test-tdx"; + + config.Entrypoint = [ "${teepot.teepot.google_metadata}/bin/google-metadata" ]; + config.Env = [ "LD_LIBRARY_PATH=/lib" ]; + contents = buildEnv { + name = "image-root"; + + paths = with dockerTools;[ + teepot.teepot.google_metadata + usrBinEnv + binSh + caCertificates + fakeNss + ]; + pathsToLink = [ "/bin" "/lib" "/etc" "/share" ]; + }; +} diff --git a/packages/teepot/default.nix b/packages/teepot/default.nix index 0879e7ed..1ab79823 100644 --- a/packages/teepot/default.nix +++ b/packages/teepot/default.nix @@ -1,6 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2024 Matter Labs -{ lib, pkgs, makeWrapper, teepotCrate }: teepotCrate.craneLib.buildPackage ( +{ lib, pkgs, makeWrapper, teepot }: +let teepotCrate = teepot.teepotCrate; in +teepotCrate.craneLib.buildPackage ( teepotCrate.commonArgs // { pname = "teepot"; inherit (teepotCrate) cargoArtifacts; @@ -17,6 +19,7 @@ outputs = [ "out" + "google_metadata" "rtmr_calc" "sha384_extend" "tdx_extend" diff --git a/teepot-crate.nix b/packages/teepotCrate/default.nix similarity index 67% rename from teepot-crate.nix rename to packages/teepotCrate/default.nix index 4b59a634..29dd051a 100644 --- a/teepot-crate.nix +++ b/packages/teepotCrate/default.nix @@ -7,11 +7,10 @@ , pkg-config , rust-bin , pkgs -, src , openssl }: let - rustVersion = rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + rustVersion = rust-bin.fromRustupToolchainFile (inputs.src + "/rust-toolchain.toml"); rustPlatform = makeRustPlatform { cargo = rustVersion; rustc = rustVersion; @@ -34,15 +33,15 @@ let strictDeps = true; src = with lib.fileset; toSource { - root = src; + root = inputs.src; fileset = unions [ - ./Cargo.lock - ./Cargo.toml - ./bin - ./crates - ./rust-toolchain.toml - ./deny.toml - ./taplo.toml + # Default files from crane (Rust and cargo files) + (craneLib.fileset.commonCargoSources inputs.src) + (fileFilter (file: file.hasExt "hcl") (inputs.src + "/bin")) + # deny.toml and friends + (fileFilter (file: file.hasExt "toml") inputs.src) + # Custom test data files + (maybeMissing (inputs.src + "/crates/teepot/tests/data")) ]; }; diff --git a/shells/teepot/default.nix b/shells/teepot/default.nix index 67bedf6a..a8e3195b 100644 --- a/shells/teepot/default.nix +++ b/shells/teepot/default.nix @@ -6,10 +6,9 @@ , teepot , nixsgx , stdenv -, teepotCrate }: let - toolchain_with_src = (teepotCrate.rustVersion.override { + toolchain_with_src = (teepot.teepot.passthru.rustVersion.override { extensions = [ "rustfmt" "clippy" "rust-src" ]; }); in @@ -19,7 +18,7 @@ mkShell { nativeBuildInputs = with pkgs; [ toolchain_with_src pkg-config - teepotCrate.rustPlatform.bindgenHook + teepot.teepot.passthru.rustPlatform.bindgenHook ]; packages = with pkgs; [