GCP Data Access logs: off by default, and other blind spots
Why GCP Data Access audit logs are the usual dead end: off by default, 30-day retention, what goes unseen without them, and what to enable before an incident.
TL;DR. Data Access audit logs are the only record of reads in Google Cloud: objects downloaded, secrets accessed, tokens minted for service accounts, IAM policies read. They are off by default (except some BigQuery services), kept 30 days by default, and cannot be turned on retroactively. When they are missing, an investigation can prove what was changed but not what was taken. Enable them now, at least for IAM, Cloud Storage and Secret Manager, and route them somewhere they outlive 30 days.
This is the most common dead end I hit in Google Cloud cases. The IAM changes, VMs and sink deletions are all there in Admin Activity. Then the question "which files did they take?" meets silence.
What Data Access logs cover
Google splits Data Access logs into three types (configure Data Access audit logs):
| Type | Examples in an investigation |
|---|---|
ADMIN_READ | GetIamPolicy, ListServiceAccounts, GetServiceAccountKey, and GenerateAccessToken on the IAM Credentials API |
DATA_READ | storage.objects.get, AccessSecretVersion, reading table data |
DATA_WRITE | storage.objects.create / delete, writing data into services |
ADMIN_WRITE is the Admin Activity log, always on. The rest is opt-in.
What goes unseen without them
| Question | Evidence needed | Without Data Access logs |
|---|---|---|
| Which objects were downloaded? | storage.objects.get | Unknown |
| Were secrets read? | AccessSecretVersion | Unknown |
| Who impersonated which service account? | GenerateAccessToken, SignJwt | Only visible on the later write calls through serviceAccountDelegationInfo (impersonation) |
| What did the attacker enumerate? | List*, Get* calls | Only failed calls on writes; reconnaissance mostly invisible |
| What did a leaked key read before escalating? | reads with serviceAccountKeyName | Only its writes |
The analyzer detects this situation and shows a warning when an export contains no Data Access entries at all: "data reads … are invisible". Rules that depend on reads (bulk_object_reads, sa_impersonation) cannot fire, and a "Clean" or "Suspicious" verdict must be read in that light.
Why they are often off
Three reasons, all legitimate:
- Cost and volume. Reads vastly outnumber writes; Data Access logs are ingested and stored like any other log.
- Side effects. Google notes that enabling Data Access logs for Cloud Storage can make some authenticated browser downloads fail (configure Data Access audit logs).
- Nobody decided. There is no default beyond BigQuery, so unless someone sets an organization-level
auditConfig, projects are created without them.
A reasonable compromise: enable DATA_READ and ADMIN_READ for IAM, Cloud Storage (on the buckets that matter, if cost is an issue) and Secret Manager at the organization level, and exempt noisy, well-understood service accounts with exemptedMembers rather than switching everything off.
Retention: 30 days unless you act
Data Access and Policy Denied logs go to the _Default bucket, 30 days by default; Admin Activity and System Event go to _Required, 400 days (routing overview, quotas). Incidents are often discovered weeks after initial access. By then the reads of the first days have expired, while the writes remain. The asymmetry produces a misleading picture: an attack that appears to start with a privilege escalation, because the reconnaissance before it is gone.
Options, in order of robustness:
- A log sink (ideally an organization-level aggregated sink) to a bucket in a separate project, with a locked retention policy.
- A longer retention on
_Defaultin each project. - A BigQuery sink for queryable history.
Sinks do not backfill. Whatever you set up today protects the next incident, not the current one. For the current one, export immediately, before the 30 days run out: see Cloud Audit Logs explained.
Other blind spots worth writing down
Data Access logs are the biggest gap, not the only one. A complete report lists what could not be seen:
- Public objects: Google states that Cloud Audit Logs does not track access to public objects (Cloud Storage audit logging). After
allUsersis granted, reads are invisible even with Data Access logs. - Inside the VM: processes, files and commands on a Compute Engine instance are outside Cloud Audit Logs. You need disk snapshots and OS logs.
- Network: without VPC Flow Logs on the subnet, egress from a compromised VM is not recorded; with them, volumes are sampled estimates.
- Caller IP redaction: calls between Google services show
private, and calls from VMs without external IP can showgce-internal-ip(AuditLog reference). - Redacted identities: for read-only calls that fail with PERMISSION_DENIED, Google may redact the caller's email unless it is a service account (Cloud Audit Logs overview).
- Other planes: GKE Kubernetes API audit logs and Google Workspace audit logs are separate stories. The analyzer hands them off to Kubernetes Forensics and Google Workspace Forensics.
Limits of the analyzer itself
To be equally explicit about the tool:
- It reads JSON only: Logs Explorer CSV downloads and BigQuery Avro / Parquet exports are rejected with an explanation.
- Heuristic thresholds are fixed (for example 100 object reads in 10 minutes), which can trip on busy ETL accounts or miss slow exfiltration.
- BigQuery extract jobs to external buckets and several newer attack paths (public Cloud Run invokers, Secret Manager bulk access, VPC Service Controls changes) are not yet covered by rules.
- "New IP" and "new region" are relative to what you exported. A short export makes the attacker's IP look like the baseline.
What to enable before the next incident
- Data Access logs (
ADMIN_READ,DATA_READ) for IAM, Cloud Storage and Secret Manager, at organization level. - An organization-level aggregated sink to a locked bucket in a dedicated project.
- VPC Flow Logs on sensitive subnets.
- Alerts on the defense-evasion methodNames in the defense evasion article.
Frequently asked questions
Are GCP Data Access logs enabled by default?
No. Data Access audit logs are disabled by default for all services except some BigQuery services. They must be enabled per service (or for allServices) in the auditConfigs section of the IAM policy, at project, folder or organization level.
How long are Data Access logs kept?
They are stored in the _Default log bucket, whose default retention is 30 days. Keeping them longer requires changing the bucket retention or routing them with a sink to Cloud Storage, BigQuery or another log bucket.
Can I enable Data Access logs after an incident to see what happened?
No. Enabling them only records calls made from that moment on; nothing is backfilled. Enable them now so the next investigation has them.
Further reading
- Configure Data Access audit logs — Google Cloud documentation.
- Best practices for Cloud Audit Logs — Google Cloud documentation.
- Google Cloud incident response: a compromised project.