Skip to content

GCP Cloud Discovery

Discover all GCP resources across your projects, identify unmanaged infrastructure, and bring it under Terraform management.

Prerequisites

  1. GCP credentials configured in Settings > Cloud
  2. Self-hosted runner (required) — must be online and connected to your organization
  3. Viewer role (roles/viewer) on each project you want to scan

Self-Hosted Runner Required

GCP cloud discovery requires a self-hosted runner with access to your GCP environment. The runner queries GCP APIs, scans Terraform state files from GCS, and reports results back to Controlinfra.

Set up a runner in Settings > Runners before running a GCP discovery scan.

Required Permissions

The service account used for discovery needs:

RoleScopePurpose
roles/viewerProject(s)Read-only access to all GCP resources
roles/storage.objectViewerState bucketRead Terraform state files from GCS
bash
# Grant Viewer on a project
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
  --member="serviceAccount:YOUR_SA@YOUR_PROJECT.iam.gserviceaccount.com" \
  --role="roles/viewer"

# Grant Storage Object Viewer on state bucket
gcloud storage buckets add-iam-policy-binding gs://YOUR_STATE_BUCKET \
  --member="serviceAccount:YOUR_SA@YOUR_PROJECT.iam.gserviceaccount.com" \
  --role="roles/storage.objectViewer"

Multi-Project Access

Grant the Viewer role on each project you want to discover. When using a service account from a central project, grant it cross-project access using IAM bindings on each target project.

Required GCP APIs

Ensure these APIs are enabled on each project you want to scan:

bash
gcloud services enable \
  compute.googleapis.com \
  container.googleapis.com \
  sqladmin.googleapis.com \
  storage.googleapis.com \
  cloudfunctions.googleapis.com \
  run.googleapis.com \
  pubsub.googleapis.com \
  dns.googleapis.com \
  cloudkms.googleapis.com \
  redis.googleapis.com \
  iam.googleapis.com \
  cloudresourcemanager.googleapis.com \
  --project=YOUR_PROJECT_ID

Running a Discovery Scan

  1. Go to Cloud Discovery in the sidebar
  2. Click Run Discovery
  3. Select GCP as the provider
  4. Configure scan options:
    • Projects — select which GCP projects to scan (all accessible projects are listed)
    • Services — choose which GCP services to scan (Compute, Networking, Storage, Database, etc.)
    • Regions — select GCP regions to include (e.g., us-central1, europe-west1)
    • State Files (optional) — enter your GCS bucket and prefix where .tfstate files are stored
  5. Click Start Scan

INFO

The Projects tab lists every project your GCP credential can access. If a project is missing, ensure the service account has the Viewer role assigned on it and that the Cloud Resource Manager API is enabled.

How It Works

Phase 1: Resource Discovery

Controlinfra queries GCP APIs for each selected service and region. Resources are enumerated using the standard list methods for each resource type.

Phase 2: Enrichment

For key resource types, additional API calls capture detailed configuration:

ServiceDetails Captured
Compute InstancesMachine type, zone, disks, network interfaces, labels, status
GKE ClustersKubernetes version, node pools (machine types, autoscaling), network config
Cloud SQLDatabase version, tier, HA config, backup settings, storage
Cloud StorageLocation, storage class, versioning, lifecycle rules, IAM
VPC NetworksSubnets, firewall rules, routes, peering connections
Cloud FunctionsRuntime, memory, trigger type, environment variables
Cloud RunImage, CPU/memory limits, scaling config, traffic splits

Phase 3: State Matching

If you provided a GCS state file location, Controlinfra downloads and parses .tfstate files from the bucket. Each discovered resource is matched against the state index using GCP resource self-links and IDs.

Phase 4: Cost Estimation

Orphaned (unmanaged) resources are priced using the GCP Cloud Billing Catalog API with static fallbacks for common machine types:

Resource TypePricing Basis
Compute InstancesMachine type + region + sustained use discount
Cloud SQLTier + storage + HA multiplier
GKE ClustersManagement fee + node pool instance costs
Cloud StorageStorage class + size + operations
Persistent DisksDisk type + size + region

