1. Rule Order — The Most Common Culprit
The first thing to check: your firewall rule order. In AWS security groups, Azure NSGs, and GCP firewall rules, the first matching allow rule wins. But most cloud providers process rules top-down. If a deny rule sits above your allow rule, traffic gets blocked before it ever sees the allow.
I've seen this with a developer who added a broad "allow HTTP from 0.0.0.0/0" rule at the bottom, but an existing "deny all inbound" rule at the top was blocking everything. The fix: move the allow rule above the deny, or remove the deny if you don't need it.
Here's what to do:
- List your firewall rules in order. In AWS CLI:
aws ec2 describe-security-group-rules --filter Name=group-id,Values=sg-xxxxxxxx - Check the priority field. Lower number means higher priority. Azure NSG uses priority numbers from 100 to 4096.
- If your allow rule has a higher priority number than a deny rule, move it up.
Real trigger: You add a new SSH rule for a specific IP, but an older "deny all" rule at priority 100 still blocks it.
2. Implicit Deny — The Silent Blocker
Every cloud firewall has an implicit deny at the end. Even if you don't see it in the rule list, it's there. This catches everything that doesn't match an explicit allow rule.
The reason step 1's fix sometimes doesn't work: you might have the right rule order, but missed something in the rule definition. Common miss: the protocol field. You set "allow TCP port 443", but your application uses UDP for WebRTC or DNS. TCP rule won't match UDP traffic.
Another miss: the source IP range. You set "allow SSH from 203.0.113.0/24" but your actual IP is 203.0.113.55 — that's fine. But if you wrote "203.0.113.0/32" by mistake, only one IP gets through. Check your CIDR notation.
Third miss: destination port. In Azure NSG, you can specify port ranges. "80-80" is fine, but "80" alone means port 80. "80,443" is not valid — you need two separate rules.
Fix script logic:
# Pseudo-check for implicit deny
if no rule matches traffic:
call support team
check cloudtrail/vpc flow logs for 'block' events
fi
3. Stateful vs Stateless — The Sneaky One
AWS security groups are stateful. That means if you allow inbound SSH on port 22, the outbound return traffic is automatically allowed. You don't need an outbound rule. But Azure NSGs and GCP firewall rules are stateless by default. You must add an outbound allow rule for the return traffic.
The typical mistake: you create an inbound allow rule for HTTP (port 80 TCP), but the server sends TCP SYN-ACK back. The stateless firewall sees a new outbound packet and drops it. Client sees a timeout.
Fix: For every inbound stateless allow rule, add a corresponding outbound rule. The outbound rule should allow the same protocol and port, with source = the internal IP range of your VPC or subnet.
In GCP, you can make firewall rules stateful by checking "enable stateful firewall" in the rule configuration. Do that if your application has many ephemeral ports.
Quick Reference Summary Table
| Cause | Symptom | Fix |
|---|---|---|
| Rule order wrong | Allow rule exists but deny above it blocks | Move allow rule above deny |
| Implicit deny | No matching rule, traffic silently dropped | Add explicit allow rule with correct protocol, port, source |
| Stateless vs stateful | Inbound rule OK but return traffic blocked | Add outbound allow rule or enable stateful |
Bottom line: check rule order first, then verify protocol and source details, then look at stateful behavior. That sequence fixes 95% of misconfigurations.