This project demonstrates best practices for managing configuration in Azure applications, showing how to use:
- Environment Variables
- Application Settings (appsettings.json)
- Azure Key Vault
- Infrastructure as Code (Bicep)
- CI/CD Pipeline Configuration
.
βββ src/
β βββ Program.cs # Main application entry point
β βββ AppSettings.cs # Strongly-typed configuration class
β βββ appsettings.json # Base configuration
β βββ appsettings.Development.json # Development environment settings
β βββ appsettings.Staging.json # Staging environment settings
β βββ appsettings.Production.json # Production environment settings
βββ infra/
β βββ main.bicep # Infrastructure as Code template
βββ azure-pipelines.yml # CI/CD pipeline configuration
- Use Case: Runtime overrides, sensitive data, environment-specific values
- Example:
ASPNETCORE_ENVIRONMENT
,ConnectionStrings__DefaultConnection
- Best Practice: Use for values that change between environments or contain sensitive data
- Use Case: Default configuration, non-sensitive settings
- Structure:
{ "AppSettings": { "Environment": "Development", "ApiSettings": { "BaseUrl": "https://api.dev.example.com", "Timeout": 30, "RetryCount": 3 } } }
- Best Practice: Use for default values and non-sensitive configuration
- Use Case: Secrets management, sensitive configuration
- Example: API keys, connection strings, certificates
- Best Practice: Use for all sensitive data, never store secrets in code or configuration files
The application follows this configuration hierarchy (highest to lowest priority):
- Environment Variables
- Azure Key Vault
- Environment-specific appsettings.json (Development/Staging/Production)
- Base appsettings.json
Each environment has its own configuration file with appropriate settings:
{
"AppSettings": {
"Environment": "Development",
"ApiSettings": {
"BaseUrl": "https://api.dev.example.com",
"Timeout": 30,
"RetryCount": 3
}
}
}
{
"AppSettings": {
"Environment": "Staging",
"ApiSettings": {
"BaseUrl": "https://api.staging.example.com",
"Timeout": 45,
"RetryCount": 5
}
}
}
{
"AppSettings": {
"Environment": "Production",
"ApiSettings": {
"BaseUrl": "https://api.example.com",
"Timeout": 60,
"RetryCount": 3
}
}
}
The project uses Bicep for infrastructure deployment:
// Key Vault setup
resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' = {
name: '${namePrefix}-kv'
// ... other properties
}
// App Service setup
resource appService 'Microsoft.Web/sites@2022-09-01' = {
name: '${namePrefix}-app'
// ... other properties
}
The Azure Pipeline (azure-pipelines.yml
) handles:
-
Build Stage:
- Builds the application
- Transforms configuration for each environment
- Creates deployment packages
-
Deploy Stage:
- Deploys infrastructure using Bicep
- Copies environment-specific configuration
- Deploys application to Azure Web App
-
Build Process:
- task: FileTransform@1 inputs: folderPath: '$(System.DefaultWorkingDirectory)/src' fileType: 'json' targetFiles: 'appsettings.json' transformFile: 'appsettings.Development.json'
-
Deployment Process:
- task: CopyFiles@2 inputs: SourceFolder: '$(Pipeline.Workspace)/drop/Development' Contents: 'appsettings.json' TargetFolder: '$(Pipeline.Workspace)/drop'
-
Never store secrets in:
- Source code
- Configuration files
- Environment variables in source control
-
Always use Azure Key Vault for:
- Connection strings
- API keys
- Certificates
- Other sensitive data
-
Environment-specific security:
- Development: Minimal security for easy debugging
- Staging: Mirror production security
- Production: Maximum security, strict access controls
-
Local Development:
dotnet run --environment Development
-
Azure Setup:
# Deploy infrastructure az deployment group create \ --resource-group $(resourceGroup) \ --template-file infra/main.bicep \ --parameters environment=dev
-
Pipeline Setup:
- Configure Azure DevOps pipeline
- Set up environment variables
- Configure service connections
-
Local Testing:
# Override settings $env:ApiSettings__BaseUrl = "https://localhost:5001" dotnet run
-
Azure Testing:
- Use Azure Portal to verify Key Vault integration
- Check App Service configuration
- Monitor application logs
-
Configuration Management:
- Use strongly-typed configuration
- Implement configuration validation
- Follow the configuration hierarchy
-
Security:
- Use Key Vault for all secrets
- Implement proper access controls
- Regular secret rotation
-
Deployment:
- Use infrastructure as code
- Automate all deployments
- Implement proper testing
-
Monitoring:
- Log configuration changes
- Monitor Key Vault access
- Track configuration errors