azure-nsg-internet-exposed
An NSG effective inbound Allow rule from Internet/0.0.0.0/0 on a service port, combined with a public IP (or internet-facing LB) on an attached resource, makes that resource internet-reachable: ExposedToInternet.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?nsg) ==
Firewall
node_type(?resource) == Compute # VM, App Service, Container, etc.
?nsg has an effective inbound security rule where: properties.access == Allow AND properties.direction == Inbound AND properties.sourceAddressPrefix in {Internet, *, 0.0.0.0/0, ::/0} AND rule priority < effective deny rule priority for the same port/proto
?resource has a public IP address (properties.publicIPAddress on NIC, or is fronted by an internet-facing LB)
emit
| source type | Compute |
|---|---|
| target type | AnonymousIdentity |
| source | ?resource |
| target | <AnonymousIdentity> |
| conditions | network_reachability |
| state logic | ACTIVE when: (1) effective NSG inbound rule allows Internet/0.0.0.0/0 on a port AND (2) the resource has a public IP or internet-facing LB confirmed by collector data. CONDITIONAL(network_reachability) if the public IP association cannot be confirmed from collected data (rule is open but public IP not yet verified). |
Narrative
{source.name} is reachable from the public internet on port {port}: NSG {nsg.name} has an effective inbound Allow rule for source=Internet/0.0.0.0/0, and the resource has a public IP. Any internet host can attempt to connect.
Raw rule rules/derived/azure/nsg.yaml
id: azure-nsg-internet-exposed
emits: ExposedToInternet
description: 'An NSG effective inbound Allow rule from Internet/0.0.0.0/0 on a service port, combined
with a public IP (or internet-facing LB) on an attached resource, makes that resource internet-reachable:
ExposedToInternet.'
applies_to:
- azure
match:
- - nsg: null
- LocatedIn
- subnetOrNic: null
- - resource: null
- LocatedIn
- subnetOrNic: null
where:
- node_type(?nsg) == Firewall
- 'node_type(?resource) == Compute # VM, App Service, Container, etc.'
- '?nsg has an effective inbound security rule where: properties.access == Allow AND properties.direction
== Inbound AND properties.sourceAddressPrefix in {Internet, *, 0.0.0.0/0, ::/0} AND rule priority <
effective deny rule priority for the same port/proto'
- ?resource has a public IP address (properties.publicIPAddress on NIC, or is fronted by an internet-facing
LB)
emit:
source_type: Compute
target_type: AnonymousIdentity
source: ?resource
target: <AnonymousIdentity>
permissions: []
conditions:
- network_reachability
state_logic: 'ACTIVE when: (1) effective NSG inbound rule allows Internet/0.0.0.0/0 on a port AND (2)
the resource has a public IP or internet-facing LB confirmed by collector data. CONDITIONAL(network_reachability)
if the public IP association cannot be confirmed from collected data (rule is open but public IP not
yet verified).'
confidence: 0.9
derived_from:
- '<NSG effective inbound rule: source=Internet/0.0.0.0/0, action=Allow, port={port}>'
- <public IP association on NIC or LB frontend>
- "<LocatedIn edge: NSG \u2192 Subnet/NIC>"
- "<LocatedIn edge: Compute \u2192 Subnet/NIC>"
false_positive_note: "Requires both: (1) effective NSG inbound Allow from Internet on the port (not\
\ raw rule list \u2014 use effectiveNetworkSecurityGroups/action) AND (2) a public IP directly on\
\ the NIC or an internet-facing load balancer in front of the resource. An open NSG rule without a\
\ public IP is NOT ExposedToInternet \u2014 it is a broader VNet-internal allow (emit CanReachPort\
\ CONDITIONAL instead). An upstream Azure Firewall or Application Gateway may further filter traffic\
\ not captured by the NSG; model those separately but do not suppress ExposedToInternet solely because\
\ an upstream appliance exists unless confirmed to block the port. Subnet NSG + NIC NSG: both must\
\ effectively allow the traffic (intersection rule). Do not emit for resources protected by no-public-IP\
\ subnets (private-only VNets). Note: source CIDRs covering all public IPv4 via multiple rules (e.g.,\
\ split /1 ranges) should also trigger this rule; document coverage via CIDR composition at collector/evaluation\
\ time."
narrative: '{source.name} is reachable from the public internet on port {port}: NSG {nsg.name} has an
effective inbound Allow rule for source=Internet/0.0.0.0/0, and the resource has a public IP. Any
internet host can attempt to connect.'