# Azure Key Vault Configuration Guide
This guide provides comprehensive instructions for configuring Azure Key Vault with the Warp SQL Server MCP project.
## Table of Contents
1. [Prerequisites](#prerequisites)
2. [Azure Key Vault Setup](#azure-key-vault-setup)
3. [Authentication Configuration](#authentication-configuration)
4. [Secret Naming and Organization](#3-secret-naming-convention)
5. [Environment Variables](#environment-variables)
6. [Complete Configuration Examples](#complete-configuration-examples)
7. [Testing and Validation](#testing-and-validation)
8. [Troubleshooting](#troubleshooting)
## Prerequisites
Before you begin, ensure you have:
- **Azure subscription** with appropriate permissions
- **Azure Key Vault** resource created
- **Azure CLI** installed (`az cli`) or **Azure PowerShell**
- **Service Principal** or **Managed Identity** configured
- **Node.js 18+** and the MCP project dependencies installed
> **📖 Environment Variables Reference**: For complete documentation of all environment variables, defaults, and configuration options, see **[ENV-VARS.md](ENV-VARS.md)**.
## Azure Key Vault Setup
### 1. Create Azure Key Vault (if not exists)
```bash
# Using Azure CLI
az keyvault create \
--name "your-sql-mcp-vault" \
--resource-group "your-resource-group" \
--location "East US" \
--enable-soft-delete \
--retention-days 7
```
### 2. Add Database Connection Secrets
The MCP server looks for specific secret names in your Azure Key Vault. Here's how to add them:
#### Core Database Secrets
```bash
# SQL Server connection details
az keyvault secret set --vault-name "your-sql-mcp-vault" --name "SQL-SERVER-HOST" --value "your-sql-server.database.windows.net"
az keyvault secret set --vault-name "your-sql-mcp-vault" --name "SQL-SERVER-PORT" --value "1433"
az keyvault secret set --vault-name "your-sql-mcp-vault" --name "SQL-SERVER-DATABASE" --value "your-database-name"
az keyvault secret set --vault-name "your-sql-mcp-vault" --name "SQL-SERVER-USER" --value "your-sql-username"
az keyvault secret set --vault-name "your-sql-mcp-vault" --name "SQL-SERVER-PASSWORD" --value "your-secure-password"
```
#### Optional Configuration Secrets
```bash
# Security settings
az keyvault secret set --vault-name "your-sql-mcp-vault" --name "SQL-SERVER-ENCRYPT" --value "true"
az keyvault secret set --vault-name "your-sql-mcp-vault" --name "SQL-SERVER-TRUST-CERT" --value "false"
az keyvault secret set --vault-name "your-sql-mcp-vault" --name "SQL-SERVER-READ-ONLY" --value "true"
# Performance settings
az keyvault secret set --vault-name "your-sql-mcp-vault" --name "SQL-SERVER-CONNECT-TIMEOUT-MS" --value "10000"
az keyvault secret set --vault-name "your-sql-mcp-vault" --name "SQL-SERVER-REQUEST-TIMEOUT-MS" --value "30000"
az keyvault secret set --vault-name "your-sql-mcp-vault" --name "SQL-SERVER-POOL-MAX" --value "10"
```
### 3. Secret Naming Convention
**Important:** Azure Key Vault secret names follow these rules:
- **Allowed characters**: Letters, numbers, and hyphens (`-`)
- **NOT allowed**: Underscores (`_`), spaces, special characters
- **Length**: 1-127 characters
- **Case**: Case-insensitive
The MCP server automatically converts environment variable names to Azure-compatible format:
| Environment Variable | Azure Key Vault Secret Name |
| --------------------- | --------------------------- |
| `SQL_SERVER_HOST` | `SQL-SERVER-HOST` |
| `SQL_SERVER_PORT` | `SQL-SERVER-PORT` |
| `SQL_SERVER_USER` | `SQL-SERVER-USER` |
| `SQL_SERVER_PASSWORD` | `SQL-SERVER-PASSWORD` |
| `SQL_SERVER_ENCRYPT` | `SQL-SERVER-ENCRYPT` |
## Authentication Configuration
### Option 1: Service Principal (Recommended for Production)
#### 1.1 Create Service Principal
```bash
# Create service principal
az ad sp create-for-rbac --name "sql-mcp-service-principal" --skip-assignment
# Output will include:
# {
# "appId": "your-app-id",
# "displayName": "sql-mcp-service-principal",
# "password": "your-client-secret",
# "tenant": "your-tenant-id"
# }
```
#### 1.2 Grant Key Vault Access
```bash
# Grant secret access to the service principal
az keyvault set-policy \
--name "your-sql-mcp-vault" \
--spn "your-app-id" \
--secret-permissions get list
```
#### 1.3 Configure Environment Variables
```bash
# Azure authentication
export AZURE_CLIENT_ID="your-app-id"
export AZURE_CLIENT_SECRET="your-client-secret"
export AZURE_TENANT_ID="your-tenant-id"
# Key Vault configuration
export SECRET_MANAGER_TYPE="azure"
export AZURE_KEY_VAULT_URL="https://your-sql-mcp-vault.vault.azure.net/"
```
### Option 2: Managed Identity (For Azure Resources)
If running on Azure VM, App Service, or Container Instances:
#### 2.1 Enable Managed Identity
```bash
# For Azure VM
az vm identity assign --resource-group "your-rg" --name "your-vm"
# For Azure App Service
az webapp identity assign --resource-group "your-rg" --name "your-webapp"
```
#### 2.2 Grant Key Vault Access
```bash
# Get the managed identity principal ID
PRINCIPAL_ID=$(az vm identity show --resource-group "your-rg" --name "your-vm" --query principalId --output tsv)
# Grant access to Key Vault
az keyvault set-policy \
--name "your-sql-mcp-vault" \
--object-id "$PRINCIPAL_ID" \
--secret-permissions get list
```
#### 2.3 Configure Environment Variables
```bash
# Only need these for managed identity
export SECRET_MANAGER_TYPE="azure"
export AZURE_KEY_VAULT_URL="https://your-sql-mcp-vault.vault.azure.net/"
```
## Environment Variables
### Required Configuration
```bash
# Secret management type (REQUIRED)
export SECRET_MANAGER_TYPE="azure"
# Azure Key Vault URL (REQUIRED)
export AZURE_KEY_VAULT_URL="https://your-vault-name.vault.azure.net/"
```
### Authentication Variables (Service Principal)
```bash
# Required for Service Principal authentication
export AZURE_CLIENT_ID="your-app-id"
export AZURE_CLIENT_SECRET="your-client-secret"
export AZURE_TENANT_ID="your-tenant-id"
```
### Optional Configuration
```bash
# Cache settings (optional)
export SECRET_CACHE_MAX_AGE="300000" # 5 minutes in milliseconds
# Logging (optional)
export LOG_LEVEL="info" # debug, info, warn, error
```
## Complete Configuration Examples
### Example 1: Production Service Principal Setup
```bash
#!/bin/bash
# production-azure-setup.sh
# Azure authentication (from service principal creation)
export AZURE_CLIENT_ID="12345678-1234-5678-9012-123456789012"
export AZURE_CLIENT_SECRET="your-secure-client-secret"
export AZURE_TENANT_ID="87654321-4321-8765-2109-876543210987"
# Key Vault configuration
export SECRET_MANAGER_TYPE="azure"
export AZURE_KEY_VAULT_URL="https://prod-sql-mcp-vault.vault.azure.net/"
# Optional: Performance and logging
export SECRET_CACHE_MAX_AGE="600000" # 10 minutes
export LOG_LEVEL="warn"
# Start the MCP server
npm start
```
### Example 2: Development Environment
```bash
#!/bin/bash
# dev-azure-setup.sh
# Azure authentication
export AZURE_CLIENT_ID="dev-app-id"
export AZURE_CLIENT_SECRET="dev-client-secret"
export AZURE_TENANT_ID="your-tenant-id"
# Key Vault configuration
export SECRET_MANAGER_TYPE="azure"
export AZURE_KEY_VAULT_URL="https://dev-sql-mcp-vault.vault.azure.net/"
# Development settings
export LOG_LEVEL="debug"
export SECRET_CACHE_MAX_AGE="60000" # 1 minute for development
# Start in development mode
npm run dev
```
### Example 3: Docker Container
```dockerfile
# Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm ci --production
# Environment variables will be provided at runtime
EXPOSE 3000
CMD ["npm", "start"]
```
```bash
# Run with Azure Key Vault configuration
docker run -d \
--name sql-mcp \
-e SECRET_MANAGER_TYPE="azure" \
-e AZURE_KEY_VAULT_URL="https://your-vault.vault.azure.net/" \
-e AZURE_CLIENT_ID="your-app-id" \
-e AZURE_CLIENT_SECRET="your-client-secret" \
-e AZURE_TENANT_ID="your-tenant-id" \
-e LOG_LEVEL="info" \
your-registry/sql-mcp:latest
```
### Example 4: Azure App Service Configuration
Using Azure App Service Configuration:
```bash
# Set application settings via Azure CLI
az webapp config appsettings set \
--resource-group "your-rg" \
--name "your-webapp" \
--settings \
SECRET_MANAGER_TYPE="azure" \
AZURE_KEY_VAULT_URL="https://your-vault.vault.azure.net/" \
LOG_LEVEL="info"
```
## Testing and Validation
### 1. Test Azure Authentication
```bash
# Test Azure CLI authentication
az account show
# Test Key Vault access
az keyvault secret list --vault-name "your-sql-mcp-vault"
```
### 2. Test Secret Retrieval
Create a simple test script:
```javascript
// test-azure-secrets.js
import { SecretManager } from './lib/config/secret-manager.js';
async function testAzureSecrets() {
const secretManager = new SecretManager({
secretSource: 'azure',
azureVaultUrl: process.env.AZURE_KEY_VAULT_URL
});
try {
// Test health check
const health = await secretManager.healthCheck();
console.log('Health Check:', JSON.stringify(health, null, 2));
// Test secret retrieval
const host = await secretManager.getSecret('SQL_SERVER_HOST');
console.log('SQL Server Host:', host ? 'Retrieved successfully' : 'Not found');
// Test full database config
const dbConfig = await secretManager.getDatabaseConfig();
console.log('Database Config:', SecretManager.maskSecrets(dbConfig));
} catch (error) {
console.error('Test failed:', error.message);
}
}
testAzureSecrets();
```
```bash
# Run the test
node test-azure-secrets.js
```
### 3. Test MCP Server Startup
```bash
# Enable debug logging to see secret loading
export LOG_LEVEL="debug"
npm start
```
Look for these log messages:
```log
[INFO] Secret Manager: Initializing with source: azure
[INFO] Secret Manager: Health check - azure: healthy
[INFO] Database config loaded successfully from Azure Key Vault
```
## Troubleshooting
### Common Issues and Solutions
#### 1. Authentication Errors
**Error:** `AADSTS70011: The provided value for the input parameter 'scope' is not valid`
**Solution:** Ensure your service principal has correct permissions:
```bash
# Re-check service principal
az ad sp show --id "your-app-id"
# Re-grant Key Vault permissions
az keyvault set-policy \
--name "your-vault" \
--spn "your-app-id" \
--secret-permissions get list
```
#### 2. Key Vault URL Issues
**Error:** `KeyVaultErrorException: Vault not found`
**Solution:** Verify the vault URL format:
```bash
# Correct format
https://vault-name.vault.azure.net/
# Get the correct URL
az keyvault show --name "your-vault" --query "properties.vaultUri" -o tsv
```
#### 3. Secret Name Issues
**Error:** `Secret not found: SQL_SERVER_HOST`
**Solution:** Check secret naming in Azure Key Vault:
```bash
# List all secrets
az keyvault secret list --vault-name "your-vault" --query "[].name" -o table
# Ensure names use hyphens, not underscores
# SQL_SERVER_HOST should be SQL-SERVER-HOST in Azure Key Vault
```
#### 4. Network Connectivity
**Error:** `getaddrinfo ENOTFOUND vault-name.vault.azure.net`
**Solution:** Check network and firewall settings:
```bash
# Test network connectivity
nslookup your-vault.vault.azure.net
curl -I https://your-vault.vault.azure.net/
# Check Azure Key Vault firewall settings
az keyvault network-rule list --name "your-vault"
```
#### 5. Permission Issues
**Error:** `Forbidden: The user, group or application does not have secrets get permission`
**Solution:** Grant proper permissions:
```bash
# For service principal
az keyvault set-policy \
--name "your-vault" \
--spn "your-app-id" \
--secret-permissions get list
# For managed identity
az keyvault set-policy \
--name "your-vault" \
--object-id "managed-identity-object-id" \
--secret-permissions get list
```
### Debug Mode
Enable comprehensive debugging:
```bash
export LOG_LEVEL="debug"
export NODE_ENV="development"
npm start
```
This will show detailed logs including:
- Secret Manager initialization
- Authentication attempts
- Secret retrieval operations
- Health check results
- Error details with stack traces
### Health Check Endpoint
The MCP server includes a health check for the secret manager:
```javascript
// Access health check programmatically
const secretManager = new SecretManager({ secretSource: 'azure' });
const health = await secretManager.healthCheck();
console.log(health);
// Expected output for healthy Azure connection:
// {
// "source": "azure",
// "status": "healthy",
// "details": {
// "azure": "authenticated"
// }
// }
```
## Best Practices
### Security Best Practices
1. **Use Managed Identity** when possible (Azure-hosted resources)
2. **Rotate secrets regularly** using Azure Key Vault features
3. **Use separate Key Vaults** for different environments
4. **Enable audit logging** for Key Vault access
5. **Use resource-specific vaults** to limit blast radius
### Configuration Best Practices
1. **Use infrastructure as code** (ARM templates, Terraform)
2. **Document secret naming conventions** for your team
3. **Test secret rotation** procedures
4. **Monitor Key Vault metrics** and alerts
5. **Use environment-specific prefixes** in secret names
### Example Infrastructure as Code
```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2021-11-01-preview",
"name": "[parameters('keyVaultName')]",
"properties": {
"tenantId": "[subscription().tenantId]",
"sku": {
"family": "A",
"name": "standard"
},
"accessPolicies": [
{
"tenantId": "[subscription().tenantId]",
"objectId": "[parameters('servicePrincipalObjectId')]",
"permissions": {
"secrets": ["get", "list"]
}
}
]
}
}
]
}
```
This completes the comprehensive Azure Key Vault configuration guide. The secret manager will
handle the automatic conversion between environment variable names and Azure-compatible secret
names, providing seamless integration with your existing configuration patterns.