GCP-221 · Lesson 10 of 12 · 19 min

Sharing data and reports securely

▶ Video coming soon A video version of this lesson is on the way.

Friday, November 6, is about access. The store manager dashboard is nearly ready, and Lena's next question is a careful one: each manager should see their own store in detail and only regional totals for the others, and nobody outside Finance should see individual transaction lines, which include payment types. Ravi uses the request to walk through BigQuery's layers of access control and how they combine with Data Studio's sharing.

The principle: least privilege, granted to groups

Every access decision follows one principle: give people the least access that lets them do their job, and no more. A second rule makes that manageable: grant access to groups, not individuals. Birchline has Google groups such as store-managers@, analytics-team@ and finance-reporting@. When a manager joins or leaves, the identity team changes group membership, and every grant follows automatically. Grants to individual accounts are hard to audit and tend to outlive the job they were made for.

Six stacked layers with descriptions. Project and dataset IAM: who can see the dataset at all; viewer, editor, job user. Table and view IAM: grant one table or view without the whole dataset. Authorized views: share query results without access to the base tables. Column-level security: policy tags hide sensitive columns. Row-level security: row access policies limit rows by user or group. Report sharing: viewer or editor on a report; owner or viewer credentials. A note says grant the least access that lets someone do the job, and grant it to groups, not individuals.
Layers of access control, from the project down to individual rows and reports.

IAM roles for BigQuery

BigQuery access is controlled with Identity and Access Management (IAM) roles, granted at the level of the organization, a project, a dataset, or a single table or view. Access to data and permission to run queries are separate. To query a table, a person needs permission to read the data, such as BigQuery Data Viewer on the dataset, and permission to run jobs in some project, such as BigQuery Job User, because every query is a job that is billed to a project.

Common predefined BigQuery IAM roles.
RoleGrantsTypical holder
BigQuery Data ViewerRead tables and views, and their metadataAnalysts who query curated data
BigQuery Data EditorRead and change data; create tables in a datasetPipelines and data engineers
BigQuery Data OwnerFull control of a dataset, including its accessThe dataset's owning team, sparingly
BigQuery Job UserRun jobs, including queries, in a projectAnyone who runs queries in that project
BigQuery UserRun jobs and create datasets in a projectAnalysts who need their own scratch datasets
BigQuery Metadata ViewerSee dataset and table metadata, not dataCatalog browsing
BigQuery AdminEverything in BigQueryA few platform administrators

Birchline grants analytics-team@ Data Viewer on curated and reference, Job User on the analytics project, and BigQuery User on a separate sandbox project for experiments. Finance gets Data Viewer on a finance dataset that includes the transaction lines. Store managers get nothing on the raw or curated datasets at all; what they see comes through the reporting layer described below.

Sharing results, not tables: authorized views and datasets

Lesson 5 introduced authorized views. Ravi creates a dataset called shared_reporting in the same location as curated, creates the view v_store_daily_reporting there, and authorizes it on the curated dataset. Store managers receive Data Viewer on shared_reporting only. They can query the view, which returns daily totals per store, but they cannot read curated.sales, see its transaction lines or write their own query against it. An authorized dataset extends the same idea: every view in an authorized dataset is allowed to read the source dataset, which saves authorizing views one at a time.

Row-level security

Lena's first requirement, detail for your own store and totals for others, needs rows filtered by who is asking. Row-level security in BigQuery uses row access policies attached to a table. Each policy names a set of users or groups and a filter; a user sees only the rows matching the filters of the policies that include them. Once any row access policy exists on a table, users who are not covered by any policy see no rows at all.

Row access policies on the detail table: each group sees only the rows its filter allows.
-- Each store's managers see their own store's rows in the detail table
CREATE ROW ACCESS POLICY store_12_managers
ON `bl-data-prod.shared_reporting.store_daily_detail`
GRANT TO ("group:store-012-managers@birchline.example")
FILTER USING (store_id = 12);

-- Regional managers see every store in their region
CREATE ROW ACCESS POLICY east_region
ON `bl-data-prod.shared_reporting.store_daily_detail`
GRANT TO ("group:region-east-managers@birchline.example")
FILTER USING (region = "East");

-- Analysts and finance see everything
CREATE ROW ACCESS POLICY all_rows
ON `bl-data-prod.shared_reporting.store_daily_detail`
GRANT TO ("group:analytics-team@birchline.example", "group:finance-reporting@birchline.example")
FILTER USING (TRUE);

