Private
Public Access
1
0
Files
linux_patch_api/src/enroll/mod.rs
Echo 945febbe96
Some checks failed
CI/CD Pipeline / Code Format (push) Failing after 2s
CI/CD Pipeline / Clippy Lints (push) Successful in 44s
CI/CD Pipeline / Enrollment Tests (push) Has been skipped
CI/CD Pipeline / All Unit Tests (push) Successful in 1m12s
CI/CD Pipeline / Build Debian Package (push) Has been skipped
CI/CD Pipeline / Build Debian Package (Ubuntu 22.04) (push) Has been skipped
CI/CD Pipeline / Build RPM Package (push) Has been skipped
CI/CD Pipeline / Build Alpine Package (push) Has been skipped
CI/CD Pipeline / Build Arch Package (push) Has been skipped
CI/CD Pipeline / Security Audit (push) Successful in 4s
CI/CD Pipeline / Verify Enrollment CLI Flag (push) Successful in 55s
feat(enrollment): add route-based IP selection and fix package versioning for v1.1.5
2026-05-18 03:35:46 +00:00

97 lines
3.4 KiB
Rust

//! Self-enrollment module for linux_patch_api daemon.
//!
//! Handles secure registration with the patch manager, including
//! identity extraction (machine-id, FQDN, IPs, OS details) and
//! mTLS enrollment via the manager API.
pub mod client;
pub mod identity;
pub mod provision;
use anyhow::{Context, Result};
/// Re-export key types for ergonomic access from parent modules.
pub use client::{
EnrollmentClient, EnrollmentRequest, EnrollmentResponse, EnrollmentStatusResponse, PkiBundle,
};
/// Re-export identity extraction functions.
pub use identity::{
get_fqdn, get_ip_addresses, get_ip_for_interface, get_machine_id, get_os_details,
get_primary_ip, get_route_source_ip, is_container_bridge, is_link_local,
};
/// Run the full enrollment flow against the manager at the given URL.
///
/// # Phases
/// 1. **Registration** - POST machine identity to manager, receive polling token
/// 2. **Polling** - Poll manager for approval with configurable interval/max attempts
/// 3. **Provisioning** - Write PKI bundle to disk (certs/keys) and append manager IP to whitelist
///
/// # Errors
/// Returns Err on registration failure, polling timeout, denial, user interruption,
/// PKI provisioning failure, or whitelist update failure.
pub async fn run_enrollment(manager_url: &str, config: &super::AppConfig) -> Result<()> {
// Extract IP reporting overrides from enrollment config
let (report_interface, report_ip) = config
.enrollment
.as_ref()
.map(|e| (e.report_interface.clone(), e.report_ip.clone()))
.unwrap_or((None, None));
let client = EnrollmentClient::with_ip_overrides(manager_url, report_interface, report_ip);
// Phase 1: Registration
tracing::info!(
manager_url = manager_url,
"Starting enrollment - registration phase"
);
let response = client.register().await?;
tracing::info!("Registration successful - received polling token");
// Get polling config (use defaults if not set)
let interval = config
.enrollment
.as_ref()
.map(|e| e.polling_interval_seconds)
.unwrap_or(60);
let max_attempts = config
.enrollment
.as_ref()
.map(|e| e.max_poll_attempts)
.unwrap_or(1440);
// Phase 2: Polling
tracing::info!(
interval_seconds = interval,
max_attempts = max_attempts,
"Starting enrollment - polling phase"
);
let pki_bundle = client
.poll_for_approval(&response.polling_token, interval, max_attempts)
.await?;
// Phase 3: PKI provisioning & whitelist update
tracing::info!("Enrollment approved - starting PKI provisioning phase");
// Write certificates to configured paths (or defaults)
provision::provision_pki_bundle(
&pki_bundle.ca_crt,
&pki_bundle.server_crt,
&pki_bundle.server_key,
config.tls_config(),
)
.await?;
tracing::info!("PKI bundle written to disk");
// Resolve manager hostname to IP and append to whitelist
let manager_ip = client
.manager_ip()
.await
.context("Failed to resolve manager IP - cannot update whitelist")?;
provision::append_manager_to_whitelist(&manager_ip, config.whitelist_path()).await?;
tracing::info!(manager_ip = %manager_ip, "Manager IP appended to whitelist");
tracing::info!("Enrollment complete - PKI and whitelist configured");
Ok(())
}