Skip to main content

Audit Configuration Change Log Alerts Should Be Enabled

More Info:

Ensures that logging and log alerts exist for audit configuration changes. Project Ownership is the highest level of privilege on a project, any changes in audit configuration should be heavily monitored to prevent unauthorized changes.

Risk Level

Medium

Address

Security

Compliance Standards

  • CIS GCP
  • CIS GCP 2.0.0
  • Cloudanix Best Practice
  • GDPR
  • HITRUST CSF
  • PCI
  • SOC2
  • Securities and Exchange Board of India (SEBI) - Cloud Security Adoption Framework

Triage and Remediation

Remediation

Using Console

To remediate Audit Configuration Logging for GCP IAM using the GCP Console, you need to ensure that Cloud Audit Logs (especially Admin Activity and appropriate Data Access logs) are enabled for IAM and that logs are being exported/retained as needed.

1. Verify IAM Audit Logs Are Enabled

  1. Go to Google Cloud Console:
    https://console.cloud.google.com

  2. Select the project (or folder/organization) you want to remediate from the top project selector.

  3. In the left menu, go to:
    IAM & Admin → Audit Logs

  4. At the top, select the scope:

    • If you have access, switch to Organization or Folder level using the scope selector.
    • Otherwise, do it at the project level.
  5. In the “Audit logs” page:

    • In the Service list, find and select:
      • IAM Service Account Credentials API
      • Cloud Identity and Access Management (iam.googleapis.com)
        (names may vary slightly, but look for IAM-related services)
    • Or simply click All services if your policy requires global coverage.
  6. For each relevant service, ensure:

    • Admin Read: Enabled (checkbox checked)
    • Admin Write: Enabled
    • Data Read: Enable if your policy requires data access logging
    • Data Write: Enable if your policy requires data access logging
  7. Click Save at the bottom.

Note:

  • Admin Activity logs are on by default and can’t be disabled, but explicitly enabling the checkboxes ensures consistent configuration and visibility in the UI.
  • Data Access logs (Data Read/Write) may incur additional cost; enable them to match your compliance requirements.

2. Confirm Logs Are Being Written

  1. Go to Logging → Logs Explorer in the left menu.

  2. Ensure the correct project is selected at the top.

  3. In the query builder, run a basic query to view IAM audit logs, for example:

    • Click “Query builder → Resource”, select a resource type like:
      • IAM Service Account, or
      • Project
    • Then in the Log name filter, choose:
      • cloudaudit.googleapis.com/activity
      • and/or cloudaudit.googleapis.com/data
  4. Click Run query and verify that IAM-related admin and data access events are appearing.


3. (Optional) Configure Log Retention or Export

If your audit requirement includes long-term retention or external SIEM:

  1. Go to Logging → Log Router.

  2. Click Create Sink:

    • Give it a name (e.g., iam-audit-logs-sink).
    • In the Sink destination, choose:
      • Cloud Storage (for archive), or
      • BigQuery (for analytics), or
      • Pub/Sub (for SIEM forwarding).
  3. In the Build inclusion filter, restrict to IAM audit logs, for example:

    logName:"cloudaudit.googleapis.com" AND
    protoPayload.serviceName="iam.googleapis.com"
  4. Complete sink creation, granting the sink’s service account the required write permissions on the destination.


4. (Optional) Enforce via Organization Policy

To prevent disabling audit logs:

  1. Go to IAM & Admin → Organization policies.

  2. Search for policies related to:

    • constraints/logging.adminActivityService
    • constraints/logging.dataAccessService
  3. Edit and set them to enforce required logging for IAM services.


This sequence ensures IAM configuration changes and access are fully logged and retained according to compliance requirements using only the GCP Console.

Using CLI

Below are the steps to remediate “Audit Configuration Logging” issues for GCP IAM by enabling Audit Logs using the gcloud CLI. I’ll show it at the project level; you can adapt for folders/organization.


1. Set your target project

gcloud config set project PROJECT_ID

Replace PROJECT_ID with your project ID.


2. Export current IAM policy to a file

gcloud projects get-iam-policy PROJECT_ID \
--format=json > iam-policy.json

This creates iam-policy.json that you’ll edit to add auditConfigs.


3. Edit the IAM policy to add audit logging

Open iam-policy.json in an editor and add or update the auditConfigs section.

Example: Enable all audit log types for all services

Add this top-level block (sibling to "bindings"):

{
"bindings": [
... existing bindings here ...
],
"auditConfigs": [
{
"service": "allServices",
"auditLogConfigs": [
{
"logType": "ADMIN_READ"
},
{
"logType": "DATA_READ"
},
{
"logType": "DATA_WRITE"
}
]
}
]
}

