Top Gradient

Connect your BigQuery Organization

Which path applies to you?

This guide covers two setups, and Steps 1–4 are identical for both.

  • DoiT resells your Google Cloud and invoices you. Your billing data lives in DoiT's project rather than your own, so skip Steps 5–6 and choose the DoiT-managed tab on the connection form.
  • Google invoices you directly. Follow every step, and choose the Direct billing tab on the connection form.

If you work with DoiT for support or tooling but Google still sends your bill, you're on the direct billing path.

Prerequisites

Permissions

A user with the following roles is needed to complete this setup. All of them apply to both paths except the last.

  • Organization Admin — for the organization-level binding in Step 3
  • Role Administrator — for the custom role in Step 1
  • Project IAM Admin — for the project-level bindings in Step 3
  • Service Usage Admin — to enable the APIs listed below
  • Billing Account Costs Manager or Billing Account Administrator. Not needed if DoiT resells your Google Cloud, since you won't be setting up billing exports.

Enabled APIs

Both paths. Ensure the following APIs are enabled on the project that will host the service account:

  • bigquery.googleapis.com
  • iam.googleapis.com
  • iamcredentials.googleapis.com
  • cloudresourcemanager.googleapis.com

Enable TABLE_STORAGE_BY_ORGANIZATION

This step applies to both paths. SELECT uses INFORMATION_SCHEMA.TABLE_STORAGE_BY_ORGANIZATION to provide storage visibility across your org, and the view must be explicitly enabled for each region where your BigQuery data resides. Run the following in Cloud Shell to discover all regions in use and enable the view for each automatically.

1gcloud asset search-all-resources \
2 --scope=organizations/${ORG_ID} \
3 --asset-types=bigquery.googleapis.com/Dataset \
4 --format="value(location)" | sort -u | tr '[:upper:]' '[:lower:]' | \
5while read region; do
6 # bq CLI requires uppercase for multi-regions (US, EU)
7 if [ "$region" = "us" ] || [ "$region" = "eu" ]; then
8 location=$(echo $region | tr '[:lower:]' '[:upper:]')
9 else
10 location=$region
11 fi
12 echo "Enabling for region: ${region}"
13 bq query \
14 --location=${location} \
15 --nouse_legacy_sql \

Allow up to 24 hours for historical data to become available after enabling. SELECT cannot display storage data until this step is complete.

Connecting your account

Steps 1 through 4 are identical for both paths. Throughout, CUSTOMER_PROJECT refers to a project in your organization where SELECT runs its queries — you can use an existing project or create one for this purpose.

1export ORG_ID="<ORG_ID>"
2export CUSTOMER_PROJECT="<CUSTOMER_PROJECT>"
3export SELECT_SERVICE_ACCOUNT="<SELECT_SERVICE_ACCOUNT>"

Step 1: Create the custom org role

Rather than binding several predefined roles separately, create one custom role at the org level. This gives you a single binding to manage and makes it easy to audit exactly what access SELECT has. It combines the permissions of roles/bigquery.resourceViewer, roles/bigquery.metadataViewer and roles/browser, plus bigquery.config.get, which is required to detect fluid scaling on reservations and is not included in any predefined role.

1gcloud iam roles create SelectOrgViewer \
2 --organization="${ORG_ID}" \
3 --title="SELECT Org Viewer" \
4 --description="Grants SELECT read-only metadata access across the org" \
5 --permissions=bigquery.bireservations.get,bigquery.capacityCommitments.get,bigquery.capacityCommitments.list,bigquery.config.get,bigquery.datasets.get,bigquery.datasets.getIamPolicy,bigquery.jobs.get,bigquery.jobs.list,bigquery.jobs.listAll,bigquery.jobs.listExecutionMetadata,bigquery.models.getMetadata,bigquery.models.list,bigquery.propertyGraphs.get,bigquery.propertyGraphs.list,bigquery.reservationAssignments.list,bigquery.reservationAssignments.search,bigquery.reservationGroups.get,bigquery.reservationGroups.list,bigquery.reservations.get,bigquery.reservations.list,bigquery.reservations.listFailoverDatasets,bigquery.routines.get,bigquery.routines.list,bigquery.tables.get,bigquery.tables.getIamPolicy,bigquery.tables.list,dataplex.projects.search,resourcemanager.organizations.get,resourcemanager.folders.get,resourcemanager.folders.list,resourcemanager.projects.get,resourcemanager.projects.getIamPolicy,resourcemanager.projects.list

