Skip to content
Back to skills

Gcp Cost Governance

ASecurity

Playbook for setting up GCP billing visibility and cost controls — billing export to BigQuery, budget alerts, label-based attribution, committed-use discounts, and the common cost leaks to eliminate first.

  • 7 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 23, 2026
ai-agentsgosqlgcpterraformapidatabase

Works with

  • api

Security analysis

A100/100

Scanned September 25, 2026

npx -y skills add mcorbett51090/RavenClaude --skill gcp-cost-governance --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gcp Cost Governance?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gcp Cost Governance
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mcorbett51090-gcp-cost-governance/badge)](https://www.skillsdirectory.com/skills/mcorbett51090-gcp-cost-governance)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gcp-cost-governance
description: "Playbook for setting up GCP billing visibility and cost controls — billing export to BigQuery, budget alerts, label-based attribution, committed-use discounts, and the common cost leaks to eliminate first."
---

# GCP Cost Governance

## When to invoke

Use when standing up cost visibility for a new GCP project or organization, investigating a billing surprise, or building the FinOps foundation before spend scales. Pairs with `gcp-resource-hierarchy` (folder/project structure is the prerequisite for meaningful attribution).

## Step 1 — Billing export to BigQuery (non-negotiable first step)

Enable detailed billing export — this is the raw material for every cost analysis:

```hcl
resource "google_billing_account_iam_member" "bq_export" {
  billing_account_id = var.billing_account_id
  role               = "roles/billing.admin"
  member             = "serviceAccount:${google_service_account.billing_export.email}"
}
```

In the GCP console: **Billing → Billing export → BigQuery export → Edit settings**:
- Enable **Standard usage cost** export (required).
- Enable **Detailed usage cost** export (adds resource-level granularity; recommended).
- Enable **Pricing** export (needed for unit economics).

Dataset location should match your primary region. Export begins from the date it is enabled — there is no backfill.

## Step 2 — Label strategy

Labels are the attribution axis. Enforce them via org policy:

```hcl
resource "google_org_policy_policy" "require_labels" {
  name   = "organizations/${var.org_id}/policies/gcp.resourceLocations"
  parent = "organizations/${var.org_id}"
  # Use Terraform google_project module with mandatory label defaults
}
```

Minimum mandatory labels on all resources:

| Label key | Example values | Purpose |
|---|---|---|
| `env` | `prod`, `staging`, `dev` | Environment split |
| `team` | `platform`, `data`, `commerce` | Team attribution |
| `service` | `api-gateway`, `ml-training` | Service-level cost |
| `cost-center` | `eng-123` | Finance allocation |

**Verify label coverage:**
```sql
-- BigQuery billing export
SELECT service.description, labels, sum(cost) AS total
FROM `billing_dataset.gcp_billing_export_*`
WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
  AND (labels IS NULL OR array_length(labels) = 0)
GROUP BY 1, 2
ORDER BY 3 DESC
LIMIT 20;
```

Any row with null/empty labels is unattributed spend.

## Step 3 — Budget alerts

Create budgets at the project level (and optionally at the folder level):

```hcl
resource "google_billing_budget" "per_project" {
  billing_account = var.billing_account_id
  display_name    = "${var.project_id}-monthly-budget"

  budget_filter {
    projects = ["projects/${var.project_number}"]
  }

  amount {
    specified_amount {
      currency_code = "USD"
      units         = "500"
    }
  }

  threshold_rules { threshold_percent = 0.5 }
  threshold_rules { threshold_percent = 0.9 }
  threshold_rules { threshold_percent = 1.0 }
  threshold_rules { threshold_percent = 1.25 }  # overage alert

  all_updates_rule {
    pubsub_topic = google_pubsub_topic.billing_alerts.id
  }
}
```

Route the Pub/Sub topic to Slack/PagerDuty via a Cloud Run function or Eventarc.

## Step 4 — Committed-use discounts (CUDs)

| Workload | CUD type | Savings |
|---|---|---|
| Steady-state GCE VMs | Resource-based CUD (1 or 3 year) | Up to 57% |
| Cloud Run / GKE Autopilot | Spend-based CUD | Up to 17% |
| BigQuery (on-demand → slots) | BigQuery editions + reservations | Up to 40% for predictable query load |

Baseline before committing: run `Recommender` (GCP console → Committed Use Discounts) for a 30-day usage analysis recommendation.

**Do not commit before you have 30+ days of stable usage** — a CUD on a workload you are about to resize is waste.

## Step 5 — Top cost leaks to check first

Run this BigQuery query weekly:

```sql
SELECT
  service.description AS service,
  sku.description AS sku,
  SUM(cost) AS cost_usd,
  SUM(usage.amount) AS usage_amount,
  usage.unit
FROM `billing_dataset.gcp_billing_export_resource_*`
WHERE DATE(_PARTITIONTIME) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
GROUP BY 1, 2, 5
ORDER BY 3 DESC
LIMIT 50;
```

| Common culprit | Diagnostic | Fix |
|---|---|---|
| Idle GCE VMs | `status = RUNNING`, low CPU | Stop or delete; use preemptible/spot for batch |
| Oversized Cloud SQL | `database_id`, high memory cost | Downsize tier; use read replicas only where needed |
| Egress to internet | Networking → external egress SKUs | Use Private Google Access; keep traffic in-region |
| Unused persistent disks | Disk SKU with no attached VM | Delete orphaned disks |
| BigQuery on-demand scans | High `Bytes processed` per query | Partition + cluster tables; use query cost estimator |
| Artifact Registry storage | Old image layers accumulating | Add lifecycle policy to delete untagged images |

## Step 6 — Cost anomaly detection

Enable **GCP Recommender / Cost Insights** and the **Billing anomaly detection** feature (under Billing → Cost Management). It sends alerts when spend increases >10% week-over-week on a service.

Supplement with a BigQuery scheduled query that fires when a service's 7-day spend exceeds 2× its 30-day average:

```sql
-- anomaly_detect.sql (run daily via scheduled query)
WITH baseline AS (
  SELECT service.description, AVG(daily_cost) AS avg_cost
  FROM (
    SELECT DATE(usage_start_time) AS d, service.description, SUM(cost) AS daily_cost
    FROM `billing_dataset.gcp_billing_export_*`
    WHERE DATE(usage_start_time) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
    GROUP BY 1, 2
  )
  GROUP BY 1
),
recent AS (
  SELECT service.description, SUM(cost) AS week_cost
  FROM `billing_dataset.gcp_billing_export_*`
  WHERE DATE(usage_start_time) >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
  GROUP BY 1
)
SELECT r.description, r.week_cost, b.avg_cost * 7 AS expected_7d_cost
FROM recent r JOIN baseline b USING (description)
WHERE r.week_cost > b.avg_cost * 7 * 2
ORDER BY r.week_cost DESC;
```

## Pitfalls

- **Not enabling billing export on day one** — there is no backfill; you lose the historical baseline needed for anomaly detection and CUD decisions.
- **Sharing a billing account across unrelated orgs or customers** — attribution becomes impossible without a separate billing account per top-level org.
- **Setting a budget alert at 100% only** — by the time it fires, the month's budget is gone. Add 50% and 90% thresholds.
- **Buying CUDs for dev/test workloads** — committed use discounts apply across the org, but committing against unpredictable workloads is waste; measure first.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…