Google Cloud

Connect BigQuery, Dataform, Data Fusion, Cloud Storage, Pub/Sub and more, and the roles Nistor needs.

The Google Cloud tool is Nistor's reference integration. It reads the Google Cloud services of the projects you monitor, builds assets and lineage from them, follows what happens in those projects through their audit logs, and runs Dataform workflows, Data Fusion pipelines and BigQuery copies and exports from rules.

Package nistor-tool-gcp, tool id gcp, connection type gcp. Its README calls it "Production"; its package classifier says Alpha (see the overview).

What needs an Enterprise module#

A pure open-source install discovers resources, builds lineage, ingests audit-log events, probes freshness and runs the four actions below. These parts need an Enterprise module (Nistor Enterprise):

Feature Module
Dataplex data-scan results and Dataform assertion results as checks and incidents Data quality
BigQuery descriptions, labels and schema into the catalog (the connection's catalog block) Catalog
Cloud Billing export and cost views (the connection's billing_export block); Recommender-based checks FinOps

The open-source code declares the catalog and billing_export blocks and does not read them. For Recommender, it provides only the client.

What it collects#

The tool declares 25 node types. A compile reads each service of each project you list (see Tell the compiler what to scan).

Service Node types
BigQuery BigqueryTable (tables, views, external tables), BigqueryLinkedDataset (Analytics Hub), BigqueryTablePubsub (a table fed by a Pub/Sub subscription)
Dataform DataformAction (actions and assertions)
Data Fusion DataFusionInstance, DataFusionPipeline
Cloud Storage CloudStorageBucket, CloudStorageBucketFileSelection
Pub/Sub PubsubTopic, PubsubSubscription
Cloud Run, Cloud Functions CloudRunService, CloudRunJob, CloudFunction
Artifact Registry ArtifactRegistryRepository, ArtifactRegistryImage
Composer ComposerEnvironment, AirflowDag
Cloud SQL, Compute Engine, Bigtable CloudSqlInstance, ComputeInstance, BigtableInstance, BigtableTable
Vertex AI VertexAIPipelineJob, VertexAIDataset
Secret Manager, Cloud Scheduler Secret (metadata only), CloudSchedulerJob

The sheets that a BigQuery external table reads become GoogleSheet nodes. That node type belongs to the Google Workspace tool.

Lineage is built at compile time, from SQL and from the links between services:

  • Table lineage comes from view definitions and from the actions of Dataform compilation results.
  • Column lineage is parsed from SQL: Dataform actions, BigQuery view SQL and source files.
  • Links between services are inferred: a Pub/Sub push subscription to the Cloud Run service or function it calls, a Cloud Scheduler job to its target, an Airflow task to the BigQuery tables its operator names, Cloud Run and Compute Engine to Cloud SQL, Vertex AI to its BigQuery and Cloud Storage artefacts, a workload to its container image.
  • A Cloud Function's reads and writes combine its source code with the BigQuery and Cloud Storage events seen for its service account.
  • With LINEAGE_LEDGER_ENABLED=true (off by default), the backend also keeps a ledger of observed writes with the tables each BigQuery job read.

See Lineage and impact for how the graph uses them.

Events reach Nistor through Cloud Logging. The monitored_project Terraform module (below) creates eleven log sinks in each monitored project and routes them to the platform's Pub/Sub topic, where the input-logs role reads them:

  • Cloud Storage object create, read and delete;
  • BigQuery job completions, child jobs, table reads, table data changes and table metadata changes, and the BigQuery Storage Write API;
  • Cloud Run and Cloud Functions deploys and deletes;
  • Data Fusion pipeline start and end lines.

The BigQuery events record the bytes billed per job.

Runs that did not start from Nistor are ingested too: Dataform workflow invocations (polled every 60 seconds by default, for the repositories in the projects a connection lists in monitored_projects) and Data Fusion pipeline runs (from the log sink and from a backfill that scans the connection's ingestion_projects).

Freshness probes read the last modification of a BigQuery table (with tables.get, which runs no job and bills nothing), of a linked dataset table and of a Cloud Storage file selection.

Before you start#

You need, for each project to monitor:

  • the APIs of the services you want read, enabled in that project. For Compute Engine, Vertex AI, Cloud SQL and Dataform a compile checks first and skips a project whose API is off. For the other services a disabled API is an error, which raises an extraction incident;
  • a service account for the connection (the "connection service account"), with the roles in Permissions;
  • for each Nistor role that reads or acts on Google resources, the right to impersonate that account (see Identity).

The platform modules create nothing in a monitored project. The monitored_project module does, and you instantiate it once per project.

Create the connection#

Create a connection of type gcp in the web shell (Connections, /admin/connections, which needs connections:manage) or through the API:

curl -X POST "$NISTOR_API_URL/api/v1/connections" \
  -H "Authorization: Bearer $NISTOR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "acme-estate",
    "tool_type": "gcp",
    "is_default": true,
    "config": {
      "billing_project": "acme-nistor-prod",
      "identity": {
        "kind": "impersonation",
        "service_account": "nistor-gcp-estate@acme-nistor-prod.iam.gserviceaccount.com"
      },
      "monitored_projects": ["acme-data-prod", "acme-ingest-prod"],
      "locations": ["europe-west1", "EU"]
    }
  }'

Then test it. The test builds the credentials and refreshes them once, which reaches Google (IAM Credentials, for an impersonated account) without a billable call. The probe answers healthy or unhealthy, never degraded. See Configuration for connections in general.

Fields#

Field Required Meaning
billing_project yes The project that pays for, and is quota-charged for, the connection's BigQuery jobs. There is no fallback to the runtime's project.
identity.kind yes impersonation, workload_identity_federation, service_account_json or application_default.
identity.service_account with impersonation The service account to impersonate.
identity.wif_config with workload_identity_federation An external_account configuration. Its token_url must be https://sts.googleapis.com and its service_account_impersonation_url must be on https://iamcredentials.googleapis.com. Its credential_source is one https URL on the identity provider (a file only in local development), never the metadata server or a program.
monitored_projects no The projects this connection reads. It decides which connection reads a project (see Identity).
locations no The locations it scans: BigQuery regions, Dataform and Dataplex locations.
ingestion_projects no Projects whose audit logs input-logs ingests. The BigQuery streaming monitor and the Data Fusion run backfill scan them, with locations.
datafusion no location, namespace (default default), api_endpoint, dataproc_region and program (default DataPipelineWorkflow).
dataplex no scan_projects and scan_locations. Used by the Dataplex routes and by the Data quality module.
catalog no ingest_enabled (default true), projects, include_undocumented_columns (default false), poll_schedule_cron, poll_schedule_tz and poll_schedule_description. Read by the Catalog module.
billing_export no project, dataset, table and billing_account, all four together. Read by the FinOps module.

The only secret is service_account_json, and only for identity.kind service_account_json.

Identity#

identity.kind Use
impersonation The runtime role's own service account impersonates the connection service account. Use this on Cloud Run.
workload_identity_federation For a project in another organisation, through its identity provider.
service_account_json A key file kept in the service_account_json secret. Local development only.
application_default The developer's own Application Default Credentials. Local development only.

The last two kinds are refused on a deployed role, because they would run as the runtime's own identity. A role is deployed on Cloud Run (a service or a job), or wherever NISTOR_DEPLOYED_ROLE is set to anything but an explicit no (0, false, no or empty). Set NISTOR_DEPLOYED_ROLE=1 on any other Google runtime, such as GKE or Compute Engine.

Every Google call of the tool runs as the connection of its unit of work. Nothing falls back to the runtime's identity. A unit of work resolves its connection in one of these ways: the run's connection, the connection of the rule or node, the poller's own connection, the one named in the compile request, or, for work that knows only a project, the connection that lists that project in monitored_projects. If several list it, the default connection wins. If none does, the work fails.

Tell the compiler what to scan#

A compile reads the projects and Dataform repositories listed in the gcp entry of the environment's compiler configuration. The entry names the connection it runs as. Save the configuration with nistor compiler sync (see CLI):

[
  {
    "environment": "prod",
    "tools": [
      {
        "id": "gcp",
        "config": {
          "connection_id": "<connection-uuid>",
          "dataprojects": ["acme-data-prod", "acme-ingest-prod"],
          "dataform": [
            "projects/acme-data-prod/locations/europe-west1/repositories/acme-dwh"
          ],
          "object_types": { "vertex_ai": false, "compute_engine": false },
          "project_object_types": { "acme-ingest-prod": { "datafusion": false } }
        }
      }
    ]
  }
]
  • object_types switches a service off for every project, and project_object_types for one project. The services are bigquery, pubsub, cloudrun, cloudfunctions, secrets, cloud_storage, cloud_scheduler, cloud_composer, cloud_sql, bigtable, compute_engine, vertex_ai, datafusion and artifact_registry. All are on by default. Switch off a service you do not use, so that a missing role does not raise an extraction incident on every compile.
  • Artifact Registry is read in the dataprojects, in the registry projects named by the images of your Cloud Run services and functions, and in any project you list in artifact_registry_projects.
  • You can add one gcp entry per connection.
  • The reference Terraform schedules the compile with cron_compilation (default 0 2 * * *).

Run Google Cloud actions from rules#

Four executors ship with the tool. A rule names one in then.do.action.type. See Rules and scheduling for the rest of a rule.

Action type Does Parameters Permission to run it
dataform_run Starts a Dataform workflow invocation for the target actions, from the latest compilation of a release configuration. release: the full release configuration path (projects/.../releaseConfigs/...), or release and release_config separately. Optional: maximum_depth, exclude_descendents_from_type, exclude_descendents_node. actions:run_dataform
datafusion_run Starts a Data Fusion pipeline run through the CDAP start API. The pipeline comes from the node, DataFusionPipeline_<project>.<instance>.<pipeline>. program (default DataPipelineWorkflow). The endpoint, namespace and Dataproc region come from the connection's datafusion block. None checked: the executor declares actions:run_datafusion, but Nistor does not enforce it.
bigquery_copy Copies tables into another environment's projects. target_environment (required), source_environment, copy_scope (this_table, ancestors, descendants or both), selected_projects, write_disposition (default WRITE_TRUNCATE), copy_method (clone, copy_job or sql_query; default sql_query). actions:run_bigquery_copy
bigquery_export_gcs Exports tables to Cloud Storage. destination_bucket (required), destination_path, output_format (csv or json; default csv), sql_filter, field_delimiter, compression (none or gzip), print_header. actions:run_bigquery_export_gcs
- name: Rebuild acme-dwh when a source changes
  priority: 3
  status: active
  code_id: dwh/acme-source-change
  applies_to:
    node_type: DataformAction
    tags:
      - dwh_rebuild
  when:
    events:
      - origin: ancestors
        types: data_updated
        ancestor_depth: direct
    wait_for_all_ancestors: true
  if:
    quiet_period_seconds: 300
    max_estimated_cost_usd: 5
  then:
    target:
      same_as_applies_to: true
      scope: node
    do:
      kind: single
      action:
        type: dataform_run
        parameters:
          release: projects/acme-data-prod/locations/europe-west1/repositories/acme-dwh/releaseConfigs/daily

Check the file with nistor rules validate --files <file>, then push it with nistor rules sync.

Things to know before you rely on the actions:

  • bigquery_copy overwrites its destination by default (WRITE_TRUNCATE). It derives the destination project by replacing the -<source_environment> suffix of the source project with the target environment, or from the project patterns of the environment mappings (nistor env-mapping). A table that maps to nothing fails the run.
  • bigquery_export_gcs writes to the bucket you name. Check the destination before you enable the rule.
  • dataform_run is the only executor that can dry-run its SQL. If the rule sets if.max_estimated_cost_usd, Nistor estimates the cost first, and blocks the run, recorded as failed, when the estimate is above the limit. For the other executors that limit has nothing to estimate.
  • An interrupted Dataform dispatch is failed, not started again, because Dataform offers no way to find the invocation that the dispatch started. A Data Fusion dispatch is found again after a crash.
  • Nistor can check, before a rule runs, that the connection holds the permissions in the last table below. The check for bigquery_copy reads parameters.target_table, and the check for bigquery_export_gcs reads parameters.gcs_uri. The executors read other parameters (above), so for a rule written as above the check reports unknown.

Permissions#

Nistor reads a project as the connection service account. Grant it the roles below in each monitored project. The monitored_project Terraform module can bind the roles marked "yes" in the Terraform default column (set grant_tool_roles = true; the deployer then needs resourcemanager.projects.setIamPolicy). By default it binds nothing, and you grant the roles yourself:

SA=nistor-gcp-estate@acme-nistor-prod.iam.gserviceaccount.com
gcloud projects add-iam-policy-binding acme-data-prod \
  --member="serviceAccount:$SA" --role="roles/dataform.viewer" --condition=None

Read roles#

Role Terraform default Needed for
roles/dataform.viewer yes Dataform repositories, compilations and workflow invocations
roles/run.viewer yes Cloud Run services and jobs
roles/cloudsql.viewer yes Cloud SQL instances
roles/secretmanager.viewer yes Secret metadata
roles/pubsub.viewer yes Topics and subscriptions
roles/cloudfunctions.viewer yes Cloud Functions
roles/cloudscheduler.viewer yes Cloud Scheduler jobs
roles/composer.user yes Composer environments and DAGs
roles/storage.bucketViewer yes Cloud Storage buckets
roles/artifactregistry.reader yes Artifact Registry repositories and images
roles/serviceusage.serviceUsageViewer yes Which APIs are enabled, so that Compute Engine, Vertex AI, Cloud SQL and Dataform are skipped when their API is off
roles/bigquery.metadataViewer no BigQuery datasets, tables and schema; the free freshness probe; the streaming views
roles/bigquery.jobUser no INFORMATION_SCHEMA queries, which run as jobs billed to the billing project
roles/bigquery.resourceViewer no Job metadata for cost enrichment, and the storage scans of the FinOps module (bigquery.jobs.listAll)
roles/bigquery.dataViewer no Optional. Table size, row count and last write from __TABLES__. Without it Nistor falls back to INFORMATION_SCHEMA.TABLE_STORAGE, whose figures can lag by a few minutes.

The default roles read metadata only: none reads a secret payload, a table row or an object. roles/bigquery.dataViewer does read table data, which is why it is optional. The Terraform default list has no BigQuery role, so grant them yourself in each monitored project, and roles/bigquery.jobUser in the billing project.

Roles for optional features#

Role Needed for
roles/datafusion.viewer and roles/dataproc.viewer Data Fusion discovery, per project. A missing role raises an extraction incident.
roles/recommender.viewer, with the Recommender API enabled in the scanned projects Recommender-based checks in the Enterprise modules

Permissions the actions need#

Before a rule runs, Nistor can ask Google which of these the connection holds (testIamPermissions):

Action Permission On
dataform_run dataform.workflowInvocations.create the repository
dataform_run bigquery.tables.updateData the table a DataformAction writes
bigquery_copy bigquery.tables.getData the source table
bigquery_copy bigquery.tables.create, bigquery.tables.updateData the target table
bigquery_export_gcs bigquery.tables.getData the source table
bigquery_export_gcs storage.objects.create the destination bucket
datafusion_run datafusion.instances.runtime the instance

The runtime side#

With impersonation, the service account of each Nistor role that reads or acts on Google resources must be allowed to create access tokens for the connection service account: roles/iam.serviceAccountTokenCreator on the connection service account. The Terraform in this repository does not grant it. The runtime accounts hold no role in the monitored projects.

Terraform for the monitored projects#

packages/integrations/gcp/terraform/monitored_project holds everything the tool creates in a monitored project:

  • one log sink for each of the eleven default filters, routed to the platform's log topic;
  • optionally, Cloud Storage object notifications for the buckets you list, which add the size, content type and generation that audit logs lack;
  • optionally, the default read roles, bound to the connection service account.

The reference root wires it from three inputs. enable_input_logs is true by default and the module needs it:

monitored_projects                  = ["acme-data-prod", "acme-ingest-prod"]
gcp_tool_connection_service_account = "nistor-gcp-estate@acme-nistor-prod.iam.gserviceaccount.com"
monitored_project_buckets           = { "acme-data-prod" = ["acme-landing"] }

The publish grants on the platform's topics are in the runtime project, so the platform modules make them. The module's README lists its inputs and how to move a deployed root onto it. For the rest of the install, see Install on GCP.

Settings#

The tool has no application-wide settings: what it reaches is the configuration of each connection. Two environment variables matter:

Variable Meaning
DATAFORM_EXTERNAL_SYNC_INTERVAL_SECONDS How often Dataform runs started outside Nistor are ingested. Default 60.
NISTOR_TOOL_LIMIT_GCP_BIGQUERY Slots per process for BigQuery requests. Default 150. See Configuration.

Edit this page on GitLab

↑ ↓ to moveEnter to openEsc to close