GCP Org or Folder Policy Was Changed Manually


Description

Alert if a GCP Org or Folder Policy Was Changed Manually.

Query · python

def rule(event):
    # Return True to match the log event and trigger an alert.
    logname = event.get("logName")
    return (
        event.deep_get("protoPayload", "methodName") == "SetIamPolicy"
        and (logname.startswith("organizations") or logname.startswith("folder"))
        and logname.endswith("/logs/cloudaudit.googleapis.com%2Factivity")
    )


def title(event):
    # use unified data model field in title
    return (
        f"{event.get('p_log_type')}: [{event.udm('actor_user')}] made manual changes to Org policy"
    )


def alert_context(event):
    return {
        "actor": event.udm("actor_user"),
        "policy_change": event.deep_get("protoPayload", "serviceData", "policyDelta"),
        "caller_ip": event.deep_get("protoPayload", "requestMetadata", "callerIP"),
        "user_agent": event.deep_get("protoPayload", "requestMetadata", "callerSuppliedUserAgent"),
    }


def severity(event):
    if (
        event.deep_get("protoPayload", "requestMetadata", "callerSuppliedUserAgent")
        .lower()
        .find("terraform")
        != -1
    ):
        return "INFO"
    return "HIGH"

Analyst notes

Contact the party that made the change. If it was intended to be temporary, ask for a window for rollback (< 24 hours). If it must be permanent, ask for change-management doc explaining why it was needed. Direct them to make the change in Terraform to avoid automated rollback. Grep for google_org and google_folder in terraform repos for places to put your new policy bindings.

Raw source GCP Org or Folder Policy Was Changed Manually · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
Filename: gcp_iam_org_folder_changes.py
RuleID: "GCP.IAM.OrgFolderIAMChanges"
DisplayName: "GCP Org or Folder Policy Was Changed Manually"
Enabled: true
DedupPeriodMinutes: 1440 # 24 hours
LogTypes:
  - GCP.AuditLog
Tags:
  - GCP
  - Identity & Access Management
  - Persistence
  - Modify Authentication Process - Conditional Access Policies 
Reports:
  GCP_CIS_1.3:
    - 1.8
  MITRE ATT&CK:
    - TA0003:T1556.009
Severity: High
Description: >
  Alert if a GCP Org or Folder Policy Was Changed Manually.
Runbook: |
  Contact the party that made the change.
  If it was intended to be temporary, ask for a window for rollback (< 24 hours).
  If it must be permanent, ask for change-management doc explaining why it was needed.
  Direct them to make the change in Terraform to avoid automated rollback.
  Grep for google_org and google_folder in terraform repos for places to
  put your new policy bindings.
Reference: https://cloud.google.com/iam/docs/granting-changing-revoking-access
SummaryAttributes:
  - severity
  - p_any_ip_addresses
