Skip to content

Network Architecture

📝 Updated (2025-10-24): This document has been updated to reflect current architecture: - Azure Bastion + Jump Box VM (replaces VPN Gateway) - ADR-050 - ACI Container Group (replaces Container Apps) - ADR-049 - Semantic layer names (Foundation, Substrate, AI Models, Apps) - ADR-052

Complete network design for Loan Defenders Azure deployment


Table of Contents

  1. Overview
  2. VNet Design
  3. Subnet Allocation
  4. CIDR Strategy
  5. Network Security Groups (NSGs)
  6. Private Endpoints
  7. Azure Bastion (Dev Environment)
  8. DNS Configuration
  9. Network Flow
  10. Best Practices
  11. Related Architecture Decisions

Overview

Loan Defenders uses a secure, private network architecture based on Azure VNet with multiple subnets for isolation, Network Security Groups for traffic control, and private endpoints for secure Azure service access.

Key Principles: - Zero Trust network architecture - Private communication by default - Subnet-based isolation - NSG-based traffic control - No public endpoints for backend services

Related Documentation: - Azure Deployment Architecture - High-level system overview - Security Architecture - Security implementation details - Bastion Dev Access - Browser-based VNet access guide


VNet Design

Network Diagram

graph TB
    subgraph "Azure VNet (10.0.0.0/16)"
        subgraph "Compute Subnet (10.0.1.0/24)"
            ACI[ACI Container Group<br/>UI + API + 3 MCP]
        end

        subgraph "Private Endpoints Subnet (10.0.2.0/24)"
            PE1[Private Endpoint<br/>AI Foundry]
            PE2[Private Endpoint<br/>ACR]
            PE3[Private Endpoint<br/>Key Vault]
        end

        subgraph "Bastion Subnet (10.0.3.0/26)"
            Bastion[Azure Bastion<br/>Dev Only]
            JumpBox[Windows Jump Box VM<br/>Dev Only]
        end
    end

    Internet[Internet] -->|HTTPS| ACI
    Devs[Developers] -->|Browser RDP| Bastion
    Bastion -->|RDP| JumpBox
    JumpBox -->|Access| ACI
    ACI -->|Private| PE1
    ACI -->|Private| PE2
    ACI -->|Private| PE3

    style ACI fill:#4CAF50
    style PE1 fill:#2196F3
    style PE2 fill:#2196F3
    style PE3 fill:#2196F3
    style Bastion fill:#FF9800
    style JumpBox fill:#FFC107
    subgraph "Application Subnet (10.0.2.0/24)"
        API[API Container App<br/>Internal Only]
    end

    subgraph "MCP Subnet (10.0.3.0/24)"
        MCP1[MCP: App Verification<br/>Port 8010]
        MCP2[MCP: Document Processing<br/>Port 8011]
        MCP3[MCP: Financial Calc<br/>Port 8012]
    end

    subgraph "AI Subnet (10.0.4.0/24)"
        AI[Azure AI Services<br/>Private Endpoint]
    end

    subgraph "Infrastructure Subnet (10.0.0.0/24)"
        ACR[Container Registry<br/>Private]
        KV[Key Vault<br/>Private]
    end

    subgraph "Bastion Subnet (10.0.5.0/26)"
        Bastion[Azure Bastion + Jump Box]
    end
end

Users[Internet Users] -->|HTTPS| UI
UI -->|Internal| API
API -->|Internal| MCP1
API -->|Internal| MCP2
API -->|Internal| MCP3
API -->|Private Endpoint| AI
API -->|Private Endpoint| ACR
API -->|Private Endpoint| KV
Devs[Developers] -.->|Browser RDP| Bastion
Bastion -.->|Jump Box → VNet| API

style UI fill:#90EE90
style API fill:#FFB6C1
style MCP1 fill:#FFD700
style MCP2 fill:#FFD700
style MCP3 fill:#FFD700
style AI fill:#87CEEB
style Bastion fill:#DDA0DD

