trelent-hyok 0.1.12

A Rust library implementing Hold Your Own Key (HYOK) encryption patterns with support for multiple cloud providers
Documentation
//! Azure Key Vault integration for DEK storage.
//!
//! This module provides integration with Azure Key Vault for secure storage
//! of Data Encryption Keys (DEKs). It supports:
//!
//! - Secret storage and retrieval
//! - Azure-compliant secret naming
//! - Proper error handling for Azure operations
//! - Secure key management
//!
#![cfg(feature = "azure")]

use std::sync::Arc;

use async_trait::async_trait;
use azure_security_keyvault::prelude::KeyVaultGetSecretResponse;
use azure_security_keyvault::KeyvaultClient;

use super::DEKPersisterTrait;
use crate::error::generator::PersistError;

/// Azure Key Vault implementation for persisting Data Encryption Keys (DEK).
///
/// This persister:
/// - Stores DEKs as secrets in Azure Key Vault
/// - Uses context strings as secret names
/// - Handles secret creation and retrieval
/// - Validates secret names against Azure requirements
///
/// # Authentication
///
/// The persister requires proper Azure authentication. This can be configured through:
/// - Environment variables
/// - Managed identities
/// - Service principals
///
/// # Example
/// ```no_run
/// use std::sync::Arc;
/// use azure_security_keyvault::KeyvaultClient;
/// use hyokashi::AzurePersister;
///
///     let client = Arc::new(KeyvaultClient::new(/* ... */));
///     let persister = AzurePersister::new(client);
///
///     // Store a key
///     let my_key = vec![1, 2, 3];
///     let stored = persister.persist(&my_key, "my-secret".to_string()).await?;
///
///     // Retrieve the key
///     let retrieved = persister.fetch("my-secret".to_string()).await?;
///
/// ```
#[derive(Debug)]
pub struct AzurePersister {
    pub(crate) client: Arc<KeyvaultClient>,
}

impl AzurePersister {
    /// Creates a new `AzurePersister` with the provided Azure Key Vault client.
    ///
    /// # Arguments
    ///
    /// * `client` - An `Arc` wrapped Azure Key Vault client
    pub fn new(client: Arc<KeyvaultClient>) -> Self {
        Self { client }
    }
}

#[async_trait]
impl DEKPersisterTrait for AzurePersister {
    /// Persists a DEK in Azure Key Vault. The label of the secret is the context.
    ///
    /// # Arguments
    ///
    /// * `dek` - The key bytes to store
    /// * `context` - The secret name to use in Key Vault
    ///
    /// # Errors
    ///
    /// Returns a `PersistError` if the secret cannot be set in Key Vault
    async fn persist(&self, dek: &Vec<u8>, context: String) -> Result<Vec<u8>, PersistError> {
        let hash_name = context;
        let hex_secret = hex::encode(dek);
        let secret_client = self.client.secret_client();
        match secret_client.set(hash_name, hex_secret.clone()).await {
            Ok(_) => Ok(hex_secret.into_bytes()),
            Err(e) => Err(PersistError::Error(format!("Could not persist secret: {:?}", e))),
        }
    }

    /// Retrieves a DEK from Azure Key Vault using the provided context as the secret name.
    ///
    /// # Arguments
    ///
    /// * `context` - The secret name in Key Vault
    ///
    /// # Errors
    ///
    /// Returns a `PersistError` if:
    /// - The secret cannot be found
    /// - The secret value cannot be decoded
    /// - Azure API calls fail
    async fn fetch(&self, context: String) -> Result<Vec<u8>, PersistError> {
        let hash_name = context;
        let secret_client = self.client.secret_client();

        let secret: Result<KeyVaultGetSecretResponse, azure_core::error::Error> = secret_client.get(
            hash_name.clone()
        ).await;
        match secret {
            Ok(secret) =>
                hex
                    ::decode(secret.value)
                    .map_err(|e| {
                        PersistError::Error(format!("Could not decode secret, Error: {:?}", e))
                    }),
            Err(e) =>
                Err(
                    PersistError::Error(
                        format!(
                            "Could not fetch secret with identifier ({}), Error: {:?}",
                            hash_name,
                            e
                        )
                    )
                ),
        }
    }
}