Ensure all data in BigQuery has been classified
A BigQuery table holds whatever its producers wrote into it, and nothing in BigQuery tells you which columns carry payment card numbers, government identifiers, or health data until something inspects the values. This control requires a Sensitive Data Protection discovery scan configuration covering the organization, folder, or project, so that every eligible BigQuery table is profiled and its columns classified.
What the benchmark asks for
The benchmark checks for the existence of a discovery scan configuration for BigQuery, at either organization or project scope. A configuration is the standing instruction that tells the discovery service which assets to profile, which inspection template to classify them against, and how often to come back. Without one, no table is profiled, and the data profiles page is empty.
The benchmark treats this as a Manual check because the console page it points at shows configurations rather than coverage. The existence of a configuration does not establish that your tables are inside its scope, that profiling succeeded, or that the results are recent. The sections below cover the conditions that separate a configuration from actual classification coverage.
How it works
Discovery runs continuously once configured, rather than as a scan you start by hand. When BigQuery data is profiled, Sensitive Data Protection generates three tiers of profile. A table data profile for each table, a column data profile for each column within it, and a project data profile that aggregates every table scanned in that project. The column profile is the useful unit. It lists the infoTypes predicted for that column, CREDIT_CARD_NUMBER and EMAIL_ADDRESS are built-in examples, and carries the calculated data risk and sensitivity levels.
Only one scan configuration can exist per combination of scope and discovery type. When organization, folder, and project configurations overlap on the same project, the organization or folder configuration closest to that project wins for organization and folder coverage, and a project-level configuration runs independently alongside it. That produces two separate sets of profiles for the same project, which matters if you bill profiling to different teams or compare profile counts against table counts.
Classification is driven by an inspection template, which holds the infoType detectors and any custom detectors you have added. The template must sit in the same region as the data it scans. If no template exists for a region and none is stored in the global region as a fallback, classification of that region's data fails with an error rather than skipping quietly. The failure is visible, but only to somebody looking at the configuration.
Profiles are not static records you curate. Deleting a data profile forces the discovery service to regenerate it on the next scan cycle, unless the underlying table is also excluded from the scan configuration. To stop profiling a table, change the scope, not the output.
Results can leave the data profiles page in three directions. They can be exported to a BigQuery table for querying, published to Pub/Sub for automation, and sent to Security Command Center as findings. In Security Command Center the output goes beyond sensitivity labels. A BigQuery table or dataset holding high- or moderate-sensitivity data that is not using a customer-managed encryption key raises a SENSITIVE_DATA_CMEK_DISABLED misconfiguration finding, separate from the DATA_SENSITIVITY and DATA_RISK observation findings. In a large organization, expect a wait of up to 12 hours after enabling discovery before findings appear there.
What the control does not cover
Coverage of BigQuery is not universal. Profiling excludes BigQuery Omni tables, non-BigLake external tables such as those backed by Google Sheets, and any table where a single row's serialized size exceeds 128 MB. A configuration at organization scope satisfies the benchmark and still leaves those tables unclassified. If your analytics estate reaches across clouds through BigQuery Omni, the data that lives there is outside this control entirely.
Freshness is the second gap. Under the default schedule a table is reprofiled only after a 30-day wait, and only if its schema, row data, or inspection template changed during that window. A table that nobody touched keeps its original profile indefinitely. That is usually correct, because an unchanged table has unchanged contents, but it means a profile's age is not evidence that anything is wrong.
Whether adding a custom infoType to an inspection template reclassifies tables already scanned comes down to one schedule setting. A schedule can be told to reprofile data when its inspection template is updated, and the discovery service treats a change to the template's updateTime as that trigger, so the tables already scanned are profiled again against the new detectors. With that setting off, the new detector reaches only tables that are profiled for some other reason, so the day after you add a detector for your internal customer identifier format, your profiles still say those columns hold nothing sensitive.
Schedules can also exclude tables by design. A schedule can set a minimum row count and a minimum age, and a table is profiled when it meets either one rather than both. A time condition sits on top of that and permanently excludes tables created before a cutoff timestamp, which is the one condition that combines with the minimums rather than competing with them. Tables that match no custom schedule fall to a catch-all schedule at the bottom of the list, and that catch-all can be turned off. An organization-wide configuration with a disabled catch-all profiles only what the named schedules reach, and the configuration still exists, so the benchmark check still passes.
What it costs to comply
Discovery profiling is billed, and the bill scales with the volume of data inspected rather than with the number of tables. The first profile of an established data warehouse is the expensive event, because every eligible table is inspected once. Steady-state cost is lower, because a table is inspected again only when it meets a reprofile condition, and an untouched table does not.
Export destinations add their own cost. Sending profiles to a BigQuery table means storing and querying that table. Publishing to Pub/Sub means a subscriber that runs continuously. Security Command Center findings consume quota in whichever tier you run.
The operational cost is larger than the billing cost. A discovery configuration produces findings against data owned by teams who did not ask for it, and the first run commonly surfaces columns of real sensitive data in places nobody expected. Tell the teams that own those tables before you turn discovery on.
Classification on its own changes nothing about access. Acting on findings is where the cost lands. Applying BigQuery policy tags to restrict sensitive columns to principals with the right access, or de-identifying the raw values through masking or tokenization. Both break queries that currently read those columns.
The case where the cost is not worth paying is a project with no production data. A sandbox, a scratch analytics project, or a project holding only synthetic test data. Profiling it costs money and produces findings that are correct and useless. Exclude those projects from the scan configuration rather than muting their findings downstream.
How to check your environment
The configuration itself is visible in the console at the Sensitive Data Protection discovery page, under data profiles. A configuration at organization or folder scope is what the benchmark looks for.
Checking coverage rather than configuration takes a query. Enable export of profiles to BigQuery, then compare the set of profiled tables against the set of tables in INFORMATION_SCHEMA.
Query the export with care. The output table keeps every historical snapshot of a table's classification result, including stale ones from before a schema change. Querying it directly for current state returns duplicate, outdated rows for the same column. The auto-generated _latest_v1 view filters to the most recent snapshot per asset, so point current-state queries at the view.
To find every table flagged as holding payment card data, filter the exported profiles on column_profile.column_info_type.info_type.name equal to CREDIT_CARD_NUMBER, which is a built-in infoType. The same filter pattern works for any other infoType name.
Anything you build on the export has to tolerate change. The exported table's schema is versioned and can change as Google adds features, so a pipeline that rejects unrecognized fields will break on a release you did not control. Select the columns you need by name rather than reading the row whole.
How to implement it
Create the scan configuration at organization or folder scope, following the organization and folder profiling guide. Organization scope is the setting that covers tomorrow's projects as well as today's, which is the difference between a control that holds and one that decays as the estate grows. The project profiling guide covers the narrower case where you own one project and not the organization.
Before the configuration runs, place an inspection template in every region where you hold BigQuery data, or store one in the global region as the fallback. Skipping this produces a region-wide classification failure rather than partial results.
Then deal with the gaps the defaults leave:
- Turn on reprofiling when the inspection template changes, so adding a custom detector reclassifies existing tables rather than only new ones.
- Leave the catch-all schedule enabled. It is what covers tables that match no named schedule, including tables in projects created after you wrote the configuration.
- Check whether any minimum row count, minimum age, or creation-time condition excludes data you care about. A cutoff timestamp that permanently excludes older tables is the most consequential of these, because the oldest tables are often the ones nobody has reviewed.
Route the output somewhere that is read. Publish profiles to Security Command Center so classification results sit beside other findings, and publish to Pub/Sub where you want alerting or automated remediation on new or changed data risk. A configuration whose output nobody consumes satisfies the benchmark and protects nothing.
Act on high data risk scores by restricting access with BigQuery policy tags on the sensitive columns, or by de-identifying the raw values. The remediation guide covers both paths.
Further reading
- Data profiles. The reference for how discovery works: profile tiers, what is excluded from BigQuery profiling, reprofile conditions, scan configuration precedence, and inspection template regionality.
- Analyze data profiles. The exported BigQuery schema, the
_latest_v1view, and sample queries for finding tables by infoType. - Profile data in an organization or folder. The setup walkthrough for organization and folder scope, including schedule conditions and the Pub/Sub and Chronicle publishing options.
- Profile data in a single project covers the same setup at project scope.
- Send data profiles to Security Command Center. The finding types produced, including
SENSITIVE_DATA_CMEK_DISABLED, and the delay before findings appear. - Data profiles covers the profile types, the data risk and sensitivity scores, and what the service does with them.
