Skip to content
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
21 changes: 21 additions & 0 deletions src/bin/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ const DEFAULT_METRICS_ADDR: &str = "[::]:8080";
const DEFAULT_METRICS_PORT: u16 = 8080;
const DEFAULT_BROKER_ADDR: &str = "[::]:9091";
const DEFAULT_CANOPY_RECONCILE_INTERVAL_SECS: u64 = 30;
/// The client certificate bestool mints at construction lives six days, so the
/// operator re-mints well inside that.
const CANOPY_CERT_RENEW_INTERVAL: Duration = Duration::from_secs(24 * 60 * 60);
const CONFIGMAP_NAME: &str = "postgres-restore-operator-config";

/// Annotate the operator's own pod with the running version.
Expand Down Expand Up @@ -442,6 +445,24 @@ async fn main() -> anyhow::Result<()> {
register_capabilities(register_ctx).await;
});

let renew_ctx = ctx.clone();
tokio::spawn(async move {
let mut interval = tokio::time::interval(CANOPY_CERT_RENEW_INTERVAL);
interval.tick().await;
loop {
interval.tick().await;
let Some(canopy) = renew_ctx.canopy.as_ref() else {
break;
};
match canopy.renew().await {
Ok(()) => info!("renewed the canopy client certificate"),
Err(error) => {
warn!(error = %error, "renewing the canopy client certificate failed");
}
}
}
});

let interval_secs = std::env::var("CANOPY_RECONCILE_INTERVAL_SECS")
.ok()
.and_then(|v| v.parse::<u64>().ok())
Expand Down
11 changes: 11 additions & 0 deletions src/canopy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,17 @@ impl Client {
Ok(Some(Self { inner }))
}

/// Mint a fresh client certificate from the device key. The certificate the
/// client builds at construction is short-lived, so a process outliving it
/// authenticates with an expired one and canopy's edge rejects every call.
pub async fn renew(&self) -> Result<()> {
self.inner
.transport()
.renew()
.await
.map_err(|err| Error::Canopy(format!("renew: {err}")))
}

/// Register the intent descriptors this consumer supports. Replaces the
/// registered set wholesale (per canopy's semantics). Each descriptor
/// carries the intent name, the canopy semantics it opts into, and its
Expand Down