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_typesswitches a service off for every project, andproject_object_typesfor one project. The services arebigquery,pubsub,cloudrun,cloudfunctions,secrets,cloud_storage,cloud_scheduler,cloud_composer,cloud_sql,bigtable,compute_engine,vertex_ai,datafusionandartifact_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 inartifact_registry_projects. - You can add one
gcpentry per connection. - The reference Terraform schedules the compile with
cron_compilation(default0 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_copyoverwrites 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_gcswrites to the bucket you name. Check the destination before you enable the rule.dataform_runis the only executor that can dry-run its SQL. If the rule setsif.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_copyreadsparameters.target_table, and the check forbigquery_export_gcsreadsparameters.gcs_uri. The executors read other parameters (above), so for a rule written as above the check reportsunknown.
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. |