Skip to content

Commit d027156

Browse files
committed
rofl-containers: Add support for persistent storage
1 parent a0508eb commit d027156

File tree

9 files changed

+329
-21
lines changed

9 files changed

+329
-21
lines changed

Cargo.lock

Lines changed: 94 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rofl-appd/src/lib.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! REST API daemon accessible by ROFL apps.
22
33
mod routes;
4-
pub(crate) mod services;
4+
pub mod services;
55
pub(crate) mod state;
66

77
use std::sync::Arc;
@@ -10,26 +10,29 @@ use rocket::{figment::Figment, routes};
1010

1111
use oasis_runtime_sdk::modules::rofl::app::{App, Environment};
1212

13+
/// API server configuration.
14+
#[derive(Clone)]
15+
pub struct Config<'a> {
16+
/// Address where the service should listen on.
17+
pub address: &'a str,
18+
/// Key management service to use.
19+
pub kms: Arc<dyn services::kms::KmsService>,
20+
}
21+
1322
/// Start the REST API server.
14-
pub async fn start<A>(address: &str, env: Environment<A>) -> Result<(), rocket::Error>
23+
pub async fn start<A>(cfg: Config<'_>, env: Environment<A>) -> Result<(), rocket::Error>
1524
where
1625
A: App,
1726
{
18-
// KMS service.
19-
let kms_service: Arc<dyn services::kms::KmsService> =
20-
Arc::new(services::kms::OasisKmsService::new(env.clone()));
21-
let kms_service_task = kms_service.clone();
22-
tokio::spawn(async move { kms_service_task.start().await });
23-
2427
// Oasis runtime environment.
2528
let env: Arc<dyn state::Env> = Arc::new(state::EnvImpl::new(env));
2629

2730
// Server configuration.
28-
let cfg = Figment::new().join(("address", address));
31+
let rocket_cfg = Figment::new().join(("address", cfg.address));
2932

30-
rocket::custom(cfg)
33+
rocket::custom(rocket_cfg)
3134
.manage(env)
32-
.manage(kms_service)
35+
.manage(cfg.kms)
3336
.mount("/rofl/v1/app", routes![routes::app::id,])
3437
.mount("/rofl/v1/keys", routes![routes::keys::generate,])
3538
.launch()

rofl-appd/src/services/kms.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::sync::{
44
};
55

66
use sp800_185::KMac;
7+
use tokio::sync::Notify;
78

89
use oasis_runtime_sdk::{
910
core::common::logger::get_logger,
@@ -17,6 +18,9 @@ pub trait KmsService: Send + Sync {
1718
/// Start the KMS service.
1819
async fn start(&self) -> Result<(), Error>;
1920

21+
/// Waits for the service to become ready to accept requests.
22+
async fn wait_ready(&self) -> Result<(), Error>;
23+
2024
/// Generate a key based on the passed parameters.
2125
async fn generate(&self, request: &GenerateRequest<'_>) -> Result<GenerateResponse, Error>;
2226
}
@@ -94,6 +98,7 @@ pub struct OasisKmsService<A: App> {
9498
root_key: Arc<Mutex<Option<Vec<u8>>>>,
9599
env: Environment<A>,
96100
logger: slog::Logger,
101+
ready_notify: Notify,
97102
}
98103

99104
impl<A: App> OasisKmsService<A> {
@@ -103,6 +108,7 @@ impl<A: App> OasisKmsService<A> {
103108
root_key: Arc::new(Mutex::new(None)),
104109
env,
105110
logger: get_logger("appd/services/kms"),
111+
ready_notify: Notify::new(),
106112
}
107113
}
108114
}
@@ -146,11 +152,25 @@ impl<A: App> KmsService for OasisKmsService<A> {
146152
// Store the key in memory.
147153
*self.root_key.lock().unwrap() = Some(root_key.key);
148154

155+
self.ready_notify.notify_waiters();
156+
149157
slog::info!(self.logger, "KMS service initialized");
150158

151159
Ok(())
152160
}
153161

162+
async fn wait_ready(&self) -> Result<(), Error> {
163+
let handle = self.ready_notify.notified();
164+
165+
if self.root_key.lock().unwrap().is_some() {
166+
return Ok(());
167+
}
168+
169+
handle.await;
170+
171+
Ok(())
172+
}
173+
154174
async fn generate(&self, request: &GenerateRequest<'_>) -> Result<GenerateResponse, Error> {
155175
let root_key_guard = self.root_key.lock().unwrap();
156176
let root_key = root_key_guard.as_ref().ok_or(Error::NotInitialized)?;
@@ -173,6 +193,10 @@ impl KmsService for MockKmsService {
173193
Ok(())
174194
}
175195

196+
async fn wait_ready(&self) -> Result<(), Error> {
197+
Ok(())
198+
}
199+
176200
async fn generate(&self, request: &GenerateRequest<'_>) -> Result<GenerateResponse, Error> {
177201
let key = Kdf::derive_key(
178202
INSECURE_MOCK_ROOT_KEY,

rofl-containers/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rofl-containers"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
edition = "2021"
55

66
[dependencies]
@@ -9,4 +9,9 @@ oasis-runtime-sdk = { path = "../runtime-sdk", features = ["tdx"] }
99
rofl-appd = { path = "../rofl-appd" }
1010

1111
# Third party.
12+
anyhow = "1.0.86"
1213
base64 = "0.22.1"
14+
cmd_lib = "1.9.5"
15+
hex = "0.4.3"
16+
nix = { version = "0.29.0", features = ["signal"] }
17+
tokio = { version = "1.38", features = ["rt", "rt-multi-thread", "sync", "time", "macros"] }

rofl-containers/src/main.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,15 @@
1111
use std::env;
1212

1313
use base64::prelude::*;
14-
use oasis_runtime_sdk::{cbor, modules::rofl::app::prelude::*};
14+
use oasis_runtime_sdk::{
15+
cbor,
16+
core::common::{logger::get_logger, process},
17+
modules::rofl::app::prelude::*,
18+
};
19+
use rofl_appd::services;
20+
21+
mod reaper;
22+
mod storage;
1523

1624
/// UNIX socket address where the REST API server will listen on.
1725
const ROFL_APPD_ADDRESS: &str = "unix:/run/rofl-appd.sock";
@@ -42,12 +50,39 @@ impl App for ContainersApp {
4250
.expect("Corrupted ROFL_CONSENSUS_TRUST_ROOT (must be Base64-encoded CBOR).")
4351
}
4452

45-
async fn run(self: Arc<Self>, env: Environment<Self>) {
53+
async fn post_registration_init(self: Arc<Self>, env: Environment<Self>) {
54+
// Temporarily disable the default process reaper as it interferes with scripts.
55+
let _guard = reaper::disable_default_reaper();
56+
let logger = get_logger("post_registration_init");
57+
58+
// Start the key management service and wait for it to initialize.
59+
let kms: Arc<dyn services::kms::KmsService> =
60+
Arc::new(services::kms::OasisKmsService::new(env.clone()));
61+
let kms_task = kms.clone();
62+
tokio::spawn(async move { kms_task.start().await });
63+
let _ = kms.wait_ready().await;
64+
65+
// Initialize storage when configured in the kernel cmdline.
66+
if let Err(err) = storage::init(kms.clone()).await {
67+
slog::error!(logger, "failed to initialize stage 2 storage"; "err" => ?err);
68+
process::abort();
69+
}
70+
4671
// Start the REST API server.
47-
let _ = rofl_appd::start(ROFL_APPD_ADDRESS, env).await;
72+
let cfg = rofl_appd::Config {
73+
address: ROFL_APPD_ADDRESS,
74+
kms,
75+
};
76+
let _ = rofl_appd::start(cfg, env).await;
4877
}
4978
}
5079

5180
fn main() {
81+
// Configure the binary search path.
82+
// SAFETY: This is safe as no other threads are running yet.
83+
unsafe {
84+
env::set_var("PATH", "/usr/sbin:/usr/bin:/sbin:/bin");
85+
}
86+
5287
ContainersApp.start();
5388
}

rofl-containers/src/reaper.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal};
2+
3+
/// Guard that re-enables the default process reaper when dropped.
4+
pub struct DisableReaperGuard {
5+
_internal: (),
6+
}
7+
8+
impl Drop for DisableReaperGuard {
9+
fn drop(&mut self) {
10+
// Re-enable default kernel process reaper.
11+
unsafe {
12+
let _ = sigaction(
13+
Signal::SIGCHLD,
14+
&SigAction::new(SigHandler::SigIgn, SaFlags::empty(), SigSet::empty()),
15+
);
16+
}
17+
}
18+
}
19+
20+
/// Temporarily disables the default process reaper. When the returned guard gets out of scope, the
21+
/// default reaper is re-enabled.
22+
///
23+
/// This assumes that the default reaper has been previously configured by core init.
24+
pub fn disable_default_reaper() -> DisableReaperGuard {
25+
unsafe {
26+
let _ = sigaction(
27+
Signal::SIGCHLD,
28+
&SigAction::new(SigHandler::SigDfl, SaFlags::empty(), SigSet::empty()),
29+
);
30+
}
31+
32+
DisableReaperGuard { _internal: () }
33+
}

0 commit comments

Comments
 (0)