Writing a policy for each of forty stores is repetitive, so Ravi uses a common alternative: a mapping table that lists each manager's email and store, and a filter that uses SESSION_USER() to look up the current user. Either way, the important property is the same. The filter is applied by BigQuery itself, so it holds in every tool: the console, a notebook, Connected Sheets or a report using viewer's credentials.

Mateo models the policy logic in Python to make sure he understands what each person will see, including the person no policy covers.

Python Example
rows = [  # (store_id, region, net_sales) for one day
    (12, "East", 9100), (15, "East", 7800), (22, "Central", 6600), (31, "West", 9400),
]
policies = {   # group -> filter
    "store-012-managers": lambda r: r[0] == 12,
    "region-east-managers": lambda r: r[1] == "East",
    "analytics-team": lambda r: True,
}
users = {
    "manager of store 12": ["store-012-managers"],
    "East regional manager": ["region-east-managers"],
    "analyst": ["analytics-team"],
    "new hire, no group yet": [],
}
for user, groups in users.items():
    visible = [r for r in rows if any(policies[g](r) for g in groups)]
    total = sum(r[2] for r in visible)
    print(f"{user:24} sees {len(visible)} rows, total {total:,}")
Output
manager of store 12      sees 1 rows, total 9,100
East regional manager    sees 2 rows, total 16,900
analyst                  sees 4 rows, total 32,900
new hire, no group yet   sees 0 rows, total 0

What this code does

Simulating which rows each person can see under row access policies. Each policy is a group with a filter, and each person belongs to some groups. A person sees a row if any of their groups' filters allows it. The output shows the store manager seeing one store, the regional manager two, the analyst all four, and the new hire, who is in no group yet, seeing nothing at all, which is how BigQuery behaves once a table has row access policies.

Column-level security and masking

Lena's second requirement, no transaction lines or payment types outside Finance, is about columns. Column-level security uses policy tags from a taxonomy managed in Dataplex. An administrator tags sensitive columns, such as tender_type or customer_email, and grants the Fine-Grained Reader role on each tag to the groups allowed to see it. A user without that role who queries the column gets an access error. Dynamic data masking goes one step further: instead of an error, users without access see a masked value, such as NULL, a hash or only the last four characters, according to a masking rule. Masking lets one table serve everyone while protecting the sensitive values.

Matching a sharing requirement to a BigQuery feature.
RequirementFeatureBehavior
Share only some rowsRow access policyUsers see only rows matching their policies
Hide a sensitive columnPolicy tag with column-level securityUnauthorized queries on the column fail
Show a sensitive column partlyDynamic data maskingUnauthorized users see a masked value
Share results without base tablesAuthorized view or authorized datasetUsers query the view; base tables stay private
Share a dataset with another organizationBigQuery sharing (formerly Analytics Hub)Subscribers get a linked, read-only dataset

For sharing data outside the organization, BigQuery offers data exchanges and listings, a feature long called Analytics Hub and now presented in the console as BigQuery sharing. A publisher lists a dataset; a subscriber in another organization gets a linked dataset that reads the publisher's data in place, without copying it, and queries are billed to the subscriber. Birchline uses it to receive weather data from a provider and plans to share sell-through figures with its two largest suppliers.

Sharing reports

Data Studio sharing works like Google Drive. A report can be shared with people or groups as viewers or editors, and link sharing can be restricted to the organization or turned off. Sharing the report and sharing the data are separate: what a viewer sees depends on the data source's credentials. With owner's credentials, viewers see whatever the source returns to its owner; with viewer's credentials, they see what their own BigQuery permissions allow, including row access policies.

Ravi's design uses both deliberately. The overview page reads a summary of regional totals through owner's credentials, because every manager may see regional totals and nobody needs BigQuery access for that. The store detail page reads store_daily_detail through viewer's credentials, so the row access policies decide which store each manager sees. Editors are limited to the analytics team, and the report is owned by a Data Studio Pro team workspace, not by Ravi's personal account.

Connected Sheets gives business users another route: from Google Sheets, they can pivot, chart and filter BigQuery tables of billions of rows, with the queries running in BigQuery under their own credentials. Finance's month-end workbook uses Connected Sheets on the governed finance views, so the familiar spreadsheet layout reads warehouse data directly instead of exported copies. Exported copies are the most common way data escapes its controls, which is why Birchline discourages downloading curated data to files.

