bytelyst-devops-tools/dashboard/backend/src/lib/azure-keyvault.ts
root fbaaa71a66 feat(devops): adopt trading web deployment model with docker-compose
- Add docker-compose.yml following trading web pattern
- Update web Dockerfile to use multi-stage build with metadata
- Add build metadata (commit SHA, branch, timestamp, author, message)
- Rewrite deploy.sh to use docker compose with build metadata
- Add hotcopy deployment script for quick updates
- Add comprehensive backend API with deployment orchestration
- Add health checks, service management, and monitoring endpoints
- Add CI/CD workflow configuration
- Add deployment documentation and guides

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-11 03:24:11 +00:00

120 lines
3.3 KiB
TypeScript

import { SecretClient } from '@azure/keyvault-secrets';
import { DefaultAzureCredential, ClientSecretCredential } from '@azure/identity';
import { config } from './config.js';
import { getAzureConfig as getStoredAzureConfig } from '../modules/azure-config/repository.js';
let keyVaultClient: SecretClient | null = null;
export async function getKeyVaultClient(): Promise<SecretClient | null> {
if (keyVaultClient) {
return keyVaultClient;
}
try {
let credential;
let keyVaultUrl = config.AZURE_KEY_VAULT_URL;
// Try to get configuration from database first
const storedConfig = await getStoredAzureConfig();
if (storedConfig && storedConfig.isActive) {
keyVaultUrl = storedConfig.keyVaultUrl;
if (storedConfig.tenantId && storedConfig.clientId && storedConfig.clientSecret) {
credential = new ClientSecretCredential(
storedConfig.tenantId,
storedConfig.clientId,
storedConfig.clientSecret
);
}
}
// Fall back to environment variables if no stored config
if (!credential && config.AZURE_TENANT_ID && config.AZURE_CLIENT_ID && config.AZURE_CLIENT_SECRET) {
credential = new ClientSecretCredential(
config.AZURE_TENANT_ID,
config.AZURE_CLIENT_ID,
config.AZURE_CLIENT_SECRET
);
}
// Use DefaultAzureCredential as last resort
if (!credential) {
credential = new DefaultAzureCredential();
}
if (!keyVaultUrl) {
return null;
}
keyVaultClient = new SecretClient(keyVaultUrl, credential);
return keyVaultClient;
} catch (error) {
console.error('Failed to initialize Azure Key Vault client:', error);
return null;
}
}
export async function getAzureSecret(secretName: string): Promise<string | null> {
const client = await getKeyVaultClient();
if (!client) {
return null;
}
try {
const secret = await client.getSecret(secretName);
return secret.value || null;
} catch (error) {
console.error(`Failed to get secret ${secretName} from Azure Key Vault:`, error);
return null;
}
}
export async function setAzureSecret(secretName: string, secretValue: string): Promise<boolean> {
const client = await getKeyVaultClient();
if (!client) {
return false;
}
try {
await client.setSecret(secretName, secretValue);
return true;
} catch (error) {
console.error(`Failed to set secret ${secretName} in Azure Key Vault:`, error);
return false;
}
}
export async function deleteAzureSecret(secretName: string): Promise<boolean> {
const client = await getKeyVaultClient();
if (!client) {
return false;
}
try {
await client.beginDeleteSecret(secretName);
return true;
} catch (error) {
console.error(`Failed to delete secret ${secretName} from Azure Key Vault:`, error);
return false;
}
}
export async function listAzureSecrets(): Promise<string[]> {
const client = await getKeyVaultClient();
if (!client) {
return [];
}
try {
const secrets: string[] = [];
for await (const secretProperties of client.listPropertiesOfSecrets()) {
if (secretProperties.name) {
secrets.push(secretProperties.name);
}
}
return secrets;
} catch (error) {
console.error('Failed to list secrets from Azure Key Vault:', error);
return [];
}
}