Skip to content

feat: Restrict backend API to private access in WAF deployment#173

Open
Prajwal-Microsoft wants to merge 2 commits intodevfrom
feature/39249-waf-api-private-access
Open

feat: Restrict backend API to private access in WAF deployment#173
Prajwal-Microsoft wants to merge 2 commits intodevfrom
feature/39249-waf-api-private-access

Conversation

@Prajwal-Microsoft
Copy link
Copy Markdown
Collaborator

Purpose

When enablePrivateNetworking (WAF mode) is active, the backend API App Service (api-{suffix}) was still publicly accessible on the internet. This PR restricts the backend API to private-only access while keeping the frontend Web App publicly reachable — aligning with the WAF security posture.

Changes

Infrastructure (infra/main.bicep & infra/main_custom.bicep):

  • Added privatelink.azurewebsites.net private DNS zone linked to VNet
  • Created private endpoint for backend API in the backend subnet
  • Set publicNetworkAccess: 'Disabled' for the backend API when enablePrivateNetworking=true
  • Frontend sets VITE_API_BASE_URL to empty (same-origin) and passes BACKEND_API_URL for the nginx proxy

Frontend (src/App/):

  • nginx.conf: Added include for dynamically generated API proxy config
  • startup.sh: Generates nginx reverse proxy config at container startup — proxies /api/* to backend over VNet using Azure DNS resolver (168.63.129.16). Sets VITE_API_BASE_URL to window.location.origin in WAF mode so the SPA correctly calls its own origin
  • Dockerfile: Creates empty placeholder api-proxy.conf during build

Architecture (WAF mode)

Browser → Frontend App (public) → nginx /api/* proxy → VNet → Backend API (private endpoint)

Non-WAF deployments are unchanged — direct public API access continues as before.

Resolves AB#39249

Does this introduce a breaking change?

  • Yes
  • No

How to Test

  • Deploy using WAF parameters:
# Copy WAF params and deploy
cp infra/main.waf.parameters.json infra/main.parameters.json
azd up
  • After deployment, run post-deployment scripts (data upload + agent creation)
  • Verify backend API is blocked from public internet:
curl https://api-{suffix}.azurewebsites.net/health   # Should return 403 Ip Forbidden
  • Verify frontend is accessible and API works through proxy:
curl https://app-{suffix}.azurewebsites.net           # Should return 200
curl https://app-{suffix}.azurewebsites.net/api/products/  # Should return product data

What to Check

Verify that the following are valid

  • Backend API returns 403 Ip Forbidden from public internet in WAF deployment
  • Frontend Web App is publicly accessible (200 OK)
  • Products load on the frontend (API calls proxied through nginx)
  • Chat functionality works end-to-end
  • Non-WAF deployment still works as before (no regressions)

Other Information

  • Tested with full WAF deployment to Australia East on CSA-CTO-Engineering-Maintenance subscription
  • Playwright e2e tests: 7/11 passed (4 failures are pre-existing and unrelated to this change)
  • The nginx proxy uses Azure DNS resolver 168.63.129.16 for private DNS resolution and proxy_ssl_server_name on for SNI

Prajwal-Microsoft and others added 2 commits April 3, 2026 16:07
When enablePrivateNetworking (WAF mode) is active:

- Add privatelink.azurewebsites.net private DNS zone linked to VNet
- Create private endpoint for backend API App Service in backend subnet
- Set publicNetworkAccess to Disabled for backend API
- Frontend nginx reverse-proxies /api/ requests to backend over VNet
- VITE_API_BASE_URL set to empty string so SPA calls same origin
- BACKEND_API_URL env var drives dynamic nginx proxy config at startup
- Non-WAF deployments remain unchanged (direct public API access)

Resolves US#39249

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When VITE_API_BASE_URL is empty string, the React app's getApiBaseUrl()
treats it as falsy and defaults to http://localhost:8000. Fix by setting
it to window.location.origin (a JS expression) in the runtime config
when in WAF/private networking mode, so the SPA correctly calls its own
origin where nginx proxies /api/ to the private backend.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant