Back to blog
Best PracticesCloud SecurityGCPMonitoring & LoggingOperations & Compliance

No Alert for Audit Configuration Changes in GCP

Learn why missing alerts on GCP audit configuration changes are a security risk, plus step-by-step gcloud, Console, and Terraform fixes to detect tampering.

TL;DR

This check flags GCP projects that have no log-based alert watching for changes to audit logging configuration. Without it, an attacker or careless admin can quietly disable audit logs and you won't know. Fix it by creating a logs-based metric on the SetIamPolicy audit config filter and wiring it to an alerting policy.

Audit logs are the record of who did what in your GCP project. If someone tampers with the audit configuration itself, say by turning off Data Access logs for a sensitive service, your visibility into the rest of their activity drops at exactly the moment you need it most. This Lensix check looks for a specific safeguard: a log-based alert that fires whenever the audit configuration changes.

The CIS Google Cloud Platform Foundations Benchmark calls this out directly (control 2.5), and for good reason. An alert on audit config changes is one of the cheapest, highest-leverage detections you can add to a project.


What this check detects

The logging_noauditconfigalert check inspects your GCP project for a logs-based metric and a paired alerting policy that monitor audit configuration changes. Specifically, it expects a metric filtering on the audit log entry that records modifications to the auditConfig setting within an IAM policy.

In GCP, audit logging is controlled per service and per log type (Admin Activity, Data Access, etc.) through the auditConfigs block of a resource's IAM policy. When someone modifies that block, the change is captured as a SetIamPolicy entry in the Admin Activity audit log. The check passes when a metric matches those entries and an alert policy is configured to notify someone when the metric count goes above zero.

Note: Admin Activity logs are always on and cannot be disabled. Data Access logs, however, are off by default for most services and must be explicitly enabled. The danger is usually someone disabling Data Access logging that you previously turned on, which an alert on config changes catches.


Why it matters

Disabling or weakening audit logging is a classic step in the defense evasion phase of an attack. The MITRE ATT&CK framework tracks it as "Impair Defenses: Disable or Modify Cloud Logs." The logic is simple: if an attacker can stop the logging before acting, the rest of their activity leaves no trail.

Consider a realistic scenario. An attacker compromises a service account with broad IAM permissions through a leaked key. Their first move is to call setIamPolicy and strip out the Data Access audit config on your Cloud Storage and BigQuery resources. They then start exfiltrating data. Without an alert on audit config changes, the first signal you get might be a customer complaint or a bill spike weeks later. With the alert, your on-call engineer gets paged the moment the config is touched.

It isn't always malicious either. A well-meaning engineer might disable Data Access logs to reduce log volume and cost, accidentally blinding the security team to access patterns on a regulated dataset. For organizations under SOC 2, PCI DSS, HIPAA, or ISO 27001, that gap can turn into an audit finding.

Warning: Data Access audit logs can generate significant volume and ingestion cost on busy projects. That cost pressure is exactly why people disable them, which is why an alert on the change matters more than the logs themselves.


How to fix it

The fix has two parts: a logs-based metric that counts audit config change events, and an alerting policy that notifies you when that count is greater than zero. You can do this in the Console, with gcloud, or in Terraform.

Step 1: Create the logs-based metric (gcloud)

The filter below matches Admin Activity entries where the IAM policy change includes an auditConfigDelta, which is what GCP emits when an audit config is added or removed.

gcloud logging metrics create audit_config_changes \
  --project=YOUR_PROJECT_ID \
  --description="Count of audit configuration changes" \
  --log-filter='protoPayload.methodName="SetIamPolicy" AND protoPayload.serviceData.policyDelta.auditConfigDeltas:*'

On some resource types the delta surfaces under protoPayload.metadata instead. A broader, resilient filter:

gcloud logging metrics create audit_config_changes \
  --project=YOUR_PROJECT_ID \
  --description="Count of audit configuration changes" \
  --log-filter='protoPayload.methodName="SetIamPolicy" AND (protoPayload.serviceData.policyDelta.auditConfigDeltas:* OR protoPayload.metadata.@type="type.googleapis.com/google.cloud.audit.AuditLog")'

