GCP Firewall Rule Deleted


Description

This rule detects deletions of GCP firewall rules.

Query · python

from panther_gcp_helpers import gcp_alert_context

RULE_DELETED_PARTS = [
    ".Firewall.Delete",
    ".compute.firewalls.delete",
]


def rule(event):
    method = event.deep_get("protoPayload", "methodName", default="")
    return any(part in method for part in RULE_DELETED_PARTS)


def title(event):
    actor = event.deep_get(
        "protoPayload", "authenticationInfo", "principalEmail", default="<ACTOR_NOT_FOUND>"
    )
    resource = event.deep_get(
        "protoPayload",
        "resourceName",
        default="<RESOURCE_NOT_FOUND>",
    )
    resource_id = event.deep_get(
        "resource",
        "labels",
        "firewall_rule_id",
        default="<RESOURCE_ID_NOT_FOUND>",
    )
    if resource_id != "<RESOURCE_ID_NOT_FOUND>":
        return f"[GCP]: [{actor}] deleted firewall rule with resource ID [{resource_id}]"
    return f"[GCP]: [{actor}] deleted firewall rule for resource [{resource}]"


def dedup(event):
    actor = event.deep_get(
        "protoPayload", "authenticationInfo", "principalEmail", default="<ACTOR_NOT_FOUND>"
    )
    return actor


def alert_context(event):
    return gcp_alert_context(event)

Analyst notes

Ensure that the rule deletion was expected. Firewall rule deletions can cause service interruptions or outages.

Raw source GCP Firewall Rule Deleted · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
DedupPeriodMinutes: 90
DisplayName: GCP Firewall Rule Deleted
Enabled: true
Filename: gcp_firewall_rule_deleted.py
RuleID: "GCP.Firewall.Rule.Deleted"
Severity: Low
LogTypes:
  - GCP.AuditLog
Tags:
  - GCP
  - Firewall
  - Networking
  - Infrastructure
Description: >
  This rule detects deletions of GCP firewall rules.
Runbook: >
  Ensure that the rule deletion was expected. Firewall rule deletions can cause service interruptions or outages.
