# Worked solution — Probe, TLS and WAF are separate decisions This solution explains the required observations. Consult VALIDATION.md for actual release results. Expected output must never be presented as a live Azure capture. ## 1. Establish the complete healthy path Run Preflight and Plan, review the saved plan, then run the reviewed Deploy and Bootstrap stages. Use the same private state throughout. Wait for periodic backend health and request validation; an ARM deployment success does not establish IIS readiness. The client connects to the recorded gateway address for appgw.lab.test and trusts the generated public CA certificate explicitly. It verifies the frontend hostname. Application Gateway connects to the private IIS address over HTTPS, trusts the CA, and expects backend.lab.test. The server certificate contains that SAN. CA-chain and hostname checks remain enabled. Windows Schannel uses the documented best-effort handling for the disposable CA's missing CRL distribution service; that client precondition is separate from the backend name-mismatch exercise. Require successful requests and the exact synthetic marker for all owned routes. Confirm the expected WAF baseline and independent denial controls. This healthy evidence is the starting point for each fault. ## 2. Probe fault: repair the request path ~~~powershell ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Fault -Scenario Probe -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Validate -Scenario Probe -StatePath $state -Execute ~~~ The fault changes only the owned probe path. The resulting periodic probe reaches IIS but receives the missing-file response. Since only 200 is accepted, the exercise combination becomes unhealthy and Application Gateway returns 502 for its route. The separate control combination remains healthy and returns 200. Read the actual backend health reason and compare paths. It is not necessary to reinstall IIS, change routing or replace a certificate. Restoring /health.txt repairs the intended mistake. Adding 404 to the accepted statuses would instead label the wrong request healthy. ~~~powershell ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Repair -Scenario Probe -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Validate -Scenario Probe -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Repair -Scenario Probe -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Validate -Scenario Probe -StatePath $state -Execute ~~~ Both routes must now return the correct marker over trusted TLS. The second repair must be safe and must preserve unrelated values. ## 3. TLS fault: restore the expected name ~~~powershell ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Fault -Scenario Tls -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Validate -Scenario Tls -StatePath $state -Execute ~~~ The exercise settings now expect wrong.lab.test while IIS presents a certificate for backend.lab.test. The CA chain can remain valid and the VM can remain reachable, but name verification fails. Its custom probe inherits that incorrect expected name and periodic health exposes the TLS mismatch. The exercise route returns 502 while the independent control still returns 200. Restore the recorded expected hostname. Do not disable SNI/name, chain or expiration validation. A different private IP or VM replacement would add unrelated changes without repairing the original setting. ~~~powershell ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Repair -Scenario Tls -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Validate -Scenario Tls -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Repair -Scenario Tls -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Validate -Scenario Tls -StatePath $state -Execute ~~~ Require healthy periodic results and fresh successful responses, then safe repeated repair. ## 4. WAF fault: recover the safe field without bypassing inspection The final baseline contains the live-calibrated field/rule exclusion. The fault removes only that owned exclusion: ~~~powershell ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Fault -Scenario Waf -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Validate -Scenario Waf -StatePath $state -Execute ~~~ The legitimate documentation fixture now returns 403 while ordinary content succeeds and the backend remains healthy. Use the retained transaction to find actual managed-rule contributors. Group names and IDs belong to the pinned DRS 2.2 catalog; do not copy legacy group names from another tutorial. The repair restores RequestArgValues, operator Equals, selector labSnippet, scoped to the contributing managed rule IDs. It does not disable the rules globally, exclude the whole request, or exclude the anomaly threshold rule. The exclusion belongs to the gateway-associated WAF policy and applies across every path inspected by that policy, not only /docs. Its boundary is the exact field name labSnippet plus the three selected XSS rules; it is not a path restriction or an allowlist of specific snippet contents. Other fields and other rules, including aggregation rule 949110, remain inspected. The application is intentionally static and never executes or reflects the snippet: this explicit safe-field assumption is what makes the tuning exercise appropriate. ~~~powershell ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Repair -Scenario Waf -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Validate -Scenario Waf -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Repair -Scenario Waf -StatePath $state -Execute ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Validate -Scenario Waf -StatePath $state -Execute ~~~ After repair, the legitimate field returns 200, the same pattern in untrustedSnippet returns 403, and labMarker=awz-block-me still returns 403. The custom block marker confirms a separate policy decision; it does not replace managed-rule evidence. ## 5. Finish with consistency and absence evidence Run healthy validation and final Plan. All owned settings must match their intended baseline; final Terraform comparison must show no unexpected changes. Inspect the cleanup preview, execute the reviewed exact deletion and repeat cleanup. Export reviewed sanitized evidence only after required checks are recorded. ~~~powershell ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Validate -StatePath $state -Execute -CollectLogs ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Plan -StatePath $state ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Cleanup -StatePath $state ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Cleanup -StatePath $state -Execute -ReviewedPlan ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Cleanup -StatePath $state -Execute -ReviewedPlan ./Invoke-AppGatewayWafWorkshop.ps1 -Stage Export -StatePath $state ~~~ Deletion acceptance means the exact recorded resources are absent, not merely that Azure accepted a delete call. The second cleanup must create nothing and unrelated protected resources must remain unchanged. Preserve the private ledger until residual checks finish.