src/config.rs
audience: ai
Operator-supplied boot configuration. Inputs read at process start and measured into the TDX quote:
- A coalition reference (which
CoalitionConfigto join and which Compute module to register with). - Per-backend credentials — one or more of:
AwsBootConfig— access-key pair, regions, instance families.GcpBootConfig— service-account JSON, project id, regions, machine types, TDX machine types.AzureBootConfig— tenant / client / secret, subscription, resource group, regions, VM sizes, TDX VM sizes.BareMetalBootConfig— a list ofBareMetalMachineentries, each carrying host, port, user, SSH key path, region label, declared CPU millicores and RAM MiB, atdx_capableflag, and an optionaltdx_mrtd_compatstring.
ZipnetBootConfig— which zipnetNetworkIdand unseal committee to bond.ProviderBootConfig— operator-level caps (capacity-refresh cadence, max grant duration, aggregate CPU / RAM ceilings).
RedactedString is a Debug-sanitising wrapper so
secrets cannot leak into traces.
The bridge refuses to start if no backend is
configured; see
backends/mod.rs.
//! Operator-supplied boot configuration.
//!
//! Input artefacts, read at process start and measured
//! into the TDX quote:
//!
//! - `COALITION_CONFIG_PATH` — the `CoalitionConfig`
//! fingerprint plus the Compute `ConfluenceConfig`
//! fingerprint the provider registers against.
//!
//! - `BACKENDS_CONFIG_PATH` — a TOML file declaring
//! which backends (aws, gcp, azure, baremetal) are
//! enabled and the operator's per-backend credentials,
//! regions, and shape preferences. At least one
//! backend must be enabled.
//!
//! The provider binary itself never contacts a secret
//! store at runtime; all secrets are measured into the
//! TDX boot so their integrity is attested.
use std::path::PathBuf;
use anyhow::{anyhow, Context};
use serde::Deserialize;
use coalition::CoalitionConfig;
#[derive(Debug, Clone)]
pub struct BootConfig {
pub coalition: CoalitionConfig<'static>,
pub backends: BackendsBootConfig,
pub zipnet: ZipnetBootConfig,
pub provider: ProviderBootConfig,
pub dashboard: DashboardBootConfig,
}
impl BootConfig {
pub fn load_from_env() -> anyhow::Result<Self> {
let coalition_path: PathBuf = std::env::var("COALITION_CONFIG_PATH")
.context("COALITION_CONFIG_PATH not set")?
.into();
let backends_path: PathBuf = std::env::var("BACKENDS_CONFIG_PATH")
.context("BACKENDS_CONFIG_PATH not set")?
.into();
// In the real deployment these come from the TDX
// initrd, not $CWD.
let coalition_raw = std::fs::read_to_string(&coalition_path)
.with_context(|| format!("reading {}", coalition_path.display()))?;
let backends_raw = std::fs::read_to_string(&backends_path)
.with_context(|| format!("reading {}", backends_path.display()))?;
// TODO: real parsing. The coalition config would
// be reconstructed via the coalition meta-crate's
// from_toml helper; backends parse straight into
// BackendsBootConfig via serde.
let _ = coalition_raw;
let _ = backends_raw;
Err(anyhow!(
"BootConfig::load_from_env is a prototype stub; \
implement once the coalition meta-crate is released"
))
}
}
/// Aggregate backends config. Every field is `Option`;
/// at least one must be `Some` or `Fleet::from_boot_config`
/// refuses to start.
#[derive(Debug, Clone, Default, Deserialize)]
pub struct BackendsBootConfig {
#[serde(default)]
pub aws: Option<AwsBootConfig>,
#[serde(default)]
pub gcp: Option<GcpBootConfig>,
#[serde(default)]
pub azure: Option<AzureBootConfig>,
#[serde(default)]
pub baremetal: Option<BareMetalBootConfig>,
}
// ---- AWS -------------------------------------------------------------------
#[derive(Debug, Clone, Deserialize)]
pub struct AwsBootConfig {
pub access_key_id: String,
pub secret_access_key: RedactedString,
pub regions: Vec<String>,
pub instance_families: Vec<String>,
pub max_concurrent_instances: u32,
}
// ---- GCP -------------------------------------------------------------------
#[derive(Debug, Clone, Deserialize)]
pub struct GcpBootConfig {
/// Path (inside the TDX initrd) to the service-
/// account JSON key. Measured into the boot.
pub service_account_key_path: PathBuf,
/// GCP project id.
pub project_id: String,
pub regions: Vec<String>,
/// Machine types the bridge will provision for
/// non-TDX grants. E.g. `["n2-standard-4", "n2-highmem-8"]`.
pub machine_families: Vec<String>,
/// Confidential-VM (TDX) machine types. Non-empty
/// marks the backend `tdx_capable`. E.g.
/// `["c3-standard-4", "c3-highmem-8"]`.
#[serde(default)]
pub tdx_machine_types: Vec<String>,
pub max_concurrent_instances: u32,
}
// ---- Azure -----------------------------------------------------------------
#[derive(Debug, Clone, Deserialize)]
pub struct AzureBootConfig {
pub tenant_id: String,
pub client_id: String,
pub client_secret: RedactedString,
pub subscription_id: String,
/// Resource group the bridge is permitted to mutate.
pub resource_group: String,
pub regions: Vec<String>,
/// VM SKUs for non-TDX grants. E.g.
/// `["Standard_D4s_v5", "Standard_E8s_v5"]`.
pub vm_sizes: Vec<String>,
/// Confidential-Compute v3 SKUs (TDX). Non-empty
/// marks the backend `tdx_capable`. E.g.
/// `["Standard_DC4ads_v5", "Standard_EC8ads_v5"]`.
#[serde(default)]
pub tdx_vm_sizes: Vec<String>,
pub max_concurrent_instances: u32,
}
// ---- Bare-metal ------------------------------------------------------------
#[derive(Debug, Clone, Deserialize)]
pub struct BareMetalBootConfig {
pub machines: Vec<BareMetalMachine>,
/// If `true`, start even when some declared machines
/// are unreachable. Default is strict.
#[serde(default)]
pub lenient_boot: bool,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BareMetalMachine {
/// DNS name or IP the bridge connects to over SSH.
pub host: String,
/// SSH port; 22 by default.
#[serde(default = "default_ssh_port")]
pub port: u16,
/// SSH user. **Must be root**: the bridge installs
/// systemd units, opens firewall ports, and creates
/// workload users.
#[serde(default = "default_root_user")]
pub user: String,
/// Path (inside the TDX initrd) to the SSH private
/// key. Measured into the boot.
pub ssh_key_path: PathBuf,
/// Operator-assigned region label. Used for
/// routing; need not be a cloud region name.
pub region: String,
/// Declared CPU millicores this machine offers.
pub cpu_millicores: u32,
/// Declared RAM MiB this machine offers.
pub ram_mib: u32,
/// True if the machine can run nested TDX guests
/// (bare-TDX host). The bridge will route TDX-
/// required grants only to machines with this flag.
#[serde(default)]
pub tdx_capable: bool,
/// Optional expected MR_TD compatibility value a
/// bare-TDX host will launch nested guests under.
/// Surfaced in the provider card so requesters can
/// cross-check.
#[serde(default)]
pub tdx_mrtd_compat: Option<String>,
}
fn default_ssh_port() -> u16 { 22 }
fn default_root_user() -> String { "root".into() }
// ---- zipnet / provider knobs ----------------------------------------------
#[derive(Debug, Clone, Deserialize)]
pub struct ZipnetBootConfig {
pub network_id: String,
pub unseal_config_hex: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ProviderBootConfig {
pub capacity_refresh_sec: u32,
pub max_grant_duration_sec: u32,
pub max_granted_cpu_millicores: u32,
pub max_granted_ram_mib: u32,
}
// ---- Dashboard -------------------------------------------------------------
/// Operator's read-only view of the bridge.
///
/// Binds to `127.0.0.1:<port>` inside the TDX guest.
/// The operator reaches it by SSH port-forwarding from
/// the host; no authentication beyond the ssh login.
#[derive(Debug, Clone, Deserialize)]
pub struct DashboardBootConfig {
pub port: u16,
/// Human-readable coalition name surfaced in the
/// dashboard header.
pub coalition_name: String,
/// Operator-supplied $/core-hour and $/GiB-hour
/// rate tables per backend; used to estimate costs
/// on the dashboard. Bare-metal entries typically
/// 0 unless the operator has amortised
/// power/cooling values.
pub rate_table: crate::dashboard::RateTable,
}
// ---- Redacted string ------------------------------------------------------
#[derive(Clone, Deserialize)]
#[serde(transparent)]
pub struct RedactedString(pub String);
impl std::fmt::Debug for RedactedString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "\"<redacted {} chars>\"", self.0.len())
}
}
Up: compute-bridge.