Monitoring Your Crown Jewels in Google Cloud with Cloud Asset Inventory and Slack

Why preventive IAM isn’t always enough for your most sensitive resources, and how to catch every critical change in Slack within seconds.
In almost every cloud security discussion I have, we start with preventive controls: enforce the principle of least privilege with IAM, lock down the environment with Organization Policy Constraints, and make sure every change goes through Terraform.
In theory, if you lock everything down tightly enough, nothing bad can happen. But anyone who has worked in a real production environment knows there is a catch.
The “Why”: Engineers Still Need Access to Your Crown Jewels
Even in an organization that does least privilege really well, you always have a group of engineers, SREs, network specialists, DBAs, break-glass responders, and CI/CD service accounts that must have permissions to touch your most critical resources.
You cannot just strip away their IAM roles. They need that access to do their day-to-day work, onboard new services, maintain databases, or fix a production outage at 2:00 AM.
At the same time, these resources are your Crown Jewels. They are simply too sensitive to leave unmonitored. When an engineer or a pipeline has legitimate access to modify a production firewall, a GKE cluster or Cloud Run service, a Compute Engine VM, a Cloud SQL instance, a Secret Manager vault or Cloud KMS key, an Organization Policy, or an IAM policy, preventive IAM stops helping you. What you need at that point is continuous, real-time change monitoring:
- Did someone open a firewall rule to a new IP address during a debugging session and forget to revert it?
- Was that change rolled out cleanly through Terraform (IaC), or did someone click around in the Google Cloud Console (ClickOps) or run a manual
gcloudcommand? - Did a specific user or service account just get extra IAM privileges, or was a GKE cluster, Cloud Run service, or Cloud SQL instance weakened?
To solve this in a clean, serverless way, I built and open-sourced google-cloud-cai-asset-change-notifications on GitHub. It uses Cloud Asset Inventory (CAI), which is part of Security Command Center (SCC), to monitor changes on your Crown Jewels in real time and send rich, human-readable alerts straight to Slack.
What the Notifications Look Like in Slack
Whenever a Crown Jewel resource, IAM policy, or Organization Policy is modified, a 2nd-gen Cloud Run function computes the before-and-after diff, checks Cloud Audit Logs to see Who made the change and How it was executed (Terraform vs. Console ClickOps vs. gcloud CLI), and posts an alert to Slack within seconds.
1. Firewall Rule Modified with a New IP Range via Google Cloud Console (ClickOps)
🚨 Crown Jewel Asset Alert: compute.googleapis.com/Firewall allow-prod-ssh-ingress was MODIFIED
allow-prod-ssh-ingress | Resource type: compute.googleapis.com/Firewallprod-networking-01 | Location: global2026-09-27T01:15:42.000Zj.doe@example.com (User Account)v1.compute.firewalls.patch | Caller IP: 198.51.100.42 | View Audit Trail in Cloud Logging ↗j.doe@example.com.0.0.0.0/0): Firewall rule exposes tcp:22,3389 to the public internet.0.0.0.0/0, removed 10.128.0.0/16.tcp:22 -> tcp:22,3389.~ allowed: [{"IPProtocol": "tcp", "ports": ["22"]}] -> [{"IPProtocol": "tcp", "ports": ["22", "3389"]}]
+ sourceRanges: added ["0.0.0.0/0"]
- sourceRanges: removed ["10.128.0.0/16"]
sourceRanges to trusted corporate CIDRs, Identity-Aware Proxy (35.235.240.0/20), or internal VPC ranges.
2. Cloud SQL SSL Enforcement Disabled & Authorized Network IP Range Expanded
🚨 Crown Jewel Asset Alert: sqladmin.googleapis.com/Instance prod-customer-orders-sql was MODIFIED
prod-customer-orders-sql | Resource type: sqladmin.googleapis.com/Instanceprod-data-01 | Location: europe-west12026-09-27T01:45:30.000Zdba-oncall@example.com (User Account)cloudsql.instances.update | Caller IP: 198.51.100.91 | View Audit Trail in Cloud Logging ↗dba-oncall@example.com.sslMode: ENCRYPTED_ONLY -> ALLOW_UNENCRYPTED_AND_ENCRYPTED).198.51.100.0/24 (external-vendor-subnet) to Cloud SQL instance.+ settings.ipConfiguration.authorizedNetworks: added [{"name": "external-vendor-subnet", "value": "198.51.100.0/24"}]
~ settings.ipConfiguration.requireSsl: true -> false
~ settings.ipConfiguration.sslMode: "ENCRYPTED_ONLY" -> "ALLOW_UNENCRYPTED_AND_ENCRYPTED"
requireSsl = true and sslMode = ENCRYPTED_ONLY) on the Cloud SQL instance.
Why Cloud Asset Inventory Instead of Raw Log Sinks?
A lot of teams try to build change monitoring with Cloud Logging sinks. The problem with raw audit logs is that an API call log only shows the request parameters that were sent—it rarely shows what the resource looked like before versus after the change.
Cloud Asset Inventory (CAI)—part of Google Cloud’s Security Command Center—solves this natively. Whenever a resource (RESOURCE), IAM policy (IAM_POLICY), or Organization Policy (ORG_POLICY) changes, CAI streams both priorAsset (before) and asset (after) to Pub/Sub. By combining that diff with Cloud Audit Logs, every alert immediately tells you:
- What changed: The exact configuration attribute, IP range, security setting, or IAM binding that was added, removed, or modified.
- Who did it: Human user, service account, Workload Identity, or a user impersonating a service account.
- How it was executed: Terraform (IaC), Google Cloud Console (ClickOps), or
gcloudCLI—flagging manual changes that bypass Git and Terraform.
Which Crown Jewel Resources Are Monitored?
You do not want alert fatigue from ephemeral development resources spinning up and down. Out of the box, the notifier focuses on six Crown Jewel categories (33 CAI asset types in total) where a single change impacts your security posture:
- Kubernetes (GKE), Cloud Run & Binary Authorization: Monitors GKE clusters, node pools, and Fleet/Service Mesh features (
container.googleapis.com/*,gkehub.googleapis.com/*) for disabled Confidential Nodes, removed Cloud KMS encryption keys, disabled GKE Security Posture or vulnerability scanning, public control plane endpoints (0.0.0.0/0), disabled Workload Identity or Shielded Nodes, and legacy ABAC. For Cloud Run (run.googleapis.com/*) and Binary Authorization, it catches unauthenticated access (invokerIamDisabled/allUsers), public ingress (INGRESS_TRAFFIC_ALL), disabled Threat Detection, CMEK removal, and Binary Authorization policy weakening or breakglass deployments. - Identity (IAM) & Organization Policies: Tracks IAM policies across Organizations, Folders, Projects, and sensitive resources, alongside Service Accounts, SA keys, Custom Roles, Workload Identity Pools, and Organization Policies (
orgpolicy.googleapis.com/*). It specifically highlights per-principal privilege escalation (when an existing user or SA gains extra roles), newly added roles, custom role permission expansion, user-managed SA key creation, and weakened Org Policy constraints (enforce: falseorallowAll). - Firewalls, VPC & Hybrid Networking: Monitors VPC firewall rules and policies, networks, subnetworks, routes, Cloud Routers/NAT, VPN tunnels, and Interconnects. It alerts on new source/destination IPs (
0.0.0.0/0), port changes, disabled Firewall Logging or VPC Flow Logs, new VPC Peerings, and default internet routes. - Cloud SQL, BigQuery & Cloud Storage: Catches disabled Cloud SQL SSL/TLS enforcement (
requireSsl: falseorsslModedowngrade), expandedauthorizedNetworksIP ranges, public IPv4 enablement, and expanded BigQuery dataset ACLs or public storage buckets. - Compute Engine VMs: Flags external public IP attachments (
ONE_TO_ONE_NAT), disabled Shielded VM or Confidential Compute controls, and machine type drift. - Secret Manager & Cloud KMS: Monitors secret and encryption key lifecycle changes and
secretAccessor/cryptoKeyDecrypterIAM bindings, while automatically redacting sensitive payload fields so secret values never leak into Slack.
How It Works Under the Hood
Just like my SCC findings notifier for Slack, the entire pipeline is serverless and deployed with Terraform:
- CAI Organization Feeds: Terraform provisions organization-wide
RESOURCE,IAM_POLICY, andORG_POLICYfeeds (plus optional SCC v2 finding notifications) streaming to a single Pub/Sub topic. - Eventarc & Cloud Run Function (2nd Gen): Eventarc triggers a Python 3.13 Cloud Run function locked down with
ALLOW_INTERNAL_ONLYingress and dedicated least-privilege service accounts. - Diff Engine & Audit Log Correlation: The function strips noisy metadata (
etag,fingerprint), skips no-op updates, deduplicates bursts, and queries Cloud Audit Logs (entries:list) to attributeWhoandHow. - Cloud KMS Secret Protection: Your Slack bot token is encrypted locally with Cloud KMS and stored only as base64 ciphertext in Terraform before being decrypted into Secret Manager at deploy time.
Get the Code on GitHub
The repository includes the complete two-stage Terraform setup as well as 12 sample CAI payloads (for Firewalls, Cloud SQL, GKE, Cloud Run, IAM privilege escalation, Org Policies, VPC Peering, VMs, and Secret Manager) that you can test in your own Slack channel with a single command before deploying to Google Cloud:
👉 github.com/jorgecalo/google-cloud-cai-asset-change-notifications
If you are setting up Crown Jewel monitoring in Google Cloud or have questions about the implementation, feel free to reach out on LinkedIn or via my contact page!

Jorge Liauw Calo
Security Engineer at Google Cloud (Google Cybershield) with 13+ years of experience in Cybersecurity across highly regulated industries including Semiconductor, Banking, Fintech, and Insurance. Active member of the Google Cloud Community BeNeLux and Google Cloud Security Community Amsterdam.