If you see "role SelectOrgViewer already exists", that's fine — continue to the next step.

Step 2: Create the service account

In your project UI navigate to IAM → Service Accounts → Create Service Account and give it a name, e.g. select-viewer. Click Create and continue, then skip the optional role and group steps and click Done. Alternatively, in Cloud Shell or any environment with gcloud authenticated:

1gcloud iam service-accounts create select-viewer \
2 --display-name="SELECT replicator viewer" \
3 --project="${CUSTOMER_PROJECT}"

This creates select-viewer@${CUSTOMER_PROJECT}.iam.gserviceaccount.com. Note this email down — you'll need it in the final step.

Step 3: Grant read and query access

First, bind the custom role at the organization level so SELECT can see every project's usage:

1gcloud organizations add-iam-policy-binding "${ORG_ID}" \
2 --member="serviceAccount:select-viewer@${CUSTOMER_PROJECT}.iam.gserviceaccount.com" \
3 --role="organizations/${ORG_ID}/roles/SelectOrgViewer"

Then grant the project-level roles that let SELECT actually run queries and read sessions. These are intentionally scoped to the project only, not the org, to limit the blast radius:

1for ROLE in roles/bigquery.jobUser roles/bigquery.readSessionUser; do
2 gcloud projects add-iam-policy-binding "${CUSTOMER_PROJECT}" \
3 --member="serviceAccount:select-viewer@${CUSTOMER_PROJECT}.iam.gserviceaccount.com" \
4 --role=$ROLE
5done

If you see a 403 "User does not have bigquery.jobs.create permission" error when testing the connection, this step was likely skipped or run against the wrong project. Confirm CUSTOMER_PROJECT matches the project ID you entered in SELECT's connection form.

Step 4: Allow SELECT to impersonate the service account

SELECT authenticates by impersonating the service account you just created — nothing leaves your organization. You can find your org-specific SELECT service account email on the Add BigQuery connection form in the SELECT app.

1gcloud iam service-accounts add-iam-policy-binding \
2 select-viewer@"${CUSTOMER_PROJECT}".iam.gserviceaccount.com \
3 --member="serviceAccount:${SELECT_SERVICE_ACCOUNT}" \
4 --role="roles/iam.serviceAccountTokenCreator" \
5 --project="${CUSTOMER_PROJECT}"

Org policy restrictions: Some organizations enforce constraints/iam.managed.allowedPolicyMembers, which blocks binding external service accounts directly to resources in your org. If you hit an error mentioning this constraint, add SELECT's service account to a Google Group in your organization, then grant roles/iam.serviceAccountTokenCreator to that group on the select-viewer SA instead of binding SELECT's SA directly.

DoiT-managed customers: you're done with the GCP-side setup. Skip Steps 5 and 6 and go straight to Add connection to SELECT — DoiT handles your billing export, so there is no billing setup on your side.

Step 5: Enable billing exports

SELECT needs three billing exports — detailed usage cost, pricing data, and committed use discount data — to give you complete cost visibility. Each is written to BigQuery and all three should land in the same dataset. In the Google Cloud Console, navigate to Billing, then click Billing export in the left pane.

5a. Detailed usage cost export

  • On the BigQuery export tab, find Detailed usage cost and click Enable detailed export.
  • For Project, select your billing project.
  • For the dataset, click create new dataset. Creating a dataset specific to SELECT lets you limit SELECT's access to just the billing data. Enter a dataset ID of your choosing (e.g. billing_export) and choose a multi-region location (US or EU). Note the ID down.

