Detection rules › Kusto
GCP Security Command Center - Detect Resources with Logging Disabled
Detects Google Cloud resources where logging is disabled for services like (Cloud Storage buckets, Firewall rules, Cloud DNS networks) based on Google Cloud Security Command Center findings.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Stealth | T1562 Impair Defenses |
Rule body kusto
id: d1fe8d30-4852-463a-b6ee-3b459788b75d
name: GCP Security Command Center - Detect Resources with Logging Disabled
description: |
Detects Google Cloud resources where logging is disabled for services like (Cloud Storage buckets, Firewall rules, Cloud DNS networks) based on Google Cloud Security Command Center findings.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: GoogleSCCDefinition
dataTypes:
- GoogleCloudSCC
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1562
tags:
- Logging
- GCP
query: |
GoogleCloudSCC
| where tostring(Findings.state) == "ACTIVE"
| extend FindingCategory = tostring(Findings.category)
| where FindingCategory in ("BUCKET_LOGGING_DISABLED", "FIREWALL_RULE_LOGGING_DISABLED", "DNS_LOGGING_DISABLED")
| extend FindingsJson = parse_json(Findings)
| extend Resource = tostring(FindingsJson.resourceName),
ExternalUri = tostring(FindingsJson.externalUri),
Description = tostring(FindingsJson.description),
Severity = tostring(FindingsJson.severity),
ProjectName = extract(@"projects/([^/]+)", 1, tostring(FindingsJson.resourceName)),
ResourceType = extract(@"//([a-z0-9_.-]+)/", 1, tostring(FindingsJson.resourceName)),
SourceProps = parse_json(tostring(FindingsJson.sourceProperties))
// Normalize display-friendly resource id
| extend ResourceName = case(
Resource contains "firewalls/", extract(@"firewalls/([^/]+)", 1, Resource),
Resource contains "storage.googleapis.com/", extract(@'storage.googleapis.com/([^/\"]+)', 1, Resource),
Resource contains "networks/", extract(@"networks/([^/]+)", 1, Resource),
Resource
)
| project TimeGenerated, ProjectName, ResourceType, ResourceName, Resource, FindingCategory, Severity, ExternalUri, Description
entityMappings:
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: ResourceName
customDetails:
ProjectName: ProjectName
ResourceType: ResourceType
FindingCategory: FindingCategory
ExternalUri: ExternalUri
Description: Description
Severity: Severity
eventGroupingSettings:
aggregationKind: AlertPerResult
alertDetailsOverride:
alertDisplayNameFormat: "GCP resources with logging disabled: {{ProjectName}} ({{ResourceType}})"
alertDescriptionFormat: |-
Resource {{ResourceName}} in project {{ProjectName}} (type: {{ResourceType}}) has logging disabled.
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
GoogleCloudSCC
Stage 2: where
| where tostring(Findings.state) == "ACTIVE"
Stage 3: extend
| extend FindingCategory = tostring(Findings.category)
Stage 4: where
| where FindingCategory in ("BUCKET_LOGGING_DISABLED", "FIREWALL_RULE_LOGGING_DISABLED", "DNS_LOGGING_DISABLED")
Stage 5: extend (3 consecutive steps)
| extend FindingsJson = parse_json(Findings)
| extend Resource = tostring(FindingsJson.resourceName),
ExternalUri = tostring(FindingsJson.externalUri),
Description = tostring(FindingsJson.description),
Severity = tostring(FindingsJson.severity),
ProjectName = extract(@"projects/([^/]+)", 1, tostring(FindingsJson.resourceName)),
ResourceType = extract(@"//([a-z0-9_.-]+)/", 1, tostring(FindingsJson.resourceName)),
SourceProps = parse_json(tostring(FindingsJson.sourceProperties))
| extend ResourceName = case(
Resource contains "firewalls/", extract(@"firewalls/([^/]+)", 1, Resource),
Resource contains "storage.googleapis.com/", extract(@'storage.googleapis.com/([^/\"]+)', 1, Resource),
Resource contains "networks/", extract(@"networks/([^/]+)", 1, Resource),
Resource
)
Stage 6: project
| project TimeGenerated, ProjectName, ResourceType, ResourceName, Resource, FindingCategory, Severity, ExternalUri, Description
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
| Field | Kind | Values |
|---|---|---|
FindingCategory | in |
|
state | eq |
|
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
Description | project |
ExternalUri | project |
FindingCategory | project |
ProjectName | project |
Resource | project |
ResourceName | project |
ResourceType | project |
Severity | project |
TimeGenerated | project |