Notes:

  • service: "allServices" enables audit logging for every supported Google Cloud service.
  • logTypes:
    • ADMIN_READ – read operations on configuration/resources.
    • DATA_READ – read access to user data.
    • DATA_WRITE – write access to user data.
  • If you need to exempt service accounts from specific logs, add:
    {
    "logType": "DATA_READ",
    "exemptedMembers": [
    "user:alice@example.com",
    "serviceAccount:sa-name@PROJECT_ID.iam.gserviceaccount.com"
    ]
    }

Keep the rest of the file unchanged.


4. Re-apply the updated IAM policy

gcloud projects set-iam-policy PROJECT_ID iam-policy.json

Confirm that the command succeeds and doesn’t report invalid JSON or fields.


5. Verify the audit configuration

gcloud projects get-iam-policy PROJECT_ID \
--format=json | jq '.auditConfigs'

You should see the allServices audit configuration with ADMIN_READ, DATA_READ, and DATA_WRITE.


6. (Optional) Do the same at org/folder level

Organization:

ORG_ID=123456789012

gcloud organizations get-iam-policy $ORG_ID --format=json > org-iam.json
# Edit org-iam.json to add the same `auditConfigs` block
gcloud organizations set-iam-policy $ORG_ID org-iam.json

Folder:

FOLDER_ID=345678901234

gcloud resource-manager folders get-iam-policy $FOLDER_ID --format=json > folder-iam.json
# Edit folder-iam.json to add `auditConfigs`
gcloud resource-manager folders set-iam-policy $FOLDER_ID folder-iam.json

These steps remediate audit configuration logging issues by ensuring IAM audit logs (Admin & Data) are enabled via the GCP CLI.

Using Python

Below are step‑by‑step instructions and a Python example to remediate missing Audit Configuration Logging for GCP IAM (i.e., enable Data Access audit logs via IAM auditConfigs).


1. Decide the Scope and Services

First decide:

  • Scope: organization, folder, or project
    • Org: organizations/1234567890
    • Folder: folders/34567890
    • Project: projects/my-project-id or projects/1234567890
  • Services to log:
    • "allServices" (recommended) or specific services like "iam.googleapis.com"
  • Log types:
    • "ADMIN_READ", "DATA_READ", "DATA_WRITE"
      (Admin Activity logs are always on and free; Data Access logs can generate cost.)

Example choice (recommended baseline):

Scope: projects/my-project-id
Service: allServices
Log types: DATA_READ, DATA_WRITE

2. Enable Required APIs

Make sure the following APIs are enabled on the project you use to run the script:

  • Cloud Resource Manager API (cloudresourcemanager.googleapis.com)
  • IAM API (iam.googleapis.com) – not strictly necessary to update auditConfigs, but often used in tandem
gcloud services enable cloudresourcemanager.googleapis.com iam.googleapis.com \
--project=YOUR-BILLING-PROJECT-ID

3. Set Up Authentication

Use a service account with Owner or at least:

  • resourcemanager.organizations.setIamPolicy or
  • resourcemanager.projects.setIamPolicy / resourcemanager.folders.setIamPolicy

Authenticate locally:

gcloud auth application-default login

Your Python code will then pick up the ADC (Application Default Credentials).


4. Python Code: Enable Audit Config Logging

This example:

  • Reads the current IAM policy at the scope.
  • Merges/updates the auditConfigs for allServices.
  • Ensures both DATA_READ and DATA_WRITE are enabled.
  • Writes the policy back.
from googleapiclient import discovery
from google.oauth2 import service_account
import google.auth

# -------------------------------------------------------------------
# 1. CONFIGURE YOUR TARGET RESOURCE
# -------------------------------------------------------------------
# Examples:
# resource = "organizations/1234567890"
# resource = "folders/34567890"
resource = "projects/my-project-id"

# Service to configure: "allServices" or specific service(s), e.g. "iam.googleapis.com"
TARGET_SERVICE = "allServices"
LOG_TYPES_TO_ENABLE = ["DATA_READ", "DATA_WRITE"] # Add "ADMIN_READ" if needed

# -------------------------------------------------------------------
# 2. BUILD THE CLOUD RESOURCE MANAGER CLIENT
# -------------------------------------------------------------------
# If you have a service account JSON file:
# credentials = service_account.Credentials.from_service_account_file("key.json")
# crm = discovery.build("cloudresourcemanager", "v1", credentials=credentials)
credentials, _ = google.auth.default(scopes=["https://www.googleapis.com/auth/cloud-platform"])
crm = discovery.build("cloudresourcemanager", "v1", credentials=credentials)

