-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Description
Sigma CLI Kusto output not directly usable in Microsoft Sentinel (AWS S3 rule)
Hi team, I am new to Sigma and currently testing AWS S3 detections with the Microsoft Sentinel (kusto) backend.
I noticed that the Sigma CLI output was not plug-and-play in Sentinel for this case, and I had to rewrite the generated query significantly before it would run.
Rule Used
title: AWS S3 C13 - Unauthorized External Bucket Access
id: 31c84e85-6e51-5005-bfdf-0b31c4fc8077
status: experimental
description: Detects S3 data events to external buckets that are not in approved account and bucket allowlists.
author: will
date: 2026-02-15
tags:
- will.aws.s3
- will.control.s3.c13
logsource:
product: aws
service: cloudtrail
detection:
selection:
eventSource: s3.amazonaws.com
resources.accountId|exists: true
resources.ARN|exists: true
filter_authorized_accounts:
resources.accountId:
- "<authorized_external_account_id_1>"
- "<authorized_external_account_id_2>"
filter_authorized_buckets:
resources.ARN|contains:
- "arn:aws:s3:::<authorized_external_bucket_1>"
- "arn:aws:s3:::<authorized_external_bucket_2>"
condition: selection and (not filter_authorized_accounts or not filter_authorized_buckets)
falsepositives:
- Newly approved external accounts or buckets that were not added to allowlists.
level: MediumSigma CLI Output (kusto backend)
(eventSource =~ "s3.amazonaws.com" and eventName =~ "PutObject") and ('requestParameters.bucketName' in~ ("<external_bucket_1>", "<external_bucket_2>")) and isnotempty('requestParameters.x-amz-acl') and (not('requestParameters.bucketName' =~ "<bucket_with_object_ownership_handover>"))Problem
This query failed in Microsoft Sentinel.
Manually Edited Query (works)
AWSCloudTrail
| where TimeGenerated > ago(24h)
| extend _raw = parse_json(coalesce(column_ifexists("RawData", ""), column_ifexists("RawEventData", ""), "{}"))
| extend eventSource_v = coalesce(tostring(column_ifexists("eventSource", "")), tostring(_raw.eventSource))
| where eventSource_v =~ "s3.amazonaws.com"
| extend resources_v = coalesce(todynamic(column_ifexists("resources", dynamic([]))), todynamic(_raw.resources))
| mv-expand r = resources_v
| extend resourceAccountId = tostring(coalesce(r.accountId, r.AccountId))
| extend resourceArn = tostring(coalesce(r.ARN, r.arn))
| where isnotempty(resourceAccountId) and isnotempty(resourceArn)
| where resourceAccountId !in~ ("<authorized_external_account_id_1>", "<authorized_external_account_id_2>")
or (
resourceArn !contains "arn:aws:s3:::<authorized_external_bucket_1>"
and resourceArn !contains "arn:aws:s3:::<authorized_external_bucket_2>"
)
| project TimeGenerated, eventSource_v, resourceAccountId, resourceArnQuestion
Is this expected behavior for the Sentinel/Kusto backend, or could this be a translation gap for nested CloudTrail fields (especially resources.*) that should be handled by Sigma CLI?
Reproduction Steps
- Create or use the Sigma rule shown above (
AWS S3 C13 - Unauthorized External Bucket Access). - Convert it to Kusto using Sigma CLI and the Sentinel/Kusto backend.
- Run the generated Kusto query in Microsoft Sentinel against
AWSCloudTrail. - Observe query failure in Sentinel.
- Replace it with the manually edited query above and re-run.
- Confirm the manual query runs successfully.
Expected Behavior
The Sigma-generated Kusto query should execute successfully in Sentinel without requiring significant manual rewrite (or even better, just plug and play).
Actual Behavior
The generated query fails in Sentinel and the eventual working version differs from the Sigma converted version significantly.
Follow-up Questions
- Is it expected that Sigma-to-backend conversion usually requires manual tweaks, or is there a recommended approach to get Sentinel output close to plug-and-play for this type of rule?
- I also tested multiple Kusto backend pipelines and got errors about missing values like
query_table(see the following section). Is there a recommended Sentinel pipeline/configuration for this use case?
Error while converting: Unable to determine table name from rule. The query table is determined in the following order of priority:
1) The value provided to processing pipeline's query_table parameter, if using a Python script.
2) If the query_table is already set in the pipeline state, such as from a custom user-defined pipeline if using sigma-cli.
3) If the rule's logsource category is present in the pipeline's category_to_table_mappings dictionary in mappings.py, use that value.
4) If the rule has an EventID, use the table name from the pipeline's eventid_to_table_mappings dictionary in mappings.py.
For more details, see https://github.com/AttackIQ/pySigma-backend-kusto/blob/main/README.md#%EF%B8%8F-custom-table-names-new-in-030-beta.
Thank you very much!