gcp-psc-private-reach-google-apis
A PSC consumer forwarding rule targeting the all-apis or vpc-sc Google API bundle gives workloads in the consumer VPC private IP access to Google APIs (Cloud Storage, Secret Manager, BigQuery, etc.) without a public IP or internet egress. An in-network attacker with code running on a consumer-VPC workload can call any Google API the workload's SA is permitted to call over this private path.
match (record)
{
"field": "purpose",
"resource_type": "compute.googleapis.com/ForwardingRule",
"value": "PRIVATE_SERVICE_CONNECT"
}
where
forwardingRule.target matches 'all-apis' OR 'vpc-sc' (Google-managed
API bundle)
forwardingRule is in an ACTIVE / operational state
emit
| source type | Compute |
|---|---|
| target type | PrivateEndpoint |
| source | <workload in the consumer VPC subnet of the forwarding rule> |
| target | <PSC consumer endpoint (ForwardingRule)> |
| conditions | network_reachability service_state |
| state logic | CONDITIONAL(network_reachability) — the endpoint exists and routes traffic privately, but an attacker must have a foothold in the consumer VPC (or a subnet that can reach the PSC endpoint IP) to exploit it. BLOCKED if the forwarding rule is deleted or if a VPC firewall denies the endpoint IP. |
Narrative
A PSC forwarding rule in {vpc.name} ({forwarding_rule.name}, target=all-apis/vpc-sc) gives any workload in that VPC private IP access to Google APIs without egressing to the internet. An attacker with a foothold in the consumer subnet can call Google APIs over this private channel using the workload's SA token.
Raw rule rules/derived/gcp/psc.yaml
id: gcp-psc-private-reach-google-apis
emits: PrivateReachability
description: A PSC consumer forwarding rule targeting the all-apis or vpc-sc Google API bundle gives workloads
in the consumer VPC private IP access to Google APIs (Cloud Storage, Secret Manager, BigQuery, etc.)
without a public IP or internet egress. An in-network attacker with code running on a consumer-VPC workload
can call any Google API the workload's SA is permitted to call over this private path.
match_record:
resource_type: compute.googleapis.com/ForwardingRule
field: purpose
value: PRIVATE_SERVICE_CONNECT
where:
- forwardingRule.target matches 'all-apis' OR 'vpc-sc' (Google-managed API bundle)
- forwardingRule is in an ACTIVE / operational state
emit:
source_type: Compute
target_type: PrivateEndpoint
source: <workload in the consumer VPC subnet of the forwarding rule>
target: <PSC consumer endpoint (ForwardingRule)>
permissions: []
conditions:
- network_reachability
- service_state
state_logic: "CONDITIONAL(network_reachability) \u2014 the endpoint exists and routes traffic privately,\
\ but an attacker must have a foothold in the consumer VPC (or a subnet that can reach the PSC endpoint\
\ IP) to exploit it. BLOCKED if the forwarding rule is deleted or if a VPC firewall denies the endpoint\
\ IP."
derived_from:
- '<ForwardingRule resource: purpose=PRIVATE_SERVICE_CONNECT, target=all-apis/vpc-sc>'
false_positive_note: "The PSC endpoint provides the NETWORK PATH to Google APIs; the backend APIs still\
\ enforce their own IAM. Do not conflate PrivateReachability (network fact) with authorization to\
\ use the APIs. VPC-SC bundle endpoints may be further constrained by VPC Service Controls perimeter\
\ policy \u2014 do not assume all-apis surface equivalence. State is CONDITIONAL(network_reachability);\
\ an attacker must have a foothold in the consumer subnet. NOTE: source_type is Compute per schema,\
\ but at graph-construction time the source may be instantiated as a VirtualNetwork or Subnet node\
\ if no specific workload is identified \u2014 the reachability applies to any node in the consumer\
\ subnet that can reach the PSC endpoint IP. Ensure graph source node resolves to a valid PrivateReachability\
\ source type (Compute, Messaging)."
narrative: A PSC forwarding rule in {vpc.name} ({forwarding_rule.name}, target=all-apis/vpc-sc) gives
any workload in that VPC private IP access to Google APIs without egressing to the internet. An attacker
with a foothold in the consumer subnet can call Google APIs over this private channel using the workload's
SA token.