Skip to content

Commit a30618d

Browse files
committed
enable environmental authentication for Azure Key Vault var provider
Signed-off-by: David Justice <[email protected]>
1 parent 08eac60 commit a30618d

File tree

7 files changed

+157
-173
lines changed

7 files changed

+157
-173
lines changed

Cargo.lock

Lines changed: 7 additions & 56 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/trigger/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ impl<Executor: TriggerExecutor> TriggerExecutorBuilder<Executor> {
204204
self.loader.add_dynamic_host_component(
205205
&mut builder,
206206
spin_variables::VariablesHostComponent::new(
207-
runtime_config.variables_providers(),
207+
runtime_config.variables_providers()?,
208208
),
209209
)?;
210210
}
@@ -225,7 +225,7 @@ impl<Executor: TriggerExecutor> TriggerExecutorBuilder<Executor> {
225225
let app_name = app.borrowed().require_metadata(APP_NAME_KEY)?;
226226

227227
let resolver =
228-
spin_variables::make_resolver(app.borrowed(), runtime_config.variables_providers())?;
228+
spin_variables::make_resolver(app.borrowed(), runtime_config.variables_providers()?)?;
229229
let prepared_resolver = std::sync::Arc::new(resolver.prepare().await?);
230230
resolver_cell
231231
.set(prepared_resolver.clone())

crates/trigger/src/runtime_config.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,17 @@ impl RuntimeConfig {
6060
}
6161

6262
/// Return a Vec of configured [`VariablesProvider`]s.
63-
pub fn variables_providers(&self) -> Vec<VariablesProvider> {
64-
let default_provider = VariablesProviderOpts::default_provider_opts(self).build_provider();
63+
pub fn variables_providers(&self) -> Result<Vec<VariablesProvider>> {
64+
let default_provider =
65+
VariablesProviderOpts::default_provider_opts(self).build_provider()?;
6566
let mut providers: Vec<VariablesProvider> = vec![default_provider];
66-
providers.extend(self.opts_layers().flat_map(|opts| {
67-
opts.variables_providers
68-
.iter()
69-
.map(|opts| opts.build_provider())
70-
}));
71-
providers
67+
for opts in self.opts_layers() {
68+
for var_provider in &opts.variables_providers {
69+
let provider = var_provider.build_provider()?;
70+
providers.push(provider);
71+
}
72+
}
73+
Ok(providers)
7274
}
7375

7476
/// Return an iterator of named configured [`KeyValueStore`]s.
@@ -473,7 +475,7 @@ mod tests {
473475
let mut config = RuntimeConfig::new(None);
474476

475477
// One default provider
476-
assert_eq!(config.variables_providers().len(), 1);
478+
assert_eq!(config.variables_providers()?.len(), 1);
477479

478480
merge_config_toml(
479481
&mut config,
@@ -485,7 +487,7 @@ mod tests {
485487
mount = "root"
486488
},
487489
);
488-
assert_eq!(config.variables_providers().len(), 2);
490+
assert_eq!(config.variables_providers()?.len(), 2);
489491

490492
Ok(())
491493
}
@@ -495,7 +497,7 @@ mod tests {
495497
let mut config = RuntimeConfig::new(None);
496498

497499
// One default provider
498-
assert_eq!(config.variables_providers().len(), 1);
500+
assert_eq!(config.variables_providers()?.len(), 1);
499501

500502
merge_config_toml(
501503
&mut config,
@@ -507,7 +509,7 @@ mod tests {
507509
mount = "root"
508510
},
509511
);
510-
assert_eq!(config.variables_providers().len(), 2);
512+
assert_eq!(config.variables_providers()?.len(), 2);
511513

512514
Ok(())
513515
}

crates/trigger/src/runtime_config/variables_provider.rs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
use std::path::PathBuf;
22

3+
use anyhow::{anyhow, Result};
34
use serde::Deserialize;
5+
use spin_variables::provider::azure_key_vault::{
6+
AzureKeyVaultAuthOptions, AzureKeyVaultRuntimeConfigOptions,
7+
};
48
use spin_variables::provider::{
59
azure_key_vault::{AzureAuthorityHost, AzureKeyVaultProvider},
610
env::EnvProvider,
@@ -27,7 +31,7 @@ impl VariablesProviderOpts {
2731
))
2832
}
2933

30-
pub fn build_provider(&self) -> VariablesProvider {
34+
pub fn build_provider(&self) -> Result<VariablesProvider> {
3135
match self {
3236
Self::Env(opts) => opts.build_provider(),
3337
Self::Vault(opts) => opts.build_provider(),
@@ -60,11 +64,11 @@ impl EnvVariablesProviderOpts {
6064
}
6165
}
6266

63-
pub fn build_provider(&self) -> VariablesProvider {
64-
Box::new(EnvProvider::new(
67+
pub fn build_provider(&self) -> Result<VariablesProvider> {
68+
Ok(Box::new(EnvProvider::new(
6569
self.prefix.clone(),
6670
self.dotenv_path.clone(),
67-
))
71+
)))
6872
}
6973
}
7074

@@ -79,35 +83,52 @@ pub struct VaultVariablesProviderOpts {
7983
}
8084

8185
impl VaultVariablesProviderOpts {
82-
pub fn build_provider(&self) -> VariablesProvider {
83-
Box::new(VaultProvider::new(
86+
pub fn build_provider(&self) -> Result<VariablesProvider> {
87+
Ok(Box::new(VaultProvider::new(
8488
&self.url,
8589
&self.token,
8690
&self.mount,
8791
self.prefix.as_deref(),
88-
))
92+
)))
8993
}
9094
}
9195

9296
#[derive(Debug, Default, Deserialize)]
9397
#[serde(deny_unknown_fields)]
9498
pub struct AzureKeyVaultVariablesProviderOpts {
95-
pub client_id: String,
96-
pub client_secret: String,
97-
pub tenant_id: String,
9899
pub vault_url: String,
99-
#[serde(default)]
100-
pub authority_host: AzureAuthorityHost,
100+
pub client_id: Option<String>,
101+
pub client_secret: Option<String>,
102+
pub tenant_id: Option<String>,
103+
pub authority_host: Option<AzureAuthorityHost>,
101104
}
102105

103106
impl AzureKeyVaultVariablesProviderOpts {
104-
pub fn build_provider(&self) -> VariablesProvider {
105-
Box::new(AzureKeyVaultProvider::new(
106-
&self.client_id,
107-
&self.client_secret,
108-
&self.tenant_id,
107+
pub fn build_provider(&self) -> Result<VariablesProvider> {
108+
let auth_config_runtime_vars = [&self.client_id, &self.tenant_id, &self.client_secret];
109+
let any_some = auth_config_runtime_vars.iter().any(|&var| var.is_some());
110+
let any_none = auth_config_runtime_vars.iter().any(|&var| var.is_none());
111+
112+
if any_none && any_some {
113+
// some of the service principal auth options were specified, but not enough to authenticate.
114+
return Err(anyhow!("The current runtime config specifies some but not all of the Azure KeyVault 'client_id', 'client_secret', and 'tenant_id' values. Provide the missing values to authenticate to Azure KeyVault with the given service principal, or remove all these values to authenticate using ambient authentication (e.g. env vars, Azure CLI, Managed Identity, Workload Identity)."));
115+
}
116+
117+
let auth_options = if any_some {
118+
// all the service principal auth options were specified in the runtime config
119+
AzureKeyVaultAuthOptions::RuntimeConfigValues(AzureKeyVaultRuntimeConfigOptions::new(
120+
self.client_id.clone().unwrap(),
121+
self.client_secret.clone().unwrap(),
122+
self.tenant_id.clone().unwrap(),
123+
self.authority_host,
124+
))
125+
} else {
126+
AzureKeyVaultAuthOptions::Environmental
127+
};
128+
129+
Ok(Box::new(AzureKeyVaultProvider::new(
109130
&self.vault_url,
110-
self.authority_host,
111-
))
131+
auth_options,
132+
)?))
112133
}
113134
}

crates/variables/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ tokio = { version = "1", features = ["rt-multi-thread"] }
1818
vaultrs = "0.6.2"
1919
serde = "1.0.188"
2020
tracing = { workspace = true }
21-
azure_security_keyvault = "0.20.0"
22-
azure_core = "0.20.0"
23-
azure_identity = "0.20.0"
21+
azure_security_keyvault = { git = "https://github.com/azure/azure-sdk-for-rust.git", rev = "8c4caa251c3903d5eae848b41bb1d02a4d65231c" }
22+
azure_core = { git = "https://github.com/azure/azure-sdk-for-rust.git", rev = "8c4caa251c3903d5eae848b41bb1d02a4d65231c" }
23+
azure_identity = { git = "https://github.com/azure/azure-sdk-for-rust.git", rev = "8c4caa251c3903d5eae848b41bb1d02a4d65231c" }
2424

2525
[dev-dependencies]
2626
toml = "0.5"

0 commit comments

Comments
 (0)