# -------------------------------------------------------------------
# 3. HELPER: MERGE/UPDATE AUDIT CONFIGS
# -------------------------------------------------------------------
def merge_audit_configs(existing_audit_configs, target_service, log_types):
"""
Ensure that 'target_service' has all 'log_types' enabled in auditConfigs.
Returns the updated auditConfigs list.
"""
if existing_audit_configs is None:
existing_audit_configs = []

# Find existing config for the service
service_config = None
for ac in existing_audit_configs:
if ac.get("service") == target_service:
service_config = ac
break

if not service_config:
service_config = {"service": target_service, "auditLogConfigs": []}
existing_audit_configs.append(service_config)

# Build a mapping of logType -> auditLogConfig
existing_log_types = {c["logType"]: c for c in service_config.get("auditLogConfigs", [])}

for lt in log_types:
if lt not in existing_log_types:
service_config.setdefault("auditLogConfigs", []).append({"logType": lt})

return existing_audit_configs

# -------------------------------------------------------------------
# 4. GET CURRENT IAM POLICY
# -------------------------------------------------------------------
get_req = crm.projects().getIamPolicy( # change to organizations().getIamPolicy or folders() if needed
resource=resource,
body={"options": {"requestedPolicyVersion": 3}}
)
policy = get_req.execute()

# -------------------------------------------------------------------
# 5. UPDATE AUDIT CONFIGS
# -------------------------------------------------------------------
audit_configs = policy.get("auditConfigs")
audit_configs = merge_audit_configs(audit_configs, TARGET_SERVICE, LOG_TYPES_TO_ENABLE)
policy["auditConfigs"] = audit_configs

# -------------------------------------------------------------------
# 6. WRITE BACK THE UPDATED POLICY
# -------------------------------------------------------------------
set_req = crm.projects().setIamPolicy( # change to organizations().setIamPolicy or folders() if needed
resource=resource,
body={"policy": policy}
)
updated_policy = set_req.execute()

print("Updated IAM policy auditConfigs for:", resource)
for ac in updated_policy.get("auditConfigs", []):
print(ac)

Adjusting for Organization or Folder

Change the client calls:

  • For organization:
get_req = crm.organizations().getIamPolicy(
resource="organizations/1234567890",
body={"options": {"requestedPolicyVersion": 3}}
)
set_req = crm.organizations().setIamPolicy(
resource="organizations/1234567890",
body={"policy": policy}
)
  • For folder:
get_req = crm.folders().getIamPolicy(
resource="folders/34567890",
body={"options": {"requestedPolicyVersion": 3}}
)
set_req = crm.folders().setIamPolicy(
resource="folders/34567890",
body={"policy": policy}
)

5. Verify in Cloud Console

  1. Go to IAM & Admin → Audit Logs.
  2. Select the project / folder / organization.
  3. Confirm:
    • Service: All services (or the one you configured).
    • Log Types: Data Read and Data Write are enabled.

If you tell me your exact scope (project/org) and whether you want all services or specific ones (like just IAM), I can tailor the code snippet precisely to that.

Using Terraform
resource "google_logging_metric" "audit_config_change" {
# Logs-based metric for detecting audit configuration changes
name = "audit_config_change_count"
project = "PROJECT_ID" # replace with your GCP project ID

description = "Count of audit configuration changes (SetIamPolicy with auditConfigDeltas)"

filter = <<-EOT
resource.type="project"
protoPayload.methodName="SetIamPolicy"
protoPayload.serviceData.policyDelta.auditConfigDeltas:*
EOT

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

label_extractors = {
"resource" = "EXTRACT(protoPayload.resourceName)"
}
}

resource "google_monitoring_alert_policy" "audit_config_change_alert" {
project = "PROJECT_ID" # replace with your GCP project ID
display_name = "Audit Configuration Change Alert"

combiner = "OR"

conditions {
display_name = "Audit config change metric > 0"

condition_threshold {
filter = "metric.type=\"logging.googleapis.com/user/${google_logging_metric.audit_config_change.name}\""

comparison = "COMPARISON_GT"
threshold_value = 0
duration = "0s"

aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_DELTA"
cross_series_reducer = "REDUCE_SUM"
group_by_fields = ["metric.label.resource"]
}
}
}

notification_channels = [
"NOTIFICATION_CHANNEL_RESOURCE_ID" # replace with google_monitoring_notification_channel.ID
]

enabled = true
}

This adds a new logs-based metric and alert policy; it does not force replacement of existing metrics unless you change an existing metric’s name.

Verification: terraform plan should show + create for google_logging_metric.audit_config_change and google_monitoring_alert_policy.audit_config_change_alert with no unexpected changes to other resources.

Additional Reading: