Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/LOCAL_DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,17 @@ Review the configuration options below. You can customize any settings that meet
|------------|-----------------------------------|----------------|
| **Configuration File** | `main.parameters.json` (sandbox) | Copy `main.waf.parameters.json` to `main.parameters.json` |
| **Security Controls** | Minimal (for rapid iteration) | Enhanced (production best practices) |
| **Network Access** | All services publicly accessible | Backend API (Function App) restricted to private network; only frontend publicly accessible |
| **Private Endpoints** | Disabled | Enabled for backend services (Storage, Key Vault, Cosmos DB/PostgreSQL, OpenAI, Search). Function App private endpoint is included for container hosting; for code hosting, keep API private access without adding a Function App private endpoint. |
| **Cost** | Lower costs | Cost optimized |
| **Use Case** | POCs, development, testing | Production workloads |
| **Framework** | Basic configuration | [Well-Architected Framework](https://learn.microsoft.com/en-us/azure/well-architected/) |
| **Features** | Core functionality | Reliability, security, operational excellence |

> **Note - WAF Deployment (Restrict API to Private Access, Function App on App Service Plan Accelerators):**
> If `AZURE_APP_SERVICE_HOSTING_MODEL` is set to `code`, do **not** implement a private endpoint for the backend API Function App.
> Keep the API restricted through App Service access restrictions/private networking controls applicable to code hosting.

**To use production configuration:**

Copy the contents from the production configuration file to your main parameters file:
Expand Down
16 changes: 16 additions & 0 deletions docs/best_practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,22 @@ Moreover, optimizing the data in the index also enhances the efficiency, the spe
- For the best results, prepare your index data and consider [analyzers](https://learn.microsoft.com/azure/search/search-analyzers).
- Analyze your [resource capacity needs](https://learn.microsoft.com/azure/search/search-capacity-planning).

**Network Security (Production/WAF Deployment)**

When deploying with the production/WAF configuration (`enablePrivateNetworking: true`), the following network security measures are automatically applied:

- **Private Endpoints**: Backend services including Azure OpenAI, Azure AI Search, Storage Account, Key Vault, and Cosmos DB/PostgreSQL are configured with private endpoints. For the Function App (backend API), private endpoint is used in container hosting; in code hosting, follow access restrictions/private networking controls without adding a Function App private endpoint.
- **Function App (Backend API)**: The Function App hosting the backend API is secured with:
- Private endpoint for inbound traffic in container hosting
- VNet integration for outbound traffic
- Public inbound access blocked using App Service access restrictions
- Communication limited to approved private paths and network controls
- **Frontend Web Apps**: The App Service (frontend) and Admin App remain publicly accessible to serve user traffic, while communicating with backend services through the private network.
- **Virtual Network**: All resources are integrated into a secure virtual network with properly configured subnets and Network Security Groups (NSGs).
- **Bastion Host**: A jumpbox VM accessible via Azure Bastion is provided for management access to private resources.

This architecture ensures that only the frontend applications are publicly accessible, while all backend APIs and data services remain protected within the private network boundary.

**Before deploying Azure RAG implementations to production**

- Follow the best practices described in [Azure Well-Architected-Framework](https://learn.microsoft.com/azure/well-architected/).
Expand Down
39 changes: 38 additions & 1 deletion infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ var privateDnsZones = [
'privatelink.openai.azure.com'
'privatelink.vaultcore.azure.net'
'privatelink.api.azureml.ms'
'privatelink.azurewebsites.net'
]

// DNS Zone Index Constants
Expand All @@ -638,6 +639,7 @@ var dnsZoneIndex = {
openAI: 7
keyVault: 8
machinelearning: 9
azureWebsites: 10 // 'privatelink.azurewebsites.net'
}

// ===================================================
Expand Down Expand Up @@ -1433,7 +1435,42 @@ module function 'modules/app/function.bicep' = {
virtualNetworkSubnetId: enablePrivateNetworking ? virtualNetwork!.outputs.webSubnetResourceId : ''
vnetRouteAllEnabled: enablePrivateNetworking ? true : false
vnetImagePullEnabled: enablePrivateNetworking ? true : false
publicNetworkAccess: 'Enabled' // Always enabling public network access
// WAF: Use IP restrictions to block public API access while allowing SCM for deployments
// publicNetworkAccess stays Enabled, but ipSecurityRestrictions blocks public traffic to the main site
publicNetworkAccess: 'Enabled'
// Block all public access to the main site (API)
ipSecurityRestrictions: (enablePrivateNetworking && hostingModel == 'container')
? [
{
name: 'DenyAllPublicAccess'
description: 'Deny public access to API endpoint.'
action: 'Deny'
priority: 100
ipAddress: '0.0.0.0/0'
}
]
: []
// SCM restrictions: Keep empty to allow deployments from any location (or restrict to specific IPs if needed)
scmIpSecurityRestrictions: []
// Do NOT inherit main site restrictions for SCM - this allows deployments while API is private
scmIpSecurityRestrictionsUseMain: false
privateEndpoints: (enablePrivateNetworking && hostingModel == 'container')
? [
{
name: 'pep-${hostingModel == 'container' ? '${functionName}-docker' : functionName}'
customNetworkInterfaceName: 'nic-${hostingModel == 'container' ? '${functionName}-docker' : functionName}'
privateDnsZoneGroup: {
privateDnsZoneGroupConfigs: [
{
privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.azureWebsites]!.outputs.resourceId
}
]
}
service: 'sites'
subnetResourceId: virtualNetwork!.outputs.pepsSubnetResourceId
}
]
: []
appSettings: union(
{
AZURE_BLOB_ACCOUNT_NAME: storageAccountName
Expand Down
Loading