Detection rules › Kusto

New CloudShell User

Status
available
Severity
low
Time window
1d
Group by
AzureIP, Caller, CategoryValue, HTTPRequest, OperationList, Properties, ResourceGroup, SubscriptionId, TenantId, TimeKey, Type, UserIP
Source
github.com/Azure/Azure-Sentinel

Identifies when a user creates an Azure CloudShell for the first time. Monitor this activity to ensure only the expected users are using CloudShell.

MITRE ATT&CK coverage

Event coverage

Rule body kusto

id: 6d7214d9-4a28-44df-aafb-0910b9e6ae3e
name: New CloudShell User
description: |
  'Identifies when a user creates an Azure CloudShell for the first time.
  Monitor this activity to ensure only the expected users are using CloudShell.'
severity: Low
status: Available
requiredDataConnectors:
  - connectorId: AzureActivity
    dataTypes:
      - AzureActivity
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Execution
relevantTechniques:
  - T1059
query: |
  let match_window = 3m;
  AzureActivity
  | where ResourceGroup has "cloud-shell"
  | where (OperationNameValue =~ "Microsoft.Storage/storageAccounts/listKeys/action")
  | where ActivityStatusValue =~ "Success"
  | extend TimeKey = bin(TimeGenerated, match_window), AzureIP = CallerIpAddress
  | join kind = inner
  (AzureActivity
  | where ResourceGroup has "cloud-shell"
  | where (OperationNameValue =~ "Microsoft.Storage/storageAccounts/write")
  | extend TimeKey = bin(TimeGenerated, match_window), UserIP = CallerIpAddress
  ) on Caller, TimeKey
  | summarize count() by TimeKey, Caller, ResourceGroup, SubscriptionId, TenantId, AzureIP, UserIP, HTTPRequest, Type, Properties, CategoryValue, OperationList = strcat(OperationNameValue, ' , ', OperationNameValue1)
  | extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: Caller
      - identifier: Name
        columnName: Name
      - identifier: UPNSuffix
        columnName: UPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: UserIP
version: 2.0.3
kind: Scheduled

Stages and Predicates

Parameters

let match_window = 3m;

Stage 1: source

AzureActivity

Stage 2: where

| where ResourceGroup has "cloud-shell"

Stage 3: where

| where (OperationNameValue =~ "Microsoft.Storage/storageAccounts/listKeys/action")

Stage 4: where

| where ActivityStatusValue =~ "Success"

Stage 5: extend

| extend TimeKey = bin(TimeGenerated, match_window), AzureIP = CallerIpAddress

Stage 6: join

| join kind = inner
(AzureActivity
| where ResourceGroup has "cloud-shell"
| where (OperationNameValue =~ "Microsoft.Storage/storageAccounts/write")
| extend TimeKey = bin(TimeGenerated, match_window), UserIP = CallerIpAddress
) on Caller, TimeKey

Stage 7: summarize

| summarize count() by TimeKey, Caller, ResourceGroup, SubscriptionId, TenantId, AzureIP, UserIP, HTTPRequest, Type, Properties, CategoryValue, OperationList = strcat(OperationNameValue, ' , ', OperationNameValue1)

Stage 8: extend

| extend Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])

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
ActivityStatusValueeq
  • Success
OperationNameValueeq
  • Microsoft.Storage/storageAccounts/listKeys/action
  • Microsoft.Storage/storageAccounts/write
ResourceGroupmatch
  • cloud-shell transforms: term

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
AzureIPsummarize
Callersummarize
CategoryValuesummarize
HTTPRequestsummarize
OperationListsummarize
Propertiessummarize
ResourceGroupsummarize
SubscriptionIdsummarize
TenantIdsummarize
TimeKeysummarize
Typesummarize
UserIPsummarize
Nameextend
UPNSuffixextend