gcp-iap-web-access
A principal with iap.webServiceVersions.accessViaIAP (or parent-level iap.webTypes.accessViaIAP / iap.web.accessViaIAP) can reach an IAP-protected web application (App Engine, Cloud Run, GKE Ingress, or backend service via HTTPS LB) after authenticating through Google IAP. This provides network-level reach to the backend application, though the backend's own authorization layer may further gate access.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?web_resource) ==
PublicEndpoint
effective_permission(?principal, ?web_resource) intersects ['iap.webServiceVersions.accessViaIAP', 'iap.webServices.accessViaIAP', 'iap.webTypes.accessViaIAP', 'iap.web.accessViaIAP']
?web_resource.provider == 'gcp'
emit
| source type | Identity |
|---|---|
| target type | PublicEndpoint |
| source | ?principal |
| target | ?web_resource |
| permissions | iap.webServiceVersions.accessViaIAP iap.webServices.accessViaIAP iap.webTypes.accessViaIAP iap.web.accessViaIAP |
| conditions | iam_permission |
| state logic | if effective_permission(?principal, ?web_resource) intersects ['iap.webServiceVersions.accessViaIAP', 'iap.webServices.accessViaIAP', 'iap.webTypes.accessViaIAP', 'iap.web.accessViaIAP'] AND NOT iam_deny_policy blocks access: ACTIVE elif iam_deny_policy or org_policy blocks web access: BLOCKED else: CONDITIONAL(iam_permission) |
Narrative
{principal.name} holds iap.webServiceVersions.accessViaIAP on {web_resource.name} and can reach the IAP-protected web application after authenticating through Google IAP. The backend application may have its own authorization layer that further gates access.
Raw rule rules/derived/gcp/iap.yaml
id: gcp-iap-web-access
emits: CanNetworkReach
description: A principal with iap.webServiceVersions.accessViaIAP (or parent-level iap.webTypes.accessViaIAP
/ iap.web.accessViaIAP) can reach an IAP-protected web application (App Engine, Cloud Run, GKE Ingress,
or backend service via HTTPS LB) after authenticating through Google IAP. This provides network-level
reach to the backend application, though the backend's own authorization layer may further gate access.
match:
- - principal: null
- HasPermission
- web_resource: null
where:
- node_type(?web_resource) == PublicEndpoint
- effective_permission(?principal, ?web_resource) intersects ['iap.webServiceVersions.accessViaIAP', 'iap.webServices.accessViaIAP',
'iap.webTypes.accessViaIAP', 'iap.web.accessViaIAP']
- ?web_resource.provider == 'gcp'
emit:
source_type: Identity
target_type: PublicEndpoint
source: ?principal
target: ?web_resource
permissions:
- iap.webServiceVersions.accessViaIAP
- iap.webServices.accessViaIAP
- iap.webTypes.accessViaIAP
- iap.web.accessViaIAP
conditions:
- iam_permission
state_logic: "if effective_permission(?principal, ?web_resource) intersects ['iap.webServiceVersions.accessViaIAP',\
\ 'iap.webServices.accessViaIAP',\n 'iap.webTypes.accessViaIAP', 'iap.web.accessViaIAP']\nAND NOT\
\ iam_deny_policy blocks access: ACTIVE elif iam_deny_policy or org_policy blocks web access: BLOCKED\
\ else: CONDITIONAL(iam_permission)"
confidence: 0.85
derived_from:
- HasPermission(?principal, ?web_resource) [iap.web*.accessViaIAP]
false_positive_note: "IAP web access provides HTTPS-level reach to the protected application after Google\
\ authentication. The backend application may have its own authorization layer (Spring Security, Django,\
\ Kubernetes RBAC, etc.) that further gates access \u2014 IAP access does not guarantee full application\
\ compromise. This rule emits only the network reach FACT; additional code-execution or credential\
\ read primitives on the backend are required for escalation. See cloudrun.yaml, appengine.yaml, and\
\ gce.yaml for backend-specific execution paths."
narrative: '{principal.name} holds iap.webServiceVersions.accessViaIAP on {web_resource.name} and can
reach the IAP-protected web application after authenticating through Google IAP. The backend application
may have its own authorization layer that further gates access.'