gcp-lb-external-exposed
A global or regional external forwarding rule with a public IP (loadBalancingScheme EXTERNAL or EXTERNAL_MANAGED) is reachable from the public internet on its configured port. IAP on backend services is an authentication layer but does not remove the internet-exposure fact.
where
forwardingRule.loadBalancingScheme in [EXTERNAL, EXTERNAL_MANAGED]
forwardingRule.IPAddress is non-null (public IP allocated)
forwardingRule references a target proxy that references at least one URL map with a backend service (non-empty routing chain)
emit
| source type | LoadBalancer |
|---|---|
| target type | AnonymousIdentity |
| source | <global or regional external ForwardingRule> |
| target | <AnonymousIdentity> |
| state logic | ACTIVE when the forwarding rule has a public IP AND references a target proxy whose URL map has at least one path rule mapping to a backend service (or default service). CONDITIONAL(service_state) if the backend service has no configured backends (empty MIG/NEG list) — the IP is public but returns 502/503 only. Do NOT emit for forwardingRules with loadBalancingScheme INTERNAL or INTERNAL_MANAGED — those are VPC-internal. |
Narrative
Forwarding rule {source.name} has a public external IP; any internet host can send HTTP/HTTPS traffic to it on port {source.portRange}. If backend services lack IAP or IAP is disabled, traffic reaches backends unauthenticated. If IAP is enabled on all backends, a valid Google identity is required to pass through, but the frontend IP itself accepts connections from the open internet.
Raw rule rules/derived/gcp/loadbalancing.yaml
id: gcp-lb-external-exposed
emits: ExposedToInternet
description: A global or regional external forwarding rule with a public IP (loadBalancingScheme EXTERNAL
or EXTERNAL_MANAGED) is reachable from the public internet on its configured port. IAP on backend services
is an authentication layer but does not remove the internet-exposure fact.
where:
- forwardingRule.loadBalancingScheme in [EXTERNAL, EXTERNAL_MANAGED]
- forwardingRule.IPAddress is non-null (public IP allocated)
- forwardingRule references a target proxy that references at least one URL map with a backend service
(non-empty routing chain)
emit:
source_type: LoadBalancer
target_type: AnonymousIdentity
source: <global or regional external ForwardingRule>
target: <AnonymousIdentity>
permissions: []
state_logic: "ACTIVE when the forwarding rule has a public IP AND references a target proxy whose URL\
\ map has at least one path rule mapping to a backend service (or default service). CONDITIONAL(service_state)\
\ if the backend service has no configured backends (empty MIG/NEG list) \u2014 the IP is public but\
\ returns 502/503 only. Do NOT emit for forwardingRules with loadBalancingScheme INTERNAL or INTERNAL_MANAGED\
\ \u2014 those are VPC-internal."
conditions: []
false_positive_note: "(a) INTERNAL / INTERNAL_MANAGED forwarding rules are NOT internet-exposed \u2014\
\ do not emit. (b) If all backend services behind the URL map have iap.enabled=true, the LB frontend\
\ is internet-reachable but requires a valid Google identity to pass IAP. Emit ExposedToInternet (the\
\ IP is public and the LB accepts connections), but note IAP presence in the narrative and reduce\
\ confidence (0.7 vs 0.95 for unprotected). (c) An empty backend service (no backends) returns 502/503;\
\ emit with CONDITIONAL(service_state) and lower confidence. (d) Backend-level firewall rules (Cloud\
\ Armor) do not change the ExposedToInternet fact \u2014 they filter L7 attacks but the frontend remains\
\ internet-reachable."
narrative: Forwarding rule {source.name} has a public external IP; any internet host can send HTTP/HTTPS
traffic to it on port {source.portRange}. If backend services lack IAP or IAP is disabled, traffic
reaches backends unauthenticated. If IAP is enabled on all backends, a valid Google identity is required
to pass through, but the frontend IP itself accepts connections from the open internet.