In January 2023, an indie developer received a $82,000 Google Cloud bill in 48 hours after their Maps API key was stolen and abused by bots over a weekend. When they spotted the issue Monday morning, Google Cloud had sent email alerts — but never cut anything off automatically. This is the core problem: Google Cloud does not offer a native hard spending cap. Budget alerts exist, but they don’t stop billing. If you want a real automatic kill switch, you need to build it yourself. Here’s how, step by step.
Why Google Cloud Has No Native Circuit Breaker
AWS, Azure, and GCP all offer billing alerts. But none of them automatically shuts down your resources when you exceed a threshold — at least not natively. The business reason is clear: cutting production services due to a billing spike would be catastrophic for enterprise customers. But for a solo dev or early-stage startup, the risk is the opposite: a stolen API key or an infinite loop can bankrupt you in 48 hours.
The solution: combine the Cloud Billing Budget API with a Cloud Function that automatically disables your project or revokes keys when the budget is exceeded.
Kill Switch Architecture
- A Google Cloud Budget Alert at 80% and 100% of your budget
- A Pub/Sub topic that receives budget notifications
- A Cloud Function triggered by Pub/Sub that disables the project
- A Service Account with minimal required permissions
Step 1 — Create the Pub/Sub Topic
export PROJECT_ID="your-gcp-project"
# Create the Pub/Sub topic
gcloud pubsub topics create billing-alerts \
--project=$PROJECT_ID
# Verify creation
gcloud pubsub topics list --project=$PROJECT_ID
Step 2 — Configure the Budget Alert
In the Google Cloud Console, go to Billing → Budgets & Alerts → Create Budget:
- Scope: select your project
- Budget type: Specified amount
- Amount: your monthly threshold (e.g., $500)
- Alert thresholds: 50%, 80%, 100%
- Manage notifications → Connect a Pub/Sub topic → select “billing-alerts”
Step 3 — Write the Cloud Function
Create a directory and write your main.py file:
import base64
import json
import os
from googleapiclient import discovery
from google.auth import default
def kill_switch(event, context):
"""Cloud Function triggered by Pub/Sub when budget is exceeded."""
pubsub_data = base64.b64decode(event['data']).decode('utf-8')
budget_notification = json.loads(pubsub_data)
cost_amount = budget_notification.get('costAmount', 0)
budget_amount = budget_notification.get('budgetAmount', 0)
# Only trigger kill switch at 100% of budget
if cost_amount <= budget_amount:
print(f"Budget at {(cost_amount/budget_amount)*100:.1f}% - no action")
return
project_id = os.environ.get('GCP_PROJECT')
print(f"ALERT: Budget exceeded! {cost_amount} > {budget_amount}")
# Disable project billing
credentials, _ = default()
billing_service = discovery.build('cloudbilling', 'v1', credentials=credentials)
billing_service.projects().updateBillingInfo(
name=f"projects/{project_id}",
body={"billingAccountName": ""} # Empty string = disable billing
).execute()
print(f"Billing disabled for project {project_id}")
requirements.txt:
google-api-python-client==2.97.0
google-auth==2.22.0
Step 4 — Create the Service Account
gcloud iam service-accounts create billing-kill-switch-sa \
--display-name="Billing Kill Switch SA" \
--project=$PROJECT_ID
SA_EMAIL="billing-kill-switch-sa@${PROJECT_ID}.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SA_EMAIL}" \
--role="roles/billing.projectManager"
Step 5 — Deploy the Cloud Function
gcloud functions deploy billing-kill-switch \
--runtime=python311 \
--trigger-topic=billing-alerts \
--entry-point=kill_switch \
--service-account=${SA_EMAIL} \
--set-env-vars=GCP_PROJECT=${PROJECT_ID} \
--region=us-central1 \
--project=$PROJECT_ID
Step 6 — Test with a Pub/Sub Simulation
Never test directly on your production project. Use a test project:
gcloud pubsub topics publish billing-alerts \
--message='{"budgetDisplayName":"Kill Switch Budget","alertThresholdExceeded":1.0,"costAmount":600,"budgetAmount":500,"currencyCode":"USD"}' \
--project=$PROJECT_ID
# Check function logs
gcloud functions logs read billing-kill-switch \
--region=us-central1 \
--project=$PROJECT_ID \
--limit=20
Alternative: Revoke API Keys Instead of Disabling the Project
Disabling project billing cuts everything — including your production services. A more surgical approach: revoke only the API keys using the Google Keys API:
from google.cloud import api_keys_v2
def revoke_api_keys(project_id):
client = api_keys_v2.ApiKeysClient()
parent = f"projects/{project_id}/locations/global"
keys = client.list_keys(parent=parent)
for key in keys:
print(f"Revoking key: {key.name}")
client.delete_key(name=key.name)
print(f"All API keys for {project_id} have been revoked")
Setup Checklist
- ☑ Pub/Sub topic “billing-alerts” created
- ☑ Budget Alert configured with Pub/Sub notifications
- ☑ Cloud Function deployed and tested on test project
- ☑ Service Account with minimal billing permissions
- ☑ Reactivation procedure documented
- ☑ Email alerts configured in parallel
Limitations of This Approach
This kill switch is effective but reactive: it acts after budget is exceeded, not in real time. There can be a few minutes between the Pub/Sub notification and the function execution — and with massive traffic, those minutes can be expensive. Always combine this with strict API quotas per key and real-time monitoring for defense in depth.
🔐 Not sure your API keys and cloud configuration are secure?
Klack offers a complete security audit: exposed key detection, billing limit setup, automatic alerts, and kill switch implementation. Response within 24-48 hours.

