Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

src/config.rs

audience: ai

Operator-supplied boot configuration. Inputs read at process start and measured into the TDX quote:

  • A coalition reference (which CoalitionConfig to 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 of BareMetalMachine entries, each carrying host, port, user, SSH key path, region label, declared CPU millicores and RAM MiB, a tdx_capable flag, and an optional tdx_mrtd_compat string.
  • ZipnetBootConfig — which zipnet NetworkId and 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.