gcp-bigquery-explicit-can-read-data
Effective data-plane query access from bigquery.tables.getData + bigquery.jobs.create combined.
match (effective permission)
{
"action": "bigquery.tables.getData",
"resource_type": "google.bigquery.Dataset"
}
where
principal ALSO holds bigquery.jobs.create at the project scope (Policy Analyzer or iam.effectivePolicy)
emit
| source type | Identity |
|---|---|
| target type | Data |
| source | <principal> |
| target | <Dataset node> |
| permissions | bigquery.tables.getData bigquery.jobs.create |
| conditions | iam_permission |
| state logic | ACTIVE when both bigquery.tables.getData and bigquery.jobs.create are confirmed ACTIVE at the same project scope and no VPC-SC perimeter blocks the bigquery API; CONDITIONAL(iam_permission) when one perm is missing or a VPC-SC perimeter is in place; BLOCKED when VPC-SC enforces and the caller is outside the perimeter. |
Narrative
{principal.name} holds bigquery.tables.getData on {dataset.name} and bigquery.jobs.create; it can submit queries to read arbitrary rows from any table in {dataset.name}.
Raw rule rules/explicit/gcp/bigquery.yaml
id: gcp-bigquery-explicit-can-read-data
emits: CanReadData
description: Effective data-plane query access from bigquery.tables.getData + bigquery.jobs.create combined.
match_effective_permission:
action: bigquery.tables.getData
resource_type: google.bigquery.Dataset
where:
- principal ALSO holds bigquery.jobs.create at the project scope (Policy Analyzer or iam.effectivePolicy)
emit:
source_type: Identity
target_type: Data
source: <principal>
target: <Dataset node>
permissions:
- bigquery.tables.getData
- bigquery.jobs.create
conditions:
- iam_permission
state_logic: ACTIVE when both bigquery.tables.getData and bigquery.jobs.create are confirmed ACTIVE
at the same project scope and no VPC-SC perimeter blocks the bigquery API; CONDITIONAL(iam_permission)
when one perm is missing or a VPC-SC perimeter is in place; BLOCKED when VPC-SC enforces and the caller
is outside the perimeter.
false_positive_note: "BOTH permissions are required: bigquery.jobs.create alone submits a query but\
\ returns a permission error if bigquery.tables.getData is absent. bigquery.tables.getData alone without\
\ a job-creation path is unreachable. BigQuery has TWO access-control layers: project-level IAM bindings\
\ AND dataset-level ACL entries (the access[] array on the Dataset). Effective permission must unify\
\ both layers. VPC-SC perimeters can BLOCK the BigQuery API for callers outside the perimeter even\
\ with valid IAM \u2014 check perimeter membership. Column-level security (Data Catalog policy tags)\
\ may restrict a subset of columns; emit as CONDITIONAL(iam_permission) when column policies exist.\
\ Row-level access policies filter rows for the principal; emit the edge and note the filter \u2014\
\ it does not negate CanReadData for the accessible rows. Public datasets (bigquery-public-data project)\
\ are intentionally public \u2014 do not flag as vulnerabilities unless customer data is involved."
narrative: '{principal.name} holds bigquery.tables.getData on {dataset.name} and bigquery.jobs.create;
it can submit queries to read arbitrary rows from any table in {dataset.name}.'
derived_from:
- bigquery.tables.getData effective permission
- bigquery.jobs.create effective permission
api_source: Cloud Asset Inventory analyzeIamPolicy, bigquery.datasets.get (access[] array)
evidence_field: bigquery.tables.getData effective permission + bigquery.jobs.create