Networking

Azure Firewall: validate Threat Intelligence before blocking production

A production runbook for qualifying Azure Firewall Threat Intelligence with logs, false positives, critical flows, targeted exceptions, deny decision and rollback before enabling Deny.

28 Jul 2026 azureazure-firewallthreat-intelligencesecuritynetworkingkqlobservabilityrunbookrollbackproduction

Azure Firewall Threat Intelligence can turn a reputation signal into a network blocking decision. That is valuable when a workload tries to reach a malicious or compromised destination. It is risky when Deny mode is enabled without enough evidence: a partner flow, SaaS API, update dependency or logging path can be blocked as if it were hostile.

The use case is an Azure hub-and-spoke platform where outbound Internet traffic goes through Azure Firewall. Threat Intelligence is currently in Alert, or the team is considering Deny after repeated alerts on external IPs and FQDNs. The runbook goal is to decide whether blocking can be enabled, whether the team should stay in alert-only mode, whether a targeted exception is justified, whether an application flow must be corrected, or whether the change must be rolled back after a false positive.

Name the security change

Start by describing what will actually change. Threat Intelligence is not an application rule written by the team. It is a filtering decision based on reputation indicators used by Azure Firewall. Moving from Alert to Deny changes production behavior even if no explicit network rule was added.

yaml threat-intel-change-scope.yml
change:
firewall: azfw-hub-prod
current_mode: Alert
target_mode: Deny
scope: outbound internet traffic from production spokes
owner: security-and-networking
window: 2026-07-28T20:00:00Z

evidence_required:
- threat_intel_alerts_by_source_and_destination
- application_or_flow_owner
- business_criticality
- known_partner_or_saas_dependency
- firewall_rule_that_currently_allows_the_flow
- validation_probe_after_change
- rollback_command_and_expected_time

Without this contract, the team can treat Threat Intelligence blocking as a small hardening step. In production, it is a routing and security change that must be observable and reversible.

Read alerts before deciding

The first move is to read Azure Firewall logs, not to change the mode. Identify sources, destinations, protocols, matching rules and trends. A single alert from a test VM does not carry the same weight as repeated alerts from several production subnets.

kusto 01-threat-intel-alerts.kql
let StartTime = ago(7d);
AZFWThreatIntel
| where TimeGenerated > StartTime
| project TimeGenerated,
        Firewall = Resource,
        SourceIp,
        DestinationIp,
        DestinationPort,
        Protocol,
        Action,
        ThreatIntelDescription,
        ThreatIntelConfidence,
        Fqdn = tostring(Fqdn)
| summarize Events=count(),
          FirstSeen=min(TimeGenerated),
          LastSeen=max(TimeGenerated),
          Actions=make_set(Action),
          Descriptions=make_set(ThreatIntelDescription, 5)
by Firewall, SourceIp, DestinationIp, DestinationPort, Protocol, Fqdn
| order by Events desc, LastSeen desc

Adapt table names if your environment uses a legacy table or a different export. The goal is stable: isolate affected flows before turning an alert into a block.

Tie the signal to a business flow

A flagged destination is not enough to decide. You need to know which workload is reaching it, which rule allows it, whether the flow is expected, and who can confirm the dependency. This avoids blocking a legitimate dependency that happens to use a shared CDN, cloud edge or provider range.

text flow-qualification.txt
Qualification questions
Which subnet or workload owns SourceIp?
Which application or job triggers the flow?
Which Azure Firewall rule currently allows the outbound path?
Is the destination a partner, CDN, SaaS API or unknown IP?
Does the flow appear in application documentation or IaC?
Does the same flow exist in preproduction?
Can broad access be replaced by an FQDN or narrower rule?

Risk signals
Undocumented destination
New flow after a recent deployment
Multiple sources without a clear owner
Unexpected port for the protocol
NAT bypass or direct egress outside the firewall

If a flow has no owner, do not allow it by habit. But do not enable global blocking without understanding the potential blast radius either.

Separate false positive, compromise and network debt

Threat Intelligence alerts usually lead to three different diagnoses. The first is a true positive: a workload is contacting a risky destination and blocking should be enabled or strengthened. The second is a false positive: a shared or legitimate service triggers a questionable reputation signal. The third is network debt: an application depends on broad outbound access that is hard to defend.

yaml threat-intel-classification.yml
classification:
likely_malicious:
  evidence:
    - destination_unknown_to_application_owner
    - repeated_attempts_after_failure
    - new_flow_after_suspicious_change
    - no_business_dependency
  action: block_or_isolate_source

