ServicesAboutNotesContact Get in touch →
EN FR
Note

IAM Drift Monitoring for GCP

Catch IAM debt before it accumulates — IAM Recommender, INFORMATION_SCHEMA job monitoring, and audit log queries to detect permission drift quarterly.

Planted
gcpbigquerydata engineering

IAM debt reaccumulates after an initial cleanup: Editor roles granted temporarily and left in place, new workloads reusing existing service accounts, permissions from ended projects never revoked. Three signals catch permission drift: IAM Recommender for over-provisioning, BigQuery INFORMATION_SCHEMA for unexpected access patterns, and audit logs for IAM changes themselves.

IAM Recommender

GCP’s IAM Recommender analyzes 90 days of actual usage data to identify principals with more permissions than they use:

Terminal window
gcloud recommender recommendations list \
--project=YOUR_PROJECT_ID \
--location=global \
--recommender=google.iam.policy.Recommender

The recommender might surface findings like:

  • A service account with bigquery.dataEditor has only performed read operations for 90 days — reduce to bigquery.dataViewer
  • A user with bigquery.admin has never modified BigQuery settings — reduce to bigquery.jobUser
  • A principal has roles/editor but only uses BigQuery-specific permissions — replace with predefined BigQuery roles

Each recommendation includes a confidence score and the specific actions to take. High-confidence recommendations from the recommender are safe to apply without investigation. Medium-confidence ones warrant checking whether the usage pattern is representative — a data engineer who only reads for 90 days might just have been in a reading-heavy phase.

Run this monthly and process the recommendations. The recommender does the analysis; you make the judgment calls.

BigQuery INFORMATION_SCHEMA for Unexpected Access

IAM policies tell you what access principals could use. INFORMATION_SCHEMA.JOBS tells you what they actually do:

SELECT
user_email,
DATE(creation_time) AS query_date,
COUNT(*) AS query_count,
SUM(total_bytes_billed) / POW(10, 12) AS tb_billed
FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE creation_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 90 DAY)
GROUP BY 1, 2
ORDER BY tb_billed DESC

Review this weekly or monthly with two questions:

Do unexpected identities appear? If a service account you’ve never seen before starts running queries, something changed — a new deployment, a credential being misused, or an old service account that was supposed to be decommissioned still running. Track down unexpected identities immediately.

Does the access pattern match expectations? A service account that ran 50 queries last quarter and now runs 5,000 warrants investigation. A user who normally runs analyst queries suddenly running large table scans at 3am is worth a conversation.

The cost attribution version of this query adds bytes-processed to the analysis — useful for catching runaway queries that result from broad permissions enabling access to large, unpartitioned tables.

Audit Logs for IAM Changes

BigQuery INFORMATION_SCHEMA covers what happens inside BigQuery. Cloud Audit Logs cover IAM changes across all of GCP. Sink audit logs to BigQuery and query them to track who grants permissions and when:

SELECT
timestamp,
protoPayload.authenticationInfo.principalEmail AS grantor,
protoPayload.serviceData.policyDelta.bindingDeltas
FROM `your_audit_dataset.cloudaudit_googleapis_com_activity`
WHERE protoPayload.methodName = 'SetIamPolicy'
AND timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
ORDER BY timestamp DESC

This surfaces every IAM policy change in the past 30 days. What you’re looking for:

  • Editor or Owner roles being granted (should almost never happen)
  • IAM changes happening outside normal business hours (could indicate compromise)
  • Changes made by unexpected principals (who has permission to modify IAM?)
  • Bursts of changes (bulk grants sometimes indicate automation gone wrong)

To set up the log sink:

Terminal window
gcloud logging sinks create iam-audit-sink \
bigquery.googleapis.com/projects/YOUR_PROJECT_ID/datasets/audit_logs \
--log-filter='protoPayload.methodName="SetIamPolicy"' \
--project=YOUR_PROJECT_ID

The sink captures new IAM changes going forward. It doesn’t backfill historical events, so set it up before you need it.

A Quarterly Review Process

Monitoring signals are most useful as inputs to a regular review cadence rather than ad-hoc investigation. A quarterly IAM review prevents drift from compounding:

Month 1: Run the full audit queries — Editor/Owner roles, service accounts with keys, shared accounts. Process findings from last quarter’s recommender output.

Month 2: Review INFORMATION_SCHEMA job patterns. Identify service accounts with unusual access patterns. Check that all active service accounts follow the naming convention (which tells you at a glance if something unauthorized was created).

Month 3: Review audit log IAM changes. Verify that IAM changes are happening through the expected mechanisms (Terraform PRs, approved access requests) rather than ad-hoc through the console or CLI.

The first review after a period of neglect is the most time-consuming. Subsequent quarterly reviews are shorter because they prevent accumulation rather than clear backlogs.

The Cost Connection

Over-permissioned IAM isn’t just a security problem. When analysts have access to tables they don’t need, they accidentally run expensive queries against them. When service accounts have Editor roles instead of scoped dataset access, they can read and scan any table in the project.

The INFORMATION_SCHEMA cost queries and the IAM INFORMATION_SCHEMA queries pull from the same data. Teams that monitor both together find that IAM cleanup often produces 20-30% reductions in BigQuery query costs — not because they optimized any queries, but because they removed the access that enabled the expensive ones.