From dadb2905f2170413d46f71ce90fb86efba8cfa8c Mon Sep 17 00:00:00 2001 From: Jernej Kos Date: Wed, 22 Jan 2025 07:54:52 +0100 Subject: [PATCH 1/3] runtime-sdk/modules/rofl: Add per-instance metadata --- runtime-sdk/src/modules/rofl/app/mod.rs | 16 +++++++++++++++- runtime-sdk/src/modules/rofl/app/registration.rs | 10 ++++++++++ runtime-sdk/src/modules/rofl/mod.rs | 1 + runtime-sdk/src/modules/rofl/types.rs | 6 ++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/runtime-sdk/src/modules/rofl/app/mod.rs b/runtime-sdk/src/modules/rofl/app/mod.rs index ef7e7b05c6..ec57ab5c71 100644 --- a/runtime-sdk/src/modules/rofl/app/mod.rs +++ b/runtime-sdk/src/modules/rofl/app/mod.rs @@ -1,5 +1,5 @@ //! Wrapper to make development of ROFL components easier. -use std::sync::Arc; +use std::{collections::BTreeMap, sync::Arc}; use anyhow::Result; use async_trait::async_trait; @@ -74,6 +74,20 @@ pub trait App: Send + Sync + 'static { tx } + /// Fetches custom app instance metadata that is included in its on-chain registration. + /// + /// This method is called before each registration refresh. Returning an error will not block + /// registration, rather it will result in the metadata being cleared. + async fn get_metadata( + self: Arc, + env: Environment, + ) -> Result> + where + Self: Sized, + { + Ok(BTreeMap::new()) + } + /// Custom post-registration initialization. It runs before any image-specific scripts are /// called by the runtime so it can be used to do things like set up custom storage after /// successful registration. diff --git a/runtime-sdk/src/modules/rofl/app/registration.rs b/runtime-sdk/src/modules/rofl/app/registration.rs index 973dbf1ce7..8b86120007 100644 --- a/runtime-sdk/src/modules/rofl/app/registration.rs +++ b/runtime-sdk/src/modules/rofl/app/registration.rs @@ -107,6 +107,15 @@ where "epoch" => epoch, ); + let metadata = match self.state.app.clone().get_metadata(self.env.clone()).await { + Ok(metadata) => metadata, + Err(err) => { + slog::error!(self.logger, "failed to get instance metadata"; "err" => ?err); + // Do not prevent registration, just clear metadata. + Default::default() + } + }; + // Refresh registration. let ect = self .state @@ -118,6 +127,7 @@ where ect, expiration: epoch + 2, extra_keys: vec![self.env.signer().public_key()], + metadata, }; let tx = self.state.app.new_transaction("rofl.Register", register); diff --git a/runtime-sdk/src/modules/rofl/mod.rs b/runtime-sdk/src/modules/rofl/mod.rs index ea8e2d806a..35a9b7b01a 100644 --- a/runtime-sdk/src/modules/rofl/mod.rs +++ b/runtime-sdk/src/modules/rofl/mod.rs @@ -372,6 +372,7 @@ impl Module { rek: body.ect.capability_tee.rek.ok_or(Error::InvalidArgument)?, // REK required. expiration: body.expiration, extra_keys: body.extra_keys, + metadata: body.metadata, }; state::update_registration(registration)?; diff --git a/runtime-sdk/src/modules/rofl/types.rs b/runtime-sdk/src/modules/rofl/types.rs index 3baebf80fd..4e69d7c224 100644 --- a/runtime-sdk/src/modules/rofl/types.rs +++ b/runtime-sdk/src/modules/rofl/types.rs @@ -100,6 +100,9 @@ pub struct Register { /// /// All of these keys need to co-sign the registration transaction to prove ownership. pub extra_keys: Vec, + /// Arbitrary app-specific metadata. + #[cbor(optional)] + pub metadata: BTreeMap, } /// Kind of key for derivation. @@ -151,6 +154,9 @@ pub struct Registration { pub expiration: EpochTime, /// Extra public keys to endorse (e.g. secp256k1 keys). pub extra_keys: Vec, + /// Arbitrary app-specific metadata. + #[cbor(optional)] + pub metadata: BTreeMap, } /// Application-related query. From cf4cb4ae1679e408728fa3dc40ecee7c3c95127e Mon Sep 17 00:00:00 2001 From: Jernej Kos Date: Wed, 22 Jan 2025 07:55:25 +0100 Subject: [PATCH 2/3] rofl-containers: Also expose secrets via env file --- Cargo.lock | 2 +- rofl-containers/Cargo.toml | 2 +- rofl-containers/src/containers.rs | 2 +- rofl-containers/src/secrets.rs | 20 +++++++++++++++++++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9e0b157b0e..55c23a86b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3974,7 +3974,7 @@ dependencies = [ [[package]] name = "rofl-containers" -version = "0.3.0" +version = "0.3.1" dependencies = [ "anyhow", "base64", diff --git a/rofl-containers/Cargo.toml b/rofl-containers/Cargo.toml index 58a23b3ef0..db4a9797c1 100644 --- a/rofl-containers/Cargo.toml +++ b/rofl-containers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rofl-containers" -version = "0.3.0" +version = "0.3.1" edition = "2021" [dependencies] diff --git a/rofl-containers/src/containers.rs b/rofl-containers/src/containers.rs index 664ccf06ec..73dda63a18 100644 --- a/rofl-containers/src/containers.rs +++ b/rofl-containers/src/containers.rs @@ -45,7 +45,7 @@ pub async fn start() -> Result<()> { // Bring containers up. run_cmd!( cd "/etc/oasis/containers"; - podman-compose up --detach --remove-orphans --force-recreate; + podman-compose --env-file "/run/podman/secrets.env" up --detach --remove-orphans --force-recreate; )?; Ok(()) diff --git a/rofl-containers/src/secrets.rs b/rofl-containers/src/secrets.rs index 15388c7322..20cb94089b 100644 --- a/rofl-containers/src/secrets.rs +++ b/rofl-containers/src/secrets.rs @@ -1,4 +1,9 @@ -use std::sync::Arc; +use std::{ + collections::BTreeSet, + fs::{self, File}, + io::Write, + sync::Arc, +}; use anyhow::Result; use cmd_lib::run_cmd; @@ -16,9 +21,14 @@ pub async fn init( // Query own app cfg to get encrypted secrets. let encrypted_secrets = env.client().app_cfg().await?.secrets; + // Also generate secrets in an environment file. + fs::create_dir_all("/run/podman")?; + let mut secrets_env = File::create("/run/podman/secrets.env")?; + // Ensure all secrets are removed. run_cmd!(podman secret rm --all)?; // Create all requested secrets. + let mut existing_env_vars = BTreeSet::new(); for (pub_name, value) in encrypted_secrets { // Decrypt and authenticate secret. In case of failures, the secret is skipped. let (name, value) = match kms @@ -33,10 +43,18 @@ pub async fn init( }; // Assume the name and value are always valid strings. let name = String::from_utf8_lossy(&name); + let name_upper = name.to_uppercase().replace(" ", "_"); let value = String::from_utf8_lossy(&value); + // Create a new Podman secret in temporary storage on /run to avoid it being persisted. let _ = run_cmd!(echo -n $value | podman secret create --driver-opts file=/run/podman/secrets --replace $name -); + // Also store in the secrets environment file. + if !existing_env_vars.contains(&name_upper) { + writeln!(&mut secrets_env, "{name_upper}={value}")?; + existing_env_vars.insert(name_upper); + } + slog::info!(logger, "provisioned secret"; "pub_name" => pub_name); } Ok(()) From f02e8c3aea5241ec7f296750751017cf39292538 Mon Sep 17 00:00:00 2001 From: Jernej Kos Date: Wed, 22 Jan 2025 11:53:38 +0100 Subject: [PATCH 3/3] rofl-containers: Show container logs --- rofl-containers/src/containers.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/rofl-containers/src/containers.rs b/rofl-containers/src/containers.rs index 73dda63a18..3bd8276662 100644 --- a/rofl-containers/src/containers.rs +++ b/rofl-containers/src/containers.rs @@ -1,3 +1,5 @@ +use std::{process::Command, time::SystemTime}; + use anyhow::Result; use cmd_lib::run_cmd; @@ -48,5 +50,14 @@ pub async fn start() -> Result<()> { podman-compose --env-file "/run/podman/secrets.env" up --detach --remove-orphans --force-recreate; )?; + // Follow container logs. + let now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH)? + .as_secs(); + Command::new("podman-compose") + .args(["logs", "--follow", "--since", &format!("{}", now)]) + .current_dir("/etc/oasis/containers") + .spawn()?; + Ok(()) }