Back to blog
Cloud SecurityGCPMonitoring & LoggingNetworkingOperations & Compliance

No Alert for VPC Firewall Rule Changes in GCP

Learn why missing alerts on GCP VPC firewall rule changes are a security risk, and how to fix it with log-based metrics, Cloud Monitoring, and Terraform.

TL;DR

This check flags GCP projects that have no log-based metric alert watching for VPC firewall rule changes. Without it, an attacker (or a careless engineer) can open ports to the internet and nobody gets paged. Create a logging metric on gce_firewall_rule activity and wire it to an alerting policy in Cloud Monitoring.

Firewall rules are the front door of your VPC. When someone adds, modifies, or deletes one, the network boundary of your environment changes in real time. The problem is that these changes are quiet by default. Cloud Audit Logs record them, but nobody reads raw logs all day. If you do not have an alert sitting on top of those logs, a firewall change that exposes a database to 0.0.0.0/0 can sit unnoticed for hours or days.

The logging_novpcfirewallalert check looks for the absence of a log-based alert that fires when VPC firewall rules are created, patched, or deleted. If the check fails, your project is blind to one of the most security-relevant events in GCP networking.


What this check detects

The check inspects your project for a log-based metric and an accompanying alerting policy that together monitor firewall rule changes. Specifically, it expects a metric filter that matches audit log entries for these API methods:

  • v1.compute.firewalls.patch
  • v1.compute.firewalls.insert
  • v1.compute.firewalls.delete

These methods correspond to modifying, creating, and deleting firewall rules. When no metric exists, or a metric exists but has no alerting policy pointed at it, the check is marked as failing.

Note: This maps directly to CIS Google Cloud Platform Foundations Benchmark recommendation 2.7, "Ensure that the log metric filter and alerts exist for VPC Network Firewall rule changes." If you run audits against CIS, this is one of the controls auditors will ask about.

It is worth understanding what data feeds this. Firewall changes show up in Admin Activity audit logs, which are enabled by default and cannot be disabled. So the underlying signal is always there. This check is purely about whether you are doing anything useful with it.


Why it matters

A firewall rule change is rarely neutral. It either tightens or loosens your perimeter, and the loosening kind is what hurts.

The classic exposure scenario

An engineer is debugging a service that is unreachable. Under time pressure, they add a temporary rule allowing ingress from 0.0.0.0/0 on port 3306 "just to test." The fix works, the incident closes, and the rule is forgotten. That rule is now an open MySQL port on the public internet. Automated scanners find it within minutes.

If you had an alert, the person who owns network security would have seen the change land and questioned it the same day. Without one, the rule lives until a pentest or a breach finds it.

The attacker scenario

Once an attacker gains credentials with compute.firewalls.create permission, opening a path to a target instance is a single API call. Lateral movement and exfiltration both get easier when the attacker can carve out their own ingress and egress rules. Firewall change alerts turn that quiet action into a noisy one and give your incident response team a chance to react before data leaves.

Warning: A deleted firewall rule can be just as dangerous as an added one. Deleting a deny rule, or a rule that restricts egress, can silently widen what your workloads can reach. Make sure your alert covers delete, not just insert and patch.

Compliance and audit pressure

SOC 2, ISO 27001, PCI DSS, and most internal security programs expect change detection on network controls. Firewall rules are the canonical example. "We log it" is not enough for an auditor who asks "and who gets notified?" An empty answer there is a finding.


How to fix it

Fixing this is a two-step process: create a log-based metric that counts firewall change events, then attach an alerting policy that notifies a channel when the metric is non-zero.

Step 1: Create the log-based metric with gcloud

Set your project and create a counter metric with a filter matching the three firewall methods.

gcloud config set project YOUR_PROJECT_ID

gcloud logging metrics create firewall-rule-changes \
  --description="Counts VPC firewall rule create, patch, and delete events" \
  --log-filter='resource.type="gce_firewall_rule"
AND (protoPayload.methodName="v1.compute.firewalls.patch"
OR protoPayload.methodName="v1.compute.firewalls.insert"
OR protoPayload.methodName="v1.compute.firewalls.delete")'

Step 2: Find or create a notification channel

An alert is useless without somewhere to send it. List existing channels or create one. Here is an email channel as an example.

# List existing channels
gcloud beta monitoring channels list

# Create an email channel if you need one
gcloud beta monitoring channels create \
  --display-name="Security Alerts" \
  --type=email \
  [email protected]

Note the channel ID returned (it looks like projects/YOUR_PROJECT_ID/notificationChannels/1234567890). You will reference it next.

Step 3: Create the alerting policy

Define the policy in JSON, then apply it. This policy fires whenever the metric records any firewall change in a 60 second window.

