> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omni.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Connecting Google BigQuery to Omni with workload identity federation

> Connect BigQuery to Omni using workload identity federation — no service account key to store, upload, or rotate.

export const BaseAccess = () => {
  return <span>
      <ParamField path="Base Access" required>
        Select the <a href="/administration/users/permissions">minimum level of access</a> users should have to models in the connection.
      </ParamField>
    </span>;
};

export const AlwaysScopeViewNames = () => {
  return <span>
      <ParamField path="Always Scope View Names" default="enabled">
        When enabled, Omni will prefix generated view names with schema and catalog, e.g. <code>my_catalog_public__orders</code> instead of <code>orders</code>. Defaults to enabled. See <a href="/connect-data/view-name-generation">View name generation</a> for more information.
      </ParamField>
    </span>;
};

export const AllowUserSpecificTimezones = () => {
  return <span>
      <ParamField path="Allow User-Specific Timezones">
        When enabled, users can override the connection timezone with their own when querying.
      </ParamField>
    </span>;
};

export const QueryTimezone = () => {
  return <span>
      <ParamField path="Query Timezone" required>
        The timezone to use for Omni queries. If a timezone is specified, data will be converted from the <strong>Database Timezone</strong> to the selected timezone.
      </ParamField>
    </span>;
};

export const DatabaseTimezone = () => {
  return <span>
      <ParamField path="Database Timezone" required>
        The timezone used by the database.
      </ParamField>
    </span>;
};

export const TableUploads = ({label = "Schema for Table Uploads", term = "schema"}) => {
  return <span>
      <ParamField path={label}>
        The name of the {term} to use for table (CSV) uploads. If left blank, you can upload tables but they won't be pushed to the database or be available for use in joins.
      </ParamField>
    </span>;
};

export const Offloaded = ({term = "Schemas"}) => {
  const lower = term.toLowerCase();
  return <span>
      <ParamField path={`Offloaded ${term}`}>
        A comma-separated list of {lower} to include in the connection, which will only load on demand. This setting is good for large {lower} or dbt dev {lower}.
      </ParamField>
    </span>;
};

export const IncludeOther = ({term = "Schemas"}) => {
  const lower = term.toLowerCase();
  return <span>
      <ParamField path={`Include Other ${term}`}>
        A comma-separated list of other {lower} to include in the connection.
      </ParamField>
    </span>;
};

export const Include = ({term = "Schemas"}) => {
  const lower = term.toLowerCase();
  return <span>
      <ParamField path={`Include ${term}`}>
        A comma-separated list of {lower} to include in the connection.
      </ParamField>
    </span>;
};

export const Default = ({term = "Schema", required = true, defaultValue}) => {
  const lower = term.toLowerCase();
  return <span>
      <ParamField path={`Default ${term}`} required={required} default={defaultValue}>
        The default {lower} for the connection.
      </ParamField>
    </span>;
};

export const DisplayName = () => {
  return <span>
      <ParamField path="Display Name" required>
        A user-friendly name for the connection, which will be used throughout Omni.
      </ParamField>
    </span>;
};

export const stepText_1 = "step 1"

export const omniPlaceholder_1 = "OMNI_WORKLOAD_IDENTITY"

export const omniFieldName_1 = "Omni Workload Identity"

export const stepText_0 = "step 1"

export const omniPlaceholder_0 = "OMNI_WORKLOAD_IDENTITY"

export const omniFieldName_0 = "Omni Workload Identity"

export const XCircleIcon = ({label}) => {
  return <span>
      <Icon icon="circle-xmark" iconType="solid" color="#ff2465" />
      {label && ` ${label}`}
    </span>;
};

export const CheckIcon = ({label}) => {
  return <span>
      <Icon icon="circle-check" iconType="solid" color="#26bd6c" />
      {label && ` ${label}`}
    </span>;
};

