Integrate Your AssetsCloudGCP

GCP Serverless Scanner

Deploy Mondoo's serverless scanner into your own GCP project with Terraform to continuously scan an organization or folder using Cloud Run, including options for CMEK, air-gapped installs, and restricted org policies.

The GCP serverless scanner runs entirely inside your GCP project. A Cloud Run service (the orchestrator) discovers the projects in a configured organization or folder on a schedule, then fans out one Cloud Run Job execution per project to run cnspec and ship results to Mondoo. Nothing scans from Mondoo's side, and no long-lived service account key is stored when you use Workload Identity Federation.

Looking for the platform-managed option instead? The GCP integration has Mondoo scan your projects for you. The serverless scanner is the self-hosted alternative: you deploy and own the scanning infrastructure with Terraform, which suits large organizations and restricted environments where scanning must originate from inside the tenancy.

What gets deployed

A single terraform apply of the serverless-scanner-gcp module (deploy/terraform) creates three Cloud Run resources plus the Pub/Sub, Cloud Storage, IAM, and (optionally) Cloud Scheduler scaffolding that connects them:

  • Orchestrator, a Cloud Run service that receives schedule ticks, enumerates the projects in scope, and dispatches one scan task per project.
  • Scanner, a Cloud Run Job. The orchestrator launches one execution per project; each execution runs cnspec against that project. The Job uses a Google Cloud SDK base image that downloads a per-execution scan script from the orchestrator bucket and runs it, so there is no cnspec image to pull.
  • Updater, a Cloud Run Job that polls Mondoo's registry for a newer orchestrator image and rolls the service to it, so you do not have to re-apply after each release.

Prerequisites

  • A dedicated GCP host project (separate from the projects you scan) with these APIs enabled: run, pubsub, iam, cloudresourcemanager, logging, secretmanager, storage, and monitoring. Add cloudscheduler only if you keep the built-in scheduler (see enable_scheduler). The module verifies the APIs read-only and stops the plan if one is missing; it never enables them for you.
  • A Mondoo GCP serverless integration created in the console, which gives you an integration MRN and a credential (a Workload Identity Federation config or a service account JSON).
  • An Artifact Registry repository the module's images are served from.
  • The runtime service account's read access to the organization or folder you scan. The module can grant this, or you can grant it out-of-band (see manage_scope_iam).

Usage

module "serverless_scanner" {
  source = "github.com/mondoohq/serverless-scanner-gcp//deploy/terraform"

  project_id = "my-scanner-host"
  region     = "europe-west3"
  image      = "europe-west3-docker.pkg.dev/my-scanner-host/mondoo/orchestrator:prod"

  # What to scan and where results go.
  scope                  = "organizations/123456789012" # or folders/<id>
  mondoo_integration_mrn = "//integrations.api.mondoo.com/spaces/<space>/integrations/<id>"
  mondoo_config_base64   = filebase64("mondoo.json") # WIF config or SA JSON
}

Configuration reference

Core inputs

InputDescription
project_idThe GCP host project the scanner runs in.
regionRegion for the Cloud Run service, Jobs, and Pub/Sub.
imageOrchestrator (and updater) container image URI.
scopeThe org or folder to discover and scan, as organizations/<id> or folders/<id>.
mondoo_integration_mrnThe integration MRN results report against.
mondoo_config_base64Base64-encoded Mondoo credential (WIF config preferred, or a service account JSON).
service_account_emailAn existing runtime service account to use. Empty makes the module create one.
name_prefixPrefix for resource names, so one project can host multiple deployments.

Schedules

The orchestrator is driven by four triggers, each a cron expression interpreted in UTC: scan_schedule (the scan pass, every 12 hours by default), metrics_schedule (telemetry), sync_schedule (backend-config sync), and checkin_schedule (a liveness ping, every 10 minutes by default). auto_update_schedule controls the updater (hourly by default).

Options for restricted environments

The following inputs exist so the module can deploy into sovereign, Assured Workloads, or otherwise policy-restricted projects. Each defaults to the unrestricted behavior, so leaving them unset changes nothing.