Privacy obligations and auditing

Access control is also a legal matter when personal information is involved. In the United States, privacy rules come from federal laws for particular sectors and a growing number of state laws, and Ohio's Data Protection Act gives businesses a legal defense if they keep a recognized cybersecurity program; either way, personal information should be limited to what is needed and protected by reasonable safeguards, which in practice means masking, minimizing and restricting customer columns. Ravi's rule is that curated sales carry no customer names or emails at all; the customer key is a pseudonymous ID, and the mapping to real customers lives in a separate, tightly restricted dataset.

Finally, Cloud Audit Logs record who changed access and, through data access logs, who read which tables. BigQuery's INFORMATION_SCHEMA views show grants and jobs. A quarterly review of who has access to what, run by the data owners, catches the grants that should have been removed.

Common mistakes

  • MistakeGranting BigQuery Data Viewer to individual managers.

    InsteadGrant roles to groups so membership changes keep access correct.

  • MistakeGiving store managers access to the base table so a report works.

    InsteadUse an authorized view or dataset, and row access policies on a reporting table.

  • MistakeAssuming a report shared as viewer-only protects the data.

    InsteadWith owner's credentials, every viewer sees what the source returns; limit the source or use viewer's credentials.

  • MistakeForgetting that a table with row access policies hides all rows from uncovered users.

    InsteadAdd a policy for every group that needs access, including analysts and service accounts.

Service accounts deserve the same care as people. The Data Studio Pro workspace, the scheduled queries and the Looker connection each run as a service account with only the roles they need, and none of them holds BigQuery Admin.

Worked problem

Designing access for the store dashboard

Managers must see their own store's daily detail, regional totals for all regions, and no payment types. Finance must see everything. What combination of features meets this?

Show solution
  1. Create shared_reporting with a regional totals view, authorized on curated; grant store-managers@ Data Viewer on shared_reporting.
  2. Build store_daily_detail in shared_reporting with row access policies per store group, plus a policy for analytics and finance.
  3. Leave payment types out of the reporting tables entirely; in curated, protect tender_type with a policy tag readable by finance-reporting@.
  4. In Data Studio, use owner's credentials for the regional overview and viewer's credentials for the store detail page.

Answer: Authorized views for totals, row access policies for store detail, policy tags for payment types, and the right credentials on each Data Studio data source, all granted to groups.

Summary and key terms

  • Grant the least access needed, to groups rather than individuals.
  • BigQuery IAM separates reading data, such as Data Viewer, from running jobs, such as Job User, and roles can be granted on projects, datasets, tables and views.
  • Authorized views and datasets share results without exposing base tables.
  • Row access policies filter rows by user or group in every tool, and users not covered by any policy see nothing.
  • Policy tags provide column-level security, and dynamic data masking shows masked values instead of errors.
  • BigQuery sharing, formerly Analytics Hub, shares datasets across organizations without copying.
  • Data Studio sharing is separate from data access: owner's credentials expose what the source returns, viewer's credentials apply each viewer's permissions.
  • Connected Sheets keeps spreadsheet users on governed data, and audit logs support regular access reviews.
Least privilege
Granting only the access needed to do a job.
IAM role
A named set of permissions granted to a principal on a resource.
BigQuery Job User
A role that lets a principal run queries and other jobs in a project.
Authorized dataset
A dataset whose views are all allowed to read a source dataset.
Row access policy
A BigQuery rule that limits which rows a user or group can see.
Policy tag
A label on a column that controls who can read it.
Dynamic data masking
Showing masked values to users without access to a sensitive column.
Connected Sheets
A Google Sheets feature for analyzing BigQuery data directly.

Practice problems

Work each problem on paper first, then reveal the answer to check.

  1. Which two roles does an analyst usually need to query a curated table?

    Show answer

    Data Viewer on the dataset and Job User on a project to run the query.

  2. What does a user with no matching row access policy see?

    Show answer

    No rows at all from that table.

  3. How can a column be visible to everyone but show real values only to Finance?

    Show answer

    Use dynamic data masking with a policy tag that Finance can read.

  4. Why might a viewer-only Data Studio report still expose sensitive data?

    Show answer

    With owner's credentials, viewers see whatever the data source returns to its owner.

Lesson quiz · 5 questions

Score 60% or more to complete this lesson.

Take the quiz