Detection rules › Kusto

AWS Security Hub - Detect CloudTrail trails lacking KMS encryption

Status
available
Severity
medium
Time window
1h
Group by
AwsAccountId, AwsRegion, AwsSecurityFindingDescription, AwsSecurityFindingId, AwsSecurityFindingTitle, ComplianceSecurityControlId, TrailId
Source
github.com/Azure/Azure-Sentinel

This query detects AWS CloudTrail trails that are not configured to use server-side encryption with a customer managed KMS key using AWS Security Hub control CloudTrail.2 findings. Unencrypted CloudTrail logs increase the risk of unauthorized access to sensitive audit data at rest.

MITRE ATT&CK coverage

Rule body kusto

id: 9c2f6c3b-7fd8-4c5a-9d9d-3c4f9e6a7b21
name: AWS Security Hub - Detect CloudTrail trails lacking KMS encryption
description: |
  This query detects AWS CloudTrail trails that are not configured to use server-side encryption with a customer managed KMS key using AWS Security Hub control CloudTrail.2 findings. 
  Unencrypted CloudTrail logs increase the risk of unauthorized access to sensitive audit data at rest.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: AWSSecurityHub
    dataTypes:
      - AWSSecurityHubFindings
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Impact
  - DefenseEvasion
relevantTechniques:
  - T1565.001
  - T1562.008
tags:
  - CIS AWS Foundations Benchmark v1.4.0
  - CIS AWS Foundations Benchmark v1.2.0
  - NIST 800-53 r5
  - PCI DSS v3.2.1
query: |
  AWSSecurityHubFindings
  | where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"
  | where tostring(AwsSecurityFindingGeneratorId) == "security-control/CloudTrail.2"
    or tostring(ComplianceSecurityControlId) == "CloudTrail.2"
  | mv-expand Resource = Resources
  | where tostring(Resource.Type) == "AwsCloudTrailTrail"
  | extend TrailId = tostring(Resource.Id)
  | summarize TimeGenerated = max(TimeGenerated)
      by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription,
         AwsSecurityFindingId, ComplianceSecurityControlId, TrailId
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AwsAccountId
      - identifier: CloudAppAccountId
        columnName: AwsAccountId
  - entityType: CloudApplication
    fieldMappings:
      - identifier: Name
        columnName: TrailId
customDetails:
  ComplianceControlId: ComplianceSecurityControlId
  Region: AwsRegion
  FindingId: AwsSecurityFindingId
alertDetailsOverride:
  alertDisplayNameFormat: "AWS CloudTrail trail {{TrailId}} lacks KMS encryption"
  alertDescriptionFormat: "AWS CloudTrail trail ({{TrailId}}) lacks customer-managed KMS encryption for Account {{AwsAccountId}}."
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

AWSSecurityHubFindings

Stage 2: where

| where RecordState == "ACTIVE" and ComplianceStatus == "FAILED"

Stage 3: where

| where tostring(AwsSecurityFindingGeneratorId) == "security-control/CloudTrail.2"
  or tostring(ComplianceSecurityControlId) == "CloudTrail.2"

Stage 4: mv-expand

| mv-expand Resource = Resources

Stage 5: where

| where tostring(Resource.Type) == "AwsCloudTrailTrail"

Stage 6: extend

| extend TrailId = tostring(Resource.Id)

Stage 7: summarize

| summarize TimeGenerated = max(TimeGenerated)
    by AwsAccountId, AwsRegion, AwsSecurityFindingTitle, AwsSecurityFindingDescription,
       AwsSecurityFindingId, ComplianceSecurityControlId, TrailId

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.

FieldKindValues
AwsSecurityFindingGeneratorIdeq
  • security-control/CloudTrail.2 transforms: tostring, cased
ComplianceSecurityControlIdeq
  • CloudTrail.2 transforms: tostring, cased
ComplianceStatuseq
  • FAILED transforms: cased
RecordStateeq
  • ACTIVE transforms: cased
Typeeq
  • AwsCloudTrailTrail transforms: tostring, cased

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.

FieldSource
AwsAccountIdsummarize
AwsRegionsummarize
AwsSecurityFindingDescriptionsummarize
AwsSecurityFindingIdsummarize
AwsSecurityFindingTitlesummarize
ComplianceSecurityControlIdsummarize
TimeGeneratedsummarize
TrailIdsummarize