A lightweight ASP.NET Core web application that allows users to retrieve secrets from Azure Key Vault using managed identity authentication.
- Simple web interface with text input for secret names
- Azure Key Vault integration using managed identity
- Secure secret retrieval without storing credentials
- Clean, responsive UI with Bootstrap
- Azure subscription
- Azure Key Vault with secrets stored
- App Service with managed identity enabled
- App Service has Key Vault access permissions
- Azure subscription
- Azure CLI installed (for Cloud Shell deployment)
-
Create App Service:
- Runtime Stack:
Node.js 22 LTS - Platform:
64 Bit - Note your App Service name and Resource Group
- Runtime Stack:
-
Create Azure Key Vault:
- Note your Key Vault URL (e.g.,
https://your-keyvault-name.vault.azure.net)
- Note your Key Vault URL (e.g.,
-
Create Secret in Key Vault:
- Name:
my-secret - Value:
Hello, this is the secret from key vault
- Name:
-
Enable Managed Identity:
- Go to App Service → Identity → System assigned → Turn ON
- Copy the Object ID
-
Grant Key Vault Access:
- Go to Key Vault → Access policies (or Access control IAM)
- Add App Service's managed identity
- Grant Key Vault admin permissions over the resource group
-
Set App Setting:
- Go to App Service → Configuration → Application settings
- Add:
KeyVaultUrl=https://your-keyvault-name.vault.azure.net(no trailing slash)
-
Upload ZIP to Cloud Shell:
- Open Azure Cloud Shell
- Upload
KeyVaultSecretApp-Working.zip
-
Deploy via Azure CLI:
az webapp deploy --resource-group "your-resource-group" --name "your-app-service-name" --src-path "KeyVaultSecretApp-Working.zip" --type zip
-
Test your app:
- Visit:
https://your-app-service-name.azurewebsites.net - Type any message → should echo back
- Type
secret→ should retrieve actual secret from Key Vault
- Visit:
For production deployments with Application Gateway and WAF protection:
- Virtual Network with Application Gateway subnet
- Custom domain names (e.g.,
yourapp1.com,yourapp2.com) - SSL certificates for custom domains
-
Use Gateway-Ready App:
- Deploy
KeyVaultSecretApp-WithGateway.zipto your App Services - This version includes
app.set('trust proxy', true)for proper proxy handling
- Deploy
-
Create Application Gateway:
# Create Application Gateway with WAF v2 az network application-gateway create \ --resource-group "your-resource-group" \ --name "your-app-gateway" \ --location "centralus" \ --sku WAF_v2 \ --capacity 2 \ --vnet-name "your-vnet" \ --subnet "ApplicationGatewaySubnet" \ --public-ip-address "your-public-ip"
-
Create DNS Zones:
# Create DNS zones for custom domains az network dns zone create \ --resource-group "your-resource-group" \ --name "yourapp1.com" az network dns zone create \ --resource-group "your-resource-group" \ --name "yourapp2.com"
-
Add A Records:
# Point domains to Application Gateway public IP az network dns record-set a add-record \ --resource-group "your-resource-group" \ --zone-name "yourapp1.com" \ --record-set-name "@" \ --ipv4-address "your-app-gateway-public-ip"
- Upload SSL Certificates:
# Upload certificate for app1 az network application-gateway ssl-cert create \ --resource-group "your-resource-group" \ --gateway-name "your-app-gateway" \ --name "app1cert" \ --cert-file "app1.crt" \ --cert-password "your-password"
- Create Backend Pools:
# Backend pool for app1 az network application-gateway address-pool create \ --resource-group "your-resource-group" \ --gateway-name "your-app-gateway" \ --name "app1" \ --servers "yourapp1.azurewebsites.net" # Backend pool for app2 az network application-gateway address-pool create \ --resource-group "your-resource-group" \ --gateway-name "your-app-gateway" \ --name "app2" \ --servers "yourapp2.azurewebsites.net"
- Create Health Probes:
# Health probe for app1 az network application-gateway probe create \ --resource-group "your-resource-group" \ --gateway-name "your-app-gateway" \ --name "probeapp1" \ --protocol Https \ --host "yourapp1.azurewebsites.net" \ --path "/health" \ --interval 30 \ --timeout 30 \ --threshold 3
- Create Backend HTTP Settings:
# HTTP settings for app1 az network application-gateway http-settings create \ --resource-group "your-resource-group" \ --gateway-name "your-app-gateway" \ --name "app1backend" \ --port 443 \ --protocol Https \ --host-name "yourapp1.azurewebsites.net" \ --probe "probeapp1" \ --timeout 20
- Create HTTPS Listeners:
# Listener for app1 az network application-gateway http-listener create \ --resource-group "your-resource-group" \ --gateway-name "your-app-gateway" \ --name "app1listener" \ --frontend-port "port_443" \ --frontend-ip "appGwPublicFrontendIpIPv4" \ --host-name "yourapp1.com" \ --ssl-cert "app1cert"
- Create Routing Rules:
# Routing rule for app1 az network application-gateway rule create \ --resource-group "your-resource-group" \ --gateway-name "your-app-gateway" \ --name "routerule1" \ --rule-type Basic \ --http-listener "app1listener" \ --address-pool "app1" \ --http-settings "app1backend" \ --priority 1
-
Create WAF Policy:
# Create WAF policy with OWASP 3.2 rules az network application-gateway waf-policy create \ --resource-group "your-resource-group" \ --name "wafpolicy" \ --location "centralus" # Add OWASP rule set az network application-gateway waf-policy managed-rule-set add \ --resource-group "your-resource-group" \ --policy-name "wafpolicy" \ --rule-set-type OWASP \ --rule-set-version 3.2 # Set WAF mode to Prevention az network application-gateway waf-policy policy-setting update \ --resource-group "your-resource-group" \ --policy-name "wafpolicy" \ --state Enabled \ --mode Prevention
-
Attach WAF Policy to Application Gateway:
az network application-gateway update \ --resource-group "your-resource-group" \ --name "your-app-gateway" \ --set firewallPolicy.id="/subscriptions/your-subscription/resourceGroups/your-resource-group/providers/Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies/wafpolicy"
-
Test Path Traversal Attack:
curl -k -i "https://yourapp1.com/?file=../../../../etc/passwd" # Should return 403 Forbidden (WAF blocked)
-
Test SQL Injection:
curl -k -i "https://yourapp1.com/api/secret/my-secret' OR 1=1--" # Should return 403 Forbidden (WAF blocked)
-
Test Normal Traffic:
curl -k -i "https://yourapp1.com/" # Should return 200 OK (normal traffic allowed)
Your Working Configuration:
- Application Gateway:
secretAppWafPoCAppGateway - Resource Group:
secretAppWafPoC - Custom Domains:
secretappwafpoc1.com→secretappwafpocapp1-euh9bkgjf2d6acea.centralus-01.azurewebsites.netsecretappwafpoc2.com→secretappwafpocapp2-aaf8hddmadftd7h4.centralus-01.azurewebsites.net
- WAF Policy:
wafpolicy(OWASP 3.2, Prevention mode) - Backend Pools:
app1,app2 - Health Probes:
/path, HTTPS, 30s interval - SSL Certificates: Self-signed certificates for custom domains
Key Configuration Details:
- SKU: WAF_v2 (Generation 2)
- Capacity: 2 instances
- Zones: 1, 2, 3 (multi-zone deployment)
- Backend Protocol: HTTPS (port 443)
- Request Timeout: 20 seconds
- Health Probe: HTTPS to
/endpoint
-
Enable Managed Identity:
- Go to your App Service in Azure Portal
- Navigate to "Identity" under Settings
- Turn on "System assigned" identity
- Note the Object ID
-
Grant Key Vault Access:
- Go to your Key Vault in Azure Portal
- Navigate to "Access policies" or "Access control (IAM)"
- Add the App Service's managed identity
- Grant "Get" permission for secrets
-
Set Application Settings:
- In your App Service, go to "Configuration"
- Add application setting:
KeyVaultUrl=https://your-keyvault-name.vault.azure.net/
- Navigate to your App Service URL
- Enter a secret name that exists in your Key Vault
- Click "Retrieve Secret"
- The secret value should be displayed
- The app uses managed identity for authentication (no stored credentials)
- Secrets are retrieved on-demand and not cached
- Ensure proper Key Vault access policies are configured
- Consider using Azure Private Endpoints for enhanced security
- "Failed to retrieve secret": Check that the secret name exists and the App Service has proper permissions
- Authentication errors: Verify managed identity is enabled and has Key Vault access
- Configuration errors: Ensure KeyVaultUrl is correctly set in app settings
View real-time logs:
az webapp log tail --resource-group "your-resource-group" --name "your-app-service-name"Download logs for analysis:
az webapp log download --resource-group "your-resource-group" --name "your-app-service-name" --log-file "logs.zip"Check App Service configuration:
az webapp config show --resource-group "your-resource-group" --name "your-app-service-name" --query "linuxFxVersion"Test API endpoint directly:
curl https://your-app-service-name.azurewebsites.net/api/secret/my-secretKeyVaultSecretApp/
├── Controllers/
│ └── HomeController.cs
├── Models/
│ └── ErrorViewModel.cs
├── Views/
│ ├── Home/
│ │ ├── Index.cshtml
│ │ └── Error.cshtml
│ ├── Shared/
│ │ └── _Layout.cshtml
│ ├── _ViewImports.cshtml
│ └── _ViewStart.cshtml
├── wwwroot/
│ ├── css/
│ │ └── site.css
│ └── js/
│ └── site.js
├── KeyVaultSecretApp.csproj
├── Program.cs
├── appsettings.json
├── appsettings.Development.json
└── web.config