> For the complete documentation index, see [llms.txt](https://docs.teleskope.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.teleskope.ai/connectors/gcp.md).

# GCP

Teleskope supports two GCP enrollment paths:

* **Organization discovery:** Configure one connector service account and grant its IAM roles on the organization. Teleskope traverses the organization and its folders to discover projects automatically.
* **Manual project enrollment:** Add projects individually and grant the connector roles on each project.

Organization discovery is optional and disabled by default. It does not replace manual project enrollment. When organization discovery is enabled, inherited organization-level permissions mean discovered projects do not need to be enrolled or assigned to connectors individually.

Organization reconciliation runs on a five-field cron schedule in UTC. During reconciliation, Teleskope:

1. Discovers projects in the organization and its folders.
2. Determines which supported GCP resources exist in each project.
3. Verifies the connector service account's effective access.
4. Enables each connector independently for the projects where it is applicable and accessible.

A project does not need every connector. If a project has no resources for a connector, that connector is marked not applicable. A permission failure for one connector does not prevent another accessible connector from running in the same project.

{% hint style="info" %}
The organization reconciliation cron controls project discovery and access verification. Each connector has a separate scan cron that controls when eligible resources are added to and refreshed in the Data Catalog.
{% endhint %}

## Configure organization discovery

Use the following sections for organization discovery. To enroll one project without scheduled organization traversal, see [Enroll a project manually](#enroll-a-project-manually).

## Runtime IAM requirements

Grant the shared dispatch permissions and the permissions for every connector you enable. The table lists the Google API calls used by the current connector paths and whether organization readiness explicitly verifies the permission. A **No** means the permission is not in the preflight's declared required-permission check; resource-discovery calls can still fail before that check runs. It does not mean the permission is optional at runtime.

| Scope           | Google API methods                                                               | Required permission                                    | Readiness preflight        |
| --------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------ | -------------------------- |
| Shared dispatch | Resource Manager `Projects.Get` and `Projects.GetAncestry`                       | `resourcemanager.projects.get`                         | No                         |
| Shared dispatch | Compute Engine `Regions.List`                                                    | `compute.regions.list`                                 | No                         |
| BigQuery        | BigQuery `Datasets.List` and `Datasets.Get`                                      | `bigquery.datasets.get`                                | No                         |
| BigQuery        | BigQuery `Tables.List` and `Tables.Get`                                          | `bigquery.tables.get`, `bigquery.tables.list`          | `bigquery.tables.get` only |
| BigQuery        | BigQuery query jobs for column discovery and scanning                            | `bigquery.jobs.create`, `bigquery.tables.getData`      | Yes                        |
| Cloud SQL       | Cloud SQL Admin `Instances.List`                                                 | `cloudsql.instances.list`                              | No                         |
| Cloud SQL       | Cloud SQL Auth Proxy connection                                                  | `cloudsql.instances.get`, `cloudsql.instances.connect` | Yes                        |
| Cloud SQL       | Cloud SQL Admin `SslCerts.Insert`, when Teleskope generates a client certificate | `cloudsql.sslCerts.create`                             | No                         |
| Cloud Storage   | Cloud Storage `Buckets.List`                                                     | `storage.buckets.list`                                 | No                         |
| Cloud Storage   | Cloud Storage `Buckets.GetIamPolicy` for each discovered bucket                  | `storage.buckets.getIamPolicy`                         | No                         |
| Cloud Storage   | Cloud Storage `Objects.List` and object reads during scanning                    | `storage.objects.list`, `storage.objects.get`          | Yes                        |
| Cloud Logging   | GKE `Projects.Locations.Clusters.List`                                           | `container.clusters.list`                              | Yes                        |
| Cloud Logging   | Cloud Logging `Entries.List`                                                     | `logging.logEntries.list`                              | Yes                        |

{% hint style="warning" %}
The preflight does not explicitly test the shared dispatch permissions, Cloud SQL certificate creation, or the Cloud Storage bucket enumeration and IAM-policy reads. Grant every permission in this table before enabling a connector; a successful readiness result is not an assertion that those permissions were tested.
{% endhint %}

Cloud SQL database permissions are separate from Google Cloud IAM. The database user still needs the read-only grants in [Cloud SQL](/connectors/gcp/cloud-sql.md).

### Create the connector service account

Create one service account for Teleskope in a GCP project that belongs to the organization. The service account can be used across all projects because its discovery and connector roles are granted on the organization.

```hcl
resource "google_service_account" "teleskope" {
  project      = var.service_account_project_id
  account_id   = "teleskope"
  display_name = "Teleskope connector"
}
```

### Grant organization discovery permissions

Create a custom role on the organization with these permissions:

* `resourcemanager.organizations.get`
* `resourcemanager.folders.get`
* `resourcemanager.folders.list`
* `resourcemanager.projects.get`
* `resourcemanager.projects.list`
* `compute.regions.list`

Grant the custom role to the connector service account on the organization.

```hcl
resource "google_organization_iam_custom_role" "teleskope_discovery" {
  org_id      = var.organization_id
  role_id     = "teleskope_org_discovery"
  title       = "Teleskope organization discovery"
  description = "Read-only organization, folder, project, and region discovery"

  permissions = [
    "resourcemanager.organizations.get",
    "resourcemanager.folders.get",
    "resourcemanager.folders.list",
    "resourcemanager.projects.get",
    "resourcemanager.projects.list",
    "compute.regions.list",
  ]
}

resource "google_organization_iam_member" "teleskope_discovery" {
  org_id = var.organization_id
  role   = google_organization_iam_custom_role.teleskope_discovery.name
  member = "serviceAccount:${google_service_account.teleskope.email}"
}
```

The organization role above includes the two shared dispatch permissions. They are required even when you enable only one connector because dispatch looks up the enrolled project and its regions before connector-specific work starts.

### Grant connector permissions on the organization

Grant the roles for every connector that you enable in Teleskope. Apply these roles to the connector service account at the **organization level**, not separately in each project.

#### BigQuery

* `roles/bigquery.jobUser`
* `roles/bigquery.metadataViewer`
* `roles/bigquery.dataViewer`

For BigQuery deletion or masking workflows, also grant `roles/bigquery.dataEditor`.

* `roles/bigquery.metadataViewer` supplies `bigquery.datasets.get`, `bigquery.tables.get`, and `bigquery.tables.list`.
* `roles/bigquery.dataViewer` supplies `bigquery.tables.getData`.
* `roles/bigquery.jobUser` supplies `bigquery.jobs.create` at the project where a BigQuery job runs.

#### Cloud SQL

* `roles/cloudsql.client`
* `roles/cloudsql.viewer`
* `roles/cloudsql.admin`
* `roles/cloudsql.viewer` supplies `cloudsql.instances.get` and `cloudsql.instances.list`.
* `roles/cloudsql.client` supplies `cloudsql.instances.connect` for the Cloud SQL Auth Proxy.
* `roles/cloudsql.admin` is used only because it includes `cloudsql.sslCerts.create`, which Teleskope uses when it generates a client SSL certificate.

Database credentials and read-only database grants are still configured per Cloud SQL instance; see [Cloud SQL](/connectors/gcp/cloud-sql.md).

#### Cloud Storage

* `roles/storage.bucketViewer`
* `roles/storage.objectViewer`
* `roles/pubsub.viewer`
* `roles/pubsub.subscriber`

`roles/storage.bucketViewer` supplies `storage.buckets.get` and `storage.buckets.list`, while `roles/storage.objectViewer` supplies `storage.objects.get` and `storage.objects.list`. Neither role grants `storage.buckets.getIamPolicy`; grant the custom role below as well. In particular, `roles/storage.objectViewer` does **not** grant bucket enumeration or bucket IAM-policy reads.

The Pub/Sub roles are required when Cloud Storage notifications are used for incremental discovery. They do not replace the Cloud Storage permissions above. Topics, subscriptions, and bucket notifications remain project- or bucket-specific resources; see [Cloud Storage](/connectors/gcp/cloud-storage.md).

```hcl
resource "google_organization_iam_custom_role" "teleskope_storage_iam_policy_reader" {
  org_id      = var.organization_id
  role_id     = "teleskope_storage_iam_policy_reader"
  title       = "Teleskope Cloud Storage IAM policy reader"
  description = "Read bucket IAM policies for Teleskope Cloud Storage discovery"

  permissions = ["storage.buckets.getIamPolicy"]
}

resource "google_organization_iam_member" "teleskope_storage_iam_policy_reader" {
  org_id = var.organization_id
  role   = google_organization_iam_custom_role.teleskope_storage_iam_policy_reader.name
  member = "serviceAccount:${google_service_account.teleskope.email}"
}
```

#### Cloud Logging

* `roles/logging.privateLogViewer`
* `roles/container.clusterViewer`

`roles/container.clusterViewer` includes `container.clusters.list`, and `roles/logging.privateLogViewer` includes `logging.logEntries.list` for private log entries.

#### Terraform example

The following example grants all supported connector roles. Remove roles for connectors you do not enable.

```hcl
locals {
  teleskope_connector_roles = toset([
    # BigQuery
    "roles/bigquery.jobUser",
    "roles/bigquery.metadataViewer",
    "roles/bigquery.dataViewer",
    # Optional: deletion and masking
    "roles/bigquery.dataEditor",

    # Cloud SQL
    "roles/cloudsql.client",
    "roles/cloudsql.viewer",
    "roles/cloudsql.admin",

    # Cloud Storage
    "roles/storage.bucketViewer",
    "roles/storage.objectViewer",
    "roles/pubsub.viewer",
    "roles/pubsub.subscriber",

    # Cloud Logging
    "roles/logging.privateLogViewer",
    "roles/container.clusterViewer",
  ])
}

resource "google_organization_iam_member" "teleskope_connectors" {
  for_each = local.teleskope_connector_roles

  org_id = var.organization_id
  role   = each.value
  member = "serviceAccount:${google_service_account.teleskope.email}"
}
```

### Allow Teleskope to use the service account

Teleskope does not require a downloaded service-account key. Configure one of the following identity methods for your deployment.

#### Teleskope SaaS

Your Teleskope account team provides the exact Workload Identity Federation principal for your environment. Grant that principal `roles/iam.workloadIdentityUser` on the connector service account.

```bash
gcloud iam service-accounts add-iam-policy-binding \
  teleskope@SERVICE_ACCOUNT_PROJECT_ID.iam.gserviceaccount.com \
  --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT" \
  --role="roles/iam.workloadIdentityUser"
```

Use the principal exactly as provided. This binding is made on the service account because it controls impersonation; the discovery and connector roles remain organization-level grants.

#### Teleskope-managed GCP deployment

Grant the Teleskope application service account permission to impersonate the connector service account. Your Teleskope account team provides the application service-account email.

```bash
gcloud iam service-accounts add-iam-policy-binding \
  teleskope@SERVICE_ACCOUNT_PROJECT_ID.iam.gserviceaccount.com \
  --member="serviceAccount:teleskope-CUSTOMER-app@DEPLOYMENT_PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/iam.serviceAccountTokenCreator"
```

### Configure organization discovery in Teleskope

In Teleskope, go to **Settings > Connectors > GCP** and configure:

* GCP organization ID
* Connector service-account email
* Workload Identity Federation project number, pool, and provider for SaaS deployments
* Reconciliation cron expression in UTC
* Scheduled discovery

The default reconciliation schedule is `0 0 * * *`, once per day at 00:00 UTC. Run a dry run first, review the discovered project counts, then enable scheduled discovery.

Organization discovery automatically uses the GCP connectors enrolled in the environment. It does not require a per-project connector mapping. Connector scan schedules are configured separately on their individual settings pages.

## Enroll a project manually

In Teleskope, go to **Settings > Connectors > GCP** and select **Enroll**. The project enrollment form collects the organization ID, project ID, project number, service-account identity, and workload-federation configuration for one project.

Grant the shared dispatch role and the connector roles only on that project. The project is stored and enabled independently of any organization enrollment profile, so scheduled organization discovery does not need to be enabled.

```hcl
resource "google_project_iam_custom_role" "teleskope_gcp_dispatch" {
  project_id  = var.project_id
  role_id     = "teleskope_gcp_dispatch"
  title       = "Teleskope GCP dispatch"
  description = "Read the enrolled project and its regions before connector dispatch"

  permissions = [
    "resourcemanager.projects.get",
    "compute.regions.list",
  ]
}

resource "google_project_iam_member" "teleskope_gcp_dispatch" {
  project = var.project_id
  role    = google_project_iam_custom_role.teleskope_gcp_dispatch.name
  member  = "serviceAccount:${google_service_account.teleskope.email}"
}
```

For manual Cloud Storage enrollment, also grant this project-scoped custom role in addition to `roles/storage.bucketViewer` and `roles/storage.objectViewer`:

```hcl
resource "google_project_iam_custom_role" "teleskope_storage_iam_policy_reader" {
  project_id  = var.project_id
  role_id     = "teleskope_storage_iam_policy_reader"
  title       = "Teleskope Cloud Storage IAM policy reader"
  description = "Read bucket IAM policies for Teleskope Cloud Storage discovery"

  permissions = ["storage.buckets.getIamPolicy"]
}

resource "google_project_iam_member" "teleskope_storage_iam_policy_reader" {
  project = var.project_id
  role    = google_project_iam_custom_role.teleskope_storage_iam_policy_reader.name
  member  = "serviceAccount:${google_service_account.teleskope.email}"
}
```