With workload identity federation, Omni connects to BigQuery using its own cloud identity instead of a stored service account key. Omni exchanges its identity for short-lived Google Cloud credentials through a [workload identity pool](https://cloud.google.com/iam/docs/workload-identity-federation) you control — there's no key to create, upload, or rotate, and you can revoke Omni's access at any time from your Google Cloud project.

## How it works

1. In your Google Cloud project, you create a workload identity pool with an AWS provider that trusts the identity Omni presents.
2. When Omni queries BigQuery or refreshes the connection's schema, it exchanges that role's credentials for a short-lived Google Cloud access token.
3. The token acts either as the federated identity itself, or as a service account you allow Omni to impersonate.

## Requirements

<Note>
  Workload identity federation is currently available for **AWS-hosted Omni deployments only**. Support for Azure-hosted deployments is planned.
</Note>

To follow the steps in this guide, you'll need:

* **Organization Admin permissions** in Omni

* **Google Cloud admin permissions**, which are required to create workload identity pools and grant IAM roles

* **The `gcloud` CLI**

* **The following details about the default dataset in your BigQuery project:**

  * The **name** of the default dataset
  * Its **data location**
  * Its **timezone** <br /><br />

  <Accordion title="Need help locating the dataset?">
    1. Navigate to your BigQuery console.
    2. Select the project your dataset resides in. Use the top middle drop-down menu to toggle between projects.
    3. Select a dataset and the info will appear in the **Dataset info** menu. In this example:

       * The dataset **name** is `products`
       * The **Data location** is `US`
       * The **timezone** is `UTC-7`, as indicated in the **Last modified** field

    <img src="https://mintcdn.com/omni-e7402367/XZwrvFN-b2pRXANo/connect-data/images/bigquery-dataset-details.png?fit=max&auto=format&n=XZwrvFN-b2pRXANo&q=85&s=5afe02cb135e73538b14ed856087a619" alt="BigQuery dataset info" width="1004" height="832" data-path="connect-data/images/bigquery-dataset-details.png" />
  </Accordion>

## Setup

<Steps>
  <Step title="Retrieve Omni's AWS identity information" id="omni-aws-info" titleSize="h3">
    1. In Omni, click **Settings > Connections**.
    2. Click the **BigQuery** option.
    3. In the **Authentication Type** menu, select **Workload Identity Federation**.
    4. Copy the **Omni Workload Identity** value. It will contain a value like the following:

       ```text theme={null}
       arn:aws:iam::123456789012:role/Prod-ProdModelTaskRole
       ```

    This identifies Omni to Google Cloud. Note that:

    * **It contains Omni's AWS account ID**. This is the `123456789012` segment. You'll need this when creating the provider in the next step.
    * **It contains a prefix, not the full role name.** The actual role has a random suffix appended by Omni's infrastructure, so your attribute condition must use a **starts-with** comparison. An exact-match condition will never match.
  </Step>

  <Step title="Create a workload identity pool and AWS provider" titleSize="h3" id="pool-provider">
    <Tabs>
      <Tab title="Console" icon="window-maximize">
        1. In the Google Cloud Console, navigate to [**IAM & Admin > Workload Identity Federation**](https://console.cloud.google.com/iam-admin/workload-identity-pools).
        2. Click **Create pool**.
        3. Enter a name, such as `omni`, and continue.
        4. Add a provider to the pool:
           * **Provider type** - AWS
           * **Provider name** - Enter a name, such as `Omni`
           * **AWS account ID** - The account ID from the value you copied in [{stepText_0}](#omni-aws-info)
        5. Configure the provider attribute mappings. AWS presents Omni's identity in a different format than the value shown in Omni, so the mappings reconstruct the role ARN before comparing it.

           1. Click **Edit mapping**.
           2. For `google.subject`, paste the following into the corresponding **AWS** field:

              ```text wrap theme={null}
              assertion.arn.extract('assumed-role/{role}/')
              ```
           3. For `attribute.aws_role_arn`, paste the following into the corresponding **AWS** field:

              ```text wrap theme={null}
              'arn:aws:iam::' + assertion.account + ':role/' + assertion.arn.extract('assumed-role/{role}/')
              ```

           The mappings should look like the following when finished:

                   <Frame caption="Configured provider attribute mappings">
                     <img src="https://mintcdn.com/omni-e7402367/WZjB9Ag_8rCWDdYV/connect-data/images/google-wif-attribute-mappings.png?fit=max&auto=format&n=WZjB9Ag_8rCWDdYV&q=85&s=8579a637d92d01d184c45dbee6456a80" alt="Configured provider attribute mappings in the Google Cloud Console" width="530" height="482" data-path="connect-data/images/google-wif-attribute-mappings.png" />
                   </Frame>
        6. Configure the provider attribute conditions:
           1. Click **Add condition**.
           2. In the text field, add the attribute condition. Replace **{omniPlaceholder_0}** with the **{omniFieldName_0}** value you copied from Omni in [{stepText_0}](#omni-aws-info):

              ```text wrap theme={null}
              attribute.aws_role_arn.startsWith('OMNI_WORKLOAD_IDENTITY')
              ```

              For example:

              ```text wrap theme={null}
              attribute.aws_role_arn.startsWith('arn:aws:iam::123456789012:role/Prod-ProdModelTaskRole')
              ```

              The attribute conditions should look like the following when finished:

        <Frame caption="Configured provider attribute condition">
          <img src="https://mintcdn.com/omni-e7402367/069S4MxcGWz9PKUT/connect-data/images/google-wif-database-attribute-conditions.png?fit=max&auto=format&n=069S4MxcGWz9PKUT&q=85&s=fb37f721ec49b97c89c6685df935cc86" alt="Configured provider attribute condition in the Google Cloud Console" width="501" height="183" data-path="connect-data/images/google-wif-database-attribute-conditions.png" />
        </Frame>

        7. Click **Save**.
      </Tab>

      <Tab title="gcloud CLI" icon="terminal">
        Using the `gcloud CLI`, run the following to create a workload identity pool:

        ```bash highlight={2} theme={null}
        gcloud iam workload-identity-pools create omni \
          --project=GCP_PROJECT_ID \
          --location=global \
          --display-name="Omni"
        ```

        Replace **GCP\_PROJECT\_ID** with the ID of your GCP project.

        Then, create the provider:

        ```bash wrap highlight={2,5,7} theme={null}
        gcloud iam workload-identity-pools providers create-aws omni-aws \
          --project=GCP_PROJECT_ID \
          --location=global \
          --workload-identity-pool=omni \
          --account-id=OMNI_AWS_ACCOUNT_ID \
          --attribute-mapping="google.subject=assertion.arn.extract('assumed-role/{role}/'),attribute.aws_role_arn='arn:aws:iam::'+assertion.account+':role/'+assertion.arn.extract('assumed-role/{role}/')" \
          --attribute-condition="attribute.aws_role_arn.startsWith('OMNI_WORKLOAD_IDENTITY')"
        ```

        Replace the following values:

        | Placeholder                | Replace with                                                                        |
        | -------------------------- | ----------------------------------------------------------------------------------- |
        | **GCP\_PROJECT\_ID**       | The ID of your GCP project                                                          |
        | **OMNI\_AWS\_ACCOUNT\_ID** | The account ID from the value you copied in [{stepText_1}](#omni-aws-info)          |
        | **{omniPlaceholder_1}**    | The entire **{omniFieldName_1}** value you copied in [{stepText_1}](#omni-aws-info) |
      </Tab>
    </Tabs>
  </Step>

  <Step title="Grant BigQuery access" titleSize="h3" id="grant-access">
    Choose how Omni's federated identity accesses BigQuery:

    <AccordionGroup>
      <Accordion title="Option 1 - Grant direct access" icon="arrow-right" description="Grant the pool the BigQuery roles directly on your project." id="direct-access">
        Grant the BigQuery roles directly to the pool's identities, replacing **GCP\_PROJECT\_ID** with the ID of your GCP project:

        ```bash theme={null}
        gcloud projects add-iam-policy-binding GCP_PROJECT_ID \
          --role=roles/bigquery.jobUser \
          --member="principalSet://iam.googleapis.com/projects/GCP_PROJECT_ID/locations/global/workloadIdentityPools/omni/*"

        gcloud projects add-iam-policy-binding GCP_PROJECT_ID \
          --role=roles/bigquery.dataViewer \
          --member="principalSet://iam.googleapis.com/projects/GCP_PROJECT_ID/locations/global/workloadIdentityPools/omni/*"
        ```

        **Optional**. Grant the `metadataViewer` role directly to the pool's identities:

        ```bash theme={null}
        gcloud projects add-iam-policy-binding GCP_PROJECT_ID \
          --role=roles/bigquery.metadataViewer \
          --member="principalSet://iam.googleapis.com/projects/GCP_PROJECT_ID/locations/global/workloadIdentityPools/omni/*"
        ```

        The `metadataViewer` role is only required if you want to give Omni access to all views within a dataset (e.g., `project.*`) when setting up the connection in Omni. If you explicitly list specific datasets without wildcards in the [connection setup step](#create-connection), Omni will skip the project-level metadata scan and work with dataset-level permissions only.

        When you configure Omni, leave the **Service account impersonation URL** field blank.
      </Accordion>

      <Accordion title="Option 2 - Impersonation through a service account" icon="mask" description="Have the pool impersonate a named service account that holds the required BigQuery roles." id="service-account">
        1. Create a service account (for example, `omni-bigquery`) and grant it the following [BigQuery roles](https://cloud.google.com/bigquery/access-control#curated_roles_comparison_matrix) on your project:
           * BigQuery Job User
           * BigQuery Data Viewer
        2. Allow the pool's identities to impersonate the service account by granting the **Workload Identity User** role on the service account to the pool:

           ```bash theme={null}
           gcloud iam service-accounts add-iam-policy-binding omni-bigquery@GCP_PROJECT_ID.iam.gserviceaccount.com \
             --project=GCP_PROJECT_ID \
             --role=roles/iam.workloadIdentityUser \
             --member="principalSet://iam.googleapis.com/projects/GCP_PROJECT_ID/locations/global/workloadIdentityPools/omni/*"
           ```

           Replace **GCP\_PROJECT\_ID** with the ID of your GCP project.

        Keep the service account email handy - you'll need it to complete the setup in Omni.
      </Accordion>
    </AccordionGroup>
  </Step>

  <Step title="Set up a table upload dataset" id="set-table-upload" titleSize="h3">
    <Callout icon="hand-point-up" color="#FF5FA2">
      **This step is optional.** However, we recommend completing it as part of the initial set up or you won't be able to use uploaded files like CSVs in joins.
    </Callout>

    In this step, you'll create a dedicated dataset to use for [table uploads](/analyze-explore/data-input-csvs). Before you create the dataset, note that:

    * This dataset can't be used for other modeled tables
    * This dataset must be in the same region as other projects and schemas in the connection, or you may encounter cross-region errors

    To create a dataset for table uploads:

    1. In the Google Cloud Console, navigate to your BigQuery project.
    2. Create the dataset.
    3. After the dataset is created, open it so that its details display.
    4. Click **Share > Manage permissions**, located next to the **Copy** option near the top right corner of the page.
    5. In the dialog that displays, click **Add principal**.
    6. For the **New principals** field, the value you enter depends on the access method you selected in [step 3](#grant-access):
       * **Direct access** - Enter the pool identity, including the `principalSet://`. This is the `member` value from the command in [step 3](#direct-access) and will look like the following:

         ```text theme={null}
         principalSet://iam.googleapis.com/projects/GCP_PROJECT_ID/locations/global/workloadIdentityPools/omni/*
         ```
       * **Service account** - Enter the email address of the service account you created in [step 3](#service-account). This will look like the following:

         ```text theme={null}
         omni-bigquery@GCP_PROJECT_ID.iam.gserviceaccount.com
         ```
    7. Add the **BigQuery Data Editor** role.
    8. Click **Save**.
  </Step>

  <Step title="Create the connection in Omni" id="create-connection" titleSize="h3">
    1. In Omni, click **Settings > Connections**.

    2. Click the **BigQuery** option.

    3. On the connection setup page, fill in the connection details:

           <DisplayName />

           <Default term="Dataset" />

           <IncludeOther term="Projects" />

           <Include term="Datasets" />

           <Tip>
             When you explicitly list datasets without wildcards (no `*` characters), Omni skips the project-level metadata scan and only requires dataset-level permissions (BigQuery Data Viewer role). Using wildcards or leaving this field empty requires project-level permissions (BigQuery Metadata Viewer role).
           </Tip>

           <Offloaded term="Datasets" />

           <TableUploads label="Dataset for CSV Upload" term="dataset" />

           <ParamField path="Authentication Type" required>
             The type of authentication to use. Select **Workload Identity Federation**.

             <Expandable title="Workload Identity Federation settings" defaultOpen>
               <ParamField path="Workload Identity Pool Provider" required>
                 The full resource name of the provider you created in [step 2](#pool-provider), prefixed with `//iam.googleapis.com/`. For example:

                 ```text theme={null}
                 //iam.googleapis.com/projects/YOUR_PROJECT_NUMBER/locations/global/workloadIdentityPools/omni/providers/omni-aws
                 ```

                 The Google Cloud console doesn't display this value for AWS providers — build it from the pool and provider names, or run `gcloud iam workload-identity-pools providers describe` and prefix the returned `name` with `//iam.googleapis.com/`.
               </ParamField>

               <ParamField path="Service Account to Impersonate">
                 **Required for [service account impersonation](#service-account)**. The service account email from [step 3](#grant-access). Otherwise, leave blank for direct access.
               </ParamField>

               <ParamField path="Billing Project ID" required>
                 The Google Cloud project queries run in and are billed to. The federated identity or impersonated service account must be able to run BigQuery jobs in it.
               </ParamField>
             </Expandable>
           </ParamField>

           <ParamField path="Region" required>
             The region the dataset resides in. Refer to the [Requirements](#requirements) section if you need help finding this information.
           </ParamField>

           <DatabaseTimezone />

           <QueryTimezone />

           <AllowUserSpecificTimezones />

           <ParamField path="Max Billing Bytes" default="1TB">
             The maximum bytes billed for queries run on this connection.
           </ParamField>

           <BaseAccess />

    4. When finished, click **Create connection**.
  </Step>
</Steps>

## Troubleshooting

| Issue                                      | What to check                                                                                                                                                                                                                                                                                                                                       |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Token exchange fails or is denied**      | Verify the attribute condition uses `startsWith` — the value Omni shows is a prefix, and the full role name includes a random suffix. Also confirm the attribute mapping reconstructs the role ARN as shown in step 2; the raw AWS assertion uses the `arn:aws:sts::...:assumed-role/...` format, which won't match the value from Omni without it. |
| **Queries fail with a permission error**   | Confirm the roles from step 3 were granted to the right principal: the service account (impersonation) or the pool's `principalSet` (direct access). IAM changes can take a couple of minutes to propagate.                                                                                                                                         |
| **Datasets appear, but contain no tables** | Check the connection's **Default Dataset** field — it must be a dataset name, not a project ID.                                                                                                                                                                                                                                                     |

## What's next?

<WhatsNext />