Phase 5: AI Analysis

Claude AI analyzes orphaned resources to identify:

  • Cost savings from unused or idle resources
  • Security risks (public buckets, permissive firewall rules)
  • Patterns (abandoned projects, orphaned disks, unused static IPs)

Supported Resource Types

Controlinfra discovers 17+ GCP resource types and maps them to Terraform equivalents:

CategoryResource TypesTerraform Resources
ComputeInstances, Instance Groups, Disks, Images, Snapshotsgoogle_compute_instance, google_compute_disk, etc.
ContainersGKE Clusters, Artifact Registrygoogle_container_cluster, google_artifact_registry_repository
NetworkingVPC Networks, Subnets, Firewall Rules, Cloud NAT, Load Balancers, Cloud DNS Zonesgoogle_compute_network, google_compute_firewall, etc.
StorageCloud Storage Bucketsgoogle_storage_bucket
DatabaseCloud SQL Instances, Cloud Spanner, Memorystore (Redis)google_sql_database_instance, google_redis_instance
ServerlessCloud Functions, Cloud Run Servicesgoogle_cloudfunctions_function, google_cloud_run_service
SecurityCloud KMS Key Rings and Keysgoogle_kms_key_ring, google_kms_crypto_key
MessagingPub/Sub Topics and Subscriptionsgoogle_pubsub_topic, google_pubsub_subscription
IAMService Accountsgoogle_service_account

GCS State Backend Configuration

When your Terraform state is stored in GCS, configure the state file location during scan setup:

  • Bucket — The GCS bucket name (e.g., my-terraform-state)
  • Prefix (optional) — Path prefix within the bucket (e.g., prod/)

The backend configuration in your Terraform code typically looks like:

hcl
terraform {
  backend "gcs" {
    bucket = "my-terraform-state"
    prefix = "prod"
  }
}

Controlinfra reads all .tfstate files under the specified bucket and prefix, then matches discovered resources against the state index.

GCP Project Selection

The scan configuration modal shows a Projects tab listing all projects your credential has access to. For each project:

  • Project ID and Project Name are displayed
  • Toggle projects on/off to include or exclude them from the scan
  • A Select All / Deselect All button is available for convenience

TIP

If you manage many GCP projects, use the search bar in the Projects tab to filter by project ID or name.

Terraform Code Generation

For orphaned (unmanaged) resources, Controlinfra generates:

  1. HCL resource blocks with actual configuration from the discovered resource
  2. terraform import commands using the GCP resource self-link
  3. Provider configuration with google provider and GCS backend

Example generated import command:

bash
terraform import google_compute_instance.my_vm \
  projects/my-project/zones/us-central1-a/instances/my-vm

Troubleshooting

"GCP credentials not configured"

Add GCP credentials in Settings > Cloud > Add Account using a Service Account JSON key or Workload Identity. See the GCP Credentials Guide.

"Permission Denied" or "Viewer role required"

The service account needs roles/viewer on each project. Assign via gcloud:

bash
gcloud projects add-iam-policy-binding YOUR_PROJECT \
  --member="serviceAccount:YOUR_SA@YOUR_PROJECT.iam.gserviceaccount.com" \
  --role="roles/viewer"

Project not showing in the dropdown

The Projects dropdown only shows projects where your credential has at least Viewer access. To add a project:

  1. Go to the GCP Console > IAM & Admin > select the target project
  2. Click Grant Access
  3. Add your service account email and assign the Viewer role
  4. Wait ~1 minute for propagation, then re-open the scan modal

API not enabled errors

If you see 403 ... has not been used in project errors, enable the required API:

bash
gcloud services enable compute.googleapis.com --project=YOUR_PROJECT

Empty state file results

Ensure the GCS bucket name and prefix are correct, and the service account has roles/storage.objectViewer on the bucket.

Missing resource types

Not all GCP resource types have Terraform equivalents. Resources without a mapping are still discovered but shown as "unknown" type.

Next Steps