Tests:
  - Name: Terraform User Agent
    ExpectedResult: true
    Log:
      {
        "insertId": "-lmjke7dbt7y",
        "logName": "organizations/888888888888/logs/cloudaudit.googleapis.com%2Factivity",
        "p_log_type": "GCP.AuditLog",
        "protoPayload":
          {
            "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog",
            "authenticationInfo":
              {
                "principalEmail": "terraform@platform.iam.gserviceaccount.com",
                "principalSubject": "serviceAccount:terraform@platform.iam.gserviceaccount.com",
                "serviceAccountKeyName": "//iam.googleapis.com/projects/platform/serviceAccounts/terraform@platform.iam.gserviceaccount.com/keys/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
              },
            "authorizationInfo":
              [
                {
                  "granted": true,
                  "permission": "resourcemanager.organizations.setIamPolicy",
                  "resource": "organizations/888888888888",
                  "resourceAttributes":
                    {
                      "name": "organizations/888888888888",
                      "service": "cloudresourcemanager.googleapis.com",
                      "type": "cloudresourcemanager.googleapis.com/Organization",
                    },
                },
              ],
            "methodName": "SetIamPolicy",
            "request":
              {
                "@type": "type.googleapis.com/google.iam.v1.SetIamPolicyRequest",
                "policy":
                  {
                    "bindings":
                      [
                        {
                          "members":
                            [
                              "joey.jojo@example.com",
                              "serviceAccount:terraform@platform.iam.gserviceaccount.com",
                            ],
                          "role": "roles/owner",
                        },
                      ],
                    "etag": "BwXcRFUAtX4=",
                  },
                "resource": "organizations/888888888888",
                "updateMask": "bindings,etag,auditConfigs",
              },
            "requestMetadata":
              {
                "callerIP": "100.100.100.100",
                "callerSuppliedUserAgent": "Terraform/0.13.2 terraform-provider-google/3.90.1",
                "destinationAttributes": {},
                "requestAttributes": {},
              },
            "resourceName": "organizations/888888888888",
            "response":
              {
                "@type": "type.googleapis.com/google.iam.v1.Policy",
                "bindings":
                  [
                    {
                      "members":
                        [
                          "joey.jojo@example.com",
                          "serviceAccount:terraform@platform.iam.gserviceaccount.com",
                        ],
                      "role": "roles/owner",
                    },
                  ],
                "etag": "BwXeRCtKxCw=",
              },
            "serviceData":
              {
                "@type": "type.googleapis.com/google.iam.v1.logging.AuditData",
                "policyDelta":
                  {
                    "bindingDeltas":
                      [
                        {
                          "action": "ADD",
                          "member": "user:backdoor@example.com",
                          "role": "roles/owner",
                        },
                      ],
                  },
              },
            "serviceName": "cloudresourcemanager.googleapis.com",
            "status": {},
          },
        "receiveTimestamp": "2022-05-05 14:00:49.450798551",
        "resource":
          {
            "labels": { "organization_id": "888888888888" },
            "type": "organization",
          },
        "severity": "NOTICE",
        "timestamp": "2022-05-05 14:00:48.814294000",
      }
  - Name: Manual Change
    ExpectedResult: true
    Log:
      {
        "insertId": "-yoga2udnx8s",
        "logName": "organizations/888888888888/logs/cloudaudit.googleapis.com%2Factivity",
        "p_log_type": "GCP.AuditLog",
        "protoPayload":
          {
            "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
            "authenticationInfo": { "principalEmail": "chris@example.com" },
            "authorizationInfo":
              [
                {
                  "granted": true,
                  "permission": "resourcemanager.organizations.setIamPolicy",
                  "resource": "organizations/888888888888",
                  "resourceAttributes":
                    {
                      "name": "organizations/888888888888",
                      "service": "cloudresourcemanager.googleapis.com",
                      "type": "cloudresourcemanager.googleapis.com/Organization",
                    },
                },
              ],
            "methodName": "SetIamPolicy",
            "request":
              {
                "@type": "type.googleapis.com/google.iam.v1.SetIamPolicyRequest",
                "etag": "BwXYPRNtbqo=",
                "policy":
                  {
                    "bindings":
                      [
                        {
                          "members":
                            [
                              "user:chris@example.com",
                              "serviceAccount:diana@platform.iam.gserviceaccount.com",
                            ],
                          "role": "roles/owner",
                        },
                      ],
                  },
              },
            "receiveTimestamp": "2022-02-17T22:52:03.190032712Z",
            "requestMetadata":
              {
                "callerIp": "38.38.38.38",
                "callerSuppliedUserAgent": "Mozilla/5.0 Chrome/98.0.4758.102",
                "destinationAttributes": {},
                "requestAttributes": {},
              },
            "resource":
              {
                "labels": { "organization_id": "888888888888" },
                "type": "organization",
              },
            "resourceName": "organizations/888888888888",
            "response":
              {
                "@type": "type.googleapis.com/google.iam.v1.Policy",
                "bindings":
                  [
                    {
                      "members": ["user:chris@example.com"],
                      "role": "roles/owner",
                    },
                  ],
                "etag": "BwXYPp1Xs/Y=",
              },
            "serviceData":
              {
                "@type": "type.googleapis.com/google.iam.v1.logging.AuditData",
                "policyDelta":
                  {
                    "bindingDeltas":
                      [
                        {
                          "action": "REMOVE",
                          "member": "serviceAccount:diana@platform.iam.gserviceaccount.com",
                          "role": "roles/owner",
                        },
                      ],
                  },
              },
          },
        "serviceName": "cloudresourcemanager.googleapis.com",
        "severity": "NOTICE",
        "status": {},
        "timestamp": "2022-02-17T22:52:02.692083Z",
      }


# ------ paired body: gcp_iam_org_folder_changes.py ------

def rule(event):
    # Return True to match the log event and trigger an alert.
    logname = event.get("logName")
    return (
        event.deep_get("protoPayload", "methodName") == "SetIamPolicy"
        and (logname.startswith("organizations") or logname.startswith("folder"))
        and logname.endswith("/logs/cloudaudit.googleapis.com%2Factivity")
    )


def title(event):
    # use unified data model field in title
    return (
        f"{event.get('p_log_type')}: [{event.udm('actor_user')}] made manual changes to Org policy"
    )


def alert_context(event):
    return {
        "actor": event.udm("actor_user"),
        "policy_change": event.deep_get("protoPayload", "serviceData", "policyDelta"),
        "caller_ip": event.deep_get("protoPayload", "requestMetadata", "callerIP"),
        "user_agent": event.deep_get("protoPayload", "requestMetadata", "callerSuppliedUserAgent"),
    }


def severity(event):
    if (
        event.deep_get("protoPayload", "requestMetadata", "callerSuppliedUserAgent")
        .lower()
        .find("terraform")
        != -1
    ):
        return "INFO"
    return "HIGH"

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.