```

VNet Configuration

Address Space: 10.0.0.0/16 (65,536 addresses) Region: Same as resource group (e.g., eastus) DNS: Azure-provided DNS with custom DNS for private endpoints


Subnet Allocation

Subnet CIDR Addresses Purpose NSG
Infrastructure 10.0.0.0/24 256 ACR, Key Vault, Managed Identities ✅ Yes
Public 10.0.1.0/24 256 UI Container App (public ingress) ✅ Yes
Application 10.0.2.0/24 256 API Container App (internal only) ✅ Yes
MCP Services 10.0.3.0/24 256 3 MCP Server Container Apps ✅ Yes
AI Services 10.0.4.0/24 256 Azure AI Services private endpoint ✅ Yes
Bastion 10.0.5.0/26 64 Azure Bastion + Jump Box ❌ No (Azure managed)
Total Allocated: 1,312 addresses (2% of VNet)
Available for Growth: 64,224 addresses (98% of VNet)
---
## CIDR Strategy
### Allocation Rationale
Why /16 VNet?
- Provides 65,536 addresses
- Room for 256 /24 subnets
- Future-proof for scaling
- Standard enterprise practice
Why /24 Subnets?
- 256 addresses per subnet
- Enough for auto-scaling (up to 100+ containers)
- Standard subnet size for Azure
- Easy to remember and manage
Why /26 for Bastion?
- Azure requirement for Gateway Subnet
- Minimum recommended size
- 32 addresses sufficient for VPN
### Reserved Addresses
Azure reserves 5 addresses per subnet:
- x.x.x.0 - Network address
- x.x.x.1 - Default gateway
- x.x.x.2, x.x.x.3 - Azure DNS
- x.x.x.255 - Broadcast address
Usable addresses per /24 subnet: 251
---
## Network Security Groups (NSGs)
### NSG Rules per Subnet
#### Infrastructure Subnet NSG
Inbound:
Priority Name Source Destination Port
---------- ------ -------- ------------- ------
100 Allow-VNet-Inbound VirtualNetwork VirtualNetwork *
4096 Deny-All-Inbound * * *
Outbound:
Priority Name Source Destination Port
---------- ------ -------- ------------- ------
100 Allow-VNet-Outbound VirtualNetwork VirtualNetwork *
110 Allow-Internet-Outbound * Internet 443
4096 Deny-All-Outbound * * *
---
#### Public Subnet NSG
Inbound:
Priority Name Source Destination Port
---------- ------ -------- ------------- ------
100 Allow-HTTPS-Inbound Internet * 443
110 Allow-VNet-Inbound VirtualNetwork VirtualNetwork *
4096 Deny-All-Inbound * * *
Outbound:
Priority Name Source Destination Port
---------- ------ -------- ------------- ------
100 Allow-VNet-Outbound VirtualNetwork VirtualNetwork *
110 Allow-Internet-Outbound * Internet 443
4096 Deny-All-Outbound * * *
---
#### Application & MCP Subnets NSG
Inbound:
Priority Name Source Destination Port
---------- ------ -------- ------------- ------
100 Allow-VNet-Inbound VirtualNetwork VirtualNetwork *
4096 Deny-All-Inbound * * *
Outbound:
Priority Name Source Destination Port
---------- ------ -------- ------------- ------
100 Allow-VNet-Outbound VirtualNetwork VirtualNetwork *
110 Allow-HTTPS-Outbound * Internet 443
4096 Deny-All-Outbound * * *
---
## Private Endpoints
### Private Endpoint Configuration
Services with Private Endpoints:
1. Azure Container Registry - Pull container images privately
2. Azure Key Vault - Access secrets privately
3. Azure AI Services - AI model inference privately
4. Azure Storage (if used) - Blob/file access privately
### Private DNS Zones
Service DNS Zone Example Record
--------- ---------- ----------------
Container Registry privatelink.azurecr.io myacr.azurecr.io10.0.0.10
Key Vault privatelink.vaultcore.azure.net mykv.vault.azure.net10.0.0.11
AI Services privatelink.cognitiveservices.azure.com myai.cognitiveservices.azure.com10.0.4.10
Storage Account privatelink.blob.core.windows.net mysa.blob.core.windows.net10.0.0.12
Configuration:
- Private DNS zones automatically created by Bicep
- Linked to VNet for resolution
- A records point to private endpoint IPs
- No public DNS exposure
---
## Azure Bastion (Dev Environment)
> 📝 Updated (2025-10-24): VPN Gateway has been replaced by Azure Bastion + Windows Jump Box VM (ADR-050).
>
> Benefits:
> - Browser-based RDP access (no VPN client installation)
> - Lower cost (~$210/month vs ~$360/month for VPN)
> - Faster provisioning (10 minutes vs 45 minutes)
> - Windows environment for UI testing
### Bastion Architecture
Azure Bastion:
- Subnet: AzureBastionSubnet (10.0.3.0/26 - 64 addresses)
- SKU: Standard
- Access: Browser-based RDP from Azure Portal
- Security: No public IP on Jump Box VM
Windows Jump Box VM:
- Image: Windows Server 2022 Datacenter
- Size: Standard_D2s_v3 (2 vCPU, 8 GB RAM)
- Network: Private subnet, no public IP
- Access: Via Bastion only
- Purpose: Browser access to ACI containers for UI testing
### Accessing VNet Resources
1. Navigate to Azure Portal
2. Go to Jump Box VM resource
3. Click ConnectBastion
4. Enter credentials
5. Browser-based RDP session opens
6. From Jump Box, access containers via:
- UI: http://10.0.1.4:80
- API: http://10.0.1.4:8000
- MCP Servers: http://10.0.1.4:8010-8012
### Cost Management
Cost Optimization:
```bash
# Stop VM when not in use (saves ~$70/month)
az vm deallocate -g -n
# Start VM when needed
az vm start -g -n
# Delete Bastion during extended breaks (saves ~$140/month, redeploys in 10 min)
az network bastion delete -g -n
```

Monthly Costs: - Bastion: ~$140/month - Jump Box VM: ~$70/month (running), $0 (stopped) - Total: ~$210/month (vs ~$360/month for VPN Gateway)

See: ADR-050: Bastion Replaces VPN Gateway


Deprecated: VPN Gateway (Historical)

⚠️ DEPRECATED: VPN Gateway has been replaced by Azure Bastion + Jump Box VM.

This section is kept for historical reference. For current dev access, see Azure Bastion.

Historical VPN Gateway Documentation ### Overview **Purpose:** Secure developer access to internal resources **Type:** Point-to-Site (P2S) VPN **Deployed:** Dev environment only (production uses Azure Bastion or private connectivity) ### Configuration **Gateway Subnet:** `10.0.5.0/27` (32 addresses) **Gateway SKU:** VpnGw1 (Basic for dev, higher for prod) **VPN Type:** RouteBased **Client Address Pool:** `172.16.0.0/24` (256 client addresses) **Authentication:** Azure Active Directory (certificate-based alternative available) **Protocols:** OpenVPN (UDP 1194), IKEv2 **Tunnel Type:** Split tunnel (only Azure traffic goes through VPN) ### Cost **Dev Environment:** ~$140/month (VpnGw1 SKU) **Production:** ~$500-1,000/month (VpnGw2-4 SKUs with high availability) **Alternative:** Azure Bastion (~$140/month, no client required) **See:** [VPN Dev Access Guide](../deployment/vpn-dev-access.md) for setup instructions (DEPRECATED)

DNS Configuration

Azure-Provided DNS

Default: 168.63.129.16 (Azure recursive resolvers)

Resolution: - Public Azure service FQDNs - Private endpoint FQDNs (via private DNS zones) - Internet domain names

Private DNS Zones

Automatic creation and linking:

resource privateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = {
  name: 'privatelink.azurecr.io'
  location: 'global'
}

resource privateDnsZoneLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = {
  parent: privateDnsZone
  name: 'vnet-link'
  location: 'global'
  properties: {
    virtualNetwork: {
      id: vnet.id
    }
    registrationEnabled: false
  }
}

DNS Resolution Flow

graph LR
    App[Container App] -->|Query: myacr.azurecr.io| AzureDNS[Azure DNS<br/>168.63.129.16]
    AzureDNS -->|Check private DNS zones| PrivateDNS[Private DNS Zone<br/>privatelink.azurecr.io]
    PrivateDNS -->|Return| PrivateIP[Private IP<br/>10.0.0.10]
    PrivateIP --> App

    App2[Container App] -->|Query: google.com| AzureDNS
    AzureDNS -->|Forward to Internet DNS| PublicDNS[Public DNS]
    PublicDNS -->|Return| PublicIP[Public IP]
    PublicIP --> App2

Network Flow

External User → UI

Internet User (HTTPS)
Azure Load Balancer (Public IP)
UI Container App (10.0.1.x)
Internal communication to API

UI → API → MCP

UI Container App (10.0.1.x)
    ↓ (Internal VNet)
API Container App (10.0.2.x)
    ↓ (Internal VNet)
MCP Container Apps (10.0.3.x)
    ↓ (Private Endpoint)
Azure AI Services (10.0.4.x)

Developer Access (Dev Environment)

Developer Laptop
    ↓ (OpenVPN/IKEv2)
VPN Gateway (10.0.5.x)
    ↓ (VNet routing)
Any internal resource (10.0.x.x)

Best Practices

Network Security

  1. Private by Default
  2. All backend services use internal communication
  3. Private endpoints for Azure services
  4. No public IPs except UI load balancer

  5. Least Privilege NSG Rules

  6. Deny all by default
  7. Allow only required traffic
  8. Document every allow rule

  9. Subnet Isolation

  10. Separate subnets per tier
  11. NSGs on every subnet
  12. No cross-tier communication except via API

Scalability

  1. Large VNet Address Space
  2. Use /16 or larger for VNet
  3. Allows future subnet additions
  4. Room for scaling within subnets

  5. Appropriately Sized Subnets

  6. /24 provides 251 usable addresses
  7. Enough for auto-scaling scenarios
  8. Not wasteful of address space

  9. Reserve Address Space

  10. Don't allocate all subnets initially
  11. Leave room for new services
  12. Plan for growth

Operations

  1. Consistent Naming
  2. {prefix}-{env}-vnet
  3. {prefix}-{env}-subnet-{purpose}
  4. {prefix}-{env}-nsg-{subnet}

  5. Tag Everything

  6. Environment (dev, staging, prod)
  7. Cost center
  8. Owner/team
  9. Application

  10. Monitor Network

  11. Enable NSG flow logs
  12. Use Network Watcher
  13. Alert on unusual traffic
  14. Regular security reviews

Network Design: - ADR-049: ACI vs Container Apps - Container platform decision - ADR-050: Bastion Replaces VPN Gateway - Dev access approach - ADR-052: Layer Renaming - Infrastructure organization

Security: - ADR-047: Layer-Specific RBAC - Access control architecture - ADR-048: Key Vault for Outputs - Deployment state management


Architecture: - Azure Deployment Architecture - High-level overview - Security Architecture - Security implementation - 4-Layer Deployment Cake - Deployment layers

Operational Guides: - Bastion Dev Access - Browser-based VNet access - Direct Azure Deployment - Deployment instructions - GitHub CI/CD Deployment - Automated deployment


For deployment instructions, see: Direct Azure Deployment or GitHub CI/CD Deployment