{
  "displayName": "Alert on VPC Firewall Rule Changes",
  "combiner": "OR",
  "conditions": [
    {
      "displayName": "Firewall rule change detected",
      "conditionThreshold": {
        "filter": "metric.type=\"logging.googleapis.com/user/firewall-rule-changes\" AND resource.type=\"global\"",
        "comparison": "COMPARISON_GT",
        "thresholdValue": 0,
        "duration": "0s",
        "aggregations": [
          {
            "alignmentPeriod": "60s",
            "perSeriesAligner": "ALIGN_COUNT"
          }
        ]
      }
    }
  ],
  "notificationChannels": [
    "projects/YOUR_PROJECT_ID/notificationChannels/1234567890"
  ]
}
gcloud alpha monitoring policies create --policy-from-file=firewall-alert-policy.json

Doing it in the Console instead

  1. Go to Logging > Log-based Metrics and click Create Metric.
  2. Choose Counter, paste the filter from Step 1, and name it firewall-rule-changes.
  3. Go to Monitoring > Alerting and click Create Policy.
  4. Select your new log-based metric, set the threshold to "is above 0," and choose a notification channel.
  5. Save the policy.

Tip: Test the alert before you trust it. Create a throwaway firewall rule with gcloud compute firewall-rules create test-alert --allow tcp:22 --source-ranges 10.0.0.0/8, confirm the alert fires, then delete the rule. If nothing arrives within a couple of minutes, recheck your filter and channel.


How to prevent it from happening again

Manually creating this metric in one project does not scale, and it tends to drift away when new projects get spun up. Bake it into your infrastructure as code so every project ships with the alert from day one.

Terraform

resource "google_logging_metric" "firewall_rule_changes" {
  name   = "firewall-rule-changes"
  filter = <<-EOT
    resource.type="gce_firewall_rule"
    AND (protoPayload.methodName="v1.compute.firewalls.patch"
    OR protoPayload.methodName="v1.compute.firewalls.insert"
    OR protoPayload.methodName="v1.compute.firewalls.delete")
  EOT

  metric_descriptor {
    metric_kind = "DELTA"
    value_type  = "INT64"
  }
}

resource "google_monitoring_alert_policy" "firewall_changes" {
  display_name = "Alert on VPC Firewall Rule Changes"
  combiner     = "OR"

  conditions {
    display_name = "Firewall rule change detected"
    condition_threshold {
      filter          = "metric.type=\"logging.googleapis.com/user/${google_logging_metric.firewall_rule_changes.name}\" AND resource.type=\"global\""
      comparison      = "COMPARISON_GT"
      threshold_value = 0
      duration        = "0s"

      aggregations {
        alignment_period   = "60s"
        per_series_aligner = "ALIGN_COUNT"
      }
    }
  }

  notification_channels = [google_monitoring_notification_channel.secops_email.id]
}

resource "google_monitoring_notification_channel" "secops_email" {
  display_name = "Security Alerts"
  type         = "email"
  labels = {
    email_address = "[email protected]"
  }
}

Make this module a required dependency in your project factory or landing zone. New projects then inherit the alert automatically.

Tip: If you manage many projects, deploy this once at the folder or organization level using an aggregated log sink plus a centralized metric, rather than per project. One alerting policy in a security project can watch firewall changes across your whole org, which is far less to maintain.

Gate it in CI/CD

Add a policy check to your pipeline so a project cannot be promoted to production without the alert in place. Open Policy Agent with Conftest works well against Terraform plans.

# Example: fail the pipeline if the firewall metric resource is missing
package main

deny[msg] {
  not input.resource.google_logging_metric.firewall_rule_changes
  msg := "Missing required log-based metric: firewall-rule-changes"
}

You can also run Lensix continuously against your live environment so that if someone deletes the metric or detaches the alerting policy out of band, you find out fast rather than during the next audit.


Best practices

Firewall change alerting is one piece of a broader logging and detection posture. A few things make it far more effective.

  • Cover the full set of network controls. The same CIS section recommends alerts for VPC network changes, route changes, and network changes generally. Build them together since they share the same metric-plus-policy pattern.
  • Route alerts somewhere people actually watch. An email channel nobody reads is theater. Send firewall alerts to a PagerDuty or Slack channel owned by the team that can act on them.
  • Add context to the notification. Use documentation fields in the alerting policy to include who to contact and a runbook link. When the alert fires at 2am, the responder should know what to do without digging.
  • Enrich, do not just notify. Forward firewall audit logs to your SIEM so you can correlate a firewall change with the identity that made it and any suspicious activity around the same time.
  • Reduce noise at the source. If legitimate automation changes firewall rules constantly, alerting on every change is unhelpful. Have that automation use a dedicated service account, and consider excluding its identity from the alert filter so human and unexpected changes stand out.

Danger: Do not silence firewall alerts by deleting the metric or pausing the policy to stop noise during an incident. Once paused, these often never get re-enabled, and you lose detection on the exact control an attacker is most likely to touch. Tune the filter instead.

The fix here is cheap and the failure mode is expensive. A log-based metric and an alerting policy cost effectively nothing, while an unnoticed open port can cost you a breach. Set it up once, enforce it in code, and verify it stays in place.