gcp-bigquery-explicit-can-read-data

Effective data-plane query access from bigquery.tables.getData + bigquery.jobs.create combined.

explicit gcp emits CanReadData

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 typeIdentity
target typeData
source<principal>
target<Dataset node>
permissionsbigquery.tables.getData bigquery.jobs.create
conditionsiam_permission
state logicACTIVE 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
move · open · esc close