First commit
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
"""
|
||||
Key Vault Service
|
||||
|
||||
Handles operations related to Azure Key Vault.
|
||||
"""
|
||||
|
||||
from azure.identity import InteractiveBrowserCredential
|
||||
from azure.keyvault.secrets import SecretClient
|
||||
from azure.mgmt.keyvault import KeyVaultManagementClient
|
||||
from datetime import datetime
|
||||
from typing import List, Dict
|
||||
import re
|
||||
|
||||
|
||||
class KeyVaultService:
|
||||
"""Service for managing Key Vault operations."""
|
||||
|
||||
def __init__(self, credential: InteractiveBrowserCredential, subscription_id: str):
|
||||
"""
|
||||
Initialize the Key Vault service.
|
||||
|
||||
Args:
|
||||
credential: Authenticated credential
|
||||
subscription_id: Azure subscription ID
|
||||
"""
|
||||
self.credential = credential
|
||||
self.subscription_id = subscription_id
|
||||
self.mgmt_client = KeyVaultManagementClient(credential, subscription_id)
|
||||
|
||||
def list_keyvaults(self, resource_group: str = None) -> List[Dict[str, str]]:
|
||||
"""
|
||||
List all Key Vaults in the subscription.
|
||||
|
||||
Args:
|
||||
resource_group: Optional resource group to filter by
|
||||
|
||||
Returns:
|
||||
List[Dict]: List of Key Vaults with name, id, location, and resource_group
|
||||
|
||||
Raises:
|
||||
Exception: If the API call fails
|
||||
"""
|
||||
try:
|
||||
vaults = []
|
||||
|
||||
if resource_group:
|
||||
# Get vaults from specific resource group
|
||||
vault_list = self.mgmt_client.vaults.list_by_resource_group(resource_group)
|
||||
else:
|
||||
# Get all vaults in subscription
|
||||
vault_list = self.mgmt_client.vaults.list_by_subscription()
|
||||
|
||||
for vault in vault_list:
|
||||
# Extract resource group from vault ID
|
||||
# Format: /subscriptions/{sub-id}/resourceGroups/{rg-name}/providers/...
|
||||
rg_name = vault.id.split('/')[4] if len(vault.id.split('/')) > 4 else ''
|
||||
|
||||
vaults.append({
|
||||
'name': vault.name,
|
||||
'id': vault.id,
|
||||
'location': vault.location,
|
||||
'resource_group': rg_name
|
||||
})
|
||||
|
||||
# Sort by name
|
||||
vaults.sort(key=lambda x: x['name'].lower())
|
||||
|
||||
return vaults
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"Failed to list Key Vaults: {str(e)}")
|
||||
|
||||
def store_secret(
|
||||
self,
|
||||
vault_name: str,
|
||||
secret_name: str,
|
||||
secret_value: str,
|
||||
description: str,
|
||||
secret_id: str,
|
||||
expires: datetime
|
||||
) -> str:
|
||||
"""
|
||||
Store a secret in Key Vault with tags.
|
||||
|
||||
Args:
|
||||
vault_name: Name of the Key Vault
|
||||
secret_name: Name for the secret (will be sanitized)
|
||||
secret_value: The secret value to store
|
||||
description: Description tag
|
||||
secret_id: Secret ID tag (from app registration)
|
||||
expires: Expiration date
|
||||
|
||||
Returns:
|
||||
str: The sanitized secret name
|
||||
|
||||
Raises:
|
||||
Exception: If the operation fails
|
||||
"""
|
||||
try:
|
||||
# Sanitize the secret name
|
||||
sanitized_name = self._sanitize_name(secret_name)
|
||||
|
||||
# Construct vault URL
|
||||
vault_url = f"https://{vault_name}.vault.azure.net"
|
||||
|
||||
# Create secret client
|
||||
secret_client = SecretClient(vault_url=vault_url, credential=self.credential)
|
||||
|
||||
# Create tags
|
||||
tags = {
|
||||
'Description': description,
|
||||
'SecretId': secret_id
|
||||
}
|
||||
|
||||
# Set the secret
|
||||
secret = secret_client.set_secret(
|
||||
name=sanitized_name,
|
||||
value=secret_value,
|
||||
tags=tags,
|
||||
expires_on=expires
|
||||
)
|
||||
|
||||
return secret.name
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"Failed to store secret in Key Vault: {str(e)}")
|
||||
|
||||
def _sanitize_name(self, name: str) -> str:
|
||||
"""
|
||||
Sanitize a name for use in Key Vault.
|
||||
Key Vault secret names can only contain alphanumeric characters and hyphens.
|
||||
|
||||
Args:
|
||||
name: The name to sanitize
|
||||
|
||||
Returns:
|
||||
str: Sanitized name
|
||||
|
||||
"""
|
||||
if not name:
|
||||
return name
|
||||
|
||||
# Replace any non-alphanumeric character (except hyphens) with hyphen
|
||||
sanitized = re.sub(r'[^0-9a-zA-Z-]', '-', name)
|
||||
|
||||
# Remove consecutive hyphens
|
||||
sanitized = re.sub(r'-+', '-', sanitized)
|
||||
|
||||
# Remove leading/trailing hyphens
|
||||
sanitized = sanitized.strip('-')
|
||||
|
||||
return sanitized
|
||||
|
||||
def get_secret(self, vault_name: str, secret_name: str) -> Dict[str, any]:
|
||||
"""
|
||||
Retrieve a secret from Key Vault.
|
||||
|
||||
Args:
|
||||
vault_name: Name of the Key Vault
|
||||
secret_name: Name of the secret
|
||||
|
||||
Returns:
|
||||
Dict: Secret properties including value and tags
|
||||
|
||||
Raises:
|
||||
Exception: If the operation fails
|
||||
"""
|
||||
try:
|
||||
# Construct vault URL
|
||||
vault_url = f"https://{vault_name}.vault.azure.net"
|
||||
|
||||
# Create secret client
|
||||
secret_client = SecretClient(vault_url=vault_url, credential=self.credential)
|
||||
|
||||
# Get the secret
|
||||
secret = secret_client.get_secret(secret_name)
|
||||
|
||||
return {
|
||||
'name': secret.name,
|
||||
'value': secret.value,
|
||||
'tags': secret.properties.tags,
|
||||
'expires_on': secret.properties.expires_on,
|
||||
'created_on': secret.properties.created_on
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
raise Exception(f"Failed to retrieve secret from Key Vault: {str(e)}")
|
||||
Reference in New Issue
Block a user