Step 2: Find the metric and create an alerting policy

You need a notification channel first. List existing channels or create one:

# List notification channels
gcloud beta monitoring channels list --project=YOUR_PROJECT_ID

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

Now create the alert policy. Save the following as audit-config-alert.json, replacing the channel name with the one from the previous command:

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

Console alternative

  1. Go to Logging > Logs-based Metrics and click Create Metric.
  2. Set the type to Counter, name it audit_config_changes, and paste the filter from Step 1.
  3. Click the three-dot menu on the new metric and choose Create alert from metric.
  4. Set the threshold to greater than 0 with an alignment period of 1 minute, attach a notification channel, and save.

Terraform

resource "google_logging_metric" "audit_config_changes" {
  name    = "audit_config_changes"
  project = var.project_id
  filter  = "protoPayload.methodName=\"SetIamPolicy\" AND protoPayload.serviceData.policyDelta.auditConfigDeltas:*"

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

resource "google_monitoring_alert_policy" "audit_config_changes" {
  project      = var.project_id
  display_name = "Alert on Audit Configuration Changes"
  combiner     = "OR"

  conditions {
    display_name = "Audit config change detected"
    condition_threshold {
      filter          = "metric.type=\"logging.googleapis.com/user/${google_logging_metric.audit_config_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.security.id]
}

resource "google_monitoring_notification_channel" "security" {
  project      = var.project_id
  display_name = "Security On-Call"
  type         = "email"
  labels = {
    email_address = "[email protected]"
  }
}

Tip: Manage this at the folder or organization level with an aggregated log sink and an org-wide metric, so every existing and future project inherits the alert instead of you wiring it up per project.


How to prevent it from happening again

Manual setup drifts. The metric gets deleted, a new project ships without it, or someone disables the alert policy. Bake the control into your delivery pipeline so it can't quietly disappear.

  • Define it in IaC. Put the Terraform above in a shared module that every project landing zone consumes. New projects get the alert on day one.
  • Gate it in CI. Run terraform plan in your pipeline and fail the build if the alert resources would be destroyed. A simple check on the plan JSON catches accidental removal.
  • Use policy-as-code. Add an Open Policy Agent or Conftest rule that asserts the presence of an audit config alert in every project's plan.

Example Conftest rule against a Terraform plan:

package main

deny[msg] {
  not has_audit_config_metric
  msg := "Project must define a logs-based metric for audit config changes"
}

has_audit_config_metric {
  some i
  input.resource_changes[i].type == "google_logging_metric"
  contains(input.resource_changes[i].change.after.filter, "auditConfigDeltas")
}

Tip: Lensix re-runs logging_noauditconfigalert on a schedule, so even if the alert is removed outside your pipeline, you get flagged. Pair continuous scanning with IaC enforcement to cover both drift and net-new projects.


Best practices

  • Alert on the whole logging control plane, not just audit config. Add matching metrics for sink modifications and log exclusion changes. An attacker who can't disable audit logs may try to redirect or filter them instead.
  • Route alerts to a real on-call destination. An email channel nobody reads is theater. Send these to PagerDuty, Opsgenie, or a monitored Slack channel with an escalation path.
  • Keep audit logs out of reach of the people they monitor. Export logs to a dedicated, locked-down logging project or an immutable Cloud Storage bucket with retention locks, so even a project admin can't erase the trail.
  • Test the detection. Periodically make a benign audit config change in a non-production project and confirm the alert fires. Detections that have never fired are detections you can't trust.
  • Tune severity, not the threshold. Audit config changes are rare and meaningful, so keep the threshold at greater than zero. Reduce noise through good change context, not by raising the bar.

Danger: Do not delete logs-based metrics or alert policies in production to "clean up" your monitoring. Removing the audit config alert is itself an audit config blind spot, and on regulated workloads it can break compliance attestations that depend on the control being present.

Setting this alert up takes about ten minutes per project, or zero if you put it in your landing zone module. The payoff is knowing the instant someone touches your audit configuration, which is often the earliest warning you'll get that something is wrong.