wasmcloud_host/
workload_identity.rs1use std::sync::Arc;
2
3#[cfg(target_family = "windows")]
4use anyhow::{bail, Result};
5#[cfg(unix)]
6use anyhow::{Context as _, Result};
7use nkeys::KeyPair;
8
9const AUTH_SERVICE_AUDIENCE_ENV: &str = "WASMCLOUD_WORKLOAD_IDENTITY_AUTH_SERVICE_AUDIENCE";
11
12#[derive(Clone, Default, Debug)]
14pub struct WorkloadIdentityConfig {
15 pub auth_service_audience: String,
18}
19
20impl WorkloadIdentityConfig {
21 #[cfg(unix)]
23 pub fn from_env() -> Result<Self> {
24 let auth_service_audience = std::env::var(AUTH_SERVICE_AUDIENCE_ENV)
27 .context("workload identity auth callout audience environment variable is missing")?;
28
29 Ok(Self {
30 auth_service_audience,
31 })
32 }
33
34 #[cfg(target_family = "windows")]
35 pub fn from_env() -> Result<Self> {
36 anyhow::bail!("workload identity is not supported on Windows")
37 }
38}
39
40#[cfg(unix)]
41pub(crate) async fn setup_workload_identity_nats_connect_options(
42 jwt: Option<&String>,
43 key: Option<Arc<KeyPair>>,
44 wid_cfg: WorkloadIdentityConfig,
45) -> anyhow::Result<async_nats::ConnectOptions> {
46 let wid_cfg = Arc::new(wid_cfg);
47 let jwt = jwt.map(String::to_string).map(Arc::new);
48 let key = key.clone();
49
50 Ok(
55 async_nats::ConnectOptions::with_auth_callback(move |nonce| {
56 let key = key.clone();
57 let jwt = jwt.clone();
58 let wid_cfg = wid_cfg.clone();
59
60 let fetch_svid_handle = tokio::spawn(async move {
61 let mut client = spiffe::WorkloadApiClient::default()
62 .await
63 .map_err(async_nats::AuthError::new)?;
64 client
65 .fetch_jwt_svid(&[wid_cfg.auth_service_audience.as_str()], None)
66 .await
67 .map_err(async_nats::AuthError::new)
68 });
69
70 async move {
71 let svid = fetch_svid_handle
72 .await
73 .map_err(async_nats::AuthError::new)?
74 .map_err(async_nats::AuthError::new)?;
75
76 let mut auth = async_nats::Auth::new();
77 if let Some(key) = key {
78 let signature = key.sign(&nonce).map_err(async_nats::AuthError::new)?;
79 auth.signature = Some(signature);
80 }
81 if let Some(jwt) = jwt {
82 auth.jwt = Some(jwt.to_string());
83 }
84 auth.token = Some(svid.token().into());
85 Ok(auth)
86 }
87 })
88 .name("wasmbus"),
89 )
90}
91
92#[cfg(target_family = "windows")]
93pub(crate) async fn setup_workload_identity_nats_connect_options(
94 jwt: Option<&String>,
95 key: Option<Arc<KeyPair>>,
96 wid_cfg: WorkloadIdentityConfig,
97) -> anyhow::Result<async_nats::ConnectOptions> {
98 bail!("workload identity is not supported on Windows")
99}