Files
gman/src/providers/azure_key_vault.rs
T

104 lines
3.1 KiB
Rust

use crate::providers::SecretProvider;
use anyhow::{Context, Result};
use azure_core::credentials::TokenCredential;
use azure_identity::DeveloperToolsCredential;
use azure_security_keyvault_secrets::models::SetSecretParameters;
use azure_security_keyvault_secrets::{ResourceExt, SecretClient};
use futures::TryStreamExt;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use std::sync::Arc;
use validator::Validate;
#[skip_serializing_none]
/// Configuration for Azure Key Vault provider
/// See [Azure Key Vault](https://azure.microsoft.com/en-us/services/key-vault/)
/// for more information.
///
/// This provider stores secrets in Azure Key Vault. It requires
/// a vault name to be specified.
///
/// Example
/// ```no_run
/// use gman::providers::{SecretProvider, SupportedProvider};
/// use gman::config::{Config, ProviderConfig};
/// use gman::providers::azure_key_vault::AzureKeyVaultProvider;
///
/// let provider = AzureKeyVaultProvider {
/// vault_name: Some("my-vault-name".to_string()),
/// };
/// let _ = provider.set_secret("MY_SECRET", "value");
#[derive(Debug, Clone, Validate, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct AzureKeyVaultProvider {
#[validate(required)]
pub vault_name: Option<String>,
}
#[async_trait::async_trait]
impl SecretProvider for AzureKeyVaultProvider {
fn name(&self) -> &'static str {
"AzureKeyVaultProvider"
}
async fn get_secret(&self, key: &str) -> Result<String> {
let response = self.get_client()?.get_secret(key, None).await?;
let body = response.into_model()?;
body.value
.with_context(|| format!("Secret '{}' not found", key))
}
async fn set_secret(&self, key: &str, value: &str) -> Result<()> {
let params = SetSecretParameters {
value: Some(value.to_string()),
..Default::default()
};
self.get_client()?
.set_secret(key, params.try_into()?, None)
.await?
.into_model()?;
Ok(())
}
async fn update_secret(&self, key: &str, value: &str) -> Result<()> {
self.set_secret(key, value).await
}
async fn delete_secret(&self, key: &str) -> Result<()> {
self.get_client()?.delete_secret(key, None).await?;
Ok(())
}
async fn list_secrets(&self) -> Result<Vec<String>> {
let mut pager = self.get_client()?.list_secret_properties(None)?;
let mut secrets = Vec::new();
while let Some(props) = pager.try_next().await? {
let name = props.resource_id()?.name;
secrets.push(name);
}
Ok(secrets)
}
}
impl AzureKeyVaultProvider {
fn get_client(&self) -> Result<SecretClient> {
let credential: Arc<dyn TokenCredential> = DeveloperToolsCredential::new(None)?;
let client = SecretClient::new(
format!(
"https://{}.vault.azure.net",
self.vault_name.as_ref().unwrap()
)
.as_str(),
credential,
None,
)?;
Ok(client)
}
}