5b. Pricing data export

Back on the Billing export page, find Pricing data, click Enable pricing export, select the same project and dataset as in 5a, and save.

5c. Committed use discount (CUD) data export

Find Committed use discount data, click Enable CUD export, select the same project and dataset, and save. It can take up to 24 hours for the first batch of billing data to appear.

Step 6: Grant read access to the billing dataset

Grant bigquery.dataViewer scoped to only the billing export dataset, so SELECT has no access to your company's data. In BigQuery Studio, navigate to the billing export dataset, click Share → Manage Permissions → Add principal, add the select-viewer service account and assign BigQuery Data Viewer. Alternatively:

1gcloud alpha bq datasets add-iam-policy-binding \
2 ${BILLING_DATASET} \
3 --project="${CUSTOMER_PROJECT}" \
4 --member="serviceAccount:select-viewer@${CUSTOMER_PROJECT}.iam.gserviceaccount.com" \
5 --role=roles/bigquery.dataViewer

Add connection to SELECT

Navigate to the connections tab in SELECT's settings and click Add Connection. The fields differ depending on your billing path.

Enter a connection name (e.g. your organization's name) and fill in:

  • Project ID — your CUSTOMER_PROJECT
  • Billing export dataset name — e.g. billing_export
  • Billing Account ID — e.g. ABCDEF-12345-67810
  • Leave Managed by DoiT unchecked.

Click Add. SELECT runs a test query to verify the connection. You'll receive an email when the initial sync completes, usually within a couple of hours.

Troubleshooting

Test fails with a "jobs.create" 403

The project ID you entered must be your own CUSTOMER_PROJECT, and that project needs the bigquery.jobUser grant from Step 3. If you are on the DoiT-managed path, don't enter a DoiT project such as doitintl-cmp-gcp-data — the service account can't run jobs there.

"Permission denied" creating the role or binding

Steps 1 and 3 act at the organization level and need Role Administrator and Organization Admin. Ask whoever owns your org's IAM to run those commands, or to grant you those roles temporarily.

"Service account does not exist"

This comes from Step 4 when SELECT_SERVICE_ACCOUNT doesn't exactly match the email on your connection form. Re-copy it from the top of the connection screen and rerun that command.

Can't find your organization ID?

Your Cloud Console org picker (top-left) shows it. DoiT resale customers who are still stuck can reach out to their DoiT account team, who can look it up from your DoiT billing data.

VPC Service Controls (optional)

Applies to both paths. If your GCP organization has VPC Service Controls enabled with a service perimeter around BigQuery, SELECT's queries will be blocked by default and you'll see "Request is prohibited by organization's policy" when adding the connection. Since SELECT authenticates by impersonating your select-viewer service account, the most reliable fix is an ingress rule scoped to SELECT's GCP project.

1- ingressFrom:
2 identityType: ANY_IDENTITY
3 sources:
4 - resource: "projects/813120990659"
5 ingressTo:
6 operations:
7 - serviceName: bigquery.googleapis.com
8 methodSelectors:
9 - method: "*"
10 resources:
11 - "*"

ANY_IDENTITY is required because SELECT's service account lives in a different GCP organization than your perimeter, and ANY_SERVICE_ACCOUNT only matches service accounts within the same org. This remains secure: the source is locked to SELECT's project, IAM enforces that only SELECT's service account can impersonate your select-viewer SA, and that SA has read-only BigQuery permissions. Apply it with:

1gcloud access-context-manager perimeters update YOUR_PERIMETER_NAME \
2 --add-ingress-policies=ingress-select.yaml \
3 --policy=YOUR_POLICY_ID

IP allowlisting will not work for most customers. SELECT runs on Google Cloud Run, which routes traffic through Google's internal network and redacts the source IP, so IP-based access levels never match. Always test perimeter changes in dry-run mode before enforcing them.

Get up and running in less than 15 minutes

Connect your Snowflake, Databricks, or BigQuery account and instantly understand your savings potential.

CTA Screen