WAF and Custom Domain¶
This page is for the platform team. It describes how to put the portal behind an Application Gateway with a Web Application Firewall (WAF) and how to serve it under a custom domain. It is a reference design: the settings below are what works for the portal, but your gateway module, names and priorities will differ. The WAF is optional and is arranged before the deployment starts (Prerequisites).
flowchart LR
user[User] -->|HTTPS, custom domain| agw[Application Gateway<br/>WAF policy, HTTPS listener]
agw -->|HTTPS, rewrite headers| app[Portal web app<br/>private endpoint]
agw -.->|probe| h[/.backstage/health/v1/liveness/]
Custom domain¶
- Entra app registration. Add the redirect URI
https://<portal-domain>/api/auth/microsoft/handler/frameto the app registration of the environment. - Terraform. Set the
domain_namevariable of thebackstagemodule in the environment root. The module then sets the app settingsAPP_CONFIG_app_baseUrlandAPP_CONFIG_backend_baseUrl, so the backend knows the URL that users use.
module "backstage" {
source = "../../modules/backstage"
# ...
domain_name = "portal.contoso.example"
}
- DNS and certificate. The customer provides the DNS record that points to the gateway (or web app) and a TLS certificate. See Prerequisites.
WAF policy¶
Use one WAF policy per environment, attached to the HTTPS listener of the portal. Microsoft's Default Rule Set 2.1 (DRS 2.1) works best with the portal when you also apply Microsoft's fine-tuning guidance for it.
| Setting | Value |
|---|---|
| Mode | Prevention |
| Rule set | Microsoft_DefaultRuleSet 2.1 |
| Request body check | Off in the example (maximum body size 128 KB, file upload limit 100 MB) |
| Log scrubbing | On |
Rule overrides in the example policy:
| Rule group | Rule | Setting | Reason |
|---|---|---|---|
| SQLI | 942110, 942150, 942260, 942430, 942440 | Disabled | Microsoft's fine-tuning guidance for DRS 2.1 |
| LFI | 930120 | Enabled, action Log | The portal can generate requests that trigger false positives |
| PROTOCOL-ENFORCEMENT | 920440 | Enabled, action Log | Same |
Tune in Log mode first
If you see blocked requests that you cannot explain, switch the rule to Log, find the request in the WAF logs and tune from there.
Application Gateway¶
Create the following elements for the portal. The names are examples.
| Element | Configuration |
|---|---|
| Backend pool | FQDN of the web app, <app-service-name>.azurewebsites.net |
| Backend setting | HTTPS on port 443, host name set to the web app FQDN, request timeout 30 seconds, cookie-based affinity disabled |
| HTTPS listener | Host name <portal-domain>, SNI required, certificate from Key Vault, the WAF policy attached |
| HTTP listener | Redirects to the HTTPS listener (permanent, keep path and query), so a URL pasted without protocol works |
| Routing rules | One for the HTTPS listener (backend pool, backend setting, rewrite rule set), one for the HTTP listener (redirect) |
| Rewrite rule set | Adds request headers X-Forwarded-Host with {var_host} and X-Original-URL with {var_uri_path} |
| Health probe | HTTPS, host set to the web app FQDN, interval 30 s, timeout 30 s, unhealthy threshold 3, expects status 200 |
Health probe endpoint¶
The portal has two health endpoints.
| Endpoint | Behaviour |
|---|---|
/.backstage/health/v1/liveness |
Returns 200 while the process is up |
/.backstage/health/v1/readiness |
Also returns 503 before the backend has finished starting, while it shuts down, and while the Microsoft auth provider credential fails validation |
The example probe uses liveness. With it, the portal stays reachable while a failing credential is being fixed. Use readiness if you want the gateway to take an instance out of the pool during start-up, shutdown or a credential failure.
Web app access¶
Decide whether the web app is reachable only through the gateway. The backstage module has a setting for public network access with three values: none, full (the default) and a restricted value intended for the Azure AI agent service. See Architecture. If you use the gateway as the only entry, restrict direct access to the web app.