Blocking an IP Without Breaking the Firewall
We got the finding late in the change window: block one destination on one MX network. The request looked harmless. The existing rule set was not. A PUT built from the alert would have replaced policy that nobody had copied into the workflow input.
We stopped and read the live rules first. That changed the implementation. The response had to carry the network identity, the current rule list, the proposed addition, and a reason for every skipped or duplicated rule. A valid API response was not enough; the next GET had to show the deny in the right position and the old rules still present.
That is the lesson: firewall automation is a read-modify-write problem. Treating it as “append this JSON” is how a small detection becomes an outage.
A generalized XDR network finding gave us an internal source and an external destination. The response looked obvious: add a Meraki MX outbound deny. We stopped before writing anything. A firewall update that overwrites existing policy is an outage disguised as automation.
Read before you write
The workflow extracts source and destination pairs, validates their address families, and groups them by affected network. For each network it first reads the existing Layer 3 outbound rules. The current policy is the baseline, not an optional input.
The source must be the internal host and the destination the external address. A reversed pair can block the wrong traffic while returning a perfectly valid API response.
Merge one decision at a time
The merge logic treats (source, destination) as the idempotency key. It canonicalizes IPs, ignores duplicate candidates, recognizes an existing deny that covers the pair, and appends only genuinely new destinations. It never replaces the whole ruleset with a list derived from the latest finding.
read existing rules
-> validate source/destination pairs
-> classify existing, duplicate, invalid, and new
-> merge new denies into a copy
-> reject capacity violations
-> PUT only the complete validated ruleset
A rule can have multiple destinations, but the provider limit still matters. The implementation checks the per-source destination limit and the overall rule limit before sending anything. If either limit would be exceeded, it records a skip and sends no partial update.
| Outcome | API action | Audit result |
|---|---|---|
| Already denied | Skip | Existing rule and pair recorded |
| Duplicate candidate | Skip | Duplicate source evidence retained |
| Invalid pair | Skip | Reason recorded for review |
| Capacity exceeded | Skip | No PUT sent |
| New safe pair | PUT merged ruleset | Rule and source incident linked |
What the operator sees
The ServiceNow payload and XDR work note carry the network, source, destination, action, and skip reasons. “Blocked” is reserved for a successful provider update. “Already present,” “capacity skipped,” and “invalid” remain distinct outcomes.
Verify the result
A successful PUT proves only that the appliance accepted the ruleset. Verification reads the rules again, finds the exact source/destination pair, and checks that unrelated rules remain. The workflow also records the network identity and request outcome so a later operator can reconcile the decision.
This is the part worth reusing: read, merge, validate, write, reread. A custom integration is safe when a retry produces the same policy, not when the first call happens to succeed.