azure-postgres-mysql-public-firewall

PostgreSQL/MySQL Flexible Server with publicNetworkAccess Enabled and an internet-wide firewall rule exposes the DB endpoint to the public internet.

derived azure emits ExposedToInternet

match

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

[{'server': None}]

where

node_class(?server) == Data and node_type(?server) == RelationalDatabase node_type(?server) matched provider_type in ['Microsoft.DBforPostgreSQL/flexibleServers', 'Microsoft.DBforMySQL/flexibleServers'] ?server.properties.publicNetworkAccess == 'Enabled' ?server.properties.firewallRules contains at least one rule where startIpAddress is not in RFC1918/link-local space (i.e., startIpAddress is publicly routable) AND endIpAddress == '255.255.255.255' (full internet range) OR equivalent (e.g., rule covering 0.0.0.0–255.255.255.255)

emit

source typeRelationalDatabase
target typeAnonymousIdentity
source?server
target<AnonymousIdentity>
state logicif ?server.properties.publicNetworkAccess == 'Disabled': DO NOT EMIT — private-access topology has no public endpoint regardless of firewallRules records (the service ignores firewall rules in that topology); elif firewallRules[] contains a rule with startIpAddress == '0.0.0.0' AND endIpAddress == '0.0.0.0' (Allow Azure services shorthand, not a public internet range): DO NOT EMIT as ExposedToInternet — only Azure backbone IPs are admitted, not arbitrary internet hosts; elif firewallRules[] contains a rule covering true public internet (startIpAddress outside RFC1918/link-local, endIpAddress == '255.255.255.255'): ACTIVE — any internet host can reach the DB port; else if firewallRules[] contains a rule with a broad public range (e.g., a /24 that includes significant public space): ACTIVE — meaningful public exposure.

Narrative

{server.name} has publicNetworkAccess=Enabled and a firewall rule admitting the full internet (0.0.0.0–255.255.255.255 or equivalent public range). Any internet-connected host can reach the database engine endpoint (PostgreSQL port 5432 or MySQL port 3306). Valid credentials are still required for data access, but the network gate is absent - enabling credential spray, brute-force, or exploitation of DB engine vulnerabilities from the internet.

Raw rule rules/derived/azure/postgres-mysql.yaml

id: azure-postgres-mysql-public-firewall
emits: ExposedToInternet
description: PostgreSQL/MySQL Flexible Server with publicNetworkAccess Enabled and an internet-wide firewall
  rule exposes the DB endpoint to the public internet.
match:
- - server: null
where:
- node_class(?server) == Data and node_type(?server) == RelationalDatabase
- node_type(?server) matched provider_type in ['Microsoft.DBforPostgreSQL/flexibleServers', 'Microsoft.DBforMySQL/flexibleServers']
- ?server.properties.publicNetworkAccess == 'Enabled'
- "?server.properties.firewallRules contains at least one rule where startIpAddress is not in RFC1918/link-local\
  \ space (i.e., startIpAddress is publicly routable) AND endIpAddress == '255.255.255.255' (full internet\
  \ range) OR equivalent (e.g., rule covering 0.0.0.0\u2013255.255.255.255)"
emit:
  source_type: RelationalDatabase
  target_type: AnonymousIdentity
  source: ?server
  target: <AnonymousIdentity>
  permissions: []
  conditions: []
  state_logic: "if ?server.properties.publicNetworkAccess == 'Disabled': DO NOT EMIT \u2014 private-access\
    \ topology has no public endpoint regardless of firewallRules records (the service ignores firewall\
    \ rules in that topology); elif firewallRules[] contains a rule with startIpAddress == '0.0.0.0' AND\
    \ endIpAddress == '0.0.0.0' (Allow Azure services shorthand, not a public internet range): DO NOT\
    \ EMIT as ExposedToInternet \u2014 only Azure backbone IPs are admitted, not arbitrary internet hosts;\
    \ elif firewallRules[] contains a rule covering true public internet (startIpAddress outside RFC1918/link-local,\
    \ endIpAddress == '255.255.255.255'): ACTIVE \u2014 any internet host can reach the DB port; else\
    \ if firewallRules[] contains a rule with a broad public range (e.g., a /24 that includes significant\
    \ public space): ACTIVE \u2014 meaningful public exposure."
  confidence: '0.93'
  derived_from:
  - 'collected ARM properties: publicNetworkAccess, firewallRules[]'
  false_positive_note: "CRITICAL: publicNetworkAccess == Disabled means the server is VNet-injected with\
    \ no public endpoint \u2014 do NOT emit regardless of firewallRules records (which are meaningless\
    \ in that topology). The \"Allow Azure services\" shorthand (startIpAddress=0.0.0.0, endIpAddress=0.0.0.0)\
    \ is frequently confused with an open internet rule \u2014 it admits only Azure backbone IPs and MUST\
    \ NOT be emitted as ExposedToInternet. Only emit ACTIVE when the rule covers a genuine public internet\
    \ range: endIpAddress == 255.255.255.255 combined with a public starting address is the canonical\
    \ indicator. Do NOT emit if endIpAddress is a private range or a non-internet-routable block. ExposedToInternet\
    \ here means the DB port is network-reachable from the internet \u2014 valid credentials are still\
    \ required for data access. This edge resolves the CONDITIONAL(network_reachability) on azure-postgres-mysql-admin-reset-readdata:\
    \ if both this edge and CanModifyConfiguration are ACTIVE, CanReadData upgrades to ACTIVE."
  narrative: "{server.name} has publicNetworkAccess=Enabled and a firewall rule admitting the full internet\
    \ (0.0.0.0\u2013255.255.255.255 or equivalent public range). Any internet-connected host can reach\
    \ the database engine endpoint (PostgreSQL port 5432 or MySQL port 3306). Valid credentials are still\
    \ required for data access, but the network gate is absent \u2014 enabling credential spray, brute-force,\
    \ or exploitation of DB engine vulnerabilities from the internet."
move · open · esc close