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.

derived azure emits ExposedToInternet

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'nsg': None} LocatedIn {'subnetOrNic': None} {'resource': None} LocatedIn {'subnetOrNic': None}

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 typeCompute
target typeAnonymousIdentity
source?resource
target<AnonymousIdentity>
conditionsnetwork_reachability
state logicACTIVE 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.'
move · open · esc close