Reference: https://cloud.google.com/firewall/docs/about-firewalls
Tests:
  - Name: compute.firewalls-delete-should-alert
    LogType: GCP.AuditLog
    ExpectedResult: true
    Log:
      {
        "insertid": "-xxxxxxxx",
        "logname": "projects/test-project-123456/logs/cloudaudit.googleapis.com%2Factivity",
        "operation":
          {
            "id": "operation-1684869594486-5fc6145ac17b3-6f92b265-43256266",
            "last": true,
            "producer": "compute.googleapis.com",
          },
        "protoPayload":
          {
            "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog",
            "authenticationInfo": { "principalEmail": "user@domain.com" },
            "methodName": "v1.compute.firewalls.delete",
            "request":
              { "@type": "type.googleapis.com/compute.firewalls.delete" },
            "requestMetadata":
              {
                "callerIP": "12.12.12.12",
                "callerSuppliedUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36,gzip(gfe),gzip(gfe)",
              },
            "resourceName": "projects/test-project-123456/global/firewalls/firewall-create",
            "serviceName": "compute.googleapis.com",
          },
        "receivetimestamp": "2023-05-23 19:20:00.728",
        "resource":
          {
            "labels":
              {
                "firewall_rule_id": "6563507997690081088",
                "project_id": "test-project-123456",
              },
            "type": "gce_firewall_rule",
          },
        "severity": "NOTICE",
        "timestamp": "2023-05-23 19:20:00.396",
      }
  - Name: appengine.firewall.delete-should-alert
    LogType: GCP.AuditLog
    ExpectedResult: true
    Log:
      {
        "insertid": "-xxxxxxxx",
        "logname": "projects/test-project-123456/logs/cloudaudit.googleapis.com%2Factivity",
        "protoPayload":
          {
            "at_sign_type": "type.googleapis.com/google.cloud.audit.AuditLog",
            "authenticationInfo": { "principalEmail": "user@domain.com" },
            "authorizationInfo":
              [
                {
                  "granted": true,
                  "permission": "appengine.applications.update",
                  "resource": "apps/test-project-123456/firewall/ingressRules/1000",
                  "resourceAttributes": {},
                },
              ],
            "methodName": "google.appengine.v1.Firewall.DeleteIngressRule",
            "requestMetadata":
              {
                "callerIP": "12.12.12.12",
                "destinationAttributes": {},
                "requestAttributes":
                  { "auth": {}, "time": "2023-05-23T19:28:48.805823Z" },
              },
            "resourceName": "apps/test-project-123456/firewall/ingressRules/1000",
            "serviceData":
              {
                "@type": "type.googleapis.com/google.appengine.v1beta4.AuditData",
              },
            "serviceName": "appengine.googleapis.com",
            "status": {},
          },
        "receivetimestamp": "2023-05-23 19:28:49.474",
        "resource":
          {
            "labels":
              {
                "module_id": "",
                "project_id": "test-project-123456",
                "version_id": "",
                "zone": "",
              },
            "type": "gae_app",
          },
        "severity": "NOTICE",
        "timestamp": "2023-05-23 19:28:48.707",
      }
  - Name: compute.non-delete.firewall.method-should-not-alert
    LogType: GCP.AuditLog
    ExpectedResult: false
    Log: { "methodName": "v1.compute.firewalls.insert" }
  - Name: appengine.non-delete.firewall.method-should-not-alert
    LogType: GCP.AuditLog
    ExpectedResult: false
    Log: { "methodName": "appengine.compute.v1.Firewall.PatchIngressRule" }
  - Name: randomservice.firewall-delete.method-should-alert
    LogType: GCP.AuditLog
    ExpectedResult: true
    Log:
      {
        "protoPayload":
          {
            "authenticationInfo": { "principalEmail": "user@domain.com" },
            "methodName": "randomservice.compute.v1.Firewall.DeleteIngressRule",
            "resourceName": "randomservice/test-project-123456/firewall/ingressRules/1000",
            "requestMetadata":
              {
                "callerIP": "12.12.12.12",
                "destinationAttributes": {},
                "requestAttributes":
                  { "auth": {}, "time": "2023-05-23T19:28:44.663413Z" },
              },
          },
        "resource":
          {
            "labels":
              {
                "firewall_rule_id": "6563507997690081088",
                "project_id": "test-project-123456",
              },
            "type": "gce_firewall_rule",
          },
      }


# ------ paired body: gcp_firewall_rule_deleted.py ------

from panther_gcp_helpers import gcp_alert_context

RULE_DELETED_PARTS = [
    ".Firewall.Delete",
    ".compute.firewalls.delete",
]


def rule(event):
    method = event.deep_get("protoPayload", "methodName", default="")
    return any(part in method for part in RULE_DELETED_PARTS)


def title(event):
    actor = event.deep_get(
        "protoPayload", "authenticationInfo", "principalEmail", default="<ACTOR_NOT_FOUND>"
    )
    resource = event.deep_get(
        "protoPayload",
        "resourceName",
        default="<RESOURCE_NOT_FOUND>",
    )
    resource_id = event.deep_get(
        "resource",
        "labels",
        "firewall_rule_id",
        default="<RESOURCE_ID_NOT_FOUND>",
    )
    if resource_id != "<RESOURCE_ID_NOT_FOUND>":
        return f"[GCP]: [{actor}] deleted firewall rule with resource ID [{resource_id}]"
    return f"[GCP]: [{actor}] deleted firewall rule for resource [{resource}]"


def dedup(event):
    actor = event.deep_get(
        "protoPayload", "authenticationInfo", "principalEmail", default="<ACTOR_NOT_FOUND>"
    )
    return actor


def alert_context(event):
    return gcp_alert_context(event)

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.