likely_false_positive:
  evidence:
    - known_partner_or_saas_endpoint
    - fqdn_documented_and_validated
    - same_destination_used_by_preproduction
    - provider_status_or_contract_confirms_usage
  action: targeted_exception_with_expiry

network_debt:
  evidence:
    - broad_application_rule
    - missing_owner
    - dependency_only_known_by_ip
    - no_synthetic_probe
  action: keep_alert_then_reduce_scope

This classification avoids a poor binary choice. The right outcome may be a block, a temporary exception, a narrower rule or an application investigation.

Prepare an exception without weakening the firewall

If an exception is required, it should be more precise than the current flow. A broad exception on an IP range or parent domain can neutralize the value of Threat Intelligence. A defensible exception has an owner, justification, expiry and application validation.

json targeted-exception-record.json
{
"exception": "threat-intel-partner-api-prod",
"firewall": "azfw-hub-prod",
"source": "subnet-app-prod",
"destinationFqdn": "api.partner.example",
"ports": ["443"],
"owner": "platform-payments",
"reason": "documented partner API used by payment reconciliation",
"expiresAt": "2026-08-28T00:00:00Z",
"validation": [
  "partner contract checked",
  "application probe passes",
  "no broader destination allowed"
]
}

An exception without expiry becomes a permanent rule in disguise. If the team does not know how to remove it, it should not add it.

Validate Deny mode on critical paths

Before switching modes, test critical flows from the affected subnets: partner APIs, system updates, log collection, package repositories, backup paths, monitoring, webhooks, private pipelines and bounded administration access. The test must prove that Deny blocks what it should without breaking expected paths.

text deny-mode-validation.txt
Validation before Deny
Critical flows reviewed with owners
Threat Intelligence alerts classified by application
Temporary exceptions are limited and dated
Synthetic probes ready on important external APIs
Azure Firewall dashboard ready during the window
Action Groups active for application errors and firewall denies
Rollback command tested or reviewed

Block the change
SourceIp is not mapped to a workload
Critical destination cannot be tested
Proposed exception is too broad
Azure Firewall logs are incomplete
No application signal is available after the change

The point is not to guarantee zero false positives. It is to detect a false positive quickly, reduce its scope and roll back if needed.

Watch the change with KQL

During and after the switch to Deny, watch Threat Intelligence denies alongside application errors. More blocks without user symptoms may be acceptable. Blocks correlated with a business journey should trigger rollback or a targeted exception.

kusto 02-threat-intel-deny-after-change.kql
let ChangeTime = datetime(2026-07-28T20:00:00Z);
AZFWThreatIntel
| where TimeGenerated between (ChangeTime .. ChangeTime + 2h)
| where Action has "Deny"
| summarize Denies=count(),
          Sources=make_set(SourceIp, 20),
          Ports=make_set(DestinationPort, 10),
          Descriptions=make_set(ThreatIntelDescription, 5)
by bin(TimeGenerated, 5m), DestinationIp, Fqdn
| order by TimeGenerated asc

Complete this view with application logs. Azure Firewall can show the block, but only the application can show whether a user-facing path is broken.

Decide hold, exception or rollback

The decision must remain readable after the incident. Keep Deny if the blocks match risky flows and critical applications stay healthy. Add a targeted exception if a legitimate flow is affected and properly justified. Return to Alert if the team loses visibility or blocking breaks a critical path it cannot explain.

text threat-intel-decision.txt
Keep Deny
Blocks match flows classified as risky
No critical journey regresses
Exceptions are limited, dated and validated
Owners confirm remaining flows

Create a targeted exception
Legitimate business flow confirmed
Destination precise and testable
Expiry and owner defined
Application probe available

Return to Alert
Blocks correlate with an application incident
Logs are insufficient to qualify denies
Several owners cannot explain their flows
Required exception would be too broad

Isolate a workload
Unknown or probably compromised source
Repeated attempts toward risky destinations
No business need confirmed

A security rollback is not a failure when the decision is documented. The failure would be staying in Deny without understanding what is broken, or returning to Alert without a follow-up plan.

Conclusion

Azure Firewall Threat Intelligence should be treated as a production control, not as a simple security switch. The useful runbook ties alerts to workloads, classifies flows, prepares minimal exceptions, validates critical paths and watches the change with application evidence.

The final decision should be explicit: keep Deny, stay in Alert, create a temporary exception, isolate a source or roll back. That discipline improves network security without turning a reputation signal into a production interruption the team cannot explain.