aws-vpc-sg-internet-exposed-compute
A compute resource is internet-exposed when its security group has an inbound rule allowing 0.0.0.0/0 (or ::/0) on a port, the resource has a public IP, and the subnet has a route to an Internet Gateway. All three conditions must be observed facts.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?sg) ==
SecurityGroup
node_type(?resource) in [VirtualMachine, ContainerService, ApplicationPlatform, GenericCompute]
sg_has_inbound_rule(?sg, cidr='0.0.0.0/0' OR cidr='::/0', any_port)
resource_has_public_ip(?resource)
subnet_routes_to_igw(?resource.subnet)
emit
| source type | Compute |
|---|---|
| target type | AnonymousIdentity |
| source | ?resource |
| target | <AnonymousIdentity> |
| conditions | network_reachability |
| state logic | if all three conditions (open SG inbound rule, public IP, IGW route) are observed ACTIVE facts: ACTIVE elif any condition is unverified (e.g., IGW attachment state unknown): CONDITIONAL(network_reachability) else: do not emit |
Narrative
{resource.name} is reachable from the public internet: security group {sg.name} allows inbound traffic from 0.0.0.0/0, the resource has a public IP address, and its subnet routes to an Internet Gateway - any unauthenticated internet host can attempt to connect to the exposed service port.
Raw rule rules/derived/aws/vpc.yaml
id: aws-vpc-sg-internet-exposed-compute
emits: ExposedToInternet
description: A compute resource is internet-exposed when its security group has an inbound rule allowing
0.0.0.0/0 (or ::/0) on a port, the resource has a public IP, and the subnet has a route to an Internet
Gateway. All three conditions must be observed facts.
match:
- - sg: null
- AttachedTo
- resource: null
where:
- node_type(?sg) == SecurityGroup
- node_type(?resource) in [VirtualMachine, ContainerService, ApplicationPlatform, GenericCompute]
- sg_has_inbound_rule(?sg, cidr='0.0.0.0/0' OR cidr='::/0', any_port)
- resource_has_public_ip(?resource)
- subnet_routes_to_igw(?resource.subnet)
emit:
source_type: Compute
target_type: AnonymousIdentity
source: ?resource
target: <AnonymousIdentity>
permissions: []
conditions:
- network_reachability
state_logic: 'if all three conditions (open SG inbound rule, public IP, IGW route) are observed ACTIVE
facts: ACTIVE elif any condition is unverified (e.g., IGW attachment state unknown): CONDITIONAL(network_reachability)
else: do not emit'
confidence: 0.92
derived_from:
- AttachedTo(?sg, ?resource)
- sg_has_inbound_rule(?sg, 0.0.0.0/0)
- resource_has_public_ip(?resource)
- subnet_routes_to_igw(?resource.subnet)
false_positive_note: "ALL THREE conditions are mandatory \u2014 missing any one eliminates internet\
\ exposure: (1) SG inbound rule must allow from 0.0.0.0/0 or ::/0 (not just any source);\n a rule\
\ scoped to a named CIDR or another SG is NOT internet-open.\n(2) Resource must have a public IP (Elastic\
\ IP or auto-assigned public IPv4/IPv6\n on the ENI); a private-only ENI is never inbound-reachable\
\ from the internet\n regardless of the SG or route.\n(3) The subnet's route table must have a\
\ default route (0.0.0.0/0) pointing to\n an attached Internet Gateway; a route to a NAT Gateway\
\ is outbound-only and\n does NOT create inbound exposure. Resources behind a NAT GW have a private\n\
\ IP only \u2014 they do not appear here.\nNetwork ACLs (stateless) may also block the traffic\
\ at the subnet level; if a NACL deny rule exists for the relevant port/CIDR, downgrade to CONDITIONAL\
\ or do not emit. However, since NACLs are subnet-wide and commonly more permissive than SGs, treat\
\ NACL blocks as a false-positive check rather than a primary gate."
narrative: "{resource.name} is reachable from the public internet: security group {sg.name} allows inbound\
\ traffic from 0.0.0.0/0, the resource has a public IP address, and its subnet routes to an Internet\
\ Gateway \u2014 any unauthenticated internet host can attempt to connect to the exposed service port."