Skip to content
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

tappd: Support for optional logs/sysinfo API #55

Merged
merged 3 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion basefiles/tappd.service
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[Unit]
Description=Tappd Service
After=network.target
After=network.target tboot.service

[Service]
ExecStartPre=-/bin/rm -f /var/run/tappd.sock
Expand Down
2 changes: 2 additions & 0 deletions tappd/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ pub fn load_config_figment(config_file: Option<&str>) -> Figment {
pub struct Config {
pub cert_file: String,
pub key_file: String,
pub public_logs: bool,
pub public_sysinfo: bool,
}
12 changes: 10 additions & 2 deletions tappd/src/http_routes.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::config::Config;
use crate::guest_api_service::{list_containers, GuestApiHandler};
use crate::rpc_service::{AppState, ExternalRpcHandler, InternalRpcHandler};
use anyhow::Result;
Expand Down Expand Up @@ -66,6 +67,7 @@ async fn index(state: &State<AppState>) -> Result<RawHtml<String>, String> {
let context = CallContext::builder().state(&**state).build();
let handler = ExternalRpcHandler::construct(context.clone())
.map_err(|e| format!("Failed to construct RPC handler: {}", e))?;
let config = state.config();
let WorkerInfo {
app_id,
instance_id,
Expand All @@ -88,6 +90,8 @@ async fn index(state: &State<AppState>) -> Result<RawHtml<String>, String> {
tcb_info,
containers,
system_info,
public_sysinfo: config.public_sysinfo,
public_logs: config.public_logs,
};
match model.render() {
Ok(html) => Ok(RawHtml(html)),
Expand Down Expand Up @@ -184,8 +188,12 @@ fn get_logs(
}
}

pub fn external_routes() -> Vec<Route> {
routes![index, external_prpc_post, external_prpc_get, get_logs]
pub fn external_routes(config: &Config) -> Vec<Route> {
let mut routes = routes![index, external_prpc_post, external_prpc_get];
if config.public_logs {
routes.extend(routes![get_logs]);
}
routes
}

mod docker_logs {
Expand Down
2 changes: 1 addition & 1 deletion tappd/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ async fn run_internal(state: AppState, figment: Figment) -> Result<()> {

async fn run_external(state: AppState, figment: Figment) -> Result<()> {
let rocket = rocket::custom(figment)
.mount("/", http_routes::external_routes())
.mount("/", http_routes::external_routes(state.config()))
.attach(AdHoc::on_response("Add app version header", |_req, res| {
Box::pin(async move {
res.set_raw_header("X-App-Version", app_version());
Expand Down
2 changes: 2 additions & 0 deletions tappd/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ pub struct Dashboard {
pub tcb_info: String,
pub containers: Vec<Container>,
pub system_info: SystemInfo,
pub public_sysinfo: bool,
pub public_logs: bool,
}
7 changes: 6 additions & 1 deletion tappd/src/rpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub struct AppState {
}

struct AppStateInner {
config: Config,
ca: CaCert,
}

Expand All @@ -32,9 +33,13 @@ impl AppState {
let ca = CaCert::load(&config.cert_file, &config.key_file)
.context("Failed to load CA certificate")?;
Ok(Self {
inner: Arc::new(AppStateInner { ca }),
inner: Arc::new(AppStateInner { config, ca }),
})
}

pub fn config(&self) -> &Config {
&self.inner.config
}
}

pub struct InternalRpcHandler {
Expand Down
2 changes: 2 additions & 0 deletions tappd/tappd.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ log_level = "debug"
[default.core]
cert_file = "/etc/tappd/app-ca.cert"
key_file = "/etc/tappd/app-ca.key"
public_logs = false
public_sysinfo = false

[internal]
address = "unix:/var/run/tappd.sock"
Expand Down
18 changes: 14 additions & 4 deletions tappd/templates/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ <h2>System Information</h2>
<div class="info-label">Instance ID</div>
<div class="info-value">{{instance_id}}</div>
</div>
{% if public_sysinfo %}
<div class="info-row">
<div class="info-label">Operating System</div>
<div class="info-value">{{system_info.os_name}} {{system_info.os_version}}</div>
Expand All @@ -163,17 +164,20 @@ <h2>System Information</h2>
</div>
<div class="info-row">
<div class="info-label">Memory Usage</div>
<div class="info-value">Used: {{system_info.used_memory|hsize}} / Total: {{system_info.total_memory|hsize}}
<div class="info-value">Used: {{system_info.used_memory|hsize}} / Total:
{{system_info.total_memory|hsize}}
(Available: {{system_info.available_memory|hsize}})</div>
</div>
<div class="info-row">
<div class="info-label">Swap Usage</div>
<div class="info-value">Used: {{system_info.used_swap|hsize}} / Total: {{system_info.total_swap|hsize}} (Free:
<div class="info-value">Used: {{system_info.used_swap|hsize}} / Total: {{system_info.total_swap|hsize}}
(Free:
{{system_info.free_swap|hsize}})</div>
</div>
<div class="info-row">
<div class="info-label">Load Average</div>
<div class="info-value">1min: {{system_info.loadavg_one as f32 / 100.0}}%, 5min: {{system_info.loadavg_five as f32 / 100.0}}%, 15min:
<div class="info-value">1min: {{system_info.loadavg_one as f32 / 100.0}}%, 5min:
{{system_info.loadavg_five as f32 / 100.0}}%, 15min:
{{system_info.loadavg_fifteen as f32 / 100.0}}%</div>
</div>
<div class="info-row">
Expand All @@ -186,6 +190,7 @@ <h2>System Information</h2>
<div class="info-value">Free: {{disk.free_size|hsize}} / Total: {{disk.total_size|hsize}}</div>
</div>
{% endfor %}
{% endif %}
</div>
</div>

Expand All @@ -195,7 +200,9 @@ <h2>Deployed Containers</h2>
<tr>
<th>Name</th>
<th>Status</th>
{% if public_logs %}
<th>Logs</th>
{% endif %}
</tr>
</thead>
<tbody>
Expand All @@ -204,9 +211,12 @@ <h2>Deployed Containers</h2>
<tr>
<td>{{name|cname}}</td>
<td>{{container.status}}</td>
{% if public_logs %}
<td>
<a href="/logs/{{name|cname}}?text&bare&timestamps&follow&since=1d&tail=1000" target="_blank">View Logs</a>
<a href="/logs/{{name|cname}}?text&bare&timestamps&follow&since=1d&tail=20" target="_blank">View
Logs</a>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
Expand Down
4 changes: 2 additions & 2 deletions tdxctl/src/fde_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ impl SetupFdeArgs {

async fn request_app_keys(&self, host_shared: &HostShared) -> Result<AppKeys> {
let kms_url = &host_shared.vm_config.kms_url;
let kms_enabled = host_shared.app_compose.feature_enabled("kms");
let kms_enabled = host_shared.app_compose.kms_enabled();
if kms_enabled {
let Some(kms_url) = kms_url else {
bail!("KMS URL is not set");
Expand Down Expand Up @@ -445,7 +445,7 @@ impl SetupFdeArgs {
let rootfs_hash = &host_shared.vm_config.rootfs_hash;
let compose_hash = sha256_file(host_shared.dir.app_compose_file())?;
let truncated_compose_hash = truncate(&compose_hash, 20);
let kms_enabled = host_shared.app_compose.feature_enabled("kms");
let kms_enabled = host_shared.app_compose.kms_enabled();
let ca_cert_hash = if kms_enabled {
sha256_file(host_shared.dir.kms_ca_cert_file())?
} else {
Expand Down
13 changes: 1 addition & 12 deletions tdxctl/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::{
use tboot::TbootArgs;
use tdx_attest as att;
use tracing::error;
use utils::{deserialize_json_file, extend_rtmr, run_command, AppCompose};
use utils::{extend_rtmr, run_command};

mod crypto;
mod fde_setup;
Expand Down Expand Up @@ -49,8 +49,6 @@ enum Commands {
GenAppKeys(GenAppKeysArgs),
/// Generate random data
Rand(RandArgs),
/// Test if an tapp feature is enabled given an app compose file
TestAppFeature(TestAppFeatureArgs),
/// Setup Disk Encryption
SetupFde(SetupFdeArgs),
/// Boot the Tapp
Expand Down Expand Up @@ -371,12 +369,6 @@ fn cmd_gen_app_keys(args: GenAppKeysArgs) -> Result<()> {
Ok(())
}

fn cmd_test_app_feature(args: TestAppFeatureArgs) -> Result<()> {
let app_compose: AppCompose = deserialize_json_file(&args.compose)?;
println!("{}", app_compose.feature_enabled(&args.feature));
Ok(())
}

async fn cmd_notify_host(args: HostNotifyArgs) -> Result<()> {
let client = NotifyClient::load_or_default(args.url)?;
client.notify(&args.event, &args.payload).await?;
Expand Down Expand Up @@ -422,9 +414,6 @@ async fn main() -> Result<()> {
Commands::GenAppKeys(args) => {
cmd_gen_app_keys(args)?;
}
Commands::TestAppFeature(args) => {
cmd_test_app_feature(args)?;
}
Commands::SetupFde(args) => {
cmd_setup_fde(args).await?;
}
Expand Down
18 changes: 17 additions & 1 deletion tdxctl/src/tboot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ impl<'a> Setup<'a> {
async fn setup(&self, nc: &NotifyClient) -> Result<()> {
self.prepare_certs()?;
nc.notify_q("boot.progress", "setting up tproxy net").await;
self.setup_tappd_config()?;
self.setup_tproxy_net().await?;
nc.notify_q("boot.progress", "setting up docker").await;
self.setup_docker_registry()?;
Expand All @@ -73,7 +74,7 @@ impl<'a> Setup<'a> {
}

async fn setup_tproxy_net(&self) -> Result<()> {
if !self.app_compose.feature_enabled("tproxy-net") {
if !self.app_compose.tproxy_enabled() {
info!("tproxy is not enabled");
return Ok(());
}
Expand Down Expand Up @@ -183,6 +184,21 @@ impl<'a> Setup<'a> {
Ok(())
}

fn setup_tappd_config(&self) -> Result<()> {
info!("Setting up tappd config");
let tappd_config = self.resolve("/etc/tappd/tappd.toml");
let config = format!(
r#"
[default.core]
public_logs = {}
public_sysinfo = {}
"#,
self.app_compose.public_logs, self.app_compose.public_sysinfo
);
fs::write(tappd_config, config)?;
Ok(())
}

fn setup_docker_registry(&self) -> Result<()> {
info!("Setting up docker registry");
let registry_url = self
Expand Down
21 changes: 19 additions & 2 deletions tdxctl/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,21 @@ pub fn run_command(command: &str, args: &[&str]) -> Result<Vec<u8>> {
pub struct AppCompose {
pub manifest_version: u32,
pub name: String,
pub version: String,
// Deprecated
#[serde(default)]
pub features: Vec<String>,
pub runner: String,
pub docker_compose_file: Option<String>,
#[serde(default)]
pub docker_config: DockerConfig,
#[serde(default)]
pub public_logs: bool,
#[serde(default)]
pub public_sysinfo: bool,
#[serde(default)]
pub kms_enabled: bool,
#[serde(default)]
pub tproxy_enabled: bool,
}

#[derive(Deserialize, Debug, Default)]
Expand All @@ -158,9 +167,17 @@ pub struct DockerConfig {
}

impl AppCompose {
pub fn feature_enabled(&self, feature: &str) -> bool {
fn feature_enabled(&self, feature: &str) -> bool {
self.features.contains(&feature.to_string())
}

pub fn tproxy_enabled(&self) -> bool {
self.tproxy_enabled || self.feature_enabled("tproxy-net")
}

pub fn kms_enabled(&self) -> bool {
self.kms_enabled || self.feature_enabled("kms")
}
}

#[derive(Deserialize)]
Expand Down
2 changes: 2 additions & 0 deletions teepod/rpc/proto/teepod_rpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ message ImageListResponse {
message ImageInfo {
string name = 1;
string description = 2;
string version = 3;
bool is_dev = 4;
}

message AppId {
Expand Down
9 changes: 3 additions & 6 deletions teepod/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,14 +247,14 @@ impl App {
Ok(lst)
}

pub fn list_image_names(&self) -> Result<Vec<String>> {
pub fn list_images(&self) -> Result<Vec<(String, ImageInfo)>> {
let image_path = self.config.image_path.clone();
let images = fs::read_dir(image_path).context("Failed to read image directory")?;
Ok(images
.flat_map(|entry| {
let path = entry.ok()?.path();
let _ = Image::load(&path).ok()?;
Some(path.file_name()?.to_string_lossy().to_string())
let img = Image::load(&path).ok()?;
Some((path.file_name()?.to_string_lossy().to_string(), img.info))
})
.collect())
}
Expand Down Expand Up @@ -317,9 +317,6 @@ impl App {

pub(crate) fn prepare_work_dir(&self, id: &str, req: &VmConfiguration) -> Result<VmWorkDir> {
let work_dir = self.work_dir(id);
if work_dir.exists() {
bail!("The instance is already exists at {}", work_dir.display());
}
let shared_dir = work_dir.join("shared");
fs::create_dir_all(&shared_dir).context("Failed to create shared directory")?;
fs::write(shared_dir.join("app-compose.json"), &req.compose_file)
Expand Down
2 changes: 2 additions & 0 deletions teepod/src/app/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ pub struct ImageInfo {
pub shared_ro: bool,
#[serde(default)]
pub version: String,
#[serde(default)]
pub is_dev: bool,
}

impl ImageInfo {
Expand Down
Loading
Loading