InputDefaultPurpose
kms_key_name""Customer-managed encryption for all data-plane resources.
installer_url""Internal mirror for cnspec and provider downloads.
scanner_imageGoogle Cloud SDKOverride the scanner Job base image.
enable_schedulertrueCreate the Cloud Scheduler jobs, or drive triggers externally.
manage_scope_iamtrueGrant the runtime SA its org/folder scan roles, or do it out-of-band.
manage_project_iamtrueGrant the runtime SA its host-project roles, or do it out-of-band.

Restricted and sovereign environments

Locked-down GCP organizations (sovereign clouds, Assured Workloads) enforce organization policies that reject the module's default resources. The options below make each requirement satisfiable.

Customer-managed encryption (CMEK)

Where constraints/gcp.restrictNonCmekServices is enforced, resources created without a customer-managed key are rejected. Set kms_key_name to a Cloud KMS key and the module encrypts the orchestrator bucket, every Pub/Sub topic, the Cloud Run service and Jobs, and the config secret with it. The secret switches to regional (user_managed) replication in region, since automatic replication cannot use a single regional key.

kms_key_name = "projects/<key-project>/locations/europe-west3/keyRings/<ring>/cryptoKeys/<key>"

The module does not manage IAM on the key. The Cloud Storage, Pub/Sub, Cloud Run, and Secret Manager service agents of project_id must hold roles/cloudkms.cryptoKeyEncrypterDecrypter on the key before the apply, or resource creation fails with a KMS permission error. Grant this out-of-band, since the key commonly lives in a separate, centrally-managed project. Also confirm constraints/gcp.restrictCmekCryptoKeyProjects allows the key's project, and that the key's location matches region.

Air-gapped scan workloads

When the scan workloads cannot reach the public internet, set installer_url to an internal mirror. The scan then fetches the cnspec binary from <installer_url>/package/... and its providers from <installer_url>/providers/..., so the mirror must serve both path layouts under one base URL.

installer_url = "https://install.mirror.example.internal"

If the host project also blocks Cloud Run from pulling the default gcr.io scanner base image, mirror a Google Cloud SDK image into your registry and set scanner_image to it.

Driving triggers without Cloud Scheduler

Where Cloud Scheduler is unavailable (for example, org policy blocks the App Engine service family), set enable_scheduler = false. The module then creates no scheduler jobs and does not require the cloudscheduler API. The scan-trigger Pub/Sub topic still exists, so an external driver, such as a Kubernetes CronJob, can publish the typed trigger payloads to it on your own schedule.

With enable_scheduler = false, nothing in the module is granted publish access on the trigger topic. Grant your external publisher roles/pubsub.publisher on the topic (exposed as the module's scan_trigger_topic output).

Delegating IAM when the deployer cannot set it

In delegated-admin setups, the identity running Terraform may not set folder, organization, or project IAM, even though it can create the resources themselves. Two flags move those grants out-of-band:

  • manage_scope_iam = false: the module does not grant the runtime SA its org/folder scan roles. Grant them yourself at the scope node.
  • manage_project_iam = false: the module does not grant the runtime SA (or the Cloud Run service agent) their host-project roles. Grant them yourself in the host project.

When manage_project_iam = false, grant these in the host project out-of-band:

MemberRoles
Runtime service accountroles/browser, roles/viewer, roles/iam.securityReviewer, roles/resourcemanager.tagViewer, roles/logging.viewer, roles/monitoring.viewer, roles/run.viewer, roles/run.developer, roles/artifactregistry.reader
Cloud Run service agent (service-<project-number>@serverless-robot-prod.iam.gserviceaccount.com)roles/artifactregistry.reader

The service agent's roles/artifactregistry.reader is required for the first revision to pull its image. If you set manage_project_iam = false and forget it, the orchestrator, scanner, and updater fail to deploy with a generic image pull error.

Resource-level IAM (Pub/Sub publisher, Cloud Run invoker, Secret Manager accessor) is always managed by the module and is unaffected by these flags.

On this page