Merge branch 'master' into domain-solution-change

This commit is contained in:
v-amolpatil 2024-06-07 15:22:47 +05:30
Родитель a09b3480ff d3077688ac
Коммит 9b7cc76dba
322 изменённых файлов: 30759 добавлений и 21315 удалений

Просмотреть файл

@ -37,7 +37,7 @@ jobs:
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
- name: Login to Azure Public Cloud with AzPowershell
uses: azure/login@v1
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}

Просмотреть файл

@ -144,6 +144,10 @@ function getConnectorCategory(dataTypes : any, instructionSteps:[])
{
return ConnectorCategory.CybleThreatIntel;
}
else if (dataTypes[0].name.includes("IndicatorsOfCompromise"))
{
return ConnectorCategory.CrowdStrikeFalconIOC;
}
return "";
}
let fileTypeSuffixes = ["json"];

Просмотреть файл

@ -0,0 +1,98 @@
{
"Name": "CommvaultSecurityIQ_CL",
"properties":
[
{
"Name": "anomaly_sub_type_s",
"Type": "String"
},
{
"Name": "created_files_count_s",
"Type": "String"
},
{
"Name": "deleted_files_count_s",
"Type": "String"
},
{
"Name": "description_s",
"Type": "String"
},
{
"Name": "external_link_s",
"Type": "String"
},
{
"Name": "files_list_s",
"Type": "String"
},
{
"Name": "job_end_time_s",
"Type": "String"
},
{
"Name": "job_id_s",
"Type": "String"
},
{
"Name": "job_start_time_s",
"Type": "String"
},
{
"Name": "originating_client_s",
"Type": "String"
},
{
"Name": "scanned_folder_list_s",
"Type": "String"
},
{
"Name": "severity_s",
"Type": "String"
},
{
"Name": "subclient_id_d",
"Type": "Real"
},
{
"Name": "user_id_d",
"Type": "Real"
},
{
"Name": "username_s",
"Type": "String"
},
{
"Name": "Computer",
"Type": "String"
},
{
"Name": "ManagementGroupName",
"Type": "String"
},
{
"Name": "MG",
"Type": "Guid"
},
{
"Name": "RawData",
"Type": "String"
},
{
"Name": "SourceSystem",
"Type": "String"
},
{
"Name": "TenantId",
"Type": "Guid"
},
{
"Name": "TimeGenerated",
"Type": "Datetime"
},
{
"Name": "Type",
"Type": "String"
}
]
}

Просмотреть файл

@ -1,77 +1,81 @@
{
"name": "JiraAudit",
"Properties": [
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "EventVendor",
"Type": "String"
},
{
"Name": "EventProduct",
"Type": "String"
},
{
"Name": "EventId",
"Type": "Double"
},
{
"Name": "EventMessage",
"Type": "String"
},
{
"Name": "SrcIpAddr",
"Type": "String"
},
{
"Name": "UserName",
"Type": "String"
},
{
"Name": "UserSid",
"Type": "String"
},
{
"Name": "EventCreationTime",
"Type": "DateTime"
},
{
"Name": "EventSource",
"Type": "String"
},
{
"Name": "ObjectItemId",
"Type": "String"
},
{
"Name": "ObjectItemName",
"Type": "String"
},
{
"Name": "ObjectItemTypeName",
"Type": "String"
},
{
"Name": "ChangedValues",
"Type": "String"
},
{
"Name": "AssociatedItems",
"Type": "String"
},
{
"Name": "ObjectItemParentId",
"Type": "String"
},
{
"Name": "ObjectItemParentName",
"Type": "String"
},
{
"Name": "EventCategoryType",
"Type": "String"
}
]
{
"name": "JiraAudit",
"Properties": [
{
"Name": "TimeGenerated",
"Type": "DateTime"
},
{
"Name": "EventVendor",
"Type": "String"
},
{
"Name": "EventProduct",
"Type": "String"
},
{
"Name": "EventId",
"Type": "Int"
},
{
"Name": "EventMessage",
"Type": "String"
},
{
"Name": "SrcIpAddr",
"Type": "String"
},
{
"Name": "UserName",
"Type": "String"
},
{
"Name": "UserSid",
"Type": "String"
},
{
"Name": "EventCreationTime",
"Type": "DateTime"
},
{
"Name": "EventSource",
"Type": "String"
},
{
"Name": "ObjectItemId",
"Type": "String"
},
{
"Name": "ObjectItemName",
"Type": "String"
},
{
"Name": "ObjectItemTypeName",
"Type": "String"
},
{
"Name": "ChangedValues",
"Type": "Dynamic"
},
{
"Name": "AssociatedItems",
"Type": "Dynamic"
},
{
"Name": "ObjectItemParentId",
"Type": "String"
},
{
"Name": "ObjectItemParentName",
"Type": "String"
},
{
"Name": "EventCategoryType",
"Type": "String"
},
{
"Name": "SourceTable",
"Type": "String"
}
]
}

Просмотреть файл

@ -0,0 +1,119 @@
{
"Name":"Jira_Audit_v2_CL",
"Properties":[
{
"name": "AssociatedItems",
"type": "dynamic",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "UserSid",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "UserName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventCategoryType",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ChangedValues",
"type": "dynamic",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventCreationTime",
"type": "datetime",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventSource",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventId",
"type": "int",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "objectItem",
"type": "dynamic",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "SrcIpAddr",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventMessage",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "TimeGenerated",
"type": "datetime",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventVendor",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventProduct",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemId",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemTypeName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemParentId",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemParentName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
}
]
}

Просмотреть файл

@ -47,6 +47,7 @@
"CEF",
"CheckPoint",
"CiscoASA",
"CiscoAsaAma",
"CiscoDuoSecurity",
"CiscoFirepowerEStreamer",
"CiscoISE",
@ -239,5 +240,7 @@
"InfobloxSOCInsightsDataConnector_Legacy",
"InfobloxSOCInsightsDataConnector_AMA",
"NetskopeDataConnector",
"NetskopeWebTransactionsDataConnector"
"NetskopeWebTransactionsDataConnector",
"CefAma",
"WindowsFirewallAma"
]

Просмотреть файл

@ -211,5 +211,6 @@ export enum ConnectorCategory {
PowerBIActivity="PowerBIActivity",
SecurityAlertOATP="SecurityAlert(OATP)",
SecurityAlertASC="SecurityAlert(ASC)",
CybleThreatIntel="CybleThreatIntel"
CybleThreatIntel="CybleThreatIntel",
CrowdStrikeFalconIOC="CrowdStrikeFalconIOC"
}

Просмотреть файл

@ -0,0 +1,440 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"title": {
"type": "string"
},
"publisher": {
"type": "string"
},
"descriptionMarkdown": {
"type": "string"
},
"graphQueries": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"metricName": {
"type": "string"
},
"legend": {
"type": "string"
},
"baseQuery": {
"type": "string"
}
},
"required": [
"metricName",
"legend",
"baseQuery"
]
}
]
},
"sampleQueries": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"description": {
"type": "string"
},
"query": {
"type": "string"
}
},
"required": [
"description",
"query"
]
}
]
},
"dataTypes": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"lastDataReceivedQuery": {
"type": "string"
}
},
"required": [
"name",
"lastDataReceivedQuery"
]
}
]
},
"connectivityCriterias": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"type": {
"type": "string"
},
"value": {
"type": "array",
"items": [
{
"type": "string"
}
]
}
},
"required": [
"type",
"value"
]
}
]
},
"availability": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"isPreview": {
"type": "boolean"
}
},
"required": [
"status",
"isPreview"
]
},
"permissions": {
"type": "object",
"properties": {
"resourceProvider": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"provider": {
"type": "string"
},
"permissionsDisplayText": {
"type": "string"
},
"providerDisplayName": {
"type": "string"
},
"scope": {
"type": "string"
},
"requiredPermissions": {
"type": "object",
"properties": {
"write": {
"type": "boolean"
},
"read": {
"type": "boolean"
},
"delete": {
"type": "boolean"
}
},
"required": [
"write",
"read",
"delete"
]
}
},
"required": [
"provider",
"permissionsDisplayText",
"providerDisplayName",
"scope",
"requiredPermissions"
]
},
{
"type": "object",
"properties": {
"provider": {
"type": "string"
},
"permissionsDisplayText": {
"type": "string"
},
"providerDisplayName": {
"type": "string"
},
"scope": {
"type": "string"
},
"requiredPermissions": {
"type": "object",
"properties": {
"action": {
"type": "boolean"
}
},
"required": [
"action"
]
}
},
"required": [
"provider",
"permissionsDisplayText",
"providerDisplayName",
"scope",
"requiredPermissions"
]
}
]
},
"customs": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"name",
"description"
]
},
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"name",
"description"
]
}
]
}
},
"required": [
"resourceProvider",
"customs"
]
},
"instructionSteps": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"title",
"description"
]
},
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"title",
"description"
]
},
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"title",
"description"
]
},
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"title",
"description"
]
},
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"instructions": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"parameters": {
"type": "object",
"properties": {
"fillWith": {
"type": "array",
"items": [
{
"type": "string"
}
]
},
"label": {
"type": "string"
}
},
"required": [
"fillWith",
"label"
]
},
"type": {
"type": "string"
}
},
"required": [
"parameters",
"type"
]
}
]
}
},
"required": [
"title",
"description",
"instructions"
]
},
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"title",
"description"
]
},
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"title",
"description"
]
},
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"title",
"description"
]
},
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"title",
"description"
]
}
]
}
},
"required": [
"id",
"title",
"publisher",
"descriptionMarkdown",
"graphQueries",
"sampleQueries",
"dataTypes",
"connectivityCriterias",
"availability",
"permissions",
"instructionSteps"
]
}

Просмотреть файл

@ -0,0 +1,23 @@
id: ba1a91ad-1f99-4386-b191-06a76ef213f8
name: Audit Email Preview-Download action
description: |
This query helps report on who Previewed/Downloaded email messages using Email entitiy page in MDO
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- CloudAppEvents
tactics:
- Privilege escalation
query: |
CloudAppEvents
| project Timestamp, ActionType, AccountDisplayName, AR=parse_json(RawEventData)
| evaluate bag_unpack(AR)
| where RecordType == "38" and ExtendedProperties contains "DownloadEMail" or ExtendedProperties contains "GetMailPreviewUrl"
| serialize
| extend RowNumber = row_number()
| mv-expand ExtendedProperties
| evaluate bag_unpack(ExtendedProperties, 'xp_')
| extend DownloadEMail = iff(tostring(xp_Name) == 'DownloadEMail', xp_Value, ''), GetMailPreviewUrl = iff(tostring(xp_Name) == 'GetMailPreviewUrl', xp_Value, ''), MailboxId = iff(tostring(xp_Name) == 'MailboxId', xp_Value, ''), InternetMessageId = iff(tostring(xp_Name) == 'InternetMessageId', xp_Value, '')
| summarize Timestamp = any(Timestamp), ActionType = any(ActionType), AccountDisplayName = any(AccountDisplayName), DownloadEmail = make_set_if(DownloadEMail, isnotempty( DownloadEMail)), GetMailPreviewUrl = make_set_if(GetMailPreviewUrl, isnotempty( GetMailPreviewUrl)), MailboxId = make_set_if(MailboxId, isnotempty( MailboxId)), InternetMessageId = make_set_if(InternetMessageId, isnotempty( InternetMessageId)) by RowNumber
| extend DownloadEmail = tobool(DownloadEmail[0]), GetMailPreviewUrl = tobool(GetMailPreviewUrl[0]), MailboxId = tostring(MailboxId[0]), InternetMessageId = tostring(InternetMessageId[0])
| project-away RowNumber

Просмотреть файл

@ -0,0 +1,14 @@
id: bc2d8214-afb6-4876-b210-25b69325b9b2
name: Hunt for TABL changes
description: |
This query helps hunting for Tenant allow/block list (TABL) changes in MDO
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- CloudAppEvents
tactics:
- Defense evasion
query: |
CloudAppEvents
| where ActionType contains "TenantAllowBlockListItems"
| order by Timestamp desc

Просмотреть файл

@ -0,0 +1,15 @@
id: 712ffdd8-ddce-4372-85dd-063029b418cf
name: Local time to UTC time conversion
description: |
Advanced Hunting has default timezone as UTC time. Filters in Advanced Hunting also work in UTC by default whereas query results are shown in local time if user has selected local time zone in security center settings. This is a sample query to convert local time to UTC time and can be used with any table. User needs to update the query with local time zone using the available options at https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/timezone
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- EmailEvents
tactics:
- Initial access
query: |
EmailEvents
| where Timestamp between (datetime_local_to_utc(datetime(2023-08-10T00:00:00Z),"Europe/Madrid") .. datetime_local_to_utc(datetime(2023-08-31T23:59:59Z),"Europe/Madrid"))
| where DeliveryAction == "Delivered"
| where LatestDeliveryLocation == "Quarantine"

Просмотреть файл

@ -0,0 +1,60 @@
id: deb4b2c6-c10e-4044-8cf4-84243e40db73
name: MDO daily detection summary report
description: |
This query helps report daily on total # of emails, total # of emails detected as Malware, Phish, Spam, Bulk, total number of user/admin submissions, total # of ZAP events, total # of AIR investigations and their result
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- CloudAppEvents
- AlertEvidence
- EmailEvents
- EmailPostDeliveryEvents
tactics:
- Initial access
query: |
let QueryTime = 30d;
let Reports = CloudAppEvents
| where Timestamp > ago(QueryTime)
| where ActionType == "UserSubmission" or ActionType == "AdminSubmission"
| extend MessageDate = todatetime((parse_json(RawEventData)).MessageDate)
| extend NetworkMessageID = tostring((parse_json(RawEventData)).ObjectId)
| extend Date_value = tostring(format_datetime( MessageDate, "yyyy-MM-dd"))
| distinct Date_value,NetworkMessageID
| summarize count() by Date_value
| project Date_value, MessagesGotReported=count_;
let ThreatByAutomation = (AlertEvidence | where Title == "Email reported by user as malware or phish")
| extend LastVerdictfromAutomation = tostring((parse_json(AdditionalFields)).LastVerdict)
| extend Date_value = tostring(format_datetime( Timestamp, "yyyy-MM-dd"))
| extend DetectionFromAIR = iif(isempty(LastVerdictfromAutomation), "NoThreatsFound", tostring(LastVerdictfromAutomation))
| summarize PostDeliveryTotalAIRInvestigations = count(),
PostDeliveryAirNoThreatsFound = countif(DetectionFromAIR contains "NoThreatsFound"),
PostDeliveryAirSuspicious = countif(DetectionFromAIR contains "Suspicious"),
PostDeliveryAirMalicious = countif(DetectionFromAIR contains "Malicious")
by Date_value //Date Reported from Message Submissions from CloudAppEvents does not match to the AIR Investigations from Alert playbooks
| project Date_value, PostDeliveryTotalAIRInvestigations, PostDeliveryAirNoThreatsFound, PostDeliveryAirSuspicious, PostDeliveryAirMalicious;
let DeliveryInboundEvents = (EmailEvents | where EmailDirection == "Inbound" and Timestamp > ago(QueryTime)
| extend Date_value = tostring(format_datetime( Timestamp, "yyyy-MM-dd"))
| project Date_value, Timestamp, NetworkMessageId, DetectionMethods ,RecipientEmailAddress);
let PostDeliveryEvents = (EmailPostDeliveryEvents | where ActionType contains "ZAP" and ActionResult == "Success"| join DeliveryInboundEvents on RecipientEmailAddress, NetworkMessageId //Only successful ZAP Events, there could still be more, join on Recipient and NetID
| extend Date_value = tostring(format_datetime( Timestamp, "yyyy-MM-dd")) //Zap Timestamp is used and not MessageDate received
| summarize PostDeliveryZAP=count() by Date_value);
let DeliveryByThreat = (DeliveryInboundEvents
| where Timestamp > ago(QueryTime)
| extend Date_value = tostring(format_datetime( Timestamp, "yyyy-MM-dd"))
| extend MDO_detection = parse_json(DetectionMethods)
| extend FirstDetection = iif(isempty(MDO_detection), "Clean", tostring(bag_keys(MDO_detection)[0]))
| extend FirstSubcategory = iif(FirstDetection != "Clean" and array_length(MDO_detection[FirstDetection]) > 0, strcat(FirstDetection, ": ", tostring(MDO_detection[FirstDetection][0])), "No Detection (clean)"))
| summarize TotalEmails = count(),
Clean = countif(FirstSubcategory contains "Clean"),
Malware = countif(FirstSubcategory contains "Malware"),
Phish = countif(FirstSubcategory contains "Phish"),
Spam = countif(FirstSubcategory contains "Spam" and FirstSubcategory !contains "Bulk"),
Bulk = countif(FirstSubcategory contains "Bulk")
by Date_value;
DeliveryByThreat
| join kind=fullouter Reports on Date_value
| join kind=fullouter PostDeliveryEvents on Date_value
| join kind=fullouter ThreatByAutomation on Date_value
| sort by Date_value asc
| project Date_value, Clean, Malware, Phish, Spam, Bulk, MessagesGotReported, PostDeliveryZAP, PostDeliveryTotalAIRInvestigations, PostDeliveryAirNoThreatsFound, PostDeliveryAirMalicious, PostDeliveryAirSuspicious
| where isnotempty(Date_value) // As Reports from CloudAppEvents Submissions could contain messages submitted before 30 days it is good to remove all > 30 days, otherwise EMailEvents wouldn't have a date

Просмотреть файл

@ -0,0 +1,16 @@
id: 81ede5df-2ec3-40a5-9dff-1fe6a841079d
name: Mail item accessed
description: |
This query helps reviewing emails accessed by end users using cloud app events data
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- CloudAppEvents
tactics:
- Initial access
query: |
CloudAppEvents
| where Timestamp > ago(30d)
| extend Record= (parse_json(RawEventData)).RecordType
| where Record == 50
| take 10

Просмотреть файл

@ -0,0 +1,17 @@
id: 63c799bc-7567-4e4d-97be-e143fcfaa333
name: Malicious email senders
description: |
This query helps reviewing emails from sender with atleast one email in quarantine
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- EmailEvents
tactics:
- Initial access
query: |
let SenderWithQuarantine = EmailEvents
| where LatestDeliveryLocation == "Quarantine"
| project SenderFromAddress;
EmailEvents
| where LatestDeliveryLocation == "Inbox/folder"
| where SenderFromAddress in (SenderWithQuarantine)

Просмотреть файл

@ -0,0 +1,22 @@
id: 57f95ba7-938d-4a76-b411-c01034c0d167
name: Hunt for malicious URLs using external IOC source
description: |
This query helps hunt for emails with malicious URLs based on external IOC source
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- EmailUrlInfo
- EmailEvents
tactics:
- Initial access
query: |
let url = (externaldata(url: string )
[@"https://urlhaus.abuse.ch/downloads/text_online/"]
with (format="txt"))
| project url;
url
| join (EmailUrlInfo
| where Timestamp > ago(2h)
) on $left.url == $right.Url
|join EmailEvents on NetworkMessageId
|project Timestamp, NetworkMessageId, Url, UrlLocation, UrlDomain, SenderFromAddress, SenderDisplayName, SenderIPv4, Subject,RecipientEmailAddress, RecipientObjectId, LatestDeliveryAction, ThreatNames, ThreatTypes, DetectionMethods, DeliveryAction,ReportId

Просмотреть файл

@ -0,0 +1,21 @@
id: 0da830c3-5d0e-4b98-bfa1-d5131a8d0ebe
name: Hunt for malicious attachments using external IOC source
description: |
This query helps hunt for emails with malicious attachments based on SH256 hash from external IOC source
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- EmailAttachmentInfo
tactics:
- Initial access
query: |
let abuse_sha256 = (externaldata(sha256_hash: string)
[@"https://bazaar.abuse.ch/export/txt/sha256/recent/"]
with (format="txt"))
| where sha256_hash !startswith "#"
| project sha256_hash;
abuse_sha256
| join (EmailAttachmentInfo
| where Timestamp > ago(1d)
) on $left.sha256_hash == $right.SHA256
| project Timestamp,SenderFromAddress,RecipientEmailAddress,FileName,FileType,SHA256,ThreatTypes,DetectionMethods,NetworkMessageId,ReportId

Просмотреть файл

@ -0,0 +1,15 @@
id: 54569b06-47fc-41ae-9b00-f7d9b61337b6
name: Inbox rule changes which forward-redirect email
description: |
This query helps hunting for Inbox rule changes which forward-redirect email
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- CloudAppEvents
tactics:
- Persistence
query: |
CloudAppEvents
| where ActionType contains "Set-InboxRule"
|extend Parameters = tostring((parse_json(RawEventData)).Parameters)
|where Parameters contains "ForwardTo" or Parameters contains "RedirectTo"

Просмотреть файл

@ -0,0 +1,34 @@
id: 9d59be10-54d9-478b-b669-fb4eb8517cd0
name: Phish detections by detection methods
description: |
This query helps reviewing detections done by some of the most frequent detection technologies in the last 7 days
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- EmailEvents
tactics:
- Initial access
query: |
EmailEvents
| where Timestamp > ago(7d)
| where isnotempty(DetectionMethods)
| extend MDO_detection = parse_json(DetectionMethods)
| where MDO_detection.Phish in
(
@'["URL malicious reputation"]',
@'["URL detonation reputation"]',
@'["URL detonation"]',
@'["Advanced filter"]',
@'["General filter"]',
@'["Spoof intra-org"]',
@'["Spoof external domain"]',
@'["Spoof DMARC"]',
@'["Impersonation brand"]',
@'["Mixed analysis detection"]',
@'["File reputation"]',
@'["File detonation reputation"]',
@'["File detonation"]',
@'["Fingerprint matching"]'
)
| extend SenderFromAddress_IPv4 = strcat(SenderFromAddress, ", ", SenderIPv4)
| project Timestamp, NetworkMessageId, Subject, SenderFromAddress_IPv4, RecipientEmailAddress, DeliveryLocation, MDO_detection.Phish

Просмотреть файл

@ -1,15 +0,0 @@
id: 0a92c884-e6dc-4552-8bec-d47c9bb29295
name: PhishingEmailUrlRedirector
description: |
This query was originally published on Twitter, by @MsftSecIntel.
The query helps detect emails associated with the open redirector URL campaign. The campaign's URLs begin with the distinct pattern, hxxps://t[.]domain[.]tld/r/?. Attackers use URL redirection to manipulate users into visiting a malicious website or to evade detection.
Reference - https://twitter.com/MsftSecIntel
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- EmailUrlInfo
tactics:
- Initial access
query: |
EmailUrlInfo
| where Url matches regex @"s?\:\/\/(?:www\.)?t\.(?:[\w\-\.]+\/+)+(?:r|redirect)\/?\?"

Просмотреть файл

@ -0,0 +1,30 @@
id: 6a570927-8638-4a6f-ac09-72a7d51ffa3c
name: Display Name - Spoof and Impersonation
description: |
This query helps reviewing incoming email messages where the Display Name of the sender contains own or other partner company/brand name
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- EmailEvents
tactics:
- Initial access
query: |
let emailDelivered = EmailEvents
| where Timestamp < ago(24hrs)
and DeliveryAction == "Delivered"
and SenderDisplayName contains "Microsoft"
| summarize count() by SenderFromAddress
| where count_ > 3 // ensuring that some level of communications has occured.
| project SenderFromAddress;
EmailEvents
| where Timestamp > ago(24hrs)
| where DeliveryAction == "Delivered"
and EmailDirection == "Inbound"
and OrgLevelAction != "Block"
and UserLevelAction != "Block"
and SenderDisplayName contains "Microsoft"
| extend NewMsg = case(Subject contains "RE:", false, Subject contains "FW:", false, true )
| project SenderDisplayName, SenderFromAddress, NetworkMessageId, SenderMailFromAddress, RecipientEmailAddress, DeliveryAction, DeliveryLocation, ThreatTypes, DetectionMethods, NewMsg, Subject
| join kind=leftanti ( emailDelivered ) on SenderFromAddress
| order by SenderMailFromAddress
| summarize count() by SenderDisplayName, SenderFromAddress, NetworkMessageId, SenderMailFromAddress, RecipientEmailAddress, DeliveryAction, DeliveryLocation, ThreatTypes, DetectionMethods, NewMsg, Subject

Просмотреть файл

@ -0,0 +1,15 @@
id: b3180ac0-6d94-494a-8b8c-fcc84319ea6e
name: Spoof and impersonation detections by sender IP
description: |
This query helps reviewing count of spoof and impersonation detections done per sender IP
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- EmailEvents
tactics:
- Initial access
query: |
EmailEvents
|where Timestamp > ago (30d) and (DetectionMethods contains 'spoof' or DetectionMethods contains "impersonation")
| project Timestamp, EmailDirection, SenderFromAddress, AdditionalFields, SenderIPv4
| summarize count() by SenderIPv4

Просмотреть файл

@ -0,0 +1,16 @@
id: 011c3d48-f6ca-405f-9763-66c7856ad2ba
name: Spoof and impersonation phish detections
description: |
This query helps reviewing count of phish detections done by spoof detection methods
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- EmailEvents
tactics:
- Initial access
query: |
EmailEvents
|where Timestamp > ago (30d) and (DetectionMethods contains 'spoof' or DetectionMethods contains "impersonation")
| project Timestamp, AR=parse_json(ThreatTypes) , DT=parse_json(DetectionMethods), EmailDirection, SenderFromAddress
| evaluate bag_unpack(DT)
| summarize count() by tostring(Phish)

Просмотреть файл

@ -0,0 +1,23 @@
id: e90345b3-439c-44e1-a85d-8ae84ad9c65b
name: User not covered under display name impersonation
description: |
This query helps to find threats using display name impersonation for users not already protected with User Impersonation
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- EmailEvents
- IdentityInfo
tactics:
- Initial access
query: |
let display_names =
IdentityInfo
| summarize by AccountDisplayName
| project-rename SenderDisplayName = AccountDisplayName;
EmailEvents
| where EmailDirection == "Inbound"
| where ThreatNames != ""
| where ThreatNames !contains "Impersonation User"
| lookup kind=inner (display_names) on SenderDisplayName, $left.SenderDisplayName == $right.SenderDisplayName
| where SenderDisplayName != ""
| summarize by SenderDisplayName

Просмотреть файл

@ -0,0 +1,40 @@
id: 75e3a1b2-bd6d-4e79-8c74-85a3bc0b0617
name: detect-impacket-atexec
description: |
This query looks for signs of impacket atexec module. Should work with others using similar technique.
Author: Jouni Mikkola
More info: https://threathunt.blog/impacket-part-3/
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceEvents
- DeviceRegistryEvents
- DeviceProcessEvents
tactics:
- Execution
relevantTechniques:
- T1053
query: |
let lookuptime = 30d;
DeviceEvents
| where Timestamp >ago(lookuptime)
| where ActionType == 'NamedPipeEvent'
| where AdditionalFields contains "atsvc"
| project DeviceName, Timestamp, DeviceId, RemoteIP, PipeName = extractjson("$.PipeName", AdditionalFields, typeof(string)), RemoteClientsAccess = extractjson("$.RemoteClientsAccess", AdditionalFields, typeof(string)), ShareName = extractjson("$.ShareName", AdditionalFields, typeof(string))
| join (
DeviceRegistryEvents
| where Timestamp >ago(lookuptime)
| where ActionType == 'RegistryKeyCreated'
| where RegistryKey contains @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\"
| project RegTimestamp = Timestamp, DeviceName, DeviceId, RegistryKey, RegistryValueData, RegistryValueName, RegistryValueType, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessId, InitiatingProcessCreationTime
) on DeviceName, DeviceId
| where RegTimestamp between ((Timestamp - 2m) .. (Timestamp + 2m))
| join (
DeviceProcessEvents
| where Timestamp >ago(lookuptime)
| where InitiatingProcessFileName =~ "svchost.exe"
| where InitiatingProcessCommandLine contains "Schedule"
| project DeviceId, DeviceName, FileName, ProcessCommandLine, ProcessId, ProcessStartTimestamp = Timestamp, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessId, InitiatingProcessCreationTime
) on DeviceName, DeviceId, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessId, InitiatingProcessCreationTime
| where ProcessStartTimestamp between ( Timestamp .. (Timestamp +2m))
| project DeviceName, Timestamp, StartedProcess = FileName, StartedProcessCommandLine = ProcessCommandLine, StartedProcessId = ProcessId, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessId, InitiatingProcessCreationTime, RegistryKey, RemoteIP, PipeName

Просмотреть файл

@ -4,9 +4,9 @@
"metadata": {
"title": "AS-Microsoft-Entra-ID-Revoke-User-Sessions-HTTP",
"description": "This playbook is intended to be run from a Microsoft Sentinel Incident. It will look up Microsoft Entra ID users associated with the incident account entities and revoke their sessions. A comment noting the affected users will be added to the Incident.",
"prerequisites": "1. An App Registration with User.ReadWrite.All permissions granted on Microsoft Graph API. 2. A client secret for the App Registration must be generated. 3. An Azure Key Vault Secret to hold the client secret. Support for the set up and configuration of each of these items can be found here: https://github.com/Accelerynt-Security/AS-Revoke-Azure-AD-User-Session-From-Incident",
"prerequisites": "1. An App Registration with User.ReadWrite.All permissions granted on Microsoft Graph API. 2. A client secret for the App Registration must be generated. 3. An Azure Key Vault Secret to hold the client secret. Support for the set up and configuration of each of these items can be found here: https://github.com/Accelerynt-Security/AS-IAM-Entra-ID-Master-Playbook/tree/main/AS-Microsoft-Entra-ID-Revoke-User-Sessions-HTTP",
"postDeployment": ["Access to the Azure Key Vault must be granted to the playbook","The Microsoft Sentinel Contributor role must be applied to the playbook"],
"lastUpdateTime": "2023-12-07T3:17:47Z",
"lastUpdateTime": "2024-05-22T23:40:50Z",
"entities": ["Account"],
"tags": ["Microsoft Sentinel", "Incident", "Microsoft Entra ID", "Revoke User Sessions"],
"support": {
@ -207,63 +207,86 @@
"For_each_-_Account": {
"foreach": "@triggerBody()",
"actions": {
"Condition_-_Check_for_aadUserId": {
"Condition_-_Set_UPN": {
"actions": {
"Condition_-_User_session_successfully_revoked": {
"actions": {
"Append_to_string_variable_-_Affected_Microsoft_Entra_ID_Users": {
"runAfter": {},
"type": "AppendToStringVariable",
"inputs": {
"name": "Affected Microsoft Entra ID Users",
"value": "@{items('For_each_-_Account')?['Name']} [@{items('For_each_-_Account')?['aadUserId']}]\n"
}
}
},
"runAfter": {
"HTTP_-_Revoke_user_sign_in_sessions": [
"Succeeded"
]
},
"expression": {
"and": [
{
"equals": [
"@outputs('HTTP_-_Revoke_user_sign_in_sessions')['statusCode']",
200
]
}
]
},
"type": "If"
},
"HTTP_-_Revoke_user_sign_in_sessions": {
"Set_variable_-_Concatenate": {
"runAfter": {},
"type": "Http",
"type": "SetVariable",
"inputs": {
"headers": {
"Authorization": "Bearer @{body('Parse_JSON_-_Access_token')?['access_token']}",
"Host": "graph.microsoft.com"
},
"method": "POST",
"uri": "https://graph.microsoft.com/v1.0/users/@{items('For_each_-_Account')?['aadUserId']}/revokeSignInSessions"
"name": "UPN",
"value": "@{concat(items('For_each_-_Account')?['accountName'], '@', items('For_each_-_Account')?['upnSuffix'])}"
}
}
},
"runAfter": {},
"else": {
"actions": {
"Set_variable_-_aadUserID": {
"runAfter": {},
"type": "SetVariable",
"inputs": {
"name": "UPN",
"value": "@items('For_each_-_Account')['aadUserId']"
}
}
}
},
"expression": {
"and": [
{
"not": {
"equals": [
"@{items('For_each_-_Account')?['aadUserId']}",
""
]
}
"equals": [
"@items('For_each_-_Account')['aadUserId']",
"@null"
]
}
]
},
"runAfter": {},
"type": "If"
},
"Condition_-_User_session_successfully_revoked": {
"actions": {
"Append_to_string_variable_-_Affected_Microsoft_Entra_ID_Users": {
"runAfter": {},
"type": "AppendToStringVariable",
"inputs": {
"name": "Affected Microsoft Entra ID Users",
"value": "@{items('For_each_-_Account')?['Name']} [@{variables('UPN')}]\n"
}
}
},
"runAfter": {
"HTTP_-_Revoke_user_sign_in_sessions": [
"Succeeded"
]
},
"expression": {
"and": [
{
"equals": [
"@outputs('HTTP_-_Revoke_user_sign_in_sessions')['statusCode']",
200
]
}
]
},
"type": "If"
},
"HTTP_-_Revoke_user_sign_in_sessions": {
"runAfter": {
"Condition_-_Set_UPN": [
"Succeeded"
]
},
"type": "Http",
"inputs": {
"headers": {
"Authorization": "Bearer @{body('Parse_JSON_-_Access_token')?['access_token']}",
"Content-Type": "application/json",
"Host": "graph.microsoft.com"
},
"method": "POST",
"uri": "https://graph.microsoft.com/v1.0/users/@{variables('UPN')}/revokeSignInSessions"
}
}
},
"runAfter": {
@ -288,7 +311,7 @@
},
"HTTP_-_Authenticate": {
"runAfter": {
"Initialize_variable_-_Affected_Microsoft_Entra_ID_Users": [
"Initialize_variable_-_UPN": [
"Succeeded"
]
},
@ -319,6 +342,22 @@
]
}
},
"Initialize_variable_-_UPN": {
"runAfter": {
"Initialize_variable_-_Affected_Microsoft_Entra_ID_Users": [
"Succeeded"
]
},
"type": "InitializeVariable",
"inputs": {
"variables": [
{
"name": "UPN",
"type": "string"
}
]
}
},
"Parse_JSON_-_Access_token": {
"runAfter": {
"HTTP_-_Authenticate": [

Просмотреть файл

@ -4,14 +4,11 @@
"metadata": {
"title": "AS-Microsoft-Entra-ID-Revoke-User-Sessions-HTTP",
"description": "This playbook is intended to be run from a Microsoft Sentinel Incident. It will look up Microsoft Entra ID users associated with the incident account entities and revoke their sessions. A comment noting the affected users will be added to the Incident.",
"prerequisites": "1. An App Registration with User.ReadWrite.All permissions granted on Microsoft Graph API. 2. A client secret for the App Registration must be generated. 3. An Azure Key Vault Secret to hold the client secret. Support for the set up and configuration of each of these items can be found here: https://github.com/Accelerynt-Security/AS-Revoke-Azure-AD-User-Session-From-Incident",
"prerequisites": "1. An App Registration with User.ReadWrite.All permissions granted on Microsoft Graph API. 2. A client secret for the App Registration must be generated. 3. An Azure Key Vault Secret to hold the client secret. Support for the set up and configuration of each of these items can be found here: https://github.com/Accelerynt-Security/AS-IAM-Master-Playbook/tree/main/AS-Microsoft-Entra-ID-Revoke-User-Sessions-HTTP",
"postDeployment": ["Access to the Azure Key Vault must be granted to the playbook","The Microsoft Sentinel Contributor role must be applied to the playbook"],
"lastUpdateTime": "2023-12-07T3:17:47Z",
"lastUpdateTime": "2024-05-22T23:40:50Z",
"entities": ["Account"],
"tags": ["Microsoft Sentinel", "Incident", "Microsoft Entra ID", "Revoke User Sessions"],
"source": {
"kind": "Community"
},
"tags": ["Microsoft Sentinel", "Incident", "Microsoft Entra ID", "Revoke User Sessions"],
"support": {
"tier": "partner"
},
@ -210,63 +207,86 @@
"For_each_-_Account": {
"foreach": "@triggerBody()",
"actions": {
"Condition_-_Check_for_aadUserId": {
"Condition_-_Set_UPN": {
"actions": {
"Condition_-_User_session_successfully_revoked": {
"actions": {
"Append_to_string_variable_-_Affected_Microsoft_Entra_ID_Users": {
"runAfter": {},
"type": "AppendToStringVariable",
"inputs": {
"name": "Affected Microsoft Entra ID Users",
"value": "@{items('For_each_-_Account')?['Name']} [@{items('For_each_-_Account')?['aadUserId']}]\n"
}
}
},
"runAfter": {
"HTTP_-_Revoke_user_sign_in_sessions": [
"Succeeded"
]
},
"expression": {
"and": [
{
"equals": [
"@outputs('HTTP_-_Revoke_user_sign_in_sessions')['statusCode']",
200
]
}
]
},
"type": "If"
},
"HTTP_-_Revoke_user_sign_in_sessions": {
"Set_variable_-_Concatenate": {
"runAfter": {},
"type": "Http",
"type": "SetVariable",
"inputs": {
"headers": {
"Authorization": "Bearer @{body('Parse_JSON_-_Access_token')?['access_token']}",
"Host": "graph.microsoft.com"
},
"method": "POST",
"uri": "https://graph.microsoft.com/v1.0/users/@{items('For_each_-_Account')?['aadUserId']}/revokeSignInSessions"
"name": "UPN",
"value": "@{concat(items('For_each_-_Account')?['accountName'], '@', items('For_each_-_Account')?['upnSuffix'])}"
}
}
},
"runAfter": {},
"else": {
"actions": {
"Set_variable_-_aadUserID": {
"runAfter": {},
"type": "SetVariable",
"inputs": {
"name": "UPN",
"value": "@items('For_each_-_Account')['aadUserId']"
}
}
}
},
"expression": {
"and": [
{
"not": {
"equals": [
"@{items('For_each_-_Account')?['aadUserId']}",
""
]
}
"equals": [
"@items('For_each_-_Account')['aadUserId']",
"@null"
]
}
]
},
"runAfter": {},
"type": "If"
},
"Condition_-_User_session_successfully_revoked": {
"actions": {
"Append_to_string_variable_-_Affected_Microsoft_Entra_ID_Users": {
"runAfter": {},
"type": "AppendToStringVariable",
"inputs": {
"name": "Affected Microsoft Entra ID Users",
"value": "@{items('For_each_-_Account')?['Name']} [@{variables('UPN')}]\n"
}
}
},
"runAfter": {
"HTTP_-_Revoke_user_sign_in_sessions": [
"Succeeded"
]
},
"expression": {
"and": [
{
"equals": [
"@outputs('HTTP_-_Revoke_user_sign_in_sessions')['statusCode']",
200
]
}
]
},
"type": "If"
},
"HTTP_-_Revoke_user_sign_in_sessions": {
"runAfter": {
"Condition_-_Set_UPN": [
"Succeeded"
]
},
"type": "Http",
"inputs": {
"headers": {
"Authorization": "Bearer @{body('Parse_JSON_-_Access_token')?['access_token']}",
"Content-Type": "application/json",
"Host": "graph.microsoft.com"
},
"method": "POST",
"uri": "https://graph.microsoft.com/v1.0/users/@{variables('UPN')}/revokeSignInSessions"
}
}
},
"runAfter": {
@ -291,7 +311,7 @@
},
"HTTP_-_Authenticate": {
"runAfter": {
"Initialize_variable_-_Affected_Microsoft_Entra_ID_Users": [
"Initialize_variable_-_UPN": [
"Succeeded"
]
},
@ -322,6 +342,22 @@
]
}
},
"Initialize_variable_-_UPN": {
"runAfter": {
"Initialize_variable_-_Affected_Microsoft_Entra_ID_Users": [
"Succeeded"
]
},
"type": "InitializeVariable",
"inputs": {
"variables": [
{
"name": "UPN",
"type": "string"
}
]
}
},
"Parse_JSON_-_Access_token": {
"runAfter": {
"HTTP_-_Authenticate": [

Просмотреть файл

@ -1,4 +1,4 @@
# AS-Revoke-Azure-AD-User-Session-From-Entity
# AS-Revoke-Entra-ID-User-Session-From-Entity
Author: Accelerynt
@ -34,7 +34,7 @@ Click "**New registration**".
![RevokeUserSession_App_Registration_1](Images/RevokeUserSession_App_Registration_1.png)
Enter "**AS-Revoke-Azure-AD-User-Session**" for the name, all else can be left as is. Click "**Register**"
Enter "**AS-Revoke-Entra-ID-User-Session**" for the name, all else can be left as is. Click "**Register**"
![RevokeUserSession_App_Registration_2](Images/RevokeUserSession_App_Registration_2.png)
@ -79,7 +79,7 @@ Navigate to an existing key vault or create a new one. From the key vault overvi
![RevokeUserSession_Key_Vault_1](Images/RevokeUserSession_Key_Vault_1.png)
Choose a name for the secret, such as "**AS-Revoke-Azure-AD-User-Session--App-Registration-Client-Secret**", and enter the client secret copied in the [previous section](https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/AS-Revoke-Azure-AD-User-Session-From-Entity#create-an-app-registration). All other settings can be left as is. Click "**Create**".
Choose a name for the secret, such as "**AS-Revoke-Entra-ID-User-Session--App-Registration-Client-Secret**", and enter the client secret copied in the [previous section](https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/AS-Revoke-Azure-AD-User-Session-From-Entity#create-an-app-registration). All other settings can be left as is. Click "**Create**".
![RevokeUserSession_Key_Vault_2](Images/RevokeUserSession_Key_Vault_2.png)
@ -108,7 +108,7 @@ In the **Project Details** section:
In the **Instance Details** section:
* **Playbook Name**: This can be left as "**AS-Revoke-Azure-AD-User-Session-From-Entity**" or you may change it.
* **Playbook Name**: This can be left as "**AS-Revoke-Entra-ID-User-Session-From-Entity**" or you may change it.
* **Client ID**: Enter the Application (client) ID of your app registration referenced in [Create an App Registration](https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/AS-Revoke-Azure-AD-User-Session-From-Entity#create-an-app-registration).
@ -143,7 +143,7 @@ Select the "**Get**" checkbox under "**Secret permissions**", then click "**Next
![RevokeUserSession_Key_Vault_Access_2](Images/RevokeUserSession_Key_Vault_Access_2.png)
Paste "**AS-Revoke-Azure-AD-User-Session-From-Entity**" into the principal search box and click the option that appears. If the app registration also appears, select the option that does **not** match the Application (client) ID of your app registration. Click "**Next**" towards the bottom of the page.
Paste "**AS-Revoke-Entra-ID-User-Session-From-Entity**" into the principal search box and click the option that appears. If the app registration also appears, select the option that does **not** match the Application (client) ID of your app registration. Click "**Next**" towards the bottom of the page.
![RevokeUserSession_Key_Vault_Access_3](Images/RevokeUserSession_Key_Vault_Access_3.png)

Просмотреть файл

@ -2,13 +2,13 @@
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"title": "AS-Revoke-Azure-AD-User-Session-From-Entity",
"description": "This playbook is intended to be run from a Microsoft Sentinel Entity. It will look up Azure AD users associated with the account entities and revoke their sessions.",
"title": "AS-Revoke-Entra-ID-User-Session-From-Entity",
"description": "This playbook is intended to be run from a Microsoft Sentinel Entity. It will look up Entra ID users associated with the account entities and revoke their sessions.",
"prerequisites": "1. An App Registration with User.ReadWrite.All permissions granted on Microsoft Graph API. 2. A client secret for the App Registration must be generated. 3. An Azure Key Vault Secret to hold the client secret. Support for the set up and configuration of each of these items can be found here: https://github.com/Accelerynt-Security/AS-Revoke-Azure-AD-User-Session-From-Entity",
"postDeployment": ["Access to the Azure Key Vault must be granted to the playbook"],
"lastUpdateTime": "2023-10-24T3:17:47Z",
"lastUpdateTime": "2024-05-22T23:40:50Z",
"entities": ["Account"],
"tags": ["Microsoft Sentinel", "Entity", "Azure AD", "Revoke User Sessions"],
"tags": ["Microsoft Sentinel", "Entity", "Entra ID", "Revoke User Sessions"],
"support": {
"tier": "partner"
},
@ -18,7 +18,7 @@
},
"parameters": {
"PlaybookName": {
"defaultValue": "AS-Revoke-Azure-AD-User-Session-From-Entity",
"defaultValue": "AS-Revoke-Entra-ID-User-Session-From-Entity",
"type": "string",
"metadata": {
"description": "Name of the Logic App resource to be created"
@ -125,6 +125,46 @@
}
},
"actions": {
"Condition": {
"actions": {
"Set_variable_-_Concatenate": {
"inputs": {
"name": "UPN",
"value": "@{concat(triggerBody()?['Entity']?['properties']?['Name'],'@', triggerBody()?['Entity']?['properties']?['UPNSuffix'])}"
},
"runAfter": {},
"type": "SetVariable"
}
},
"else": {
"actions": {
"Set_variable_-_UID": {
"inputs": {
"name": "UPN",
"value": "@triggerBody()?['Entity']?['properties']?['AadUserId']"
},
"runAfter": {},
"type": "SetVariable"
}
}
},
"expression": {
"and": [
{
"equals": [
"@triggerBody()?['Entity']?['properties']?['AadUserId']",
"@null"
]
}
]
},
"runAfter": {
"Initialize_variable_-_UPN": [
"Succeeded"
]
},
"type": "If"
},
"Get_Client_Secret": {
"runAfter": {},
"type": "ApiConnection",
@ -157,7 +197,7 @@
},
"HTTP_-_Revoke_user_sign_in_sessions": {
"runAfter": {
"Parse_JSON_-_Access_token": [
"Condition": [
"Succeeded"
]
},
@ -165,12 +205,29 @@
"inputs": {
"headers": {
"Authorization": "Bearer @{body('Parse_JSON_-_Access_token')?['access_token']}",
"Content-Type": "application/json",
"Host": "graph.microsoft.com"
},
"method": "POST",
"uri": "https://graph.microsoft.com/v1.0/users/@{triggerBody()?['Entity']?['properties']?['AadUserId']}/revokeSignInSessions"
"uri": "https://graph.microsoft.com/v1.0/users/@{variables('UPN')}/revokeSignInSessions"
}
},
"Initialize_variable_-_UPN": {
"inputs": {
"variables": [
{
"name": "UPN",
"type": "string"
}
]
},
"runAfter": {
"Parse_JSON_-_Access_token": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Parse_JSON_-_Access_token": {
"runAfter": {
"HTTP_-_Authenticate": [

Просмотреть файл

@ -1,4 +1,4 @@
# AS-Revoke-Azure-AD-User-Session-From-Incident
# AS-Revoke-Entra-ID-User-Session-From-Incident
Author: Accelerynt
For any technical questions, please contact info@accelerynt.com
@ -33,7 +33,7 @@ Click "**New registration**".
![RevokeUserSession_App_Registration_1](Images/RevokeUserSession_App_Registration_1.png)
Enter "**AS-Revoke-Azure-AD-User-Session-From-Incident**" for the name, all else can be left as is. Click "**Register**"
Enter "**AS-Revoke-Entra-ID-User-Session-From-Incident**" for the name, all else can be left as is. Click "**Register**"
![RevokeUserSession_App_Registration_2](Images/RevokeUserSession_App_Registration_2.png)
@ -78,7 +78,7 @@ Navigate to an existing key vault or create a new one. From the key vault overvi
![RevokeUserSession_Key_Vault_1](Images/RevokeUserSession_Key_Vault_1.png)
Choose a name for the secret, such as "**AS-Revoke-Azure-AD-User-Session-From-Incident--App-Registration-Client-Secret**", and enter the client secret copied in the [previous section](https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/AS-Revoke-Azure-AD-User-Session-From-Incident#create-an-app-registration). All other settings can be left as is. Click "**Create**".
Choose a name for the secret, such as "**AS-Revoke-Entra-ID-User-Session-From-Incident--App-Registration-Client-Secret**", and enter the client secret copied in the [previous section](https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/AS-Revoke-Azure-AD-User-Session-From-Incident#create-an-app-registration). All other settings can be left as is. Click "**Create**".
![RevokeUserSession_Key_Vault_2](Images/RevokeUserSession_Key_Vault_2.png)
@ -107,7 +107,7 @@ In the **Project Details** section:
In the **Instance Details** section:
* **Playbook Name**: This can be left as "**AS-Revoke-Azure-AD-User-Session-From-Incident**" or you may change it.
* **Playbook Name**: This can be left as "**AS-Revoke-Entra-ID-User-Session-From-Incident**" or you may change it.
* **Client ID**: Enter the Application (client) ID of your app registration referenced in [Create an App Registration](https://github.com/Azure/Azure-Sentinel/tree/master/Playbooks/AS-Revoke-Azure-AD-User-Session-From-Incident#create-an-app-registration).
@ -142,7 +142,7 @@ Select the "**Get**" checkbox under "**Secret permissions**", then click "**Next
![RevokeUserSession_Key_Vault_Access_2](Images/RevokeUserSession_Key_Vault_Access_2.png)
Paste "**AS-Revoke-Azure-AD-User-Session-From-Incident**" into the principal search box and click the option that appears. If the app registration also appears, select the option that does **not** match the Application (client) ID of your app registration. Click "**Next**" towards the bottom of the page.
Paste "**AS-Revoke-Entra-ID-User-Session-From-Incident**" into the principal search box and click the option that appears. If the app registration also appears, select the option that does **not** match the Application (client) ID of your app registration. Click "**Next**" towards the bottom of the page.
![RevokeUserSession_Key_Vault_Access_3](Images/RevokeUserSession_Key_Vault_Access_3.png)
@ -166,7 +166,7 @@ Select the "**Microsoft Sentinel Contributor**" role, then click "**Next**".
![RevokeUserSession_Add_Contributor_Role_2](Images/RevokeUserSession_Add_Contributor_Role_2.png)
Select the "**Managed identity**" option, then click "**Select Members**". Under the subscription the Logic App is located, set the value of "**Managed identity**" to "**Logic app**". Next, enter "**AS-Revoke-Azure-AD-User-Session-From-Incident**", or the alternative playbook name used during deployment, in the field labeled "**Select**". Select the playbook, then click "**Select**".
Select the "**Managed identity**" option, then click "**Select Members**". Under the subscription the Logic App is located, set the value of "**Managed identity**" to "**Logic app**". Next, enter "**AS-Revoke-Entra-ID-User-Session-From-Incident**", or the alternative playbook name used during deployment, in the field labeled "**Select**". Select the playbook, then click "**Select**".
![RevokeUserSession_Add_Contributor_Role_3](Images/RevokeUserSession_Add_Contributor_Role_3.png)

Просмотреть файл

@ -2,13 +2,13 @@
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"title": "AS-Revoke-Azure-AD-User-Session-From-Incident",
"description": "This playbook is intended to be run from a Microsoft Sentinel Incident. It will look up Azure AD users associated with the incident account entities and revoke their sessions. A comment noting the affected users will be added to the Incident.",
"title": "AS-Revoke-Entra-ID-User-Session-From-Incident",
"description": "This playbook is intended to be run from a Microsoft Sentinel Incident. It will look up Entra ID users associated with the incident account entities and revoke their sessions. A comment noting the affected users will be added to the Incident.",
"prerequisites": "1. An App Registration with User.ReadWrite.All permissions granted on Microsoft Graph API. 2. A client secret for the App Registration must be generated. 3. An Azure Key Vault Secret to hold the client secret. Support for the set up and configuration of each of these items can be found here: https://github.com/Accelerynt-Security/AS-Revoke-Azure-AD-User-Session-From-Incident",
"postDeployment": ["Access to the Azure Key Vault must be granted to the playbook","The Microsoft Sentinel Contributor role must be applied to the playbook"],
"lastUpdateTime": "2023-10-24T3:17:47Z",
"lastUpdateTime": "2024-05-22T23:40:50Z",
"entities": ["Account"],
"tags": ["Microsoft Sentinel", "Incident", "Azure AD", "Revoke User Sessions"],
"tags": ["Microsoft Sentinel", "Incident", "Entra ID", "Revoke User Sessions"],
"support": {
"tier": "partner"
},
@ -18,7 +18,7 @@
},
"parameters": {
"PlaybookName": {
"defaultValue": "AS-Revoke-Azure-AD-User-Session-From-Incident",
"defaultValue": "AS-Revoke-Entra-ID-User-Session-From-Incident",
"type": "string",
"metadata": {
"description": "Name of the Logic App resource to be created"
@ -133,7 +133,7 @@
"inputs": {
"body": {
"incidentArmId": "@triggerBody()?['object']?['id']",
"message": "<p><strong>Revoked the following Azure AD user sessions:<br>\n</strong>@{variables('Affected Azure AD Users')}</p>"
"message": "<p><strong>Revoked the following Entra ID user sessions:<br>\n</strong>@{variables('Affected Entra ID Users')}</p>"
},
"host": {
"connection": {
@ -154,7 +154,7 @@
"and": [
{
"greater": [
"@length(variables('Affected Azure AD Users'))",
"@length(variables('Affected Entra ID Users'))",
0
]
}
@ -179,14 +179,50 @@
"For_each": {
"foreach": "@body('Entities_-_Get_Accounts')?['Accounts']",
"actions": {
"Condition_-_Determine_which_value_to_use_for_UPN": {
"actions": {
"Set_variable_-_Concatenate_Account_Name_and_UPN_Suffix": {
"runAfter": {},
"type": "SetVariable",
"inputs": {
"name": "UPN",
"value": "@{concat(items('For_each')?['accountName'],'@', items('For_each')?['upnSuffix'])}"
}
}
},
"runAfter": {},
"else": {
"actions": {
"Set_variable_-_Use_AadUserId_for_UPN": {
"runAfter": {},
"type": "SetVariable",
"inputs": {
"name": "UPN",
"value": "@{items('For_each')?['AadUserId']}"
}
}
}
},
"expression": {
"and": [
{
"equals": [
"@items('For_each')?['AadUserId']",
"@null"
]
}
]
},
"type": "If"
},
"Condition_-_User_session_successfully_revoked": {
"actions": {
"Append_to_string_variable_-_Affected_Azure_AD_Users": {
"Append_to_string_variable_-_Affected_Entra_ID_Users": {
"runAfter": {},
"type": "AppendToStringVariable",
"inputs": {
"name": "Affected Azure AD Users",
"value": "@{items('For_each')?['Name']} [@{items('For_each')?['AadUserId']}]\n"
"name": "Affected Entra ID Users",
"value": "@{items('For_each')?['accountName']} [@{variables('UPN')}]\n"
}
}
},
@ -208,15 +244,20 @@
"type": "If"
},
"HTTP_-_Revoke_user_sign_in_sessions": {
"runAfter": {},
"runAfter": {
"Condition_-_Determine_which_value_to_use_for_UPN": [
"Succeeded"
]
},
"type": "Http",
"inputs": {
"headers": {
"Authorization": "Bearer @{body('Parse_JSON_-_Access_token')?['access_token']}",
"Content-Type": "application/json",
"Host": "graph.microsoft.com"
},
"method": "POST",
"uri": "https://graph.microsoft.com/v1.0/users/@{items('For_each')?['AadUserId']}/revokeSignInSessions"
"uri": "https://graph.microsoft.com/v1.0/users/@{variables('UPN')}/revokeSignInSessions"
}
}
},
@ -246,7 +287,7 @@
},
"HTTP_-_Authenticate": {
"runAfter": {
"Initialize_variable_-_Affected_Azure_AD_Users": [
"Initialize_variable_-_UPN": [
"Succeeded"
]
},
@ -261,7 +302,7 @@
"uri": "[concat('https://login.microsoftonline.com/', subscription().tenantId, '/oauth2/v2.0/token')]"
}
},
"Initialize_variable_-_Affected_Azure_AD_Users": {
"Initialize_variable_-_Affected_Entra_ID_Users": {
"runAfter": {
"Get_Client_Secret": [
"Succeeded"
@ -271,7 +312,23 @@
"inputs": {
"variables": [
{
"name": "Affected Azure AD Users",
"name": "Affected Entra ID Users",
"type": "string"
}
]
}
},
"Initialize_variable_-_UPN": {
"runAfter": {
"Initialize_variable_-_Affected_Entra_ID_Users": [
"Succeeded"
]
},
"type": "InitializeVariable",
"inputs": {
"variables": [
{
"name": "UPN",
"type": "string"
}
]
@ -337,4 +394,4 @@
}
}
]
}
}

Просмотреть файл

@ -0,0 +1,29 @@
[{
"severity": 6,
"anomaly_sub_type": "File Type",
"severity": "High",
"originating_client": "client_name",
"affected_files_count": 100,
"modified_files_count": 20,
"deleted_files_count": 5,
"renamed_files_count": 10,
"created_files_count": 15,
"job_start_time": "2023-01-01 12:00:00",
"job_end_time": "2023-01-01 13:00:00",
"eventCode": "234881361",
"jobId": 176312,
"acknowledge": 0,
"eventCodeString": "14:337",
"subsystem": "CvStatAnalysis",
"files_list": ["file1.txt", "file2.txt"],
"scanned_folder_list": ["/folder1", "/folder2"],
"description": "<html>Detected file type classification anomaly in job [176312] for client [client_name]. Number of files affected [1340]. Please click <a href='http://webservice_url.commvault.com:80/commandcenter/#/fileAnomaly/5185?anomalyTypes=mime'> here</a> for more details.<span style='display: none'>AnomalyType:[2];ClientName:[client_name];BackupSetName:[defaultBackupSet];SubclientName:[AnomalySubclient];SuspiciousFileCount:[1340];ModifiedFileCount:[0];RenamedFileCount:[0];CreatedFileCount:[0];DeletedFileCount:[0];ApplicationType:[33];BackupSetId:[0];SubclientId:[0];JobId:[176312]</span></html>'",
"id": 4627966,
"timeSource": 1683622448,
"type": 0,
"clientEntity": {
"clientId": 5185,
"clientName": "client_name",
"displayName": "client_name"
}
}]

Просмотреть файл

@ -0,0 +1,29 @@
[{
"severity": 6,
"anomaly_sub_type": "File Type",
"severity": "High",
"originating_client": "client_name",
"affected_files_count": 100,
"modified_files_count": 20,
"deleted_files_count": 5,
"renamed_files_count": 10,
"created_files_count": 15,
"job_start_time": "2023-01-01 12:00:00",
"job_end_time": "2023-01-01 13:00:00",
"eventCode": "234881361",
"jobId": 176312,
"acknowledge": 0,
"eventCodeString": "14:337",
"subsystem": "CvStatAnalysis",
"files_list": ["file1.txt", "file2.txt"],
"scanned_folder_list": ["/folder1", "/folder2"],
"description": "<html>Detected file type classification anomaly in job [176312] for client [client_name]. Number of files affected [1340]. Please click <a href='http://webservice_url.commvault.com:80/commandcenter/#/fileAnomaly/5185?anomalyTypes=mime'> here</a> for more details.<span style='display: none'>AnomalyType:[2];ClientName:[client_name];BackupSetName:[defaultBackupSet];SubclientName:[AnomalySubclient];SuspiciousFileCount:[1340];ModifiedFileCount:[0];RenamedFileCount:[0];CreatedFileCount:[0];DeletedFileCount:[0];ApplicationType:[33];BackupSetId:[0];SubclientId:[0];JobId:[176312]</span></html>'",
"id": 4627966,
"timeSource": 1683622448,
"type": 0,
"clientEntity": {
"clientId": 5185,
"clientName": "client_name",
"displayName": "client_name"
}
}]

Просмотреть файл

@ -1,62 +1,136 @@
[{
"vendor": "FortiNDRCloudExample",
"product": "FNC",
"signal_version": "1",
"event_type": "detection",
"subject": "none",
"timestamp": "1970-01-01T15:05:01.139Z",
"device_ip": "192.80.44.123",
"name": "Sample Rule Name",
"category": "Sample Rule Detection Category",
"severity": "low",
"confidence": "high",
"sensor_id": "bob999",
"muted": false,
"uuid": "db4148cc-fe79-4d16-9feb-ddbd026e679e",
"rule_uuid": "b43a7ca9-b5d2-494f-b28d-d8741d4aabca",
"device_ip": "12.34.5.678",
"sensor_id": "fnc1",
"account_uuid": "f342c92b-8b32-4341-a345-8ff2077403c5",
"status": "resolved",
"muted_device_uuid": null,
"muted_rule": false,
"rule_uuid": "65ca67e0-5a28-4eb6-912e-577b93bb3b7f",
"muted_comment": "",
"first_seen": "1970-01-01T14:58:45.447Z",
"last_seen": "1970-01-01T14:59:05.536Z",
"created": "1970-01-01T14:58:45.447Z",
"updated": "1970-01-01T14:58:45.447Z",
"uuid": "2a497a81-3706-42be-8c04-da9f3b66e625",
"status": "active",
"muted": false,
"muted_comment": null,
"muted_user_uuid": null,
"muted_timestamp": null,
"resolution_user_uuid": null,
"resolution_timestamp": "1970-05-05T00:30:37.227088Z",
"resolution": "auto_resolved",
"resolution_comment": null,
"indicators": [
{
"field": "dst.ip",
"values": [
"123.234.456.78"
"123.45.678.901"
]
},
{
"field": "ssl:issuer",
"field": "http:host",
"values": [
"Sample usdrasdfkl;jzfg;nmadfg;jdfgSDRESRWERzdfgadf"
"234.56.789.012"
]
},
{
"field": "ssl:server_name_indication",
"field": "http:uri.uri",
"values": [
"123-234-345-56.fortinet.sample.com"
"/ab3c"
]
},
{
"field": "ssl:subject",
"field": "http:user_agent",
"values": [
"CN=*.fortinet.sample.com"
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"
]
}
],
"customer_id": "fortindrcloud",
"primary_dhcp_machost_pairs": [
"c1:2a:b3:df:45:46/ENEDEF5EW3"
"event_count": 1,
"username": null,
"hostname": null,
"first_seen": "1970-01-01T00:10:39.909645Z",
"last_seen": "1970-01-01T00:30:00.562892Z",
"created": "1970-01-01T00:23:31.344038Z",
"updated": "1970-01-01T00:42:35.972781Z",
"rule_name": "FNC example rule name",
"rule_severity": "high",
"rule_confidence": "moderate",
"rule_category": "FNC Example Rule Category",
"PDNS": [
{
"resolved": "fortinet.fortindrcloud-dns.com",
"first_seen": "1970-01-01T00:00:00.000Z",
"last_seen": "1970-01-01T00:00:00.000Z",
"record_type": "a",
"source": "fnc_dns",
"customer_id": null,
"account_uuid": "f342c92b-8b32-4341-a345-8ff2077403c5",
"sensor_id": "fnc123"
}
],
"other_dhcp_machost_pairs": [
"12:3c:0a:g5:12:dc/H1789-9Rp1-12DC",
"12:3c:0a:g5:21:b8/H1789-9Rp1-21B8",
"12:3c:0a:g5:11:34/H1789-9Rp1-1134",
"12:3c:0a:67:3b:14/H1789-9M64-3B14",
"12:3c:0a:67:07:54/H1789-9M64-0754",
"a1:b2:3c:67:tt:po/FOFPL2M0KS2"
"dhcp": [
{
"customer_id": "abc",
"sensor_id": null,
"ip": "12.12.1.123",
"mac": "12:ab:c3:45:6d:e7",
"lease_start": "1970-01-01T04:45:18.043Z",
"lease_end": null,
"hostnames": [],
"start_lease_as_long": 1667191518043
}
],
"events": [
{
"rule_uuid": "b43a7ca9-b5d2-494f-b28d-d8741d4aabca",
"event": {
"event_type": "observation",
"uuid": "21cac053-04b2-11ef-bd63-02423399754b",
"customer_id": "abc",
"sensor_id": "abc123",
"timestamp": "1970-04-27T14:24:13.450Z",
"flow_id": null,
"src": {
"ip": "23.23.2.234",
"port": null,
"ip_bytes": null,
"pkts": null,
"geo": null,
"asn": null,
"internal": true
},
"dst": {
"ip": "123.456.789.01",
"port": null,
"ip_bytes": null,
"pkts": null,
"geo": {
"location": null,
"country": "RU",
"subdivision": null,
"city": null
},
"asn": {
"asn": 59504,
"org": "SOME ORG",
"isp": "SOME ORG",
"asn_org": "SOME ORG"
},
"internal": false
},
"geo_distance": null,
"intel": null,
"source": "Fortinet",
"evidence_end_timestamp": "1970-04-27T14:24:17.966Z",
"evidence_iql": "event_type = 'ftp'",
"evidence_start_timestamp": "1970-04-27T14:24:13.450Z",
"observation_category": "flow",
"observation_class": "specific",
"observation_confidence": "low",
"observation_context": "{'FTP Username':'exampleusername','Filenames':['FNC_Example_NDR_1970_01_01_12_40_53.html','FNC_Example_NDR_2_1970_01_01_12_41_07.html'],'Time Since FTP Server First Seen in Last 30 Days':'0.000s','Time Since Username First Seen in Last 30 Days':'0.000s'}",
"observation_description": "Potential data exfiltration to an external FTP server.",
"observation_title": "Suspicious File Write to External FTP Server",
"observation_uuid": "a094fb82-f2db-4814-a3dd-17043577c59d",
"sensor_ids": [
"abc123"
]
}
}
]
}]

Двоичный файл не отображается.

Просмотреть файл

@ -10,6 +10,8 @@ import azure.durable_functions as df
API_HOST = os.environ.get('API_HOST', 'https://api.abnormalplatform.com/v1')
MAX_THREATS = int(os.environ.get('MAX_NUMBER_OF_THREATS', 120))
TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
TIME_FORMAT_WITHMS = "%Y-%m-%dT%H:%M:%S.%fZ"
class Resources(Enum):
threats = 0
@ -46,7 +48,7 @@ class AbnormalSoarConnectorAsync:
return {
"Authorization": f"Bearer {self.api_key}",
"Soar-Integration-Origin": "AZURE SENTINEL",
"Azure-Sentinel-Version": "2023-11-09"
"Azure-Sentinel-Version": "2024-05-29"
}
def _get_filter_query(self, filter_param, gte_datetime=None, lte_datetime=None):
@ -74,7 +76,46 @@ class AbnormalSoarConnectorAsync:
return f"{self.BASEURL}/{resource_name}/{resource_id}"
def _extract_messages(self, context, threat_resp):
return [message for message in threat_resp.get("messages") if message.get("receivedTime") >= context.get("gte_datetime") and message.get("receivedTime") <= context.get("lte_datetime")]
threat_id = threat_resp.get("threatId")
gte_datetime_str = context['gte_datetime']
lte_datetime_str = context['lte_datetime']
ctx = {
"threat_id": threat_id,
"gte_datetime_str": gte_datetime_str,
"lte_datetime_str": lte_datetime_str
}
try:
gte_datetime = datetime.strptime(gte_datetime_str, TIME_FORMAT)
lte_datetime = datetime.strptime(lte_datetime_str, TIME_FORMAT)
except Exception as e:
logging.error(f"Failed to parse time for threat_id: {ctx} with error {e}")
return []
filtered_messages = []
for message in threat_resp.get("messages"):
message_id = message.get("abxMessageId")
remediation_time_str = message.get("remediationTimestamp")
ctx = {
**ctx,
"message_id": message_id,
"remediation_time_str": remediation_time_str
}
try:
remediation_time = datetime.strptime(remediation_time_str, TIME_FORMAT_WITHMS)
if remediation_time >= gte_datetime and remediation_time <= lte_datetime:
filtered_messages.append(message)
logging.info(f"Successfully processed message for threat: {ctx}")
else:
logging.warn(f"Skipped processing message for threat: {ctx}")
except Exception as e:
logging.error(f"Failed to process message for threat: {ctx} with error {e}")
return filtered_messages
def _extract_message_ids(self, threats_resp):
return [threat.get("threatId") for threat in threats_resp.get('threats', [])]
@ -137,8 +178,8 @@ class AbnormalSoarConnectorAsync:
"""
gte_datetime_str = context['gte_datetime']
lte_datetime_str = context['lte_datetime']
gte_datetime = datetime.strptime(gte_datetime_str, "%Y-%m-%dT%H:%M:%SZ")
lte_datetime = datetime.strptime(lte_datetime_str, "%Y-%m-%dT%H:%M:%SZ")
gte_datetime = datetime.strptime(gte_datetime_str, TIME_FORMAT)
lte_datetime = datetime.strptime(lte_datetime_str, TIME_FORMAT)
if (lte_datetime - gte_datetime) <= timedelta(minutes=1):
logging.warning("Reached minimum date range for filter query")
@ -157,10 +198,10 @@ class AbnormalSoarConnectorAsync:
try:
gte_datetime_str = threats_date_filter['gte_datetime']
lte_datetime_str = threats_date_filter['lte_datetime']
gte_datetime = datetime.strptime(gte_datetime_str, "%Y-%m-%dT%H:%M:%SZ")
lte_datetime = datetime.strptime(lte_datetime_str, "%Y-%m-%dT%H:%M:%SZ")
gte_datetime = datetime.strptime(gte_datetime_str, TIME_FORMAT)
lte_datetime = datetime.strptime(lte_datetime_str, TIME_FORMAT)
midpoint_datetime = gte_datetime + (lte_datetime - gte_datetime) / 2
midpoint_datetime_str = midpoint_datetime.strftime("%Y-%m-%dT%H:%M:%SZ")
midpoint_datetime_str = midpoint_datetime.strftime(TIME_FORMAT)
threats_date_filter['lte_datetime'] = midpoint_datetime_str
logging.warning(f"Halved date range, too many results. New date range is {gte_datetime_str} - {midpoint_datetime_str}")
except Exception as e:

Просмотреть файл

Просмотреть файл

@ -0,0 +1,106 @@
import unittest
from ..SentinelFunctionsOrchestrator.soar_connector_async import AbnormalSoarConnectorAsync
from copy import deepcopy
DUMMY_API_KEY = "DUMMY_API_KEY"
NUM_CONSUMERS = 0
class TestAbnormalSoarConnectorAsync(unittest.TestCase):
threat_resp = {
"threatId": "40080400-6300-9600-f800-afb76fd00000",
"messages": [
{
"abxMessageId": 4670020130001212344,
"receivedTime": "2024-05-07T08:09:00Z",
"remediationTimestamp": "2024-05-07T08:09:03.183578Z"
},
{
"abxMessageId": 4670020130001212345,
"receivedTime": "2024-05-07T08:09:00Z",
"remediationTimestamp": "2024-05-07T08:10:03.183578Z"
},
{
"abxMessageId": 4670020130001212346,
"receivedTime": "2024-05-07T08:09:00Z",
"remediationTimestamp": "2024-05-07T08:15:03.183578Z"
}
]
}
context = {
"gte_datetime": "2024-05-07T08:10:00Z",
"lte_datetime": "2024-05-07T08:15:00Z"
}
def test_wrong_time_format_in_context(self):
# Initialize values
threat_response = deepcopy(self.threat_resp)
context = deepcopy(self.context)
connector = AbnormalSoarConnectorAsync(DUMMY_API_KEY, NUM_CONSUMERS)
# Override values
context["lte_datetime"] = "2024-05-0708:15:00Z"
result = connector._extract_messages(context, threat_response)
self.assertEqual(len(result), 0)
def test_wrong_time_format_in_remediation_timestamp(self):
# Initialize values
threat_response = deepcopy(self.threat_resp)
context = deepcopy(self.context)
connector = AbnormalSoarConnectorAsync(DUMMY_API_KEY, NUM_CONSUMERS)
# Override values
threat_response["messages"][1]["remediationTimestamp"] = "2024-05-07T08:10:03Z"
result = connector._extract_messages(context, threat_response)
self.assertEqual(len(result), 0)
def test_correct_flow_with_one_filtered_message(self):
# Initialize values
threat_response = deepcopy(self.threat_resp)
context = deepcopy(self.context)
connector = AbnormalSoarConnectorAsync(DUMMY_API_KEY, NUM_CONSUMERS)
result = connector._extract_messages(context, threat_response)
self.assertEqual(len(result), 1)
self.assertEqual(result[0]["abxMessageId"], 4670020130001212345)
def test_correct_flow_with_two_filtered_message(self):
# Initialize values
threat_response = deepcopy(self.threat_resp)
context = deepcopy(self.context)
connector = AbnormalSoarConnectorAsync(DUMMY_API_KEY, NUM_CONSUMERS)
context = {
"gte_datetime": "2024-05-07T08:09:00Z",
"lte_datetime": "2024-05-07T08:15:00Z"
}
result = connector._extract_messages(context, threat_response)
self.assertEqual(len(result), 2)
self.assertEqual(result[0]["abxMessageId"], 4670020130001212344)
self.assertEqual(result[1]["abxMessageId"], 4670020130001212345)
def test_correct_flow_with_three_filtered_message(self):
# Initialize values
threat_response = deepcopy(self.threat_resp)
context = deepcopy(self.context)
connector = AbnormalSoarConnectorAsync(DUMMY_API_KEY, NUM_CONSUMERS)
context = {
"gte_datetime": "2024-05-07T08:09:00Z",
"lte_datetime": "2024-05-07T08:16:00Z"
}
result = connector._extract_messages(context, threat_response)
self.assertEqual(len(result), 3)
self.assertEqual(result[0]["abxMessageId"], 4670020130001212344)
self.assertEqual(result[1]["abxMessageId"], 4670020130001212345)
self.assertEqual(result[2]["abxMessageId"], 4670020130001212346)

Просмотреть файл

@ -13,7 +13,7 @@ relevantTechniques:
- T1619
query: |
AWSCloudTrail
| where EventName == "GetObject" and isempty(ErrorCode) and isempty(ErrorMessage)
| where EventName == "GetObject" and not(isempty(ErrorCode) and isempty(ErrorMessage))
| where UserIdentityAccountId == "ANONYMOUS_PRINCIPAL" or UserIdentityAccessKeyId <> RecipientAccountId
| extend bucketName = tostring(parse_json(RequestParameters).bucketName), keyName = tostring(parse_json(RequestParameters).key)
| summarize arg_max(TimeGenerated, *), failed_attempts = dcount(keyName) by UserIdentityAccountId, SourceIpAddress, bucketName
@ -28,4 +28,4 @@ entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
columnName: IPCustomEntity

Двоичные данные
Solutions/Amazon Web Services/Package/3.0.3.zip Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -6,7 +6,7 @@
"config": {
"isWizard": false,
"basics": {
"description": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/Aws.svg\" width=\"75px\" height=\"75px\">\n\n**Note:** Please refer to the following before installing the solution: \n\n• Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/Amazon%20Web%20Services/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe Amazon Web Services solution for Microsoft Sentinel allows you to enable Security monitoring of AWS services by allowing ingestion of logs from the AWS CloudTrail platform, VPC Flow Logs, AWS GuardDuty and AWS CloudWatch.\n\n**Data Connectors:** 2, **Workbooks:** 2, **Analytic Rules:** 57, **Hunting Queries:** 36\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)",
"description": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/Aws.svg\" width=\"75px\" height=\"75px\">\n\n**Note:** Please refer to the following before installing the solution: \n\n• Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/Amazon%20Web%20Services/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe Amazon Web Services solution for Microsoft Sentinel allows you to enable Security monitoring of AWS services by allowing ingestion of logs from the AWS CloudTrail platform, VPC Flow Logs, AWS GuardDuty and AWS CloudWatch. \n\n**Data Connectors:** 2, **Workbooks:** 2, **Analytic Rules:** 57, **Hunting Queries:** 36\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)",
"subscription": {
"resourceProviders": [
"Microsoft.OperationsManagement/solutions",
@ -180,7 +180,7 @@
"name": "analytic2-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Amazon Virtual Private Cloud (Amazon VPC) lets you provision a logically isolated section of the AWS Cloud where you can launch AWS resources\nin a virtual network that you define.\nThis identifies changes to Amazon VPC (Virtual Private Cloud) settings such as new ACL entries,routes, routetable or Gateways.\nMore information: https://medium.com/@GorillaStack/the-most-important-aws-cloudtrail-security-events-to-track-a5b9873f8255 \nand AWS VPC API Docs: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/OperationList-query-vpc.html"
"text": "Amazon Virtual Private Cloud (Amazon VPC) lets you provision a logically isolated section of the AWS Cloud where you can launch AWS resources in a virtual network that you define.\nThis identifies changes to Amazon VPC (Virtual Private Cloud) settings such as new ACL entries,routes, routetable or Gateways.\nMore information: https://medium.com/@GorillaStack/the-most-important-aws-cloudtrail-security-events-to-track-a5b9873f8255 \nand AWS VPC API Docs: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/OperationList-query-vpc.html"
}
}
]
@ -222,7 +222,7 @@
"name": "analytic5-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Multi-Factor Authentication (MFA) helps you to prevent credential compromise. This alert identifies logins to the AWS Management Console without MFA.\nYou can limit this detection to trigger for adminsitrative accounts if you do not have MFA enabled on all accounts.\nThis is done by looking at the eventName ConsoleLogin and if the AdditionalEventData field indicates MFA was NOT used\nand the ResponseElements field indicates NOT a Failure. Thereby indicating that a non-MFA login was successful."
"text": "Multi-Factor Authentication (MFA) helps you to prevent credential compromise. This alert identifies logins to the AWS Management Console without MFA.\nYou can limit this detection to trigger for adminsitrative accounts if you do not have MFA enabled on all accounts.\nThis is done by looking at the eventName ConsoleLogin and if the AdditionalEventData field indicates MFA was NOT used and the ResponseElements field indicates NOT a Failure. Thereby indicating that a non-MFA login was successful."
}
}
]
@ -292,7 +292,7 @@
"name": "analytic10-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Multi-Factor Authentication (MFA) helps you to prevent credential compromise. This alert identifies logins to the AWS Management Console without MFA.\nYou can limit this detection to trigger for administrative accounts if you do not have MFA enabled on all accounts.\nThis is done by looking at the eventName ConsoleLogin and if the AdditionalEventData field indicates MFA was NOT used\nand the ResponseElements field indicates NOT a Failure. Thereby indicating that a non-MFA login was successful."
"text": "Multi-Factor Authentication (MFA) helps you to prevent credential compromise. This alert identifies logins to the AWS Management Console without MFA.\nYou can limit this detection to trigger for administrative accounts if you do not have MFA enabled on all accounts.\nThis is done by looking at the eventName ConsoleLogin and if the AdditionalEventData field indicates MFA was NOT used and the ResponseElements field indicates NOT a Failure. Thereby indicating that a non-MFA login was successful."
}
}
]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,5 +1,6 @@
| **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** |
|-------------|--------------------------------|---------------------------------------------|
| 3.0.3 | 27-05-2024 | Updated **Hunting Query** AWS_FailedBruteForceS3Bucket.yaml |
| 3.0.2 | 05-04-2024 | Updated awsS3 **Data connector**, added new Data Type CloudWatch |
| 3.0.1 | 22-12-2023 | Added new **Analytic Rule** (AWS Config Service Resource Deletion Attempts) |
| 3.0.0 | 04-12-2023 | Updated **Analytical Rule** AWS_GuardDuty_template with entity mappings |

Просмотреть файл

@ -26,6 +26,9 @@ requiredDataConnectors:
- connectorId: CiscoASA
dataTypes:
- CommonSecurityLog
- connectorId: CiscoAsaAma
dataTypes:
- CommonSecurityLog
- connectorId: PaloAltoNetworks
dataTypes:
- CommonSecurityLog
@ -210,5 +213,5 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: IPEntity
version: 2.0.4
version: 2.0.5
kind: Scheduled

Просмотреть файл

@ -50,7 +50,7 @@
],
"BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\Apache Log4j Vulnerability Detection",
"Metadata": "SolutionMetadata.json",
"Version": "3.0.3",
"Version": "3.0.4",
"TemplateSpec": true,
"Is1Pconnector": true
}

Просмотреть файл

@ -13,6 +13,9 @@ requiredDataConnectors:
- connectorId: CiscoASA
dataTypes:
- CommonSecurityLog (Cisco)
- connectorId: CiscoAsaAma
dataTypes:
- CommonSecurityLog (Cisco)
- connectorId: PaloAltoNetworks
dataTypes:
- CommonSecurityLog (PaloAlto)
@ -59,4 +62,4 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: DestinationIP
version: 1.0.2
version: 1.0.3

Двоичные данные
Solutions/Apache Log4j Vulnerability Detection/Package/3.0.4.zip Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -6,7 +6,7 @@
"config": {
"isWizard": false,
"basics": {
"description": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Apache%20Log4j%20Vulnerability%20Detection/Workbooks/Images/Logos/Log4j.svg\" width=\"150px\" height=\"75px\">\n\n**Note:** Please refer to the following before installing the solution: \r \n • Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/Apache%20Log4j%20Vulnerability%20Detection/ReleaseNotes.md)\r \n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nMicrosoft's security research teams have been tracking threats taking advantage of [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2021-44228), a remote code execution (RCE) vulnerability in [Apache Log4j 2](https://logging.apache.org/log4j/2.x/) referred to as “Log4Shell”. The vulnerability allows unauthenticated remote code execution, and it is triggered when a specially crafted string provided by the attacker through a variety of different input vectors is parsed and processed by the Log4j 2 vulnerable component. For more technical and mitigation information about the vulnerability, please read the [Microsoft Security Response Center blog](https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/). This solution provides content to monitor, detect and investigate signals related to exploitation of this vulnerability in Microsoft Sentinel.\n\n**Prerequisite :-**\n\n This is a [domain solution](https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fsentinel%2Fsentinel-solutions-catalog%23domain-solutions&data=05%7C01%7Ckavishbakshi%40microsoft.com%7Cbe2a496082b24caa4b8c08da9cefacca%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637994850502413731%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=OJegu%2B2EqD7rmYmK9pm9QniD6YWp5ooloZ6tHzcwVi0%3D&reserved=0) and does not include any data connectors. Install one or more of the listed solutions, or develop your custom ASIM parsers to unlock the value provided by this solution.\n 1. Azure Web Application Firewall (WAF) \n 2. Microsoft 365 \n 3. Windows Server DNS \n 4. CiscoASA \n 5. PaloAlto-PAN-OS \n 6. Microsoft Entra ID \n 7. Azure Activity \n 8. Amazon Web Services \n 9. Azure Firewall \n 10. SquidProxy \n 11. Zscaler Private Access (ZPA) \n 12. Syslog \n 13. Check Point \n 14. Microsoft Defender XDR\n\n**Workbooks:** 2, **Analytic Rules:** 4, **Hunting Queries:** 10, **Watchlists:** 1, **Playbooks:** 2\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)",
"description": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Apache%20Log4j%20Vulnerability%20Detection/Workbooks/Images/Logos/Log4j.svg\" width=\"150px\" height=\"75px\">\n\n**Note:** Please refer to the following before installing the solution: \n\n• Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/Apache%20Log4j%20Vulnerability%20Detection/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nMicrosoft's security research teams have been tracking threats taking advantage of [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2021-44228), a remote code execution (RCE) vulnerability in [Apache Log4j 2](https://logging.apache.org/log4j/2.x/) referred to as “Log4Shell”. The vulnerability allows unauthenticated remote code execution, and it is triggered when a specially crafted string provided by the attacker through a variety of different input vectors is parsed and processed by the Log4j 2 vulnerable component. For more technical and mitigation information about the vulnerability, please read the [Microsoft Security Response Center blog](https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/). This solution provides content to monitor, detect and investigate signals related to exploitation of this vulnerability in Microsoft Sentinel.\n\n**Prerequisite :-**\n\n This is a [domain solution](https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fsentinel%2Fsentinel-solutions-catalog%23domain-solutions&data=05%7C01%7Ckavishbakshi%40microsoft.com%7Cbe2a496082b24caa4b8c08da9cefacca%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637994850502413731%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=OJegu%2B2EqD7rmYmK9pm9QniD6YWp5ooloZ6tHzcwVi0%3D&reserved=0) and does not include any data connectors. Install one or more of the listed solutions, or develop your custom ASIM parsers to unlock the value provided by this solution.\n 1. Azure Web Application Firewall (WAF) \n 2. Microsoft 365 \n 3. Windows Server DNS \n 4. CiscoASA \n 5. PaloAlto-PAN-OS \n 6. Microsoft Entra ID \n 7. Azure Activity \n 8. Amazon Web Services \n 9. Azure Firewall \n 10. SquidProxy \n 11. Zscaler Private Access (ZPA) \n 12. Syslog \n 13. Check Point \n 14. Microsoft Defender XDR\n\n**Workbooks:** 2, **Analytic Rules:** 4, **Hunting Queries:** 10, **Watchlists:** 1, **Playbooks:** 2\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)",
"subscription": {
"resourceProviders": [
"Microsoft.OperationsManagement/solutions",
@ -142,7 +142,7 @@
"name": "analytic1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This query uses the Azure Defender Security Nested Recommendations data to find machines vulnerable to log4j CVE-2021-44228. Log4j is an open-source Apache logging library that is used in\n many Java-based applications. Security Nested Recommendations data is sent to Microsoft Sentinel using the continuous export feature of Azure Defender(refrence link below).\n Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/\n Reference: https://docs.microsoft.com/azure/security-center/continuous-export?tabs=azure-portal\n Reference: https://techcommunity.microsoft.com/t5/microsoft-defender-for-cloud/how-defender-for-cloud-displays-machines-affected-by-log4j/ba-p/3037271"
"text": "This query uses the Azure Defender Security Nested Recommendations data to find machines vulnerable to log4j CVE-2021-44228.\nLog4j is an open-source Apache logging library that is used in many Java-based applications. Security Nested Recommendations data is sent to Microsoft Sentinel using the continuous export feature of Azure Defender(refrence link below).\n Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/\n Reference: https://docs.microsoft.com/azure/security-center/continuous-export?tabs=azure-portal\n Reference: https://techcommunity.microsoft.com/t5/microsoft-defender-for-cloud/how-defender-for-cloud-displays-machines-affected-by-log4j/ba-p/3037271"
}
}
]
@ -156,7 +156,7 @@
"name": "analytic2-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This query will alert on a positive pattern match by Azure WAF for CVE-2021-44228 log4j vulnerability exploitation attempt. If possible, it then decodes the malicious command for further analysis.\n Refrence: https://www.microsoft.com/security/blog/2021/12/11/guidance-for-preventing-detecting-and-hunting-for-cve-2021-44228-log4j-2-exploitation/"
"text": "This query will alert on a positive pattern match by Azure WAF for CVE-2021-44228 log4j vulnerability exploitation attempt. If possible, it then decodes the malicious command for further analysis.\n Reference: https://www.microsoft.com/security/blog/2021/12/11/guidance-for-preventing-detecting-and-hunting-for-cve-2021-44228-log4j-2-exploitation/"
}
}
]
@ -184,7 +184,7 @@
"name": "analytic4-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This query uses various log sources having user agent data to look for log4j CVE-2021-44228 exploitation attempt based on user agent pattern. Log4j is an open-source Apache logging library that is used in \n many Java-based applications. The regex and the string matching look for the most common attacks. This might not be comprehensive to detect every possible user agent variation.\n Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/"
"text": "This query uses various log sources having user agent data to look for log4j CVE-2021-44228 exploitation attempt based on user agent pattern.\nLog4j is an open-source Apache logging library that is used in many Java-based applications. The regex and the string matching look for the most common attacks. This might not be comprehensive to detect every possible user agent variation.\n Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/"
}
}
]
@ -348,7 +348,7 @@
"name": "huntingquery10-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This query detects outbound network connections using the LDAP protocol to external IP addresses that have not had an LDAP network connection in the past 14 days. This could indicate exploitation of CVE-2021-44228 vulnerability. This hunting query depends on CheckPoint CiscoASA PaloAltoNetworks data connector (CommonSecurityLog (CheckPoint) CommonSecurityLog (Cisco) CommonSecurityLog (PaloAlto) Parser or Table)"
"text": "This query detects outbound network connections using the LDAP protocol to external IP addresses that have not had an LDAP network connection in the past 14 days. This could indicate exploitation of CVE-2021-44228 vulnerability. This hunting query depends on CheckPoint CiscoASA CiscoAsaAma PaloAltoNetworks data connector (CommonSecurityLog (CheckPoint) CommonSecurityLog (Cisco) CommonSecurityLog (Cisco) CommonSecurityLog (PaloAlto) Parser or Table)"
}
}
]
@ -384,7 +384,7 @@
"name": "watchlist1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Watchlist provide lookup for IOC of different sources."
"text": "[parameters('watchlistdescription')]"
}
}
]

Просмотреть файл

@ -57,7 +57,7 @@
"email": "support@microsoft.com",
"_email": "[variables('email')]",
"_solutionName": "Apache Log4j Vulnerability Detection",
"_solutionVersion": "3.0.3",
"_solutionVersion": "3.0.4",
"solutionId": "azuresentinel.azure-sentinel-solution-apachelog4jvulnerability",
"_solutionId": "[variables('solutionId')]",
"workbookVersion1": "1.0.0",
@ -74,32 +74,32 @@
"_workbookContentId2": "[variables('workbookContentId2')]",
"_workbookcontentProductId2": "[concat(take(variables('_solutionId'),50),'-','wb','-', uniqueString(concat(variables('_solutionId'),'-','Workbook','-',variables('_workbookContentId2'),'-', variables('workbookVersion2'))))]",
"analyticRuleObject1": {
"analyticRuleVersion1": "1.0.2",
"analyticRuleVersion1": "1.0.3",
"_analyticRulecontentId1": "3d71fc38-f249-454e-8479-0a358382ef9a",
"analyticRuleId1": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '3d71fc38-f249-454e-8479-0a358382ef9a')]",
"analyticRuleTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('3d71fc38-f249-454e-8479-0a358382ef9a')))]",
"_analyticRulecontentProductId1": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','3d71fc38-f249-454e-8479-0a358382ef9a','-', '1.0.2')))]"
"_analyticRulecontentProductId1": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','3d71fc38-f249-454e-8479-0a358382ef9a','-', '1.0.3')))]"
},
"analyticRuleObject2": {
"analyticRuleVersion2": "1.0.3",
"analyticRuleVersion2": "1.0.4",
"_analyticRulecontentId2": "2de8abd6-a613-450e-95ed-08e503369fb3",
"analyticRuleId2": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '2de8abd6-a613-450e-95ed-08e503369fb3')]",
"analyticRuleTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('2de8abd6-a613-450e-95ed-08e503369fb3')))]",
"_analyticRulecontentProductId2": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','2de8abd6-a613-450e-95ed-08e503369fb3','-', '1.0.3')))]"
"_analyticRulecontentProductId2": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','2de8abd6-a613-450e-95ed-08e503369fb3','-', '1.0.4')))]"
},
"analyticRuleObject3": {
"analyticRuleVersion3": "2.0.4",
"analyticRuleVersion3": "2.0.5",
"_analyticRulecontentId3": "6e575295-a7e6-464c-8192-3e1d8fd6a990",
"analyticRuleId3": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '6e575295-a7e6-464c-8192-3e1d8fd6a990')]",
"analyticRuleTemplateSpecName3": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('6e575295-a7e6-464c-8192-3e1d8fd6a990')))]",
"_analyticRulecontentProductId3": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','6e575295-a7e6-464c-8192-3e1d8fd6a990','-', '2.0.4')))]"
"_analyticRulecontentProductId3": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','6e575295-a7e6-464c-8192-3e1d8fd6a990','-', '2.0.5')))]"
},
"analyticRuleObject4": {
"analyticRuleVersion4": "1.0.7",
"analyticRuleVersion4": "1.0.8",
"_analyticRulecontentId4": "29283b22-a1c0-4d16-b0a9-3460b655a46a",
"analyticRuleId4": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '29283b22-a1c0-4d16-b0a9-3460b655a46a')]",
"analyticRuleTemplateSpecName4": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('29283b22-a1c0-4d16-b0a9-3460b655a46a')))]",
"_analyticRulecontentProductId4": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','29283b22-a1c0-4d16-b0a9-3460b655a46a','-', '1.0.7')))]"
"_analyticRulecontentProductId4": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','29283b22-a1c0-4d16-b0a9-3460b655a46a','-', '1.0.8')))]"
},
"huntingQueryObject1": {
"huntingQueryVersion1": "1.0.4",
@ -147,7 +147,7 @@
"huntingQueryTemplateSpecName9": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-hq-',uniquestring('09e45ec6-ac42-4b5a-be69-54623c4aa062')))]"
},
"huntingQueryObject10": {
"huntingQueryVersion10": "1.0.2",
"huntingQueryVersion10": "1.0.3",
"_huntingQuerycontentId10": "bf094505-fd2e-484f-b72a-acd79ee00ce8",
"huntingQueryTemplateSpecName10": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-hq-',uniquestring('bf094505-fd2e-484f-b72a-acd79ee00ce8')))]"
},
@ -181,7 +181,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Log4jPostCompromiseHunting Workbook with template version 3.0.3",
"description": "Log4jPostCompromiseHunting Workbook with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('workbookVersion1')]",
@ -297,7 +297,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Log4jImpactAssessment Workbook with template version 3.0.3",
"description": "Log4jImpactAssessment Workbook with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('workbookVersion2')]",
@ -405,7 +405,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Log4jVulnerableMachines_AnalyticalRules Analytics Rule with template version 3.0.3",
"description": "Log4jVulnerableMachines_AnalyticalRules Analytics Rule with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject1').analyticRuleVersion1]",
@ -415,11 +415,11 @@
{
"type": "Microsoft.SecurityInsights/AlertRuleTemplates",
"name": "[variables('analyticRuleObject1')._analyticRulecontentId1]",
"apiVersion": "2022-04-01-preview",
"apiVersion": "2023-02-01-preview",
"kind": "Scheduled",
"location": "[parameters('workspace-location')]",
"properties": {
"description": "This query uses the Azure Defender Security Nested Recommendations data to find machines vulnerable to log4j CVE-2021-44228. Log4j is an open-source Apache logging library that is used in\n many Java-based applications. Security Nested Recommendations data is sent to Microsoft Sentinel using the continuous export feature of Azure Defender(refrence link below).\n Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/\n Reference: https://docs.microsoft.com/azure/security-center/continuous-export?tabs=azure-portal\n Reference: https://techcommunity.microsoft.com/t5/microsoft-defender-for-cloud/how-defender-for-cloud-displays-machines-affected-by-log4j/ba-p/3037271",
"description": "This query uses the Azure Defender Security Nested Recommendations data to find machines vulnerable to log4j CVE-2021-44228.\nLog4j is an open-source Apache logging library that is used in many Java-based applications. Security Nested Recommendations data is sent to Microsoft Sentinel using the continuous export feature of Azure Defender(refrence link below).\n Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/\n Reference: https://docs.microsoft.com/azure/security-center/continuous-export?tabs=azure-portal\n Reference: https://techcommunity.microsoft.com/t5/microsoft-defender-for-cloud/how-defender-for-cloud-displays-machines-affected-by-log4j/ba-p/3037271",
"displayName": "Vulnerable Machines related to log4j CVE-2021-44228",
"enabled": false,
"query": "SecurityNestedRecommendation\n| where RemediationDescription has 'CVE-2021-44228'\n| parse ResourceDetails with * 'virtualMachines/' VirtualMachine '\"' *\n| summarize arg_min(TimeGenerated, *) by TenantId, RecommendationSubscriptionId, VirtualMachine, RecommendationName,Description,RemediationDescription, tostring(AdditionalData),VulnerabilityId\n| extend Timestamp = TimeGenerated\n",
@ -431,7 +431,6 @@
"triggerOperator": "GreaterThan",
"triggerThreshold": 0,
"status": "Available",
"requiredDataConnectors": [],
"tactics": [
"InitialAccess",
"Execution"
@ -442,13 +441,13 @@
],
"entityMappings": [
{
"entityType": "Host",
"fieldMappings": [
{
"identifier": "HostName",
"columnName": "VirtualMachine"
}
]
],
"entityType": "Host"
}
]
}
@ -504,7 +503,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "AzureWAFmatching_log4j_vuln_AnalyticalRules Analytics Rule with template version 3.0.3",
"description": "AzureWAFmatching_log4j_vuln_AnalyticalRules Analytics Rule with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject2').analyticRuleVersion2]",
@ -514,11 +513,11 @@
{
"type": "Microsoft.SecurityInsights/AlertRuleTemplates",
"name": "[variables('analyticRuleObject2')._analyticRulecontentId2]",
"apiVersion": "2022-04-01-preview",
"apiVersion": "2023-02-01-preview",
"kind": "Scheduled",
"location": "[parameters('workspace-location')]",
"properties": {
"description": "This query will alert on a positive pattern match by Azure WAF for CVE-2021-44228 log4j vulnerability exploitation attempt. If possible, it then decodes the malicious command for further analysis.\n Refrence: https://www.microsoft.com/security/blog/2021/12/11/guidance-for-preventing-detecting-and-hunting-for-cve-2021-44228-log4j-2-exploitation/",
"description": "This query will alert on a positive pattern match by Azure WAF for CVE-2021-44228 log4j vulnerability exploitation attempt. If possible, it then decodes the malicious command for further analysis.\n Reference: https://www.microsoft.com/security/blog/2021/12/11/guidance-for-preventing-detecting-and-hunting-for-cve-2021-44228-log4j-2-exploitation/",
"displayName": "Azure WAF matching for Log4j vuln(CVE-2021-44228)",
"enabled": false,
"query": "let log4jioc = dynamic([\"jndi\",\"ldap\",\"${::\"]);\nAzureDiagnostics\n| where ResourceProvider == \"MICROSOFT.NETWORK\" and Category in (\"ApplicationGatewayFirewallLog\", \"FrontdoorWebApplicationFirewallLog\")\n| extend details_data_s = column_ifexists(\"details_data_s\", tostring(AdditionalFields.details_data))\n|where requestUri_s has_any (log4jioc) or details_message_s has_any (log4jioc) or details_data_s has_any (log4jioc)\n| extend Malicious = iff(isnotempty( details_data_s),details_data_s,iff(isnotempty( requestUri_s),requestUri_s,\"\"))\n|parse Malicious with * '${' MaliciousCommand '}' * \n| extend EncodeCmd = iff(MaliciousCommand has 'Base64/', split(split(MaliciousCommand, \"Base64/\",1)[0], \"}\", 0)[0], \"\")\n| extend EncodeCmd1 = iff(MaliciousCommand has 'base64/', split(split(MaliciousCommand, \"base64/\",1)[0], \"}\", 0)[0], \"\")\n| extend CmdLine = iff( isnotempty(EncodeCmd), EncodeCmd, EncodeCmd1)\n| extend DecodedCmdLine = base64_decode_tostring(tostring(CmdLine))\n| extend DecodedCmdLine = iff( isnotempty(DecodedCmdLine), DecodedCmdLine, \"Unable to decode/Doesn't need decoding\")\n| project TimeGenerated, Target=column_ifexists(\"hostname_s\", tostring(AdditionalFields.hostname)), MaliciousHost = column_ifexists(\"clientIp_s\", tostring(AdditionalFields.clientIp)) , MaliciousCommand, details_data_s = column_ifexists(\"details_data_s\", tostring(AdditionalFields.details_data)), DecodedCmdLine, Message,\nruleSetType_s = column_ifexists(\"ruleSetType_s\", tostring(AdditionalFields.ruleSetType)), OperationName, SubscriptionId, details_message_s = column_ifexists(\"details_message_s\", tostring(AdditionalFields.details_message)), \ndetails_file_s = column_ifexists(\"details_message_s\", tostring(AdditionalFields.details_file))\n| extend timestamp = TimeGenerated\n",
@ -546,13 +545,13 @@
],
"entityMappings": [
{
"entityType": "IP",
"fieldMappings": [
{
"identifier": "Address",
"columnName": "MaliciousHost"
}
]
],
"entityType": "IP"
}
]
}
@ -608,7 +607,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Log4J_IPIOC_Dec112021_AnalyticalRules Analytics Rule with template version 3.0.3",
"description": "Log4J_IPIOC_Dec112021_AnalyticalRules Analytics Rule with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject3').analyticRuleVersion3]",
@ -618,7 +617,7 @@
{
"type": "Microsoft.SecurityInsights/AlertRuleTemplates",
"name": "[variables('analyticRuleObject3')._analyticRulecontentId3]",
"apiVersion": "2022-04-01-preview",
"apiVersion": "2023-02-01-preview",
"kind": "Scheduled",
"location": "[parameters('workspace-location')]",
"properties": {
@ -659,6 +658,12 @@
],
"connectorId": "CiscoASA"
},
{
"dataTypes": [
"CommonSecurityLog"
],
"connectorId": "CiscoAsaAma"
},
{
"dataTypes": [
"CommonSecurityLog"
@ -725,7 +730,6 @@
],
"entityMappings": [
{
"entityType": "Account",
"fieldMappings": [
{
"identifier": "Name",
@ -735,10 +739,10 @@
"identifier": "UPNSuffix",
"columnName": "UPNSuffix"
}
]
],
"entityType": "Account"
},
{
"entityType": "Host",
"fieldMappings": [
{
"identifier": "HostName",
@ -748,16 +752,17 @@
"identifier": "DnsDomain",
"columnName": "DnsDomain"
}
]
],
"entityType": "Host"
},
{
"entityType": "IP",
"fieldMappings": [
{
"identifier": "Address",
"columnName": "IPEntity"
}
]
],
"entityType": "IP"
}
]
}
@ -813,7 +818,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "UserAgentSearch_log4j_AnalyticalRules Analytics Rule with template version 3.0.3",
"description": "UserAgentSearch_log4j_AnalyticalRules Analytics Rule with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject4').analyticRuleVersion4]",
@ -823,11 +828,11 @@
{
"type": "Microsoft.SecurityInsights/AlertRuleTemplates",
"name": "[variables('analyticRuleObject4')._analyticRulecontentId4]",
"apiVersion": "2022-04-01-preview",
"apiVersion": "2023-02-01-preview",
"kind": "Scheduled",
"location": "[parameters('workspace-location')]",
"properties": {
"description": "This query uses various log sources having user agent data to look for log4j CVE-2021-44228 exploitation attempt based on user agent pattern. Log4j is an open-source Apache logging library that is used in \n many Java-based applications. The regex and the string matching look for the most common attacks. This might not be comprehensive to detect every possible user agent variation.\n Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/",
"description": "This query uses various log sources having user agent data to look for log4j CVE-2021-44228 exploitation attempt based on user agent pattern.\nLog4j is an open-source Apache logging library that is used in many Java-based applications. The regex and the string matching look for the most common attacks. This might not be comprehensive to detect every possible user agent variation.\n Reference: https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/",
"displayName": "User agent search for log4j exploitation attempt",
"enabled": false,
"query": "let UserAgentString = dynamic ([\"${jndi:ldap:/\", \"${jndi:rmi:/\", \"${jndi:ldaps:/\", \"${jndi:dns:/\", \"${jndi:iiop:/\",\"${jndi:\",\"${jndi:nds:/\",\"${jndi:corba/\"]);\nlet UARegexMinimalString=dynamic(['{','%7b', '%7B']);\nlet UARegex = @'(\\\\$|%24)(\\\\{|%7B)([^jJ]*[jJ])([^nN]*[nN])([^dD]*[dD])([^iI]*[iI])(:|%3A|\\\\$|%24|}|%7D)';\n(union isfuzzy=true\n(OfficeActivity\n| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = ClientIP, Account = UserId, Type, Operation\n),\n(AzureDiagnostics\n| where Category in (\"FrontdoorWebApplicationFirewallLog\", \"FrontdoorAccessLog\", \"ApplicationGatewayFirewallLog\", \"ApplicationGatewayAccessLog\")\n| where userAgent_s has_any (UserAgentString) or userAgent_s matches regex UARegex\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = userAgent_s, SourceIP = column_ifexists(\"clientIp_s\",clientIP_s), Type, column_ifexists(\"originalHost_s\",host_s), Url = requestUri_s, HttpStatus = column_ifexists(\"httpStatusDetails_s\",httpStatus_d), column_ifexists(\"transactionId_g\",trackingReference_s), ruleName_s, ResourceType, ResourceId\n),\n(\nW3CIISLog\n| where csUserAgent has_any (UserAgentString) or csUserAgent matches regex UARegex\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent = csUserAgent, SourceIP = cIP, Account = csUserName, Type, sSiteName, csMethod, Url = csUriStem\n),\n(\nAWSCloudTrail\n| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = SourceIpAddress, Account = UserIdentityUserName, Type, EventName\n),\n(SigninLogs\n| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, Operation = OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed\n),\n(AADNonInteractiveUserSignInLogs \n| where UserAgent has_any (UserAgentString) or UserAgent matches regex UARegex\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserAgent, SourceIP = IPAddress, Account = UserPrincipalName, Type, Operation = OperationName, tostring(LocationDetails), tostring(DeviceDetail), AppDisplayName, ClientAppUsed\n),\n(_Im_WebSession (httpuseragent_has_any=array_concat(UserAgentString,UARegexMinimalString))\n| where HttpUserAgent has_any (UserAgentString) or HttpUserAgent matches regex UARegex\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by HttpUserAgent, SourceIP = SrcIpAddr, DstIpAddr, Account = SrcUsername, Url, Type\n)\n)\n",
@ -897,31 +902,31 @@
],
"entityMappings": [
{
"entityType": "URL",
"fieldMappings": [
{
"identifier": "Url",
"columnName": "Url"
}
]
],
"entityType": "URL"
},
{
"entityType": "IP",
"fieldMappings": [
{
"identifier": "Address",
"columnName": "SourceIP"
}
]
],
"entityType": "IP"
},
{
"entityType": "Account",
"fieldMappings": [
{
"identifier": "Name",
"columnName": "Account"
}
]
],
"entityType": "Account"
}
]
}
@ -977,7 +982,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "WAF_log4j_vulnerability_HuntingQueries Hunting Query with template version 3.0.3",
"description": "WAF_log4j_vulnerability_HuntingQueries Hunting Query with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject1').huntingQueryVersion1]",
@ -1062,7 +1067,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "NetworkConnectionldap_log4j_HuntingQueries Hunting Query with template version 3.0.3",
"description": "NetworkConnectionldap_log4j_HuntingQueries Hunting Query with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject2').huntingQueryVersion2]",
@ -1147,7 +1152,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Firewall_Disable_Activity_HuntingQueries Hunting Query with template version 3.0.3",
"description": "Firewall_Disable_Activity_HuntingQueries Hunting Query with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject3').huntingQueryVersion3]",
@ -1232,7 +1237,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Apache_log4j_Vulnerability_HuntingQueries Hunting Query with template version 3.0.3",
"description": "Apache_log4j_Vulnerability_HuntingQueries Hunting Query with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject4').huntingQueryVersion4]",
@ -1317,7 +1322,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Process_Termination_Activity_HuntingQueries Hunting Query with template version 3.0.3",
"description": "Process_Termination_Activity_HuntingQueries Hunting Query with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject5').huntingQueryVersion5]",
@ -1402,7 +1407,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Suspicious_ShellScript_Activity_HuntingQueries Hunting Query with template version 3.0.3",
"description": "Suspicious_ShellScript_Activity_HuntingQueries Hunting Query with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject6').huntingQueryVersion6]",
@ -1487,7 +1492,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Base64_Download_Activity_HuntingQueries Hunting Query with template version 3.0.3",
"description": "Base64_Download_Activity_HuntingQueries Hunting Query with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject7').huntingQueryVersion7]",
@ -1572,7 +1577,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Container_Miner_Activity_HuntingQueries Hunting Query with template version 3.0.3",
"description": "Container_Miner_Activity_HuntingQueries Hunting Query with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject8').huntingQueryVersion8]",
@ -1657,7 +1662,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Linux_Toolkit_Detected_HuntingQueries Hunting Query with template version 3.0.3",
"description": "Linux_Toolkit_Detected_HuntingQueries Hunting Query with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject9').huntingQueryVersion9]",
@ -1742,7 +1747,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "NetworkConnectionToNewExternalLDAPServer_HuntingQueries Hunting Query with template version 3.0.3",
"description": "NetworkConnectionToNewExternalLDAPServer_HuntingQueries Hunting Query with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('huntingQueryObject10').huntingQueryVersion10]",
@ -1813,9 +1818,9 @@
"contentId": "[variables('huntingQueryObject10')._huntingQuerycontentId10]",
"contentKind": "HuntingQuery",
"displayName": "Network Connection to New External LDAP Server",
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject10')._huntingQuerycontentId10,'-', '1.0.2')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject10')._huntingQuerycontentId10,'-', '1.0.2')))]",
"version": "1.0.2"
"contentProductId": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject10')._huntingQuerycontentId10,'-', '1.0.3')))]",
"id": "[concat(take(variables('_solutionId'),50),'-','hq','-', uniqueString(concat(variables('_solutionId'),'-','HuntingQuery','-',variables('huntingQueryObject10')._huntingQuerycontentId10,'-', '1.0.3')))]",
"version": "1.0.3"
}
},
{
@ -1827,7 +1832,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "BatchImportToSentinel Playbook with template version 3.0.3",
"description": "BatchImportToSentinel Playbook with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('playbookVersion1')]",
@ -2046,7 +2051,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Log4jIndicatorProcessor Playbook with template version 3.0.3",
"description": "Log4jIndicatorProcessor Playbook with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('playbookVersion2')]",
@ -2345,12 +2350,12 @@
"apiVersion": "2023-04-01-preview",
"location": "[parameters('workspace-location')]",
"properties": {
"version": "3.0.3",
"version": "3.0.4",
"kind": "Solution",
"contentSchemaVersion": "3.0.0",
"displayName": "Apache Log4j Vulnerability Detection",
"publisherDisplayName": "Microsoft Sentinel, Microsoft Corporation",
"descriptionHtml": "<p><strong>Note:</strong> <em>There may be <a href=\"https://aka.ms/sentinelsolutionsknownissues\">known issues</a> pertaining to this Solution, please refer to them before installing.</em></p>\n<p>Microsoft's security research teams have been tracking threats taking advantage of <a href=\"https://cve.mitre.org/cgi-bin/cvename.cgi?name=2021-44228\">CVE-2021-44228</a>, a remote code execution (RCE) vulnerability in <a href=\"https://logging.apache.org/log4j/2.x/\">Apache Log4j 2</a> referred to as “Log4Shell”. The vulnerability allows unauthenticated remote code execution, and it is triggered when a specially crafted string provided by the attacker through a variety of different input vectors is parsed and processed by the Log4j 2 vulnerable component. For more technical and mitigation information about the vulnerability, please read the <a href=\"https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/\">Microsoft Security Response Center blog</a>. This solution provides content to monitor, detect and investigate signals related to exploitation of this vulnerability in Microsoft Sentinel.</p>\n<p><strong>Prerequisite :-</strong></p>\n<p>This is a <a href=\"https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fsentinel%2Fsentinel-solutions-catalog%23domain-solutions&amp;data=05%7C01%7Ckavishbakshi%40microsoft.com%7Cbe2a496082b24caa4b8c08da9cefacca%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637994850502413731%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=OJegu%2B2EqD7rmYmK9pm9QniD6YWp5ooloZ6tHzcwVi0%3D&amp;reserved=0\">domain solution</a> and does not include any data connectors. Install one or more of the listed solutions, or develop your custom ASIM parsers to unlock the value provided by this solution.</p>\n<ol>\n<li>Azure Web Application Firewall (WAF)</li>\n<li>Microsoft 365</li>\n<li>Windows Server DNS</li>\n<li>CiscoASA</li>\n<li>PaloAlto-PAN-OS</li>\n<li>Microsoft Entra ID</li>\n<li>Azure Activity</li>\n<li>Amazon Web Services</li>\n<li>Azure Firewall</li>\n<li>SquidProxy</li>\n<li>Zscaler Private Access (ZPA)</li>\n<li>Syslog</li>\n<li>Check Point</li>\n<li>Microsoft Defender XDR</li>\n</ol>\n<p><strong>Workbooks:</strong> 2, <strong>Analytic Rules:</strong> 4, <strong>Hunting Queries:</strong> 10, <strong>Watchlists:</strong> 1, <strong>Playbooks:</strong> 2</p>\n<p><a href=\"https://aka.ms/azuresentinel\">Learn more about Microsoft Sentinel</a> | <a href=\"https://aka.ms/azuresentinelsolutionsdoc\">Learn more about Solutions</a></p>\n",
"descriptionHtml": "<p><strong>Note:</strong> Please refer to the following before installing the solution:</p>\n<p>• Review the solution <a href=\"https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/Apache%20Log4j%20Vulnerability%20Detection/ReleaseNotes.md\">Release Notes</a></p>\n<p>• There may be <a href=\"https://aka.ms/sentinelsolutionsknownissues\">known issues</a> pertaining to this Solution, please refer to them before installing.</p>\n<p>Microsoft's security research teams have been tracking threats taking advantage of <a href=\"https://cve.mitre.org/cgi-bin/cvename.cgi?name=2021-44228\">CVE-2021-44228</a>, a remote code execution (RCE) vulnerability in <a href=\"https://logging.apache.org/log4j/2.x/\">Apache Log4j 2</a> referred to as “Log4Shell”. The vulnerability allows unauthenticated remote code execution, and it is triggered when a specially crafted string provided by the attacker through a variety of different input vectors is parsed and processed by the Log4j 2 vulnerable component. For more technical and mitigation information about the vulnerability, please read the <a href=\"https://msrc-blog.microsoft.com/2021/12/11/microsofts-response-to-cve-2021-44228-apache-log4j2/\">Microsoft Security Response Center blog</a>. This solution provides content to monitor, detect and investigate signals related to exploitation of this vulnerability in Microsoft Sentinel.</p>\n<p><strong>Prerequisite :-</strong></p>\n<p>This is a <a href=\"https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fsentinel%2Fsentinel-solutions-catalog%23domain-solutions&amp;data=05%7C01%7Ckavishbakshi%40microsoft.com%7Cbe2a496082b24caa4b8c08da9cefacca%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637994850502413731%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata=OJegu%2B2EqD7rmYmK9pm9QniD6YWp5ooloZ6tHzcwVi0%3D&amp;reserved=0\">domain solution</a> and does not include any data connectors. Install one or more of the listed solutions, or develop your custom ASIM parsers to unlock the value provided by this solution.</p>\n<ol>\n<li>Azure Web Application Firewall (WAF)</li>\n<li>Microsoft 365</li>\n<li>Windows Server DNS</li>\n<li>CiscoASA</li>\n<li>PaloAlto-PAN-OS</li>\n<li>Microsoft Entra ID</li>\n<li>Azure Activity</li>\n<li>Amazon Web Services</li>\n<li>Azure Firewall</li>\n<li>SquidProxy</li>\n<li>Zscaler Private Access (ZPA)</li>\n<li>Syslog</li>\n<li>Check Point</li>\n<li>Microsoft Defender XDR</li>\n</ol>\n<p><strong>Workbooks:</strong> 2, <strong>Analytic Rules:</strong> 4, <strong>Hunting Queries:</strong> 10, <strong>Watchlists:</strong> 1, <strong>Playbooks:</strong> 2</p>\n<p><a href=\"https://aka.ms/azuresentinel\">Learn more about Microsoft Sentinel</a> | <a href=\"https://aka.ms/azuresentinelsolutionsdoc\">Learn more about Solutions</a></p>\n",
"contentKind": "Solution",
"contentProductId": "[variables('_solutioncontentProductId')]",
"id": "[variables('_solutioncontentProductId')]",
@ -2373,6 +2378,7 @@
"link": "https://support.microsoft.com/"
},
"dependencies": {
"operator": "AND",
"criteria": [
{
"kind": "Workbook",
@ -2467,63 +2473,7 @@
{
"kind": "Watchlist",
"contentId": "[variables('_Campaign')]",
"version": "3.0.3"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-azurewebapplicationfirewal"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-office365"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-dns"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-ciscoasa"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-paloaltopanos"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-azureactivedirectory"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-azureactivity"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-amazonwebservices"
},
{
"kind": "Solution",
"contentId": "sentinel4azurefirewall.sentinel4azurefirewall"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-squidproxy"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-zscalerprivateaccess"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-syslog"
},
{
"kind": "Solution",
"contentId": "checkpoint.checkpoint-sentinel-solutions"
},
{
"kind": "Solution",
"contentId": "azuresentinel.azure-sentinel-solution-microsoft365defender"
"version": "3.0.4"
}
]
},

Просмотреть файл

@ -1,5 +1,6 @@
| **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** |
|-------------|--------------------------------|----------------------------------------------------------------------------|
| 3.0.4 | 31-05-2024 | Added missing AMA **Data Connector** reference in **Analytic rules** and **Hunting Query** |
| 3.0.3 | 15-02-2024 | Updated the solution to fix **Analytic Rules** deployment issue |
| 3.0.2 | 07-02-2024 | Updated solution description |
| 3.0.1 | 02-01-2024 | Tagged for dependent solutions for deployment |

Просмотреть файл

@ -1,134 +1,134 @@
import requests
import json
import datetime
from requests.auth import HTTPBasicAuth
import azure.functions as func
import base64
import hmac
import hashlib
import os
import tempfile
import logging
import re
from .state_manager import StateManager
customer_id = os.environ['WorkspaceID']
shared_key = os.environ['WorkspaceKey']
jira_token = os.environ['JiraAccessToken']
jira_username = os.environ['JiraUsername']
jira_homesite_name = os.environ['JiraHomeSiteName']
connection_string = os.environ['AzureWebJobsStorage']
logAnalyticsUri = os.environ.get('logAnalyticsUri')
log_type = 'Jira_Audit'
jira_uri_audit = "https://" + jira_homesite_name + ".atlassian.net/rest/api/3/auditing/record"
if ((logAnalyticsUri in (None, '') or str(logAnalyticsUri).isspace())):
logAnalyticsUri = 'https://' + customer_id + '.ods.opinsights.azure.com'
pattern = r"https:\/\/([\w\-]+)\.ods\.opinsights\.azure.([a-zA-Z\.]+)$"
match = re.match(pattern,str(logAnalyticsUri))
if(not match):
raise Exception("Invalid Log Analytics Uri.")
logging.info("Jira Audit Uri: {}".format(jira_uri_audit))
def generate_date():
current_time = datetime.datetime.utcnow().replace(second=0, microsecond=0) - datetime.timedelta(minutes=10)
state = StateManager(connection_string=connection_string)
past_time = state.get()
if past_time is not None:
logging.info("The last time point is: {}".format(past_time))
else:
logging.info("There is no last time point, trying to get events for last hour.")
past_time = (current_time - datetime.timedelta(minutes=60)).strftime("%Y-%m-%dT%H:%M:%SZ")
state.post(current_time.strftime("%Y-%m-%dT%H:%M:%SZ"))
return (past_time, current_time.strftime("%Y-%m-%dT%H:%M:%SZ"))
def get_result_request(offset,limit,from_time,to_time):
try:
r = requests.get(url=jira_uri_audit,
headers={'Accept': 'application/json'},
auth=HTTPBasicAuth(jira_username, jira_token),
params={
"offset": offset,
"limit": limit,
"from": from_time,
"to": to_time
})
if r.status_code == 200:
return r.json().get("records")
elif r.status_code == 401:
logging.error("The authentication credentials are incorrect or missing. Error code: {}".format(r.status_code))
elif r.status_code == 403:
logging.error("The user does not have the required permissions or Jira products are on free plans. Audit logs are available when at least one Jira product is on a paid plan. Error code: {}".format(r.status_code))
else:
logging.info("Jira Audit Uri: {}".format(jira_uri_audit))
logging.error("Something wrong. Error code: {}".format(r.status_code))
except Exception as err:
logging.error("Something wrong. Exception error text: {}".format(err))
def get_result(time_range):
from_time = time_range[0]
to_time = time_range[1]
offset = 0
limit = 1000
element_count = None
global_element_count = 0
while element_count != 0:
result = get_result_request(offset,limit,from_time,to_time)
if result is not None:
element_count = len(result)
else:
element_count = 0
if offset == 0 and element_count == 0:
logging.info("Logs not founded. Time period: from {} to {}.".format(from_time,to_time))
elif offset != 0 and element_count != 0:
logging.info("Processing {} events".format(element_count))
offset = offset + limit
if element_count > 0:
post_status_code = post_data(json.dumps(result))
if post_status_code is not None:
global_element_count = global_element_count + element_count
logging.info("Processed {} events to Microsoft Sentinel. Time period: from {} to {}.".format(global_element_count,from_time, to_time))
def build_signature(customer_id, shared_key, date, content_length, method, content_type, resource):
x_headers = 'x-ms-date:' + date
string_to_hash = method + "\n" + str(content_length) + "\n" + content_type + "\n" + x_headers + "\n" + resource
bytes_to_hash = bytes(string_to_hash, encoding="utf-8")
decoded_key = base64.b64decode(shared_key)
encoded_hash = base64.b64encode(hmac.new(decoded_key, bytes_to_hash, digestmod=hashlib.sha256).digest()).decode()
authorization = "SharedKey {}:{}".format(customer_id,encoded_hash)
return authorization
def post_data(body):
method = 'POST'
content_type = 'application/json'
resource = '/api/logs'
rfc1123date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
content_length = len(body)
signature = build_signature(customer_id, shared_key, rfc1123date, content_length, method, content_type, resource)
uri = logAnalyticsUri + resource + '?api-version=2016-04-01'
headers = {
'content-type': content_type,
'Authorization': signature,
'Log-Type': log_type,
'x-ms-date': rfc1123date
}
response = requests.post(uri,data=body, headers=headers)
if (response.status_code >= 200 and response.status_code <= 299):
return response.status_code
else:
logging.warn("Events are not processed into Azure. Response code: {}".format(response.status_code))
return None
def main(mytimer: func.TimerRequest) -> None:
if mytimer.past_due:
logging.info('The timer is past due!')
logging.info('Starting program')
get_result(generate_date())
import requests
import json
import datetime
from requests.auth import HTTPBasicAuth
import azure.functions as func
import base64
import hmac
import hashlib
import os
import tempfile
import logging
import re
from .state_manager import StateManager
customer_id = os.environ['WorkspaceID']
shared_key = os.environ['WorkspaceKey']
jira_token = os.environ['JiraAccessToken']
jira_username = os.environ['JiraUsername']
jira_homesite_name = os.environ['JiraHomeSiteName']
connection_string = os.environ['AzureWebJobsStorage']
logAnalyticsUri = os.environ.get('logAnalyticsUri')
log_type = 'Jira_Audit'
jira_uri_audit = "https://" + jira_homesite_name + ".atlassian.net/rest/api/3/auditing/record"
if ((logAnalyticsUri in (None, '') or str(logAnalyticsUri).isspace())):
logAnalyticsUri = 'https://' + customer_id + '.ods.opinsights.azure.com'
pattern = r"https:\/\/([\w\-]+)\.ods\.opinsights\.azure.([a-zA-Z\.]+)$"
match = re.match(pattern,str(logAnalyticsUri))
if(not match):
raise Exception("Invalid Log Analytics Uri.")
logging.info("Jira Audit Uri: {}".format(jira_uri_audit))
def generate_date():
current_time = datetime.datetime.utcnow().replace(second=0, microsecond=0) - datetime.timedelta(minutes=10)
state = StateManager(connection_string=connection_string)
past_time = state.get()
if past_time is not None:
logging.info("The last time point is: {}".format(past_time))
else:
logging.info("There is no last time point, trying to get events for last hour.")
past_time = (current_time - datetime.timedelta(minutes=60)).strftime("%Y-%m-%dT%H:%M:%SZ")
state.post(current_time.strftime("%Y-%m-%dT%H:%M:%SZ"))
return (past_time, current_time.strftime("%Y-%m-%dT%H:%M:%SZ"))
def get_result_request(offset,limit,from_time,to_time):
try:
r = requests.get(url=jira_uri_audit,
headers={'Accept': 'application/json'},
auth=HTTPBasicAuth(jira_username, jira_token),
params={
"offset": offset,
"limit": limit,
"from": from_time,
"to": to_time
})
if r.status_code == 200:
return r.json().get("records")
elif r.status_code == 401:
logging.error("The authentication credentials are incorrect or missing. Error code: {}".format(r.status_code))
elif r.status_code == 403:
logging.error("The user does not have the required permissions or Jira products are on free plans. Audit logs are available when at least one Jira product is on a paid plan. Error code: {}".format(r.status_code))
else:
logging.info("Jira Audit Uri: {}".format(jira_uri_audit))
logging.error("Something wrong. Error code: {}".format(r.status_code))
except Exception as err:
logging.error("Something wrong. Exception error text: {}".format(err))
def get_result(time_range):
from_time = time_range[0]
to_time = time_range[1]
offset = 0
limit = 1000
element_count = None
global_element_count = 0
while element_count != 0:
result = get_result_request(offset,limit,from_time,to_time)
if result is not None:
element_count = len(result)
else:
element_count = 0
if offset == 0 and element_count == 0:
logging.info("Logs not founded. Time period: from {} to {}.".format(from_time,to_time))
elif offset != 0 and element_count != 0:
logging.info("Processing {} events".format(element_count))
offset = offset + limit
if element_count > 0:
post_status_code = post_data(json.dumps(result))
if post_status_code is not None:
global_element_count = global_element_count + element_count
logging.info("Processed {} events to Microsoft Sentinel. Time period: from {} to {}.".format(global_element_count,from_time, to_time))
def build_signature(customer_id, shared_key, date, content_length, method, content_type, resource):
x_headers = 'x-ms-date:' + date
string_to_hash = method + "\n" + str(content_length) + "\n" + content_type + "\n" + x_headers + "\n" + resource
bytes_to_hash = bytes(string_to_hash, encoding="utf-8")
decoded_key = base64.b64decode(shared_key)
encoded_hash = base64.b64encode(hmac.new(decoded_key, bytes_to_hash, digestmod=hashlib.sha256).digest()).decode()
authorization = "SharedKey {}:{}".format(customer_id,encoded_hash)
return authorization
def post_data(body):
method = 'POST'
content_type = 'application/json'
resource = '/api/logs'
rfc1123date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
content_length = len(body)
signature = build_signature(customer_id, shared_key, rfc1123date, content_length, method, content_type, resource)
uri = logAnalyticsUri + resource + '?api-version=2016-04-01'
headers = {
'content-type': content_type,
'Authorization': signature,
'Log-Type': log_type,
'x-ms-date': rfc1123date
}
response = requests.post(uri,data=body, headers=headers)
if (response.status_code >= 200 and response.status_code <= 299):
return response.status_code
else:
logging.warn("Events are not processed into Azure. Response code: {}".format(response.status_code))
return None
def main(mytimer: func.TimerRequest) -> None:
if mytimer.past_due:
logging.info('The timer is past due!')
logging.info('Starting program')
get_result(generate_date())

Просмотреть файл

@ -1,11 +1,11 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "mytimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 */10 * * * *"
}
]
}
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "mytimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 */10 * * * *"
}
]
}

Просмотреть файл

@ -1,22 +1,22 @@
from azure.storage.fileshare import ShareClient
from azure.storage.fileshare import ShareFileClient
from azure.core.exceptions import ResourceNotFoundError
class StateManager:
def __init__(self, connection_string, share_name='funcstatemarkershare', file_path='funcstatemarkerfile'):
self.share_cli = ShareClient.from_connection_string(conn_str=connection_string, share_name=share_name)
self.file_cli = ShareFileClient.from_connection_string(conn_str=connection_string, share_name=share_name, file_path=file_path)
def post(self, marker_text: str):
try:
self.file_cli.upload_file(marker_text)
except ResourceNotFoundError:
self.share_cli.create_share()
self.file_cli.upload_file(marker_text)
def get(self):
try:
return self.file_cli.download_file().readall().decode()
except ResourceNotFoundError:
return None
from azure.storage.fileshare import ShareClient
from azure.storage.fileshare import ShareFileClient
from azure.core.exceptions import ResourceNotFoundError
class StateManager:
def __init__(self, connection_string, share_name='funcstatemarkershare', file_path='funcstatemarkerfile'):
self.share_cli = ShareClient.from_connection_string(conn_str=connection_string, share_name=share_name)
self.file_cli = ShareFileClient.from_connection_string(conn_str=connection_string, share_name=share_name, file_path=file_path)
def post(self, marker_text: str):
try:
self.file_cli.upload_file(marker_text)
except ResourceNotFoundError:
self.share_cli.create_share()
self.file_cli.upload_file(marker_text)
def get(self):
try:
return self.file_cli.download_file().readall().decode()
except ResourceNotFoundError:
return None

Просмотреть файл

@ -0,0 +1,79 @@
{
"name": "AtlassianJIRADCR",
"apiVersion": "2021-09-01-preview",
"type": "Microsoft.Insights/dataCollectionRules",
"location": "{{location}}",
"properties": {
"dataCollectionEndpointId": "{{dataCollectionEndpointId}}",
"streamDeclarations": {
"Custom-Jira_Audit_v2_CL": {
"columns": [
{
"name": "id",
"type": "int"
},
{
"name": "summary",
"type": "string"
},
{
"name": "created",
"type": "datetime"
},
{
"name": "category",
"type": "string"
},
{
"name": "eventSource",
"type": "string"
},
{
"name": "objectItem",
"type": "dynamic"
},
{
"name": "changedValues",
"type": "dynamic"
},
{
"name": "associatedItems",
"type": "dynamic"
},
{
"name": "remoteAddress",
"type": "string"
},
{
"name": "authorKey",
"type": "string"
},
{
"name": "authorAccountId",
"type": "string"
}
]
}
},
"destinations": {
"logAnalytics": [
{
"workspaceResourceId": "{{workspaceResourceId}}",
"name": "clv2ws1"
}
]
},
"dataFlows": [
{
"streams": [
"Custom-Jira_Audit_v2_CL"
],
"destinations": [
"clv2ws1"
],
"transformKql": "source\n| extend TimeGenerated = now(), EventVendor=\"Atlassian\", EventProduct=\"Jira Audit\"\n| project-rename EventId=id,\n EventMessage=summary,\n SrcIpAddr=remoteAddress,\n UserName=authorKey,\n UserSid=authorAccountId,\n EventCreationTime=created,\n EventSource=eventSource,\n ChangedValues=changedValues,\n AssociatedItems=associatedItems,\n EventCategoryType= category \n|extend ObjectItemId=objectItem.id,\n ObjectItemName=objectItem.name,\n ObjectItemTypeName=objectItem.typeName,\n ObjectItemParentId=objectItem.parentId,\n ObjectItemParentName=objectItem.parentName\n | extend ObjectItemId=tostring(ObjectItemId), ObjectItemName=tostring(ObjectItemName), ObjectItemTypeName=tostring(ObjectItemTypeName), ObjectItemParentId=tostring(ObjectItemParentId), ObjectItemParentName=tostring(ObjectItemParentName) ",
"outputStream": "Custom-Jira_Audit_v2_CL"
}
]
}
}

Просмотреть файл

@ -0,0 +1,132 @@
{
"name": "JiraAuditCCPDefinition",
"apiVersion": "2022-09-01-preview",
"type": "Microsoft.SecurityInsights/dataConnectorDefinitions",
"location": "{{location}}",
"kind": "Customizable",
"availability": {
"isPreview": false
},
"properties": {
"connectorUiConfig": {
"title": "Atlassian Jira Audit (using REST API) (Preview)",
"id": "JiraAuditCCPDefinition",
"publisher": "Microsoft",
"descriptionMarkdown": "The [Atlassian Jira](https://www.atlassian.com/software/jira) Audit data connector provides the capability to ingest [Jira Audit Records](https://support.atlassian.com/jira-cloud-administration/docs/audit-activities-in-jira-applications/) events into Microsoft Sentinel through the REST API. Refer to [API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-audit-records/) for more information. The connector provides ability to get events which helps to examine potential security risks, analyze your team's use of collaboration, diagnose configuration problems and more.",
"graphQueriesTableName": "Jira_Audit_v2_CL",
"graphQueries": [
{
"metricName": "Total data received",
"legend": "Jira Audit Events",
"baseQuery": "{{graphQueriesTableName}}"
}
],
"sampleQueries": [
{
"description": "All Atlassian Jira audit logs",
"query": "{{graphQueriesTableName}}\n| sort by TimeGenerated desc"
},
{
"description": "Total Events",
"query": "{{graphQueriesTableName}}\n | summarize count() by OriginalEventUid"
}
],
"dataTypes": [
{
"name": "{{graphQueriesTableName}}",
"lastDataReceivedQuery": "{{graphQueriesTableName}}|summarize Time = max (TimeGenerated)\n|where isnotempty(Time)"
}
],
"connectivityCriteria": [
{
"type": "HasDataConnectors"
}
],
"permissions": {
"resourceProvider": [
{
"provider": "Microsoft.OperationalInsights/workspaces",
"permissionsDisplayText": "Read and Write permissions are required.",
"providerDisplayName": "Workspace",
"scope": "Workspace",
"requiredPermissions": {
"write": true,
"read": true,
"delete": true
}
}
],
"customs": [
{
"name": "Atlassian Jira API access",
"description": "Permission of [Administer Jira](https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/#authentication) is required to get access to the Jira Audit logs API. See [Jira API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-audit-records/#api-group-audit-records) to learn more about the audit API."
}
]
},
"instructionSteps": [
{
"description": "To enable the Atlassian Jira connector for Microsoft Sentinel, click to add an organization, fill the form with the Jira environment credentials and click to Connect. \n Follow [these steps](https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/) to create an API token.\n ",
"instructions": [
{
"type": "DataConnectorsGrid",
"parameters": {
"mapping": [
{
"columnName": "Atlassian Jira organization URL",
"columnValue": "properties.request.apiEndpoint"
}
],
"menuItems": [
"DeleteConnector"
]
}
},
{
"type": "ContextPane",
"parameters": {
"isPrimary": true,
"label": "Add organization",
"title": "Add organization",
"subtitle": "Add Atlassian Jira organization",
"contextPaneType": "DataConnectorsContextPane",
"instructionSteps": [
{
"instructions": [
{
"type": "Textbox",
"parameters": {
"label": "Atlassian Jira organization URL",
"placeholder": "Atlassian Jira organization URL",
"type": "string",
"name": "jiraorganizationurl"
}
},
{
"type": "Textbox",
"parameters": {
"label": "User Name",
"placeholder": "User Name (e.g., user@example.com)",
"type": "securestring",
"name": "userid"
}
},
{
"type": "Textbox",
"parameters": {
"label": "API Key",
"placeholder": "API Key",
"type": "password",
"name": "apikey"
}
}
]
}
]
}
}
]
}
]
}
}
}

Просмотреть файл

@ -0,0 +1,46 @@
{
"name": "AtlassianJiraCCPPolling",
"apiVersion": "2022-12-01-preview",
"type": "Microsoft.SecurityInsights/dataConnectors",
"location": "{{location}}",
"kind": "RestApiPoller",
"properties": {
"connectorDefinitionName": "JiraAuditCCPDefinition",
"dataType": "Jira_Audit_v2_CL",
"dcrConfig": {
"dataCollectionEndpoint": "{{dataCollectionEndpoint}}",
"dataCollectionRuleImmutableId": "{{dataCollectionRuleImmutableId}}",
"streamName": "Custom-Jira_Audit_v2_CL"
},
"auth": {
"type": "Basic",
"UserName": "{{userid}}",
"Password": "{{apikey}}"
},
"request": {
"apiEndpoint": "https://{{jiraorganizationurl}}/rest/api/3/auditing/record",
"httpMethod": "GET",
"retryCount": 3,
"timeoutInSeconds": 60,
"queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ",
"headers": {
"Accept": "application/json",
"User-Agent": "Scuba"
},
"startTimeAttributeName": "from",
"endTimeAttributeName": "to"
},
"paging": {
"pagingType": "Offset",
"offsetParaName": "offset",
"pageSizeParaName": "limit",
"pageSize": 1000
},
"response": {
"eventsJsonPaths": [
"$.records"
],
"format": "json"
}
}
}

Просмотреть файл

@ -0,0 +1,127 @@
{
"name": "Jira_Audit_v2_CL",
"apiVersion": "2021-03-01-privatepreview",
"type": "Microsoft.OperationalInsights/workspaces/tables",
"location": "{{location}}",
"properties": {
"schema": {
"name": "Jira_Audit_v2_CL",
"columns": [
{
"name": "AssociatedItems",
"type": "dynamic",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "UserSid",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "UserName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventCategoryType",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ChangedValues",
"type": "dynamic",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventCreationTime",
"type": "datetime",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventSource",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventId",
"type": "int",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "objectItem",
"type": "dynamic",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "SrcIpAddr",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventMessage",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "TimeGenerated",
"type": "datetime",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventVendor",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventProduct",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemId",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemTypeName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemParentId",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemParentName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
}
]
}
}
}

Просмотреть файл

@ -0,0 +1,692 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"minLength": 1,
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Not used, but needed to pass arm-ttk test `Location-Should-Not-Be-Hardcoded`. We instead use the `workspace-location` which is derived from the LA workspace"
}
},
"workspace-location": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "[concat('Region to deploy solution resources -- separate from location selection',parameters('location'))]"
}
},
"subscription": {
"defaultValue": "[last(split(subscription().id, '/'))]",
"type": "string",
"metadata": {
"description": "subscription id where Microsoft Sentinel is setup"
}
},
"resourceGroupName": {
"defaultValue": "[resourceGroup().name]",
"type": "string",
"metadata": {
"description": "resource group name where Microsoft Sentinel is setup"
}
},
"workspace": {
"defaultValue": "",
"type": "string",
"metadata": {
"description": "Workspace name for Log Analytics where Microsoft Sentinel is setup"
}
}
},
"variables": {
"workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]",
"_solutionName": "Atlassian Jira Connector",
"_solutionVersion": "3.0.0",
"_solutionAuthor": "Microsoft",
"_packageIcon": "icon icon icon icon",
"_solutionId": "azuresentinel.azure-sentinel-solution-azuresentinel.azure-sentinel-JIRAConnector",
"dataConnectorVersionConnectorDefinition": "1.0.0",
"dataConnectorVersionConnections": "1.0.0",
"_solutionTier": "Microsoft",
"_dataConnectorContentIdConnectorDefinition": "JIRAConnectorDefinition",
"dataConnectorTemplateNameConnectorDefinition": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnectorDefinition')))]",
"_dataConnectorContentIdConnections": "JIRATemplateConnections",
"dataConnectorTemplateNameConnections": "[concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentIdConnections')))]",
"_logAnalyticsTableId1": "Jira_Audit_v2_CL"
},
"resources": [
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
"apiVersion": "2023-04-01-preview",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnectorDefinition'), variables('dataConnectorVersionConnectorDefinition'))]",
"location": "[parameters('workspace-location')]",
"dependsOn": [
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]",
"displayName": "[concat(variables('_solutionName'), variables('dataConnectorTemplateNameConnectorDefinition'))]",
"contentKind": "DataConnector",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('dataConnectorVersionConnectorDefinition')]",
"parameters": {
},
"variables": {
},
"resources": [
{
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition')))]",
"apiVersion": "2022-01-01-preview",
"type": "Microsoft.OperationalInsights/workspaces/providers/metadata",
"properties": {
"parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition'))]",
"contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]",
"kind": "DataConnector",
"version": "[variables('dataConnectorVersionConnectorDefinition')]",
"source": {
"sourceId": "[variables('_solutionId')]",
"name": "[variables('_solutionName')]",
"kind": "Solution"
},
"author": {
"name": "[variables('_solutionAuthor')]"
},
"support": {
"name": "[variables('_solutionAuthor')]",
"tier": "[variables('_solutionTier')]"
},
"dependencies": {
"criteria": [
{
"version": "[variables('dataConnectorVersionConnections')]",
"contentId": "[variables('_dataConnectorContentIdConnections')]",
"kind": "ResourcesDataConnector"
}
]
}
}
},
{
"name": "AtlassianJIRADCR",
"apiVersion": "2021-09-01-preview",
"type": "Microsoft.Insights/dataCollectionRules",
"location": "[parameters('workspace-location')]",
"kind": null,
"properties": {
"streamDeclarations": {
"[concat('Custom-', variables('_logAnalyticsTableId1'))]": {
"columns": [
{
"name": "id",
"type": "int"
},
{
"name": "summary",
"type": "string"
},
{
"name": "created",
"type": "datetime"
},
{
"name": "category",
"type": "string"
},
{
"name": "eventSource",
"type": "string"
},
{
"name": "objectItem",
"type": "dynamic"
},
{
"name": "changedValues",
"type": "dynamic"
},
{
"name": "associatedItems",
"type": "dynamic"
},
{
"name": "remoteAddress",
"type": "string"
},
{
"name": "authorKey",
"type": "string"
},
{
"name": "authorAccountId",
"type": "string"
}
]
}
},
"dataSources": {
},
"destinations": {
"logAnalytics": [
{
"workspaceResourceId": "[variables('workspaceResourceId')]",
"name": "clv2ws1"
}
]
},
"dataFlows": [
{
"streams": [
"[concat('Custom-', variables('_logAnalyticsTableId1'))]"
],
"destinations": [
"clv2ws1"
],
"transformKql": "source\n| extend TimeGenerated = now(), EventVendor=\"Atlassian\", EventProduct=\"Jira Audit\"\n| project-rename EventId=id,\n EventMessage=summary,\n SrcIpAddr=remoteAddress,\n UserName=authorKey,\n UserSid=authorAccountId,\n EventCreationTime=created,\n EventSource=eventSource,\n ChangedValues=changedValues,\n AssociatedItems=associatedItems,\n EventCategoryType= category \n|extend ObjectItemId=objectItem.id,\n ObjectItemName=objectItem.name,\n ObjectItemTypeName=objectItem.typeName,\n ObjectItemParentId=objectItem.parentId,\n ObjectItemParentName=objectItem.parentName\n | extend ObjectItemId=tostring(ObjectItemId), ObjectItemName=tostring(ObjectItemName), ObjectItemTypeName=tostring(ObjectItemTypeName), ObjectItemParentId=tostring(ObjectItemParentId), ObjectItemParentName=tostring(ObjectItemParentName) ",
"outputStream": "[concat('Custom-', variables('_logAnalyticsTableId1'))]"
}
],
"provisioningState": "Succeeded",
"dataCollectionEndpointId": "[concat('/subscriptions/',parameters('subscription'),'/resourceGroups/',parameters('resourceGroupName'),'/providers/Microsoft.Insights/dataCollectionEndpoints/',parameters('workspace'))]"
}
},
{
"name": "[variables('_logAnalyticsTableId1')]",
"apiVersion": "2021-03-01-privatepreview",
"type": "Microsoft.OperationalInsights/workspaces/tables",
"location": "[parameters('workspace-location')]",
"kind": null,
"properties": {
"schema": {
"tableSubType": "DataCollectionRuleBased",
"name": "[variables('_logAnalyticsTableId1')]",
"tableType": "CustomLog",
"columns": [
{
"name": "AssociatedItems",
"type": "dynamic",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "UserSid",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "UserName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventCategoryType",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ChangedValues",
"type": "dynamic",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventCreationTime",
"type": "datetime",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventSource",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventId",
"type": "int",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "objectItem",
"type": "dynamic",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "SrcIpAddr",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventMessage",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "TimeGenerated",
"type": "datetime",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventVendor",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "EventProduct",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemId",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemTypeName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemParentId",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
},
{
"name": "ObjectItemParentName",
"type": "string",
"isDefaultDisplay": false,
"isHidden": false
}
],
"standardColumns": [
{
"name": "TenantId",
"type": "guid",
"isDefaultDisplay": false,
"isHidden": false
}
],
"solutions": [
"LogManagement"
],
"isTroubleshootingAllowed": true
}
}
}
]
},
"packageKind": "Solution",
"packageVersion": "[variables('_solutionVersion')]",
"packageName": "[variables('_solutionName')]",
"contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentIdConnectorDefinition'),'-', variables('dataConnectorVersionConnectorDefinition'))))]",
"packageId": "[variables('_solutionId')]",
"contentSchemaVersion": "3.0.0",
"version": "[variables('_solutionVersion')]"
}
},
{
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentIdConnectorDefinition'))]",
"apiVersion": "2022-09-01-preview",
"type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectorDefinitions",
"location": "[parameters('workspace-location')]",
"kind": "Customizable",
"properties": {
"connectorUiConfig": {
"title": " Atlassian Jira Audit (using REST API) (Preview)",
"publisher": "Microsoft",
"descriptionMarkdown": "The [Atlassian Jira](https://www.atlassian.com/software/jira) Audit data connector provides the capability to ingest [Jira Audit Records](https://support.atlassian.com/jira-cloud-administration/docs/audit-activities-in-jira-applications/) events into Microsoft Sentinel through the REST API. Refer to [API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-audit-records/) for more information. The connector provides ability to get events which helps to examine potential security risks, analyze your team's use of collaboration, diagnose configuration problems and more.",
"graphQueriesTableName": "[variables('_logAnalyticsTableId1')]",
"graphQueries": [
{
"metricName": "Total data received",
"legend": "Jira Audit Events",
"baseQuery": "{{graphQueriesTableName}}"
}
],
"sampleQueries": [
{
"description": "All Atlassian Jira audit logs",
"query": "{{graphQueriesTableName}}\n| sort by TimeGenerated desc"
},
{
"description": "Total Events",
"query": "{{graphQueriesTableName}}\n | summarize count() by OriginalEventUid"
}
],
"dataTypes": [
{
"name": "{{graphQueriesTableName}}",
"lastDataReceivedQuery": "{{graphQueriesTableName}}|summarize Time = max (TimeGenerated)\n|where isnotempty(Time)"
}
],
"connectivityCriteria": [
{
"type": "HasDataConnectors"
}
],
"availability": {
"isPreview": false
},
"permissions": {
"resourceProvider": [
{
"provider": "Microsoft.OperationalInsights/workspaces",
"permissionsDisplayText": "Read and Write permissions are required.",
"providerDisplayName": "Workspace",
"scope": "Workspace",
"requiredPermissions": {
"write": true,
"read": true,
"delete": true
}
}
],
"customs": [
{
"name": "Atlassian Jira API access",
"description": "Permission of [Administer Jira](https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/#authentication) is required to get access to the Jira Audit logs API. See [Jira API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-audit-records/#api-group-audit-records) to learn more about the audit API."
}
]
},
"instructionSteps": [
{
"description": "To enable the Atlassian Jira connector for Microsoft Sentinel, click to add an organization, fill the form with the Jira environment credentials and click to Connect. \n Follow [these steps](https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/) to create an API token.\n ",
"instructions": [
{
"type": "DataConnectorsGrid",
"parameters": {
"mapping": [
{
"columnName": "Atlassian Jira organization URL",
"columnValue": "properties.request.apiEndpoint"
}
],
"menuItems": [
"DeleteConnector"
]
}
},
{
"type": "ContextPane",
"parameters": {
"isPrimary": true,
"label": "Add organization",
"title": "Add organization",
"subtitle": "Add Atlassian Jira organization",
"contextPaneType": "DataConnectorsContextPane",
"instructionSteps": [
{
"instructions": [
{
"type": "Textbox",
"parameters": {
"label": "Atlassian Jira organization URL",
"placeholder": "<your-domain>.atlassian.net",
"type": "string",
"name": "jiraorganizationurl"
}
},
{
"type": "Textbox",
"parameters": {
"label": "User Name",
"placeholder": "User Name (e.g., user@example.com)",
"type": "securestring",
"name": "userid"
}
},
{
"type": "Textbox",
"parameters": {
"label": "API Token",
"placeholder": "API Token",
"type": "password",
"name": "apikey"
}
}
]
}
]
}
}
]
}
]
}
}
},
{
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnectorDefinition')))]",
"apiVersion": "2022-01-01-preview",
"type": "Microsoft.OperationalInsights/workspaces/providers/metadata",
"properties": {
"parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectorDefinitions', variables('_dataConnectorContentIdConnectorDefinition'))]",
"contentId": "[variables('_dataConnectorContentIdConnectorDefinition')]",
"kind": "DataConnector",
"version": "[variables('dataConnectorVersionConnectorDefinition')]",
"source": {
"sourceId": "[variables('_solutionId')]",
"name": "[variables('_solutionName')]",
"kind": "Solution"
},
"author": {
"name": "[variables('_solutionAuthor')]"
},
"support": {
"name": "[variables('_solutionAuthor')]",
"tier": "[variables('_solutionTier')]"
},
"dependencies": {
"criteria": [
{
"version": "[variables('dataConnectorVersionConnections')]",
"contentId": "[variables('_dataConnectorContentIdConnections')]",
"kind": "ResourcesDataConnector"
}
]
}
}
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates",
"apiVersion": "2023-04-01-preview",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('dataConnectorTemplateNameConnections'), variables('dataConnectorVersionConnections'))]",
"location": "[parameters('workspace-location')]",
"dependsOn": [
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"contentId": "[variables('_dataConnectorContentIdConnections')]",
"displayName": "[concat(variables('_solutionName'), variables('dataConnectorTemplateNameConnections'))]",
"contentKind": "ResourcesDataConnector",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('dataConnectorVersionConnections')]",
"parameters": {
"connectorDefinitionName": {
"defaultValue": "connectorDefinitionName",
"type": "string",
"minLength": 1
},
"workspace": {
"defaultValue": "[parameters('workspace')]",
"type": "string"
},
"dcrConfig": {
"defaultValue": {
"dataCollectionEndpoint": "data collection Endpoint",
"dataCollectionRuleImmutableId": "data collection rule immutableId"
},
"type": "object"
},
"jiraorganizationurl": {
"defaultValue": "domain name",
"type": "string",
"minLength": 1
},
"userid": {
"defaultValue": "JIRA email",
"type": "string",
"minLength": 1
},
"apikey": {
"defaultValue": "API Key",
"type": "securestring",
"minLength": 1
}
},
"variables": {
"_dataConnectorContentIdConnections": "[variables('_dataConnectorContentIdConnections')]"
},
"resources": [
{
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', variables('_dataConnectorContentIdConnections')))]",
"apiVersion": "2022-01-01-preview",
"type": "Microsoft.OperationalInsights/workspaces/providers/metadata",
"properties": {
"parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentIdConnections'))]",
"contentId": "[variables('_dataConnectorContentIdConnections')]",
"kind": "ResourcesDataConnector",
"version": "[variables('dataConnectorVersionConnections')]",
"source": {
"sourceId": "[variables('_solutionId')]",
"name": "[variables('_solutionName')]",
"kind": "Solution"
},
"author": {
"name": "[variables('_solutionAuthor')]"
},
"support": {
"name": "[variables('_solutionAuthor')]",
"tier": "[variables('_solutionTier')]"
}
}
},
{
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', 'AtlassianJira')]",
"apiVersion": "2022-12-01-preview",
"type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors",
"location": "[parameters('workspace-location')]",
"kind": "RestApiPoller",
"properties": {
"connectorDefinitionName": "[[parameters('connectorDefinitionName')]",
"dataType": "[variables('_logAnalyticsTableId1')]",
"dcrConfig": {
"dataCollectionEndpoint": "[[parameters('dcrConfig').dataCollectionEndpoint]",
"dataCollectionRuleImmutableId": "[[parameters('dcrConfig').dataCollectionRuleImmutableId]",
"streamName": "[concat('Custom-', variables('_logAnalyticsTableId1'))]"
},
"auth": {
"type": "Basic",
"UserName": "[[parameters('userid')]",
"Password": "[[parameters('apikey')]"
},
"request": {
"apiEndpoint": "[[concat('https://',parameters('jiraorganizationurl'),'/rest/api/3/auditing/record')]",
"httpMethod": "GET",
"retryCount": 3,
"timeoutInSeconds": 60,
"queryTimeFormat": "yyyy-MM-ddTHH:mm:ssZ",
"headers": {
"Accept": "application/json",
"User-Agent": "Scuba"
},
"startTimeAttributeName": "from",
"endTimeAttributeName": "to"
},
"paging": {
"pagingType": "Offset",
"offsetParaName": "offset",
"pageSizeParaName": "limit",
"pageSize": 1000
},
"response": {
"eventsJsonPaths": [
"$.records"
],
"format": "json"
}
}
}
]
},
"packageKind": "Solution",
"packageVersion": "[variables('_solutionVersion')]",
"packageName": "[variables('_solutionName')]",
"contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','rdc','-', uniqueString(concat(variables('_solutionId'),'-','ResourcesDataConnector','-',variables('_dataConnectorContentIdConnections'),'-', variables('dataConnectorVersionConnections'))))]",
"packageId": "[variables('_solutionId')]",
"contentSchemaVersion": "3.0.0",
"version": "[variables('_solutionVersion')]"
}
},
{
"type": "Microsoft.OperationalInsights/workspaces/providers/contentPackages",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/', variables('_solutionId'))]",
"location": "[parameters('workspace-location')]",
"apiVersion": "2023-04-01-preview",
"properties": {
"version": "[variables('_solutionVersion')]",
"kind": "Solution",
"contentSchemaVersion": "3.0.0",
"contentId": "[variables('_solutionId')]",
"source": {
"kind": "Solution",
"name": "[variables('_solutionName')]",
"sourceId": "[variables('_solutionId')]"
},
"author": {
"name": "[variables('_solutionAuthor')]"
},
"support": {
"name": "[variables('_solutionAuthor')]"
},
"dependencies": {
"operator": "AND",
"criteria": [
{
"kind": "DataConnector",
"contentId": "[variables('dataConnectorVersionConnectorDefinition')]",
"version": "[variables('_dataConnectorContentIdConnectorDefinition')]"
}
]
},
"firstPublishDate": "2022-06-24",
"providers": [
"[variables('_solutionAuthor')]"
],
"contentKind": "Solution",
"packageId": "[variables('_solutionId')]",
"contentProductId": "[concat(substring(variables('_solutionId'), 0, 50),'-','sl','-', uniqueString(concat(variables('_solutionId'),'-','Solution','-',variables('_solutionId'),'-', variables('_solutionVersion'))))]",
"displayName": "[variables('_solutionName')]",
"publisherDisplayName": "[variables('_solutionId')]",
"descriptionHtml": "test",
"icon": "[variables('_packageIcon')]"
}
}
]
}

Просмотреть файл

@ -118,4 +118,4 @@
"description": "**2. Configure the Function App**\n\n1. In the Function App, select the Function App Name and select **Configuration**.\n2. In the **Application settings** tab, select ** New application setting**.\n3. Add each of the following application settings individually, with their respective string values (case-sensitive): \n\t\tJiraUsername\n\t\tJiraAccessToken\n\t\tJiraHomeSiteName\n\t\tWorkspaceID\n\t\tWorkspaceKey\n\t\tlogAnalyticsUri (optional)\n> - Use logAnalyticsUri to override the log analytics API endpoint for dedicated cloud. For example, for public cloud, leave the value empty; for Azure GovUS cloud environment, specify the value in the following format: `https://<CustomerId>.ods.opinsights.azure.us`.\n3. Once all application settings have been entered, click **Save**."
}
]
}
}

Просмотреть файл

@ -1,211 +1,211 @@
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"FunctionName": {
"defaultValue": "JiraAudit",
"minLength": 1,
"maxLength": 11,
"type": "string"
},
"WorkspaceID": {
"type": "string",
"defaultValue": "<workspaceID>"
},
"WorkspaceKey": {
"type": "securestring",
"defaultValue": "<workspaceKey>"
},
"JiraAccessToken": {
"type": "securestring",
"defaultValue": "<JiraAccessToken>"
},
"JiraUsername": {
"type": "string",
"defaultValue": "<JiraUsername>"
},
"JiraHomeSiteName": {
"type": "string",
"defaultValue": "<JiraHomeSiteName>"
},
"AppInsightsWorkspaceResourceID": {
"type": "string",
"metadata": {
"description": "Migrate Classic Application Insights to Log Analytic Workspace which is retiring by 29 Febraury 2024. Use 'Log Analytic Workspace-->Properties' blade having 'Resource ID' property value. This is a fully qualified resourceId which is in format '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}'"
}
}
},
"variables": {
"FunctionName": "[concat(toLower(parameters('FunctionName')), uniqueString(resourceGroup().id))]",
"StorageSuffix": "[environment().suffixes.storage]",
"LogAnaltyicsUri": "[replace(environment().portal, 'https://portal', concat('https://', toLower(parameters('WorkspaceID')), '.ods.opinsights'))]"
},
"resources": [
{
"type": "Microsoft.Insights/components",
"apiVersion": "2020-02-02",
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"kind": "web",
"properties": {
"Application_Type": "web",
"ApplicationId": "[variables('FunctionName')]",
"WorkspaceResourceId": "[parameters('AppInsightsWorkspaceResourceID')]"
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[tolower(variables('FunctionName'))]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Allow"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"keyType": "Account",
"enabled": true
},
"blob": {
"keyType": "Account",
"enabled": true
}
},
"keySource": "Microsoft.Storage"
}
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
],
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"properties": {
"cors": {
"corsRules": []
},
"deleteRetentionPolicy": {
"enabled": false
}
}
},
{
"type": "Microsoft.Storage/storageAccounts/fileServices",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
],
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"properties": {
"cors": {
"corsRules": []
}
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]",
"[resourceId('Microsoft.Insights/components', variables('FunctionName'))]"
],
"kind": "functionapp,linux",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"name": "[variables('FunctionName')]",
"httpsOnly": true,
"clientAffinityEnabled": true,
"alwaysOn": true,
"reserved": true,
"siteConfig": {
"linuxFxVersion": "python|3.8"
}
},
"resources": [
{
"apiVersion": "2018-11-01",
"type": "config",
"name": "appsettings",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('FunctionName'))]"
],
"properties": {
"FUNCTIONS_EXTENSION_VERSION": "~4",
"FUNCTIONS_WORKER_RUNTIME": "python",
"APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(resourceId('Microsoft.insights/components', variables('FunctionName')), '2015-05-01').InstrumentationKey]",
"APPLICATIONINSIGHTS_CONNECTION_STRING": "[reference(resourceId('microsoft.insights/components', variables('FunctionName')), '2015-05-01').ConnectionString]",
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=',toLower(variables('StorageSuffix')))]",
"WorkspaceID": "[parameters('WorkspaceID')]",
"WorkspaceKey": "[parameters('WorkspaceKey')]",
"JiraAccessToken": "[parameters('JiraAccessToken')]",
"JiraUsername": "[parameters('JiraUsername')]",
"JiraHomeSiteName": "[parameters('JiraHomeSiteName')]",
"logAnalyticsUri": "[variables('LogAnaltyicsUri')]",
"WEBSITE_RUN_FROM_PACKAGE": "https://aka.ms/sentinel-jiraauditapi-functionapp"
}
}
]
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-hosts')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-secrets')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Storage/storageAccounts/fileServices/shares",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/', tolower(variables('FunctionName')))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/fileServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"shareQuota": 5120
}
}
]
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"FunctionName": {
"defaultValue": "JiraAudit",
"minLength": 1,
"maxLength": 11,
"type": "string"
},
"WorkspaceID": {
"type": "string",
"defaultValue": "<workspaceID>"
},
"WorkspaceKey": {
"type": "securestring",
"defaultValue": "<workspaceKey>"
},
"JiraAccessToken": {
"type": "securestring",
"defaultValue": "<JiraAccessToken>"
},
"JiraUsername": {
"type": "string",
"defaultValue": "<JiraUsername>"
},
"JiraHomeSiteName": {
"type": "string",
"defaultValue": "<JiraHomeSiteName>"
},
"AppInsightsWorkspaceResourceID": {
"type": "string",
"metadata": {
"description": "Migrate Classic Application Insights to Log Analytic Workspace which is retiring by 29 Febraury 2024. Use 'Log Analytic Workspace-->Properties' blade having 'Resource ID' property value. This is a fully qualified resourceId which is in format '/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName}'"
}
}
},
"variables": {
"FunctionName": "[concat(toLower(parameters('FunctionName')), uniqueString(resourceGroup().id))]",
"StorageSuffix": "[environment().suffixes.storage]",
"LogAnaltyicsUri": "[replace(environment().portal, 'https://portal', concat('https://', toLower(parameters('WorkspaceID')), '.ods.opinsights'))]"
},
"resources": [
{
"type": "Microsoft.Insights/components",
"apiVersion": "2020-02-02",
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"kind": "web",
"properties": {
"Application_Type": "web",
"ApplicationId": "[variables('FunctionName')]",
"WorkspaceResourceId": "[parameters('AppInsightsWorkspaceResourceID')]"
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[tolower(variables('FunctionName'))]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "StorageV2",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Allow"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"keyType": "Account",
"enabled": true
},
"blob": {
"keyType": "Account",
"enabled": true
}
},
"keySource": "Microsoft.Storage"
}
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
],
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"properties": {
"cors": {
"corsRules": []
},
"deleteRetentionPolicy": {
"enabled": false
}
}
},
{
"type": "Microsoft.Storage/storageAccounts/fileServices",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
],
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"properties": {
"cors": {
"corsRules": []
}
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2018-11-01",
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]",
"[resourceId('Microsoft.Insights/components', variables('FunctionName'))]"
],
"kind": "functionapp,linux",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"name": "[variables('FunctionName')]",
"httpsOnly": true,
"clientAffinityEnabled": true,
"alwaysOn": true,
"reserved": true,
"siteConfig": {
"linuxFxVersion": "python|3.8"
}
},
"resources": [
{
"apiVersion": "2018-11-01",
"type": "config",
"name": "appsettings",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('FunctionName'))]"
],
"properties": {
"FUNCTIONS_EXTENSION_VERSION": "~4",
"FUNCTIONS_WORKER_RUNTIME": "python",
"APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(resourceId('Microsoft.insights/components', variables('FunctionName')), '2015-05-01').InstrumentationKey]",
"APPLICATIONINSIGHTS_CONNECTION_STRING": "[reference(resourceId('microsoft.insights/components', variables('FunctionName')), '2015-05-01').ConnectionString]",
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=',toLower(variables('StorageSuffix')))]",
"WorkspaceID": "[parameters('WorkspaceID')]",
"WorkspaceKey": "[parameters('WorkspaceKey')]",
"JiraAccessToken": "[parameters('JiraAccessToken')]",
"JiraUsername": "[parameters('JiraUsername')]",
"JiraHomeSiteName": "[parameters('JiraHomeSiteName')]",
"logAnalyticsUri": "[variables('LogAnaltyicsUri')]",
"WEBSITE_RUN_FROM_PACKAGE": "https://aka.ms/sentinel-jiraauditapi-functionapp"
}
}
]
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-hosts')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-secrets')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Storage/storageAccounts/fileServices/shares",
"apiVersion": "2019-06-01",
"name": "[concat(variables('FunctionName'), '/default/', tolower(variables('FunctionName')))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/fileServices', variables('FunctionName'), 'default')]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
],
"properties": {
"shareQuota": 5120
}
}
]
}

Просмотреть файл

@ -1,15 +1,15 @@
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[3.*, 4.0.0)"
}
}
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[3.*, 4.0.0)"
}
}

Просмотреть файл

@ -1,4 +1,4 @@
{
"$schema": "http://json.schemastore.org/proxies",
"proxies": {}
}
{
"$schema": "http://json.schemastore.org/proxies",
"proxies": {}
}

Просмотреть файл

@ -1,7 +1,7 @@
# DO NOT include azure-functions-worker in this file
# The Python Worker is managed by Azure Functions platform
# Manually managing azure-functions-worker may cause unexpected issues
azure-functions
requests
# DO NOT include azure-functions-worker in this file
# The Python Worker is managed by Azure Functions platform
# Manually managing azure-functions-worker may cause unexpected issues
azure-functions
requests
azure-storage-file-share==12.3.0

Просмотреть файл

@ -1,51 +1,56 @@
{
"Name": "AtlassianJiraAudit",
"Author": "Microsoft - support@microsoft.com",
"Logo": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/atlassian.svg\"width=\"75px\"height=\"75px\">",
"Description": "The [Atlassian Jira](https://www.atlassian.com/software/jira) Audit solution provides the capability to ingest [Jira Audit Records](https://support.atlassian.com/jira-cloud-administration/docs/audit-activities-in-jira-applications/) events into Microsoft Sentinel through the REST API. Refer to [API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-audit-records/) for more information.\n\n**Underlying Microsoft Technologies used:**\n\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs: \n\n a. [Azure Monitor HTTP Data Collector API](https://docs.microsoft.com/azure/azure-monitor/logs/data-collector-api) \n\n b.[Azure Functions](https://azure.microsoft.com/services/functions/#overview)",
"Workbooks": [
"Workbooks/AtlassianJiraAudit.json"
],
"Analytic Rules": [
"Analytic Rules/JiraGlobalPermissionAdded.yaml",
"Analytic Rules/JiraNewPrivilegedUser.yaml",
"Analytic Rules/JiraNewUser.yaml",
"Analytic Rules/JiraPermissionSchemeUpdated.yaml",
"Analytic Rules/JiraPrivilegedUserPasswordChanged.yaml",
"Analytic Rules/JiraProjectRolesChanged.yaml",
"Analytic Rules/JiraUserPasswordChange.yaml",
"Analytic Rules/JiraUserRemovedFromGroup.yaml",
"Analytic Rules/JiraUserRemovedFromProject.yaml",
"Analytic Rules/JiraWorkflowSchemeCopied.yaml"
],
"Hunting Queries": [
"Hunting Queries/JiraBlockedTasks.yaml",
"Hunting Queries/JiraNewUsers.yaml",
"Hunting Queries/JiraProjectVersionsReleased.yaml",
"Hunting Queries/JiraUpdatedProjectVersions.yaml",
"Hunting Queries/JiraUpdatedProjects.yaml",
"Hunting Queries/JiraUpdatedUsers.yaml",
"Hunting Queries/JiraUpdatedWorkflowSchemes.yaml",
"Hunting Queries/JiraUpdatedWorkflows.yaml",
"Hunting Queries/JiraUserIPs.yaml",
"Hunting Queries/JiraWorkflowAddedToProject.yaml"
],
"Data Connectors": [
"Data Connectors/JiraAudit_API_FunctionApp.json"
],
"Playbooks": [
"Playbooks/Create-Jira-Issue/alert-trigger/azuredeploy.json",
"Playbooks/Create-Jira-Issue/incident-trigger/azuredeploy.json",
"Playbooks/Jira-CreateAndUpdateIssue/azuredeploy.json",
"Playbooks/Sync-AssignedUser/azuredeploy.json",
"Playbooks/Add-JiraLinkComment/azuredeploy.json",
"Playbooks/Sync-CommentsFunctionApp/azuredeploy.json",
"Playbooks/Sync-Incidents/azuredeploy.json",
"Playbooks/Sync-Status/azuredeploy.json"
],
"BasePath": "C:\\GitHub\\azure-Sentinel\\Solutions\\AtlassianJiraAudit",
"Version": "3.0.1",
"Metadata": "SolutionMetadata.json",
"TemplateSpec": true,
"Is1PConnector": false
{
"Name": "AtlassianJiraAudit",
"Author": "Microsoft - support@microsoft.com",
"Logo": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/atlassian.svg\"width=\"75px\"height=\"75px\">",
"Description": "The [Atlassian Jira](https://www.atlassian.com/software/jira) Audit solution provides the capability to ingest [Jira Audit Records](https://support.atlassian.com/jira-cloud-administration/docs/audit-activities-in-jira-applications/) events into Microsoft Sentinel through the REST API. Refer to [API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-audit-records/) for more information.\n\n**Underlying Microsoft Technologies used:**\n\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs: \n\n a. [Azure Monitor HTTP Data Collector API](https://docs.microsoft.com/azure/azure-monitor/logs/data-collector-api) \n\n b.[Azure Functions](https://azure.microsoft.com/services/functions/#overview) \n\n c.[Codeless Connector Platform (CCP)](https://learn.microsoft.com/en-us/azure/sentinel/create-custom-connector#connect-with-the-codeless-connector-platform)",
"Workbooks": [
"Workbooks/AtlassianJiraAudit.json"
],
"Analytic Rules": [
"Analytic Rules/JiraGlobalPermissionAdded.yaml",
"Analytic Rules/JiraNewPrivilegedUser.yaml",
"Analytic Rules/JiraNewUser.yaml",
"Analytic Rules/JiraPermissionSchemeUpdated.yaml",
"Analytic Rules/JiraPrivilegedUserPasswordChanged.yaml",
"Analytic Rules/JiraProjectRolesChanged.yaml",
"Analytic Rules/JiraUserPasswordChange.yaml",
"Analytic Rules/JiraUserRemovedFromGroup.yaml",
"Analytic Rules/JiraUserRemovedFromProject.yaml",
"Analytic Rules/JiraWorkflowSchemeCopied.yaml"
],
"Hunting Queries": [
"Hunting Queries/JiraBlockedTasks.yaml",
"Hunting Queries/JiraNewUsers.yaml",
"Hunting Queries/JiraProjectVersionsReleased.yaml",
"Hunting Queries/JiraUpdatedProjectVersions.yaml",
"Hunting Queries/JiraUpdatedProjects.yaml",
"Hunting Queries/JiraUpdatedUsers.yaml",
"Hunting Queries/JiraUpdatedWorkflowSchemes.yaml",
"Hunting Queries/JiraUpdatedWorkflows.yaml",
"Hunting Queries/JiraUserIPs.yaml",
"Hunting Queries/JiraWorkflowAddedToProject.yaml"
],
"Data Connectors": [
"Data Connectors/JiraAuditAPISentinelConnector_ccpv2/JiraAudit_DataConnectorDefinition.json",
"Data Connectors/JiraAudit_API_FunctionApp.json"
],
"Parsers": [
"Parsers/JiraAudit.yaml"
],
"Playbooks": [
"Playbooks/Create-Jira-Issue/alert-trigger/azuredeploy.json",
"Playbooks/Create-Jira-Issue/incident-trigger/azuredeploy.json",
"Playbooks/Jira-CreateAndUpdateIssue/azuredeploy.json",
"Playbooks/Sync-AssignedUser/azuredeploy.json",
"Playbooks/Add-JiraLinkComment/azuredeploy.json",
"Playbooks/Sync-CommentsFunctionApp/azuredeploy.json",
"Playbooks/Sync-Incidents/azuredeploy.json",
"Playbooks/Sync-Status/azuredeploy.json"
],
"BasePath": "C:\\GitHub\\azure-Sentinel\\Solutions\\AtlassianJiraAudit",
"Version": "3.0.0",
"Metadata": "SolutionMetadata.json",
"TemplateSpec": true,
"Is1PConnector": false
}

Двоичные данные
Solutions/AtlassianJiraAudit/Package/3.0.2.zip Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -1,487 +1,494 @@
{
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
"handler": "Microsoft.Azure.CreateUIDef",
"version": "0.1.2-preview",
"parameters": {
"config": {
"isWizard": false,
"basics": {
"description": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/atlassian.svg\"width=\"75px\"height=\"75px\">\n\n**Note:** Please refer to the following before installing the solution: \n\n• Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/AtlassianJiraAudit/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe [Atlassian Jira](https://www.atlassian.com/software/jira) Audit solution provides the capability to ingest [Jira Audit Records](https://support.atlassian.com/jira-cloud-administration/docs/audit-activities-in-jira-applications/) events into Microsoft Sentinel through the REST API. Refer to [API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-audit-records/) for more information.\n\n**Underlying Microsoft Technologies used:**\n\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs: \n\n a. [Azure Monitor HTTP Data Collector API](https://docs.microsoft.com/azure/azure-monitor/logs/data-collector-api) \n\n b.[Azure Functions](https://azure.microsoft.com/services/functions/#overview)\n\n**Data Connectors:** 1, **Workbooks:** 1, **Analytic Rules:** 10, **Hunting Queries:** 10, **Function Apps:** 1, **Playbooks:** 7\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)",
"subscription": {
"resourceProviders": [
"Microsoft.OperationsManagement/solutions",
"Microsoft.OperationalInsights/workspaces/providers/alertRules",
"Microsoft.Insights/workbooks",
"Microsoft.Logic/workflows"
]
},
"location": {
"metadata": {
"hidden": "Hiding location, we get it from the log analytics workspace"
},
"visible": false
},
"resourceGroup": {
"allowExisting": true
}
}
},
"basics": [
{
"name": "getLAWorkspace",
"type": "Microsoft.Solutions.ArmApiControl",
"toolTip": "This filters by workspaces that exist in the Resource Group selected",
"condition": "[greater(length(resourceGroup().name),0)]",
"request": {
"method": "GET",
"path": "[concat(subscription().id,'/providers/Microsoft.OperationalInsights/workspaces?api-version=2020-08-01')]"
}
},
{
"name": "workspace",
"type": "Microsoft.Common.DropDown",
"label": "Workspace",
"placeholder": "Select a workspace",
"toolTip": "This dropdown will list only workspace that exists in the Resource Group selected",
"constraints": {
"allowedValues": "[map(filter(basics('getLAWorkspace').value, (filter) => contains(toLower(filter.id), toLower(resourceGroup().name))), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]",
"required": true
},
"visible": true
}
],
"steps": [
{
"name": "dataconnectors",
"label": "Data Connectors",
"bladeTitle": "Data Connectors",
"elements": [
{
"name": "dataconnectors1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This Solution installs the data connector for AtlassianJiraAudit. You can get AtlassianJiraAudit custom log data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view."
}
},
{
"name": "dataconnectors-link2",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more about connecting data sources",
"uri": "https://docs.microsoft.com/azure/sentinel/connect-data-sources"
}
}
}
]
},
{
"name": "workbooks",
"label": "Workbooks",
"subLabel": {
"preValidation": "Configure the workbooks",
"postValidation": "Done"
},
"bladeTitle": "Workbooks",
"elements": [
{
"name": "workbooks-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This solution installs workbook(s) to help you gain insights into the telemetry collected in Microsoft Sentinel. After installing the solution, start using the workbook in Manage solution view."
}
},
{
"name": "workbooks-link",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more",
"uri": "https://docs.microsoft.com/azure/sentinel/tutorial-monitor-your-data"
}
}
},
{
"name": "workbook1",
"type": "Microsoft.Common.Section",
"label": "AtlassianJiraAudit",
"elements": [
{
"name": "workbook1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Sets the time name for analysis"
}
}
]
}
]
},
{
"name": "analytics",
"label": "Analytics",
"subLabel": {
"preValidation": "Configure the analytics",
"postValidation": "Done"
},
"bladeTitle": "Analytics",
"elements": [
{
"name": "analytics-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This solution installs the following analytic rule templates. After installing the solution, create and enable analytic rules in Manage solution view."
}
},
{
"name": "analytics-link",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more",
"uri": "https://docs.microsoft.com/azure/sentinel/tutorial-detect-threats-custom?WT.mc_id=Portal-Microsoft_Azure_CreateUIDef"
}
}
},
{
"name": "analytic1",
"type": "Microsoft.Common.Section",
"label": "Jira - Global permission added",
"elements": [
{
"name": "analytic1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when global permission added."
}
}
]
},
{
"name": "analytic2",
"type": "Microsoft.Common.Section",
"label": "Jira - New site admin user",
"elements": [
{
"name": "analytic2-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects new site admin user."
}
}
]
},
{
"name": "analytic3",
"type": "Microsoft.Common.Section",
"label": "Jira - New user created",
"elements": [
{
"name": "analytic3-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when new user was created."
}
}
]
},
{
"name": "analytic4",
"type": "Microsoft.Common.Section",
"label": "Jira - Permission scheme updated",
"elements": [
{
"name": "analytic4-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when permission scheme was updated."
}
}
]
},
{
"name": "analytic5",
"type": "Microsoft.Common.Section",
"label": "Jira - New site admin user",
"elements": [
{
"name": "analytic5-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects new site admin user."
}
}
]
},
{
"name": "analytic6",
"type": "Microsoft.Common.Section",
"label": "Jira - Project roles changed",
"elements": [
{
"name": "analytic6-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when project roles were changed."
}
}
]
},
{
"name": "analytic7",
"type": "Microsoft.Common.Section",
"label": "Jira - User's password changed multiple times",
"elements": [
{
"name": "analytic7-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when user's password was changed multiple times from different IP addresses."
}
}
]
},
{
"name": "analytic8",
"type": "Microsoft.Common.Section",
"label": "Jira - User removed from group",
"elements": [
{
"name": "analytic8-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when a user was removed from group."
}
}
]
},
{
"name": "analytic9",
"type": "Microsoft.Common.Section",
"label": "Jira - User removed from project",
"elements": [
{
"name": "analytic9-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when a user was removed from project."
}
}
]
},
{
"name": "analytic10",
"type": "Microsoft.Common.Section",
"label": "Jira - Workflow scheme copied",
"elements": [
{
"name": "analytic10-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when workflow scheme was copied."
}
}
]
}
]
},
{
"name": "huntingqueries",
"label": "Hunting Queries",
"bladeTitle": "Hunting Queries",
"elements": [
{
"name": "huntingqueries-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This solution installs the following hunting queries. After installing the solution, run these hunting queries to hunt for threats in Manage solution view. "
}
},
{
"name": "huntingqueries-link",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more",
"uri": "https://docs.microsoft.com/azure/sentinel/hunting"
}
}
},
{
"name": "huntingquery1",
"type": "Microsoft.Common.Section",
"label": "Jira - Blocked tasks",
"elements": [
{
"name": "huntingquery1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for blocked tasks. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery2",
"type": "Microsoft.Common.Section",
"label": "Jira - New users",
"elements": [
{
"name": "huntingquery2-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for new users created. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery3",
"type": "Microsoft.Common.Section",
"label": "Jira - Project versions released",
"elements": [
{
"name": "huntingquery3-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for project versions released. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery4",
"type": "Microsoft.Common.Section",
"label": "Jira - Project versions",
"elements": [
{
"name": "huntingquery4-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for project versions. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery5",
"type": "Microsoft.Common.Section",
"label": "Jira - Updated projects",
"elements": [
{
"name": "huntingquery5-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for updated projects. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery6",
"type": "Microsoft.Common.Section",
"label": "Jira - Updated users",
"elements": [
{
"name": "huntingquery6-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for updated users. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery7",
"type": "Microsoft.Common.Section",
"label": "Jira - Updated workflow schemes",
"elements": [
{
"name": "huntingquery7-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for updated workflow schemes. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery8",
"type": "Microsoft.Common.Section",
"label": "Jira - Updated workflows",
"elements": [
{
"name": "huntingquery8-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for updated workflows. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery9",
"type": "Microsoft.Common.Section",
"label": "Jira - Users' IP addresses",
"elements": [
{
"name": "huntingquery9-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for users' IP addresses. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery10",
"type": "Microsoft.Common.Section",
"label": "Jira - Workflow schemes added to projects",
"elements": [
{
"name": "huntingquery10-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for workflow schemes added to projects. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
}
]
},
{
"name": "playbooks",
"label": "Playbooks",
"subLabel": {
"preValidation": "Configure the playbooks",
"postValidation": "Done"
},
"bladeTitle": "Playbooks",
"elements": [
{
"name": "playbooks-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This solution installs the Playbook templates to help implement your Security Orchestration, Automation and Response (SOAR) operations. After installing the solution, these will be deployed under Playbook Templates in the Automation blade in Microsoft Sentinel. They can be configured and managed from the Manage solution view in Content Hub."
}
},
{
"name": "playbooks-link",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more",
"uri": "https://docs.microsoft.com/azure/sentinel/tutorial-respond-threats-playbook?WT.mc_id=Portal-Microsoft_Azure_CreateUIDef"
}
}
}
]
}
],
"outputs": {
"workspace-location": "[first(map(filter(basics('getLAWorkspace').value, (filter) => and(contains(toLower(filter.id), toLower(resourceGroup().name)),equals(filter.name,basics('workspace')))), (item) => item.location))]",
"location": "[location()]",
"workspace": "[basics('workspace')]"
}
}
}
{
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
"handler": "Microsoft.Azure.CreateUIDef",
"version": "0.1.2-preview",
"parameters": {
"config": {
"isWizard": false,
"basics": {
"description": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/atlassian.svg\"width=\"75px\"height=\"75px\">\n\n**Note:** Please refer to the following before installing the solution: \n\n• Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/AtlassianJiraAudit/ReleaseNotes.md)\n\n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe [Atlassian Jira](https://www.atlassian.com/software/jira) Audit solution provides the capability to ingest [Jira Audit Records](https://support.atlassian.com/jira-cloud-administration/docs/audit-activities-in-jira-applications/) events into Microsoft Sentinel through the REST API. Refer to [API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-audit-records/) for more information.\n\n**Underlying Microsoft Technologies used:**\n\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs: \n\n a. [Azure Monitor HTTP Data Collector API](https://docs.microsoft.com/azure/azure-monitor/logs/data-collector-api) \n\n b.[Azure Functions](https://azure.microsoft.com/services/functions/#overview) \n\n c.[Codeless Connector Platform (CCP)](https://learn.microsoft.com/en-us/azure/sentinel/create-custom-connector#connect-with-the-codeless-connector-platform)\n\n**Data Connectors:** 2, **Parsers:** 1, **Workbooks:** 1, **Analytic Rules:** 10, **Hunting Queries:** 10, **Function Apps:** 1, **Playbooks:** 7\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)",
"subscription": {
"resourceProviders": [
"Microsoft.OperationsManagement/solutions",
"Microsoft.OperationalInsights/workspaces/providers/alertRules",
"Microsoft.Insights/workbooks",
"Microsoft.Logic/workflows"
]
},
"location": {
"metadata": {
"hidden": "Hiding location, we get it from the log analytics workspace"
},
"visible": false
},
"resourceGroup": {
"allowExisting": true
}
}
},
"basics": [
{
"name": "getLAWorkspace",
"type": "Microsoft.Solutions.ArmApiControl",
"toolTip": "This filters by workspaces that exist in the Resource Group selected",
"condition": "[greater(length(resourceGroup().name),0)]",
"request": {
"method": "GET",
"path": "[concat(subscription().id,'/providers/Microsoft.OperationalInsights/workspaces?api-version=2020-08-01')]"
}
},
{
"name": "workspace",
"type": "Microsoft.Common.DropDown",
"label": "Workspace",
"placeholder": "Select a workspace",
"toolTip": "This dropdown will list only workspace that exists in the Resource Group selected",
"constraints": {
"allowedValues": "[map(filter(basics('getLAWorkspace').value, (filter) => contains(toLower(filter.id), toLower(resourceGroup().name))), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]",
"required": true
},
"visible": true
}
],
"steps": [
{
"name": "dataconnectors",
"label": "Data Connectors",
"bladeTitle": "Data Connectors",
"elements": [
{
"name": "dataconnectors1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This Solution installs the data connector for AtlassianJiraAudit. You can get AtlassianJiraAudit custom log data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view."
}
},
{
"name": "dataconnectors-parser-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "The Solution installs a parser that transforms the ingested data into Microsoft Sentinel normalized format. The normalized format enables better correlation of different types of data from different data sources to drive end-to-end outcomes seamlessly in security monitoring, hunting, incident investigation and response scenarios in Microsoft Sentinel."
}
},
{
"name": "dataconnectors-link1",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more about connecting data sources",
"uri": "https://docs.microsoft.com/azure/sentinel/connect-data-sources"
}
}
}
]
},
{
"name": "workbooks",
"label": "Workbooks",
"subLabel": {
"preValidation": "Configure the workbooks",
"postValidation": "Done"
},
"bladeTitle": "Workbooks",
"elements": [
{
"name": "workbooks-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This solution installs workbook(s) to help you gain insights into the telemetry collected in Microsoft Sentinel. After installing the solution, start using the workbook in Manage solution view."
}
},
{
"name": "workbooks-link",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more",
"uri": "https://docs.microsoft.com/azure/sentinel/tutorial-monitor-your-data"
}
}
},
{
"name": "workbook1",
"type": "Microsoft.Common.Section",
"label": "AtlassianJiraAudit",
"elements": [
{
"name": "workbook1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Sets the time name for analysis"
}
}
]
}
]
},
{
"name": "analytics",
"label": "Analytics",
"subLabel": {
"preValidation": "Configure the analytics",
"postValidation": "Done"
},
"bladeTitle": "Analytics",
"elements": [
{
"name": "analytics-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This solution installs the following analytic rule templates. After installing the solution, create and enable analytic rules in Manage solution view."
}
},
{
"name": "analytics-link",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more",
"uri": "https://docs.microsoft.com/azure/sentinel/tutorial-detect-threats-custom?WT.mc_id=Portal-Microsoft_Azure_CreateUIDef"
}
}
},
{
"name": "analytic1",
"type": "Microsoft.Common.Section",
"label": "Jira - Global permission added",
"elements": [
{
"name": "analytic1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when global permission added."
}
}
]
},
{
"name": "analytic2",
"type": "Microsoft.Common.Section",
"label": "Jira - New site admin user",
"elements": [
{
"name": "analytic2-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects new site admin user."
}
}
]
},
{
"name": "analytic3",
"type": "Microsoft.Common.Section",
"label": "Jira - New user created",
"elements": [
{
"name": "analytic3-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when new user was created."
}
}
]
},
{
"name": "analytic4",
"type": "Microsoft.Common.Section",
"label": "Jira - Permission scheme updated",
"elements": [
{
"name": "analytic4-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when permission scheme was updated."
}
}
]
},
{
"name": "analytic5",
"type": "Microsoft.Common.Section",
"label": "Jira - New site admin user",
"elements": [
{
"name": "analytic5-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects new site admin user."
}
}
]
},
{
"name": "analytic6",
"type": "Microsoft.Common.Section",
"label": "Jira - Project roles changed",
"elements": [
{
"name": "analytic6-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when project roles were changed."
}
}
]
},
{
"name": "analytic7",
"type": "Microsoft.Common.Section",
"label": "Jira - User's password changed multiple times",
"elements": [
{
"name": "analytic7-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when user's password was changed multiple times from different IP addresses."
}
}
]
},
{
"name": "analytic8",
"type": "Microsoft.Common.Section",
"label": "Jira - User removed from group",
"elements": [
{
"name": "analytic8-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when a user was removed from group."
}
}
]
},
{
"name": "analytic9",
"type": "Microsoft.Common.Section",
"label": "Jira - User removed from project",
"elements": [
{
"name": "analytic9-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when a user was removed from project."
}
}
]
},
{
"name": "analytic10",
"type": "Microsoft.Common.Section",
"label": "Jira - Workflow scheme copied",
"elements": [
{
"name": "analytic10-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Detects when workflow scheme was copied."
}
}
]
}
]
},
{
"name": "huntingqueries",
"label": "Hunting Queries",
"bladeTitle": "Hunting Queries",
"elements": [
{
"name": "huntingqueries-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This solution installs the following hunting queries. After installing the solution, run these hunting queries to hunt for threats in Manage solution view. "
}
},
{
"name": "huntingqueries-link",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more",
"uri": "https://docs.microsoft.com/azure/sentinel/hunting"
}
}
},
{
"name": "huntingquery1",
"type": "Microsoft.Common.Section",
"label": "Jira - Blocked tasks",
"elements": [
{
"name": "huntingquery1-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for blocked tasks. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery2",
"type": "Microsoft.Common.Section",
"label": "Jira - New users",
"elements": [
{
"name": "huntingquery2-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for new users created. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery3",
"type": "Microsoft.Common.Section",
"label": "Jira - Project versions released",
"elements": [
{
"name": "huntingquery3-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for project versions released. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery4",
"type": "Microsoft.Common.Section",
"label": "Jira - Project versions",
"elements": [
{
"name": "huntingquery4-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for project versions. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery5",
"type": "Microsoft.Common.Section",
"label": "Jira - Updated projects",
"elements": [
{
"name": "huntingquery5-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for updated projects. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery6",
"type": "Microsoft.Common.Section",
"label": "Jira - Updated users",
"elements": [
{
"name": "huntingquery6-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for updated users. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery7",
"type": "Microsoft.Common.Section",
"label": "Jira - Updated workflow schemes",
"elements": [
{
"name": "huntingquery7-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for updated workflow schemes. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery8",
"type": "Microsoft.Common.Section",
"label": "Jira - Updated workflows",
"elements": [
{
"name": "huntingquery8-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for updated workflows. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery9",
"type": "Microsoft.Common.Section",
"label": "Jira - Users' IP addresses",
"elements": [
{
"name": "huntingquery9-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for users' IP addresses. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
},
{
"name": "huntingquery10",
"type": "Microsoft.Common.Section",
"label": "Jira - Workflow schemes added to projects",
"elements": [
{
"name": "huntingquery10-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "Query searches for workflow schemes added to projects. This hunting query depends on JiraAuditAPI data connector (JiraAudit Parser or Table)"
}
}
]
}
]
},
{
"name": "playbooks",
"label": "Playbooks",
"subLabel": {
"preValidation": "Configure the playbooks",
"postValidation": "Done"
},
"bladeTitle": "Playbooks",
"elements": [
{
"name": "playbooks-text",
"type": "Microsoft.Common.TextBlock",
"options": {
"text": "This solution installs the Playbook templates to help implement your Security Orchestration, Automation and Response (SOAR) operations. After installing the solution, these will be deployed under Playbook Templates in the Automation blade in Microsoft Sentinel. They can be configured and managed from the Manage solution view in Content Hub."
}
},
{
"name": "playbooks-link",
"type": "Microsoft.Common.TextBlock",
"options": {
"link": {
"label": "Learn more",
"uri": "https://docs.microsoft.com/azure/sentinel/tutorial-respond-threats-playbook?WT.mc_id=Portal-Microsoft_Azure_CreateUIDef"
}
}
}
]
}
],
"outputs": {
"workspace-location": "[first(map(filter(basics('getLAWorkspace').value, (filter) => and(contains(toLower(filter.id), toLower(resourceGroup().name)),equals(filter.name,basics('workspace')))), (item) => item.location))]",
"location": "[location()]",
"workspace": "[basics('workspace')]"
}
}
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,32 +1,46 @@
{
"location": {
"type": "string",
"minLength": 1,
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Not used, but needed to pass arm-ttk test `Location-Should-Not-Be-Hardcoded`. We instead use the `workspace-location` which is derived from the LA workspace"
}
},
"workspace-location": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "[concat('Region to deploy solution resources -- separate from location selection',parameters('location'))]"
}
},
"workspace": {
"defaultValue": "",
"type": "string",
"metadata": {
"description": "Workspace name for Log Analytics where Microsoft Sentinel is setup"
}
},
"workbook1-name": {
"type": "string",
"defaultValue": "AtlassianJiraAudit",
"minLength": 1,
"metadata": {
"description": "Name for the workbook"
}
}
}
{
"location": {
"type": "string",
"minLength": 1,
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Not used, but needed to pass arm-ttk test `Location-Should-Not-Be-Hardcoded`. We instead use the `workspace-location` which is derived from the LA workspace"
}
},
"workspace-location": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "[concat('Region to deploy solution resources -- separate from location selection',parameters('location'))]"
}
},
"workspace": {
"defaultValue": "",
"type": "string",
"metadata": {
"description": "Workspace name for Log Analytics where Microsoft Sentinel is setup"
}
},
"workbook1-name": {
"type": "string",
"defaultValue": "AtlassianJiraAudit",
"minLength": 1,
"metadata": {
"description": "Name for the workbook"
}
},
"resourceGroupName": {
"type": "string",
"defaultValue": "[resourceGroup().name]",
"metadata": {
"description": "resource group name where Microsoft Sentinel is setup"
}
},
"subscription": {
"type": "string",
"defaultValue": "[last(split(subscription().id, '/'))]",
"metadata": {
"description": "subscription id where Microsoft Sentinel is setup"
}
}
}

Просмотреть файл

@ -0,0 +1,55 @@
id: 4ed36a9b-accd-491d-b22b-2454c137d90d
Function:
Title: Parser for Jira Audit Logs
Version: '3.0.0'
LastUpdated: '2024-01-29'
Category: Microsoft Sentinel Parser
FunctionName: JiraAudit
FunctionAlias: JiraAudit
FunctionQuery: |
let Jira_Audit_view = view() {
Jira_Audit_CL
| extend
EventVendor="Atlassian",
EventProduct="Jira Audit",
EventId=toint(column_ifexists('id_d', '')),
EventMessage=column_ifexists('summary_s', ''),
SrcIpAddr=column_ifexists('remoteAddress_s', ''),
UserName=column_ifexists('authorKey_s', ''),
UserSid=column_ifexists('authorAccountId_s', ''),
EventCreationTime=column_ifexists('created_t', ''),
EventSource=column_ifexists('eventSource_s', ''),
ObjectItemId=column_ifexists('objectItem_id_s', ''),
ObjectItemName=column_ifexists('objectItem_name_s', ''),
ObjectItemTypeName=column_ifexists('objectItem_typeName_s', ''),
ChangedValues=todynamic(column_ifexists('changedValues_s', '')),
AssociatedItems=todynamic(column_ifexists('associatedItems_s', '')),
ObjectItemParentId=column_ifexists('objectItem_parentId_s', ''),
ObjectItemParentName=column_ifexists('objectItem_parentName_s', ''),
EventCategoryType=column_ifexists('Category', '')
};
let Jira_Audit_v2_view=view() {
Jira_Audit_v2_CL
};
union withsource='SourceTable' isfuzzy=true
Jira_Audit_view, Jira_Audit_v2_view
| project
TimeGenerated,
EventVendor,
EventProduct,
EventId,
EventMessage,
SrcIpAddr,
UserName,
UserSid,
EventCreationTime,
EventSource,
ObjectItemId,
ObjectItemName,
ObjectItemTypeName,
ChangedValues,
AssociatedItems,
ObjectItemParentId,
ObjectItemParentName,
EventCategoryType,
SourceTable

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,184 +1,184 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"title": "Create Jira Issue alert-trigger",
"description": "This playbook will open a Jira Issue when a new incident is opened in Microsoft Sentinel.",
"prerequisites": "We will need following data to make Jira connector: 1. Jira instance (ex. xyz.atlassian.net); 2. Jira API; 3. Username.; After deployment assign Microsoft Sentinel Reader role to the Playbooks Managed Identity.",
"lastUpdateTime": "2022-07-20T00:00:00.000Z",
"Post-deployment": [
"Go to Playbook edit mode and fix Jira connection with data from Prerequisite. \n\n When connection is fixed, choose your: \n\n 1. Jira Project (where you want to sync Microsoft Sentinel incidents to) and \n\n 2. Issue Type Id (Microsoft Sentinel incident issue type in Jira - Task, Story, Bug,...)"
],
"entities": [],
"tags": [
"Sync"
],
"support": {
"tier": "community"
},
"author": {
"name": "Yaniv Shasha and Benjamin Kovacevic"
},
"releaseNotes": [
{
"version": "1.0.0",
"title": "Create Jira Issue alert-trigger",
"notes": [ "Initial version" ]
}
]
},
"parameters": {
"PlaybookName": {
"defaultValue": "CreateJiraIssue",
"type": "string",
"metadata": {
"description": "Alert trigger"
}
}
},
"variables": {
"AzureSentinelConnectionName": "[concat('azuresentinel-', parameters('PlaybookName'))]",
"JiraConnectionName": "[concat('jira-', parameters('PlaybookName'))]"
},
"resources": [
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[variables('AzureSentinelConnectionName')]",
"location": "[resourceGroup().location]",
"properties": {
"displayName": "[variables('AzureSentinelConnectionName')]",
"customParameterValues": {},
"parameterValueType": "Alternative",
"api": {
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]"
}
}
},
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[variables('jiraConnectionName')]",
"location": "[resourceGroup().location]",
"properties": {
"displayName": "[variables('jiraConnectionName')]",
"customParameterValues": {},
"api": {
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/jira')]"
}
}
},
{
"type": "Microsoft.Logic/workflows",
"apiVersion": "2017-07-01",
"name": "[parameters('PlaybookName')]",
"location": "[resourceGroup().location]",
"tags": {
"hidden-SentinelTemplateName": "CreateJiraIssue-Alert",
"hidden-SentinelTemplateVersion": "1.0"
},
"identity": {
"type": "SystemAssigned"
},
"dependsOn": [
"[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
"[resourceId('Microsoft.Web/connections', variables('JiraConnectionName'))]"
],
"properties": {
"state": "Enabled",
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"Microsoft_Sentinel_alert": {
"type": "ApiConnectionWebhook",
"inputs": {
"body": {
"callback_url": "@{listCallbackUrl()}"
},
"host": {
"connection": {
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
}
},
"path": "/subscribe"
}
}
},
"actions": {
"Alert_-_Get_incident": {
"runAfter": {},
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
}
},
"method": "get",
"path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}"
}
},
"Create_a_new_issue": {
"runAfter": {
"Alert_-_Get_incident": [
"Succeeded"
]
},
"type": "ApiConnection",
"inputs": {
"body": {
"fields": {
"description": "Incident description: @{body('Alert_-_Get_incident')?['properties']?['description']};\nSeverity: @{body('Alert_-_Get_incident')?['properties']?['severity']};\nIncident URL: @{body('Alert_-_Get_incident')?['properties']?['incidentUrl']}",
"issuetype": {
"id": "10007"
},
"summary": "@body('Alert_-_Get_incident')?['properties']?['title']"
}
},
"host": {
"connection": {
"name": "@parameters('$connections')['Jira']['connectionId']"
}
},
"method": "post",
"path": "/issue",
"queries": {
"projectKey": "SOC"
}
}
}
},
"outputs": {}
},
"parameters": {
"$connections": {
"value": {
"azuresentinel": {
"connectionId": "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
"connectionName": "[variables('AzureSentinelConnectionName')]",
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]",
"connectionProperties": {
"authentication": {
"type": "ManagedServiceIdentity"
}
}
},
"Jira": {
"connectionId": "[resourceId('Microsoft.Web/connections', variables('jiraConnectionName'))]",
"connectionName": "[variables('jiraConnectionName')]",
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/jira')]"
}
}
}
}
}
}
]
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"title": "Create Jira Issue alert-trigger",
"description": "This playbook will open a Jira Issue when a new incident is opened in Microsoft Sentinel.",
"prerequisites": "We will need following data to make Jira connector: 1. Jira instance (ex. xyz.atlassian.net); 2. Jira API; 3. Username.; After deployment assign Microsoft Sentinel Reader role to the Playbooks Managed Identity.",
"lastUpdateTime": "2022-07-20T00:00:00.000Z",
"Post-deployment": [
"Go to Playbook edit mode and fix Jira connection with data from Prerequisite. \n\n When connection is fixed, choose your: \n\n 1. Jira Project (where you want to sync Microsoft Sentinel incidents to) and \n\n 2. Issue Type Id (Microsoft Sentinel incident issue type in Jira - Task, Story, Bug,...)"
],
"entities": [],
"tags": [
"Sync"
],
"support": {
"tier": "community"
},
"author": {
"name": "Yaniv Shasha and Benjamin Kovacevic"
},
"releaseNotes": [
{
"version": "1.0.0",
"title": "Create Jira Issue alert-trigger",
"notes": [ "Initial version" ]
}
]
},
"parameters": {
"PlaybookName": {
"defaultValue": "CreateJiraIssue",
"type": "string",
"metadata": {
"description": "Alert trigger"
}
}
},
"variables": {
"AzureSentinelConnectionName": "[concat('azuresentinel-', parameters('PlaybookName'))]",
"JiraConnectionName": "[concat('jira-', parameters('PlaybookName'))]"
},
"resources": [
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[variables('AzureSentinelConnectionName')]",
"location": "[resourceGroup().location]",
"properties": {
"displayName": "[variables('AzureSentinelConnectionName')]",
"customParameterValues": {},
"parameterValueType": "Alternative",
"api": {
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]"
}
}
},
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[variables('jiraConnectionName')]",
"location": "[resourceGroup().location]",
"properties": {
"displayName": "[variables('jiraConnectionName')]",
"customParameterValues": {},
"api": {
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/jira')]"
}
}
},
{
"type": "Microsoft.Logic/workflows",
"apiVersion": "2017-07-01",
"name": "[parameters('PlaybookName')]",
"location": "[resourceGroup().location]",
"tags": {
"hidden-SentinelTemplateName": "CreateJiraIssue-Alert",
"hidden-SentinelTemplateVersion": "1.0"
},
"identity": {
"type": "SystemAssigned"
},
"dependsOn": [
"[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
"[resourceId('Microsoft.Web/connections', variables('JiraConnectionName'))]"
],
"properties": {
"state": "Enabled",
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"Microsoft_Sentinel_alert": {
"type": "ApiConnectionWebhook",
"inputs": {
"body": {
"callback_url": "@{listCallbackUrl()}"
},
"host": {
"connection": {
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
}
},
"path": "/subscribe"
}
}
},
"actions": {
"Alert_-_Get_incident": {
"runAfter": {},
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
}
},
"method": "get",
"path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}"
}
},
"Create_a_new_issue": {
"runAfter": {
"Alert_-_Get_incident": [
"Succeeded"
]
},
"type": "ApiConnection",
"inputs": {
"body": {
"fields": {
"description": "Incident description: @{body('Alert_-_Get_incident')?['properties']?['description']};\nSeverity: @{body('Alert_-_Get_incident')?['properties']?['severity']};\nIncident URL: @{body('Alert_-_Get_incident')?['properties']?['incidentUrl']}",
"issuetype": {
"id": "10007"
},
"summary": "@body('Alert_-_Get_incident')?['properties']?['title']"
}
},
"host": {
"connection": {
"name": "@parameters('$connections')['Jira']['connectionId']"
}
},
"method": "post",
"path": "/issue",
"queries": {
"projectKey": "SOC"
}
}
}
},
"outputs": {}
},
"parameters": {
"$connections": {
"value": {
"azuresentinel": {
"connectionId": "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
"connectionName": "[variables('AzureSentinelConnectionName')]",
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]",
"connectionProperties": {
"authentication": {
"type": "ManagedServiceIdentity"
}
}
},
"Jira": {
"connectionId": "[resourceId('Microsoft.Web/connections', variables('jiraConnectionName'))]",
"connectionName": "[variables('jiraConnectionName')]",
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/jira')]"
}
}
}
}
}
}
]
}

Просмотреть файл

@ -1,170 +1,170 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"title": "Create Jira Issue incident-trigger",
"description": "This playbook will open a Jira Issue when a new incident is opened in Microsoft Sentinel.",
"prerequisites": [
"1. Jira instance (ex. xyz.atlassian.net)",
"2. Jira API",
"3. Username."
],
"lastUpdateTime": "2022-07-20T00:00:00.000Z",
"Post-deployment": [
"Go to Playbook edit mode and fix Jira connection with data from Prerequisite. \n\n When connection is fixed, choose your: \n\n 1. Jira Project (where you want to sync Microsoft Sentinel incidents to) and \n\n 2. Issue Type Id (Microsoft Sentinel incident issue type in Jira - Task, Story, Bug,...)"
],
"entities": [],
"tags": [ "Sync" ],
"support": {
"tier": "community"
},
"author": {
"name": "Yaniv Shasha and Benjamin Kovacevic"
},
"releaseNotes": [
{
"version": "1.0.0",
"title": "Create Jira Issue incident-trigger",
"notes": [ "Initial version" ]
}
]
},
"parameters": {
"PlaybookName": {
"defaultValue": "CreateJiraIssue",
"type": "string",
"metadata": {
"description": "Incident trigger"
}
}
},
"variables": {
"AzureSentinelConnectionName": "[concat('azuresentinel-', parameters('PlaybookName'))]",
"JiraConnectionName": "[concat('jira-', parameters('PlaybookName'))]"
},
"resources": [
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[variables('AzureSentinelConnectionName')]",
"location": "[resourceGroup().location]",
"properties": {
"displayName": "[variables('AzureSentinelConnectionName')]",
"customParameterValues": {},
"parameterValueType": "Alternative",
"api": {
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]"
}
}
},
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[variables('jiraConnectionName')]",
"location": "[resourceGroup().location]",
"properties": {
"displayName": "[variables('jiraConnectionName')]",
"customParameterValues": {
},
"api": {
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/jira')]"
}
}
},
{
"type": "Microsoft.Logic/workflows",
"apiVersion": "2017-07-01",
"name": "[parameters('PlaybookName')]",
"location": "[resourceGroup().location]",
"tags": {
"hidden-SentinelTemplateName": "CreateJiraIssue-Incident",
"hidden-SentinelTemplateVersion": "1.0"
},
"identity": {
"type": "SystemAssigned"
},
"dependsOn": [
"[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
"[resourceId('Microsoft.Web/connections', variables('JiraConnectionName'))]"
],
"properties": {
"state": "Enabled",
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"Microsoft_Sentinel_incident": {
"type": "ApiConnectionWebhook",
"inputs": {
"body": {
"callback_url": "@{listCallbackUrl()}"
},
"host": {
"connection": {
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
}
},
"path": "/incident-creation"
}
}
},
"actions": {
"Create_a_new_issue": {
"runAfter": {},
"type": "ApiConnection",
"inputs": {
"body": {
"fields": {
"description": "Incident description: @{triggerBody()?['object']?['properties']?['description']};\nSeverity: @{triggerBody()?['object']?['properties']?['severity']};\nIncident URL: @{triggerBody()?['object']?['properties']?['incidentUrl']}",
"issuetype": {
"id": "10007"
},
"summary": "@triggerBody()?['object']?['properties']?['title']"
}
},
"host": {
"connection": {
"name": "@parameters('$connections')['Jira']['connectionId']"
}
},
"method": "post",
"path": "/issue",
"queries": {
"projectKey": "SOC"
}
}
}
},
"outputs": {}
},
"parameters": {
"$connections": {
"value": {
"azuresentinel": {
"connectionId": "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
"connectionName": "[variables('AzureSentinelConnectionName')]",
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]",
"connectionProperties": {
"authentication": {
"type": "ManagedServiceIdentity"
}
}
},
"Jira": {
"connectionId": "[resourceId('Microsoft.Web/connections', variables('jiraConnectionName'))]",
"connectionName": "[variables('jiraConnectionName')]",
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/jira')]"
}
}
}
}
}
}
]
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"title": "Create Jira Issue incident-trigger",
"description": "This playbook will open a Jira Issue when a new incident is opened in Microsoft Sentinel.",
"prerequisites": [
"1. Jira instance (ex. xyz.atlassian.net)",
"2. Jira API",
"3. Username."
],
"lastUpdateTime": "2022-07-20T00:00:00.000Z",
"Post-deployment": [
"Go to Playbook edit mode and fix Jira connection with data from Prerequisite. \n\n When connection is fixed, choose your: \n\n 1. Jira Project (where you want to sync Microsoft Sentinel incidents to) and \n\n 2. Issue Type Id (Microsoft Sentinel incident issue type in Jira - Task, Story, Bug,...)"
],
"entities": [],
"tags": [ "Sync" ],
"support": {
"tier": "community"
},
"author": {
"name": "Yaniv Shasha and Benjamin Kovacevic"
},
"releaseNotes": [
{
"version": "1.0.0",
"title": "Create Jira Issue incident-trigger",
"notes": [ "Initial version" ]
}
]
},
"parameters": {
"PlaybookName": {
"defaultValue": "CreateJiraIssue",
"type": "string",
"metadata": {
"description": "Incident trigger"
}
}
},
"variables": {
"AzureSentinelConnectionName": "[concat('azuresentinel-', parameters('PlaybookName'))]",
"JiraConnectionName": "[concat('jira-', parameters('PlaybookName'))]"
},
"resources": [
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[variables('AzureSentinelConnectionName')]",
"location": "[resourceGroup().location]",
"properties": {
"displayName": "[variables('AzureSentinelConnectionName')]",
"customParameterValues": {},
"parameterValueType": "Alternative",
"api": {
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]"
}
}
},
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[variables('jiraConnectionName')]",
"location": "[resourceGroup().location]",
"properties": {
"displayName": "[variables('jiraConnectionName')]",
"customParameterValues": {
},
"api": {
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/jira')]"
}
}
},
{
"type": "Microsoft.Logic/workflows",
"apiVersion": "2017-07-01",
"name": "[parameters('PlaybookName')]",
"location": "[resourceGroup().location]",
"tags": {
"hidden-SentinelTemplateName": "CreateJiraIssue-Incident",
"hidden-SentinelTemplateVersion": "1.0"
},
"identity": {
"type": "SystemAssigned"
},
"dependsOn": [
"[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
"[resourceId('Microsoft.Web/connections', variables('JiraConnectionName'))]"
],
"properties": {
"state": "Enabled",
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"Microsoft_Sentinel_incident": {
"type": "ApiConnectionWebhook",
"inputs": {
"body": {
"callback_url": "@{listCallbackUrl()}"
},
"host": {
"connection": {
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
}
},
"path": "/incident-creation"
}
}
},
"actions": {
"Create_a_new_issue": {
"runAfter": {},
"type": "ApiConnection",
"inputs": {
"body": {
"fields": {
"description": "Incident description: @{triggerBody()?['object']?['properties']?['description']};\nSeverity: @{triggerBody()?['object']?['properties']?['severity']};\nIncident URL: @{triggerBody()?['object']?['properties']?['incidentUrl']}",
"issuetype": {
"id": "10007"
},
"summary": "@triggerBody()?['object']?['properties']?['title']"
}
},
"host": {
"connection": {
"name": "@parameters('$connections')['Jira']['connectionId']"
}
},
"method": "post",
"path": "/issue",
"queries": {
"projectKey": "SOC"
}
}
}
},
"outputs": {}
},
"parameters": {
"$connections": {
"value": {
"azuresentinel": {
"connectionId": "[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]",
"connectionName": "[variables('AzureSentinelConnectionName')]",
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/azuresentinel')]",
"connectionProperties": {
"authentication": {
"type": "ManagedServiceIdentity"
}
}
},
"Jira": {
"connectionId": "[resourceId('Microsoft.Web/connections', variables('jiraConnectionName'))]",
"connectionName": "[variables('jiraConnectionName')]",
"id": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', resourceGroup().location, '/managedApis/jira')]"
}
}
}
}
}
}
]
}

Просмотреть файл

@ -1,55 +1,55 @@
# Create-Jira-Issue
author: Yaniv Shasha, Benjamin Kovacevic
This playbook will open a Jira Issue when a new incident is opened in Microsoft Sentinel.<br>
<br>
## Prerequisites
We will need following data to make Jira connector:<br>
1. Jira instance (ex. xyz.atlassian.net)<br>
2. Jira API (create API token on https://id.atlassian.com/manage-profile/security/api-tokens)<br>
3. User email<br>
![Jira connector requirements](./images/jira-connector-requirements.png)<br>
<br>
## Quick Deployment
**Deploy with incident trigger** (recommended)
After deployment, attach this playbook to an **automation rule** so it runs when the incident is created.
[Learn more about automation rules](https://docs.microsoft.com/azure/sentinel/automate-incident-handling-with-automation-rules#creating-and-managing-automation-rules)
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FCreate-Jira-Issue%2Fincident-trigger%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FCreate-Jira-Issue%2Fincident-trigger%2Fazuredeploy.json)
**Deploy with alert trigger**
After deployment, you can run this playbook manually on an alert or attach it to an **analytics rule** so it will rune when an alert is created.
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FCreate-Jira-Issue%2Falert-trigger%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FCreate-Jira-Issue%2Falert-trigger%2Fazuredeploy.json)<br>
<br>
## Post-deployment
Go to Playbook edit mode and fix Jira connection with data from Prerequisite. <br>
When connection is fixed, choose your:
1. Jira Project (where you want to sync Microsoft Sentinel incidents to) and
2. Issue Type Id (Microsoft Sentinel incident issue type in Jira - Task, Story, Bug,...).<br>
<br>
<strong>Note: This step is necessary only if you are deploying the Playbook using Alert trigger method from above</strong><br>
We will need to assign Microsoft Sentinel Reader role to the Playbooks Managed Identity:<br>
1. Open Playbook and go to Settings > Identity
2. Click on Azure Role Assignments and then on Add Role Assignment
3. For Scope choose Resource group and make sure that subscription and resource group are where Microsoft Sentinel and Playbook are deployed. For Role choose Microsoft Sentinel Reader and click on Save.<br>
<br>
## Screenshots
**Incident Trigger**<br>
![Incident Trigger dark](./incident-trigger/images/dark-Playbook-incident-trigger.png)<br>
![Incident Trigger light](./incident-trigger/images/light-Playbook-incident-trigger.png)<br>
<br>
**Alert Trigger**<br>
![Alert Trigger dark](./alert-trigger/images/dark-Playbook-alert-trigger.png)<br>
![Alert Trigger light](./alert-trigger/images/light-Playbook-alert-trigger.png)<br>
<br>
**Example in Jira**<br>
# Create-Jira-Issue
author: Yaniv Shasha, Benjamin Kovacevic
This playbook will open a Jira Issue when a new incident is opened in Microsoft Sentinel.<br>
<br>
## Prerequisites
We will need following data to make Jira connector:<br>
1. Jira instance (ex. xyz.atlassian.net)<br>
2. Jira API (create API token on https://id.atlassian.com/manage-profile/security/api-tokens)<br>
3. User email<br>
![Jira connector requirements](./images/jira-connector-requirements.png)<br>
<br>
## Quick Deployment
**Deploy with incident trigger** (recommended)
After deployment, attach this playbook to an **automation rule** so it runs when the incident is created.
[Learn more about automation rules](https://docs.microsoft.com/azure/sentinel/automate-incident-handling-with-automation-rules#creating-and-managing-automation-rules)
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FCreate-Jira-Issue%2Fincident-trigger%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FCreate-Jira-Issue%2Fincident-trigger%2Fazuredeploy.json)
**Deploy with alert trigger**
After deployment, you can run this playbook manually on an alert or attach it to an **analytics rule** so it will rune when an alert is created.
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FCreate-Jira-Issue%2Falert-trigger%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FCreate-Jira-Issue%2Falert-trigger%2Fazuredeploy.json)<br>
<br>
## Post-deployment
Go to Playbook edit mode and fix Jira connection with data from Prerequisite. <br>
When connection is fixed, choose your:
1. Jira Project (where you want to sync Microsoft Sentinel incidents to) and
2. Issue Type Id (Microsoft Sentinel incident issue type in Jira - Task, Story, Bug,...).<br>
<br>
<strong>Note: This step is necessary only if you are deploying the Playbook using Alert trigger method from above</strong><br>
We will need to assign Microsoft Sentinel Reader role to the Playbooks Managed Identity:<br>
1. Open Playbook and go to Settings > Identity
2. Click on Azure Role Assignments and then on Add Role Assignment
3. For Scope choose Resource group and make sure that subscription and resource group are where Microsoft Sentinel and Playbook are deployed. For Role choose Microsoft Sentinel Reader and click on Save.<br>
<br>
## Screenshots
**Incident Trigger**<br>
![Incident Trigger dark](./incident-trigger/images/dark-Playbook-incident-trigger.png)<br>
![Incident Trigger light](./incident-trigger/images/light-Playbook-incident-trigger.png)<br>
<br>
**Alert Trigger**<br>
![Alert Trigger dark](./alert-trigger/images/dark-Playbook-alert-trigger.png)<br>
![Alert Trigger light](./alert-trigger/images/light-Playbook-alert-trigger.png)<br>
<br>
**Example in Jira**<br>
![Alert Trigger light](./images/jira.png)<br>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,40 +1,40 @@
# Jira-CreateAndUpdateIssue
author: Benjamin Kovacevic
This playbook will create or update incident in Jira. When incident is created, playbook will run and create issue in Jira. When incident is updated, playbook will run and add update to comment section.
# Prerequisites
We will need following data to make Jira connector:<br>
1. Jira instance (ex. xyz.atlassian.net)<br>
2. Jira API (create API token on https://id.atlassian.com/manage-profile/security/api-tokens)<br>
3. User email<br>
![Jira connector requirements](./images/jira-connector-requirementsDark.png)<br>
# Quick Deployment
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FJira-CreateAndUpdateIssue%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/deploytoazuregov.png)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FJira-CreateAndUpdateIssue%2Fazuredeploy.json)
<br><br>
# Post-deployment
1. Authorize Jira connector and choose:
- Jira Project (where you want to sync Microsoft Sentinel incidents to) and
- Issue Type Id (Microsoft Sentinel incident issue type in Jira - Task, Story, Bug,...).<br>
2. Assign Microsoft Sentinel Responder role to playbook's managed identity. To do so, choose Identity blade under Settings of the Logic App.
3. Add playbook as an action to the automation rule, ex.:
- Trigger = When incident is updated;
- Condition = Staus > Changed To > Closed;.<br>
**Automation rule example**<br>
![Automation Rule Example](./images/AutomationRuleExampleDark.jpg)
# Screenshots
**Playbook** <br>
![playbook screenshot](./images/JiraPlaybookDark.jpg)<br>
![playbook screenshot](./images/JiraPlaybookLight.jpg)<br><br>
**Jira New Issue** <br>
![jira screenshot new](./images/JiraNewIssue.jpg)<br><br>
**Jira Update Issue** <br>
# Jira-CreateAndUpdateIssue
author: Benjamin Kovacevic
This playbook will create or update incident in Jira. When incident is created, playbook will run and create issue in Jira. When incident is updated, playbook will run and add update to comment section.
# Prerequisites
We will need following data to make Jira connector:<br>
1. Jira instance (ex. xyz.atlassian.net)<br>
2. Jira API (create API token on https://id.atlassian.com/manage-profile/security/api-tokens)<br>
3. User email<br>
![Jira connector requirements](./images/jira-connector-requirementsDark.png)<br>
# Quick Deployment
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FJira-CreateAndUpdateIssue%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/1-CONTRIBUTION-GUIDE/images/deploytoazuregov.png)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FJira-CreateAndUpdateIssue%2Fazuredeploy.json)
<br><br>
# Post-deployment
1. Authorize Jira connector and choose:
- Jira Project (where you want to sync Microsoft Sentinel incidents to) and
- Issue Type Id (Microsoft Sentinel incident issue type in Jira - Task, Story, Bug,...).<br>
2. Assign Microsoft Sentinel Responder role to playbook's managed identity. To do so, choose Identity blade under Settings of the Logic App.
3. Add playbook as an action to the automation rule, ex.:
- Trigger = When incident is updated;
- Condition = Staus > Changed To > Closed;.<br>
**Automation rule example**<br>
![Automation Rule Example](./images/AutomationRuleExampleDark.jpg)
# Screenshots
**Playbook** <br>
![playbook screenshot](./images/JiraPlaybookDark.jpg)<br>
![playbook screenshot](./images/JiraPlaybookLight.jpg)<br><br>
**Jira New Issue** <br>
![jira screenshot new](./images/JiraNewIssue.jpg)<br><br>
**Jira Update Issue** <br>
![jira screenshot update](./images/JiraUpdateIssue.jpg)<br>

Просмотреть файл

@ -1460,4 +1460,4 @@
}
}
]
}
}

Просмотреть файл

@ -1,233 +1,233 @@
# Synchronization Tool for Sentinel and JIRA
Author: Thijs Lecomte
## Overview
This tool will synchronize incidents between Microsoft Sentinel and JIRA Service Management using the following tools:
* Azure Logic Apps
* Azure Functions
* Automation for JIRA
* Microsoft Sentinel Automation Rules
* Azure Key Vault
This tool will do the following:
* Create an incident in JIRA when an incident is created in Sentinel
* Sync the assigned user from JIRA to Sentinel
* Sync the status from JIRA to Sentinel
* Add the URL to the JIRA incident as a comment in Sentinel
* Sync public comments from JIRA to Sentinel
![Overview](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Solution%20overview.png)
[Blog post with more background information](https://www.thecollective.eu/en/insights/setting-up-a-bidirectional-sync-between-sentinel-and-jira)
## Implementation
To implement this solution, a few different steps need to be done:
1. Create necessary Service Principals
2. JIRA Configuration
1. Custom fields
2. Deploy Automation for JIRA rules (used for sync from JIRA to Microsoft Sentinel)
3. Deploy the Key Vault and add secrets
4. Deploy Azure Logic Apps (4) through ARM deployment
5. Deploy Azure Function for comment sychronization and add the Powershell code (check the Functions)
6. Create Sentinel Automation Rule
## 1. Create Service Principal
The tool requires a service principals for authentication to different services:
* Authentication to Microsoft Entra ID to retrieve user ID's (for assigning incidents in Sentinel)
### Microsoft Entra ID Service Principal
This Service Principal needs to have User.Read.All application permissions.
This Service Principal is used in the Logic app 'Sync-AssignedUser.
## 2. JIRA Configuration
### JIRA Custom Fields
#### Introduction
A lot of the Sentinel specific information is stored inside of Custom Fields in JIRA which need to be created.
This document contains an overview of the different custom fields that are used in the Logic Apps.
All Logic Apps need to be updated with the correct ID's of the fields.
#### Custom Fields overview
| **Field Name** | **Field ID** | **Field Type**|
| --- | --- | --- |
| Organizations | customfield_10002 | Built-in |
| Sentinel Incident URL | customfield_10144 | Url Field |
| Incident ID | customfield_10145 | Text Field (Single line) |
| Closure Comment | customfield_10146 | Text Field (Multiline) |
| Closure Reason | customfield_10047 | Select List (Single choice) |
| Tenant Name | customfield_10149 | Select List (Single Choice) |
| Created At | customfield_10154 | Date Time Picker |
| Att&ck Tactics | customfield_10155 | Select List (Multiple choices) |
| Affected User | customfield_10158 | Text Field (Multiline) |
| Subscription ID | customfield_10162 | Text Field (Singline) |
| Sentinel Resource Group | customfield_10169 | Text Field (Singline) |
| Sentinel Workspace Name | customfield_10170 | Text Field (Singline) |
| Sentinel Workspace ID | customfield_10172 | Text Field (Singline) |
| Sentinel Incident ID | customfield_10173 | Text Field (Singline) |
| Sentinel Incident ARM ID | customfield_10175 | Text Field (Singline) |
The Att&ck Tactics list contains all Sentinel Tactics.
The Closure Reason contains all valid Sentinel Closure Reasons
### JIRA Automation Rules
In order to synchronize changes from JIRA to Sentinel, Automation for JIRA is used to trigger Logic Apps when certain conditions are met.
Automation for JIRA is an integrated plugin that is free to use for JIRA Service Management.
This document will describe the different automation rules that are necessary to trigger the correct Logic Apps/Functions.
In almost every rule, the step 're-fetch issue data' is used. This will make sure we are using the most up to date information in our Logic Apps.
If you are not using this, you might encouter failures.
Navigate to the project settings, then go to Automation to create rules.
#### Sync Status
This automation rule has a trigger 'Issue Transitioned' and will trigger the Logic App 'Sync-Status'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Status.png)
#### Sync Assigned User
This automation rule has a trigger 'Issue Assigned' and will trigger the Logic App 'Sync-AssignedUser'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Assigned%20User.png)
#### Create Link
This automation rule has a trigger 'Issue created' and will trigger the Logic App 'Add-JIRALinkComment'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Create%20Link.png)
#### Sync comment
This automation rule will trigger the function app to sync public comments to Microsoft Sentinel.
Provide the POST URL of the Sync Comment Function in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Comment.png)
## 3. Deploy Key Vault
The Key Vault is used to store three secrets:
* One for the Microsoft Entra ID Service Principal
* One for the Microsoft Sentinel Service Principal
* One for the JIRA Secret
Create a new Key Vault or deploy an existing one and add the different secrets to it.
The names will need to be provided when deploying the ARM Templates from the Logic Apps.
Edit the Access Policy and assign 'Secret - Get' permissions to the Key Vault Service Principal.
## 4. Deploy Logic Apps
The solution consists of four different Logic Apps:
* Sync Incidents from Sentinel to JIRA (Sync-Incidents.json)
* Sync status from JIRA to Sentinel (Sync-Status.json)
* Sync assigned user from JIRA to Sentinel (Sync-AssignedUser.json)
* Add a link to the JIRA incident to the Sentinel incident (Add-JiraLinkComment.json)
This will enable a two way synchronization between JIRA and Sentinel. Not all Logic Apps are mandatory, you can deploy the ones your organization needs.
Each Logic App can be deployed using the provided ARM templates.
After deploying the Logic Apps, you can copy the HTTP trigger URLs and paste them in the JIRA Automation Rules.
### Custom Fields Configuration
A lot of JIRA Custom fields are used within these Logic Apps. It's important to create these custom fields in your own JIRA environment and change the correct ID's in the Logic Apps.
For more information about the different custom fields used, please check the JIRA Configuration.
### Sync Incidents from Sentinel to JIRA
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
This Logic App will create a new incident in JIRA when an incident in Sentinel is created.
It uses the 'Incident Trigger' from Sentinel and is triggered by an Automation Rule (see Sentinel Configuration).
This Logic App does the following:
* Retrieve all the incident information
* Retrieve the Tactics in this incident
* Retrieve the details from the Account Entity
* Check which customer this incident is coming from (to add the right organization in JIRA)
* Create JIRA ticket through an API call
It uses two connections:
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the JIRA API Key (Managed Identity)
In order to correlate the right add the incident in JIRA to the correct Organization, we use a switch and determine the correct organization based on the originate Subscription ID.
Add a case per customer and add the right Subscription ID, Customer name and Organization ID.
If you do not use organizations in JIRA, you can remove the switch.
![Switch](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Azure%20-%20Switch%20Organization.png)
### Sync status from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
This Logic App will change the status in Sentinel when the status has been changed in JIRA.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It's important you use the same closure reason in JIRA as the ones in Sentinel, otherwise the sync will fail.
It uses one connections:
* One connection to Sentinel through a Managed Identity.
### Sync assigned user from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
When a incident is assigned in JIRA, this will assign the correct user inside of Microsoft Sentinel.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule when the assigned user of an incident is changed.
It will retrieve the client secret for the service principal with permissions to retrieve users in your Microsoft Entra ID. With this, it will query the user and retrieve the Microsoft Entra ID Object ID from that user. Wit this information, we will update the incident in Microsoft Sentinel.
There is a check built-in to make sure that JIRA provides the assigned user. Sometimes it does not and then we don't need to update the incident in Sentinel.
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the Secret for the Service Principal with Microsoft Entra ID permissions (also configured when deploying the Logic App)
### Add a link to the JIRA incident to the Sentinel incident
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FAdd-JiraLinkComment%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FAdd-JiraLinkComment%2Fazuredeploy.json)
This Logic App will add a URL to the JIRA incident as a comment to the Sentinel Incident.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It will add the link to the JIRA Customer Portal, which enables a customer to view the details of an incident inside JIRA.
It uses one connections:
* One connection to Sentinel through a Managed Identity
## 5. Deploy Azure Function
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-CommentsFunctionApp%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-CommentsFunctionApp%2Fazuredeploy.json)
To sync incident comments from JIRA to Microsoft Sentinel an Azure Function is used. This Function App contains one Powershell Function.
There are two types of comments in JIRA: internal and public comments. This script will only sync the public comments, so that customers don't have access to the internal ones.
The code for this function can be found [in this repository](Sync-Comments/Sync-Comment.ps1).
This Function uses a managed identity to authenticate to the Key Vault.
Either deployment the Function App through the ARM template linked above or deploy a Function app manually and paste the ps1 code
After deployment, configure the parameters in the Powershell file.
* jiraUser => Used for authentication to JIRA
* jiraSecretURL => The URL to the JIRA Secret in our Key Vault
* sentinelSecretURL => The URL to the Sentinel Secret in our Key Vault
* tenantID => Tenant ID for the Sentinel Service Principals
* clientID => Client ID for the Sentinel Service Principal
Enable the Managed Identity (Identity => System Assigned).
Provide 'Secret - Get' permissions to the Function app in the Access Policies of the Key Vault.
## 6. Sentinel Automation Rule
In order to trigger the Logic App that creates incidents in JIRA, we use an Automation Rule in Sentinel.
This will enable us to trigger a Logic App (Playbook) each time an incident is created.
Navigate to your Sentinel workspace and choose 'Automation', after this click 'Create Rule'.
Provide a name for the rule and for conditions choose 'Analytics Rule Name contains All'. This will trigger out Logic app each time an incident is created.
If you only want to sync certain incidents, choose the right condition.
For actions, choose 'Run Playbook' and select the 'Sync-Incidents' Playbook.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Sentinel%20-%20Automation%20Rule.png)
## Conclusion
After this solution, you are able to work on Microsoft Sentinel incidents while staying in your trusted ITSM tool.
This tool should take care of any previous synchronization issues between the JIRA and Sentinel.
For any issues with the tool or requested improvements, feel free to create an issue on Github or contact me through [Twitter](https://twitter.com/thijslecomte).
# Synchronization Tool for Sentinel and JIRA
Author: Thijs Lecomte
## Overview
This tool will synchronize incidents between Microsoft Sentinel and JIRA Service Management using the following tools:
* Azure Logic Apps
* Azure Functions
* Automation for JIRA
* Microsoft Sentinel Automation Rules
* Azure Key Vault
This tool will do the following:
* Create an incident in JIRA when an incident is created in Sentinel
* Sync the assigned user from JIRA to Sentinel
* Sync the status from JIRA to Sentinel
* Add the URL to the JIRA incident as a comment in Sentinel
* Sync public comments from JIRA to Sentinel
![Overview](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Solution%20overview.png)
[Blog post with more background information](https://www.thecollective.eu/en/insights/setting-up-a-bidirectional-sync-between-sentinel-and-jira)
## Implementation
To implement this solution, a few different steps need to be done:
1. Create necessary Service Principals
2. JIRA Configuration
1. Custom fields
2. Deploy Automation for JIRA rules (used for sync from JIRA to Microsoft Sentinel)
3. Deploy the Key Vault and add secrets
4. Deploy Azure Logic Apps (4) through ARM deployment
5. Deploy Azure Function for comment sychronization and add the Powershell code (check the Functions)
6. Create Sentinel Automation Rule
## 1. Create Service Principal
The tool requires a service principals for authentication to different services:
* Authentication to Microsoft Entra ID to retrieve user ID's (for assigning incidents in Sentinel)
### Microsoft Entra ID Service Principal
This Service Principal needs to have User.Read.All application permissions.
This Service Principal is used in the Logic app 'Sync-AssignedUser.
## 2. JIRA Configuration
### JIRA Custom Fields
#### Introduction
A lot of the Sentinel specific information is stored inside of Custom Fields in JIRA which need to be created.
This document contains an overview of the different custom fields that are used in the Logic Apps.
All Logic Apps need to be updated with the correct ID's of the fields.
#### Custom Fields overview
| **Field Name** | **Field ID** | **Field Type**|
| --- | --- | --- |
| Organizations | customfield_10002 | Built-in |
| Sentinel Incident URL | customfield_10144 | Url Field |
| Incident ID | customfield_10145 | Text Field (Single line) |
| Closure Comment | customfield_10146 | Text Field (Multiline) |
| Closure Reason | customfield_10047 | Select List (Single choice) |
| Tenant Name | customfield_10149 | Select List (Single Choice) |
| Created At | customfield_10154 | Date Time Picker |
| Att&ck Tactics | customfield_10155 | Select List (Multiple choices) |
| Affected User | customfield_10158 | Text Field (Multiline) |
| Subscription ID | customfield_10162 | Text Field (Singline) |
| Sentinel Resource Group | customfield_10169 | Text Field (Singline) |
| Sentinel Workspace Name | customfield_10170 | Text Field (Singline) |
| Sentinel Workspace ID | customfield_10172 | Text Field (Singline) |
| Sentinel Incident ID | customfield_10173 | Text Field (Singline) |
| Sentinel Incident ARM ID | customfield_10175 | Text Field (Singline) |
The Att&ck Tactics list contains all Sentinel Tactics.
The Closure Reason contains all valid Sentinel Closure Reasons
### JIRA Automation Rules
In order to synchronize changes from JIRA to Sentinel, Automation for JIRA is used to trigger Logic Apps when certain conditions are met.
Automation for JIRA is an integrated plugin that is free to use for JIRA Service Management.
This document will describe the different automation rules that are necessary to trigger the correct Logic Apps/Functions.
In almost every rule, the step 're-fetch issue data' is used. This will make sure we are using the most up to date information in our Logic Apps.
If you are not using this, you might encouter failures.
Navigate to the project settings, then go to Automation to create rules.
#### Sync Status
This automation rule has a trigger 'Issue Transitioned' and will trigger the Logic App 'Sync-Status'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Playbooks/Sync-IncidentsWithJIRA/Images/JIRA%20-%20Automation%20-%20Sync%20Status.png)
#### Sync Assigned User
This automation rule has a trigger 'Issue Assigned' and will trigger the Logic App 'Sync-AssignedUser'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Playbooks/Sync-IncidentsWithJIRA/Images/JIRA%20-%20Automation%20-%20Sync%20Assigned%20User.png)
#### Create Link
This automation rule has a trigger 'Issue created' and will trigger the Logic App 'Add-JIRALinkComment'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Playbooks/Sync-IncidentsWithJIRA/Images/JIRA%20-%20Automation%20-%20Create%20Link.png)
#### Sync comment
This automation rule will trigger the function app to sync public comments to Microsoft Sentinel.
Provide the POST URL of the Sync Comment Function in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Playbooks/Sync-IncidentsWithJIRA/Images/JIRA%20-%20Automation%20-%20Sync%20Comment.png)
## 3. Deploy Key Vault
The Key Vault is used to store three secrets:
* One for the Microsoft Entra ID Service Principal
* One for the Microsoft Sentinel Service Principal
* One for the JIRA Secret
Create a new Key Vault or deploy an existing one and add the different secrets to it.
The names will need to be provided when deploying the ARM Templates from the Logic Apps.
Edit the Access Policy and assign 'Secret - Get' permissions to the Key Vault Service Principal.
## 4. Deploy Logic Apps
The solution consists of four different Logic Apps:
* Sync Incidents from Sentinel to JIRA (Sync-Incidents.json)
* Sync status from JIRA to Sentinel (Sync-Status.json)
* Sync assigned user from JIRA to Sentinel (Sync-AssignedUser.json)
* Add a link to the JIRA incident to the Sentinel incident (Add-JiraLinkComment.json)
This will enable a two way synchronization between JIRA and Sentinel. Not all Logic Apps are mandatory, you can deploy the ones your organization needs.
Each Logic App can be deployed using the provided ARM templates.
After deploying the Logic Apps, you can copy the HTTP trigger URLs and paste them in the JIRA Automation Rules.
### Custom Fields Configuration
A lot of JIRA Custom fields are used within these Logic Apps. It's important to create these custom fields in your own JIRA environment and change the correct ID's in the Logic Apps.
For more information about the different custom fields used, please check the JIRA Configuration.
### Sync Incidents from Sentinel to JIRA
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
This Logic App will create a new incident in JIRA when an incident in Sentinel is created.
It uses the 'Incident Trigger' from Sentinel and is triggered by an Automation Rule (see Sentinel Configuration).
This Logic App does the following:
* Retrieve all the incident information
* Retrieve the Tactics in this incident
* Retrieve the details from the Account Entity
* Check which customer this incident is coming from (to add the right organization in JIRA)
* Create JIRA ticket through an API call
It uses two connections:
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the JIRA API Key (Managed Identity)
In order to correlate the right add the incident in JIRA to the correct Organization, we use a switch and determine the correct organization based on the originate Subscription ID.
Add a case per customer and add the right Subscription ID, Customer name and Organization ID.
If you do not use organizations in JIRA, you can remove the switch.
![Switch](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Playbooks/Sync-IncidentsWithJIRA/Images/Azure%20-%20Switch%20Organization.png)
### Sync status from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FSync-IncidentsWithJIRA%2FSync-Status%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FSync-IncidentsWithJIRA%2FSync-Status%2Fazuredeploy.json)
This Logic App will change the status in Sentinel when the status has been changed in JIRA.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It's important you use the same closure reason in JIRA as the ones in Sentinel, otherwise the sync will fail.
It uses one connections:
* One connection to Sentinel through a Managed Identity.
### Sync assigned user from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-AssignedUser%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-AssignedUser%2Fazuredeploy.json)
When a incident is assigned in JIRA, this will assign the correct user inside of Microsoft Sentinel.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule when the assigned user of an incident is changed.
It will retrieve the client secret for the service principal with permissions to retrieve users in your Microsoft Entra ID. With this, it will query the user and retrieve the Microsoft Entra ID Object ID from that user. Wit this information, we will update the incident in Microsoft Sentinel.
There is a check built-in to make sure that JIRA provides the assigned user. Sometimes it does not and then we don't need to update the incident in Sentinel.
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the Secret for the Service Principal with Microsoft Entra ID permissions (also configured when deploying the Logic App)
### Add a link to the JIRA incident to the Sentinel incident
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FSync-IncidentsWithJIRA%2FAdd-JiraLinkComment%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FSync-IncidentsWithJIRA%2FAdd-JiraLinkCommnet%2Fazuredeploy.json)
This Logic App will add a URL to the JIRA incident as a comment to the Sentinel Incident.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It will add the link to the JIRA Customer Portal, which enables a customer to view the details of an incident inside JIRA.
It uses one connections:
* One connection to Sentinel through a Managed Identity
## 5. Deploy Azure Function
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FSync-IncidentsWithJIRA%2FSync-Comments%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FSync-IncidentsWithJIRA%2FSync-Comments%2Fazuredeploy.json)
To sync incident comments from JIRA to Microsoft Sentinel an Azure Function is used. This Function App contains one Powershell Function.
There are two types of comments in JIRA: internal and public comments. This script will only sync the public comments, so that customers don't have access to the internal ones.
The code for this function can be found [in this repository](Sync-Comments/Sync-Comment.ps1).
This Function uses a managed identity to authenticate to the Key Vault.
Either deployment the Function App through the ARM template linked above or deploy a Function app manually and paste the ps1 code
After deployment, configure the parameters in the Powershell file.
* jiraUser => Used for authentication to JIRA
* jiraSecretURL => The URL to the JIRA Secret in our Key Vault
* sentinelSecretURL => The URL to the Sentinel Secret in our Key Vault
* tenantID => Tenant ID for the Sentinel Service Principals
* clientID => Client ID for the Sentinel Service Principal
Enable the Managed Identity (Identity => System Assigned).
Provide 'Secret - Get' permissions to the Function app in the Access Policies of the Key Vault.
## 6. Sentinel Automation Rule
In order to trigger the Logic App that creates incidents in JIRA, we use an Automation Rule in Sentinel.
This will enable us to trigger a Logic App (Playbook) each time an incident is created.
Navigate to your Sentinel workspace and choose 'Automation', after this click 'Create Rule'.
Provide a name for the rule and for conditions choose 'Analytics Rule Name contains All'. This will trigger out Logic app each time an incident is created.
If you only want to sync certain incidents, choose the right condition.
For actions, choose 'Run Playbook' and select the 'Sync-Incidents' Playbook.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Playbooks/Sync-IncidentsWithJIRA/Images/Sentinel%20-%20Automation%20Rule.png)
## Conclusion
After this solution, you are able to work on Microsoft Sentinel incidents while staying in your trusted ITSM tool.
This tool should take care of any previous synchronization issues between the JIRA and Sentinel.
For any issues with the tool or requested improvements, feel free to create an issue on Github or contact me through [Twitter](https://twitter.com/thijslecomte).

Просмотреть файл

@ -1,120 +1,120 @@
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
#variables
$jiraUser = ""
$jiraSecretURL = ""
$sentinelSecretURL = ""
$tenantId = ""
$clientid = ""
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
#find comment with highest updated time => comment we want to sync
$max = ($Request.body.fields.comment.comments | Measure-Object -Property updated -Maximum).Maximum
#Get latest comment
$newComment = $Request.body.fields.comment.comments | ? {$_.updated -eq $max}
Write-Host $newComment.body
#Retrieve Graph API Secret
$tokenAuthURI = $Env:MSI_ENDPOINT +"?resource=https://vault.azure.net&api-version=2017-09-01"
$tokenResponse = Invoke-RestMethod -Method Get -Headers @{"Secret"="$env:MSI_SECRET"} -Uri $tokenAuthURI
$accessToken = $tokenResponse.access_token
#Retrieve JIRA secret
$headers = @{ 'Authorization' = "Bearer $accessToken" }
$queryUrl = $jiraSecretURL + "?api-version=7.0"
$keyResponse = Invoke-RestMethod -Method GET -Uri $queryUrl -Headers $headers
$jiraSecret= $keyResponse.value
$pair = "$($jiraUser):$($jiraSecret)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
$basicAuthValue = "Basic $encodedCreds"
$Headers = @{
Authorization = $basicAuthValue
'Content-Type'='application/json'
}
#Retrieve latest comment
$comment = (Invoke-WebRequest -uri $newComment.self -Method GET -Headers $Headers).Content
$jsonComment = $comment | ConvertFrom-Json
#Check if this is a public or internal comment. We only sync public comments
if($jsonComment.jsdPublic -eq "True"){
Write-Host "This is a public comment that will be posted"
#remove images from comments
$sanitizedComment = $newComment.body -replace "(?<=!image)(.*)(?=!)" -replace "!image!"
#Create author text to add to incident
$Author = "$($newcomment.updateAuthor.displayName) (The Collective) wrote: `n"
#add author to comment
$commentWithAuthor = $Author + $sanitizedComment
Write-Host $commentWithAuthor
Write-Host $sanitizedComment
$tokenAuthURI = $Env:MSI_ENDPOINT +"?resource=https://vault.azure.net&api-version=2017-09-01"
$tokenResponse = Invoke-RestMethod -Method Get -Headers @{"Secret"="$env:MSI_SECRET"} -Uri $tokenAuthURI
$accessToken = $tokenResponse.access_token
# get secret value sentinel
$headers = @{ 'Authorization' = "Bearer $accessToken" }
$queryUrl = $sentinelSecretURL + "?api-version=7.0"
$keyResponse = Invoke-RestMethod -Method GET -Uri $queryUrl -Headers $headers
$apiSecret= $keyResponse.value
$body=@{
client_id=$clientid
client_secret=$apiSecret
resource="https://management.azure.com"
grant_type="client_credentials"
}
$accesstoken = Invoke-WebRequest -Uri "https://login.microsoftonline.com/$tenantId/oauth2/token" -ContentType "application/x-www-form-urlencoded" -Body $body -Method Post
$accessToken=$accessToken.content | ConvertFrom-Json
$authHeader = @{
'Content-Type'='application/json'
'Authorization'="Bearer " + $accessToken.access_token
'ExpiresOn'=$accessToken.expires_in
}
$guid = (New-Guid).Guid
#Create correct URL for api call
$SentinelURL = "https://management.azure.com/subscriptions/$($request.body.fields.customfield_10162)/resourceGroups/$($request.body.fields.customfield_10169)/providers/Microsoft.OperationalInsights/workspaces/$($request.body.fields.customfield_10170)/providers/Microsoft.SecurityInsights/incidents/$($request.body.fields.customfield_10145)/comments/$($guid)?api-version=2019-01-01-preview"
$body = @{
"properties"= @{
"message"= $commentWithAuthor
}
}
$JSON = ConvertTo-Json $body
#Add comment to Sentinel incident
$data = Invoke-RestMethod -Headers $authHeader -URI $sentinelURL -Body $JSON -Method PUT -ContentType 'application/json'
}
else{
Write-Host "Internal comment, not posting"
}
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = $body
})
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
#variables
$jiraUser = ""
$jiraSecretURL = ""
$sentinelSecretURL = ""
$tenantId = ""
$clientid = ""
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
#find comment with highest updated time => comment we want to sync
$max = ($Request.body.fields.comment.comments | Measure-Object -Property updated -Maximum).Maximum
#Get latest comment
$newComment = $Request.body.fields.comment.comments | ? {$_.updated -eq $max}
Write-Host $newComment.body
#Retrieve Graph API Secret
$tokenAuthURI = $Env:MSI_ENDPOINT +"?resource=https://vault.azure.net&api-version=2017-09-01"
$tokenResponse = Invoke-RestMethod -Method Get -Headers @{"Secret"="$env:MSI_SECRET"} -Uri $tokenAuthURI
$accessToken = $tokenResponse.access_token
#Retrieve JIRA secret
$headers = @{ 'Authorization' = "Bearer $accessToken" }
$queryUrl = $jiraSecretURL + "?api-version=7.0"
$keyResponse = Invoke-RestMethod -Method GET -Uri $queryUrl -Headers $headers
$jiraSecret= $keyResponse.value
$pair = "$($jiraUser):$($jiraSecret)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
$basicAuthValue = "Basic $encodedCreds"
$Headers = @{
Authorization = $basicAuthValue
'Content-Type'='application/json'
}
#Retrieve latest comment
$comment = (Invoke-WebRequest -uri $newComment.self -Method GET -Headers $Headers).Content
$jsonComment = $comment | ConvertFrom-Json
#Check if this is a public or internal comment. We only sync public comments
if($jsonComment.jsdPublic -eq "True"){
Write-Host "This is a public comment that will be posted"
#remove images from comments
$sanitizedComment = $newComment.body -replace "(?<=!image)(.*)(?=!)" -replace "!image!"
#Create author text to add to incident
$Author = "$($newcomment.updateAuthor.displayName) (The Collective) wrote: `n"
#add author to comment
$commentWithAuthor = $Author + $sanitizedComment
Write-Host $commentWithAuthor
Write-Host $sanitizedComment
$tokenAuthURI = $Env:MSI_ENDPOINT +"?resource=https://vault.azure.net&api-version=2017-09-01"
$tokenResponse = Invoke-RestMethod -Method Get -Headers @{"Secret"="$env:MSI_SECRET"} -Uri $tokenAuthURI
$accessToken = $tokenResponse.access_token
# get secret value sentinel
$headers = @{ 'Authorization' = "Bearer $accessToken" }
$queryUrl = $sentinelSecretURL + "?api-version=7.0"
$keyResponse = Invoke-RestMethod -Method GET -Uri $queryUrl -Headers $headers
$apiSecret= $keyResponse.value
$body=@{
client_id=$clientid
client_secret=$apiSecret
resource="https://management.azure.com"
grant_type="client_credentials"
}
$accesstoken = Invoke-WebRequest -Uri "https://login.microsoftonline.com/$tenantId/oauth2/token" -ContentType "application/x-www-form-urlencoded" -Body $body -Method Post
$accessToken=$accessToken.content | ConvertFrom-Json
$authHeader = @{
'Content-Type'='application/json'
'Authorization'="Bearer " + $accessToken.access_token
'ExpiresOn'=$accessToken.expires_in
}
$guid = (New-Guid).Guid
#Create correct URL for api call
$SentinelURL = "https://management.azure.com/subscriptions/$($request.body.fields.customfield_10162)/resourceGroups/$($request.body.fields.customfield_10169)/providers/Microsoft.OperationalInsights/workspaces/$($request.body.fields.customfield_10170)/providers/Microsoft.SecurityInsights/incidents/$($request.body.fields.customfield_10145)/comments/$($guid)?api-version=2019-01-01-preview"
$body = @{
"properties"= @{
"message"= $commentWithAuthor
}
}
$JSON = ConvertTo-Json $body
#Add comment to Sentinel incident
$data = Invoke-RestMethod -Headers $authHeader -URI $sentinelURL -Body $JSON -Method PUT -ContentType 'application/json'
}
else{
Write-Host "Internal comment, not posting"
}
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = $body
})

Просмотреть файл

@ -1,100 +1,100 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"FunctionAppName": {
"defaultValue": "jira-sync",
"type": "string"
}
},
"variables": {
"hostingPlanName": "[concat(parameters('FunctionAppName'),'hostingPlan')]",
"storageName":"[concat('deploy', uniqueString(resourceGroup().id))]",
"packageURL":"https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/AtlassianJiraAudit/Playbooks/Sync-CommentsFunctionApp/tc-function-cc-sync.zip?raw=true"
},
"resources": [
{
"apiVersion": "2021-09-01",
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageName')]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
}
},
{
"apiVersion": "2015-08-01",
"name": "[variables('hostingPlanName')]",
"kind": "functionapp",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"sku": {
"name": "Y1",
"tier": "Dynamic",
"size": "Y1",
"family": "Y",
"capacity": 0
},
"properties": {
"name": "[variables('hostingPlanName')]"
}
},
{
"apiVersion": "2015-08-01",
"name": "[parameters('FunctionAppName')]",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"kind": "functionapp",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))]"
],
"properties": {
"serverFarmId": "[variables('hostingPlanName')]",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsDashboard",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageName')), '2022-05-01').keys[0].value)]"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageName')), '2022-05-01').keys[0].value)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~3"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageName')), '2022-05-01').keys[0].value)]"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "~10"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(parameters('FunctionAppName'))]"
}
]
}
},
"resources": [
{
"name": "MSDeploy",
"type": "extensions",
"location": "[resourceGroup().location]",
"apiVersion": "2015-08-01",
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('FunctionAppName'))]"
],
"properties": {
"packageUri": "[variables('packageURL')]"
}
}
]
}
]
}
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"FunctionAppName": {
"defaultValue": "jira-sync",
"type": "string"
}
},
"variables": {
"hostingPlanName": "[concat(parameters('FunctionAppName'),'hostingPlan')]",
"storageName":"[concat('deploy', uniqueString(resourceGroup().id))]",
"packageURL":"https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/AtlassianJiraAudit/Playbooks/Sync-CommentsFunctionApp/tc-function-cc-sync.zip?raw=true"
},
"resources": [
{
"apiVersion": "2021-09-01",
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageName')]",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
}
},
{
"apiVersion": "2015-08-01",
"name": "[variables('hostingPlanName')]",
"kind": "functionapp",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"sku": {
"name": "Y1",
"tier": "Dynamic",
"size": "Y1",
"family": "Y",
"capacity": 0
},
"properties": {
"name": "[variables('hostingPlanName')]"
}
},
{
"apiVersion": "2015-08-01",
"name": "[parameters('FunctionAppName')]",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"kind": "functionapp",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageName'))]"
],
"properties": {
"serverFarmId": "[variables('hostingPlanName')]",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsDashboard",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageName')), '2023-04-01').keys[0].value)]"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageName')), '2023-04-01').keys[0].value)]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~3"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageName')), '2023-04-01').keys[0].value)]"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "~10"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(parameters('FunctionAppName'))]"
}
]
}
},
"resources": [
{
"name": "MSDeploy",
"type": "extensions",
"location": "[resourceGroup().location]",
"apiVersion": "2015-08-01",
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('FunctionAppName'))]"
],
"properties": {
"packageUri": "[variables('packageURL')]"
}
}
]
}
]
}

Просмотреть файл

@ -1,233 +1,233 @@
# Synchronization Tool for Sentinel and JIRA
Author: Thijs Lecomte
## Overview
This tool will synchronize incidents between Microsoft Sentinel and JIRA Service Management using the following tools:
* Azure Logic Apps
* Azure Functions
* Automation for JIRA
* Microsoft Sentinel Automation Rules
* Azure Key Vault
This tool will do the following:
* Create an incident in JIRA when an incident is created in Sentinel
* Sync the assigned user from JIRA to Sentinel
* Sync the status from JIRA to Sentinel
* Add the URL to the JIRA incident as a comment in Sentinel
* Sync public comments from JIRA to Sentinel
![Overview](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Solution%20overview.png)
[Blog post with more background information](https://www.thecollective.eu/en/insights/setting-up-a-bidirectional-sync-between-sentinel-and-jira)
## Implementation
To implement this solution, a few different steps need to be done:
1. Create necessary Service Principals
2. JIRA Configuration
1. Custom fields
2. Deploy Automation for JIRA rules (used for sync from JIRA to Microsoft Sentinel)
3. Deploy the Key Vault and add secrets
4. Deploy Azure Logic Apps (4) through ARM deployment
5. Deploy Azure Function for comment sychronization and add the Powershell code (check the Functions)
6. Create Sentinel Automation Rule
## 1. Create Service Principal
The tool requires a service principals for authentication to different services:
* Authentication to Microsoft Entra ID to retrieve user ID's (for assigning incidents in Sentinel)
### Microsoft Entra ID Service Principal
This Service Principal needs to have User.Read.All application permissions.
This Service Principal is used in the Logic app 'Sync-AssignedUser.
## 2. JIRA Configuration
### JIRA Custom Fields
#### Introduction
A lot of the Sentinel specific information is stored inside of Custom Fields in JIRA which need to be created.
This document contains an overview of the different custom fields that are used in the Logic Apps.
All Logic Apps need to be updated with the correct ID's of the fields.
#### Custom Fields overview
| **Field Name** | **Field ID** | **Field Type**|
| --- | --- | --- |
| Organizations | customfield_10002 | Built-in |
| Sentinel Incident URL | customfield_10144 | Url Field |
| Incident ID | customfield_10145 | Text Field (Single line) |
| Closure Comment | customfield_10146 | Text Field (Multiline) |
| Closure Reason | customfield_10047 | Select List (Single choice) |
| Tenant Name | customfield_10149 | Select List (Single Choice) |
| Created At | customfield_10154 | Date Time Picker |
| Att&ck Tactics | customfield_10155 | Select List (Multiple choices) |
| Affected User | customfield_10158 | Text Field (Multiline) |
| Subscription ID | customfield_10162 | Text Field (Singline) |
| Sentinel Resource Group | customfield_10169 | Text Field (Singline) |
| Sentinel Workspace Name | customfield_10170 | Text Field (Singline) |
| Sentinel Workspace ID | customfield_10172 | Text Field (Singline) |
| Sentinel Incident ID | customfield_10173 | Text Field (Singline) |
| Sentinel Incident ARM ID | customfield_10175 | Text Field (Singline) |
The Att&ck Tactics list contains all Sentinel Tactics.
The Closure Reason contains all valid Sentinel Closure Reasons
### JIRA Automation Rules
In order to synchronize changes from JIRA to Sentinel, Automation for JIRA is used to trigger Logic Apps when certain conditions are met.
Automation for JIRA is an integrated plugin that is free to use for JIRA Service Management.
This document will describe the different automation rules that are necessary to trigger the correct Logic Apps/Functions.
In almost every rule, the step 're-fetch issue data' is used. This will make sure we are using the most up to date information in our Logic Apps.
If you are not using this, you might encouter failures.
Navigate to the project settings, then go to Automation to create rules.
#### Sync Status
This automation rule has a trigger 'Issue Transitioned' and will trigger the Logic App 'Sync-Status'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Status.png)
#### Sync Assigned User
This automation rule has a trigger 'Issue Assigned' and will trigger the Logic App 'Sync-AssignedUser'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Assigned%20User.png)
#### Create Link
This automation rule has a trigger 'Issue created' and will trigger the Logic App 'Add-JIRALinkComment'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Create%20Link.png)
#### Sync comment
This automation rule will trigger the function app to sync public comments to Microsoft Sentinel.
Provide the POST URL of the Sync Comment Function in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Comment.png)
## 3. Deploy Key Vault
The Key Vault is used to store three secrets:
* One for the Microsoft Entra ID Service Principal
* One for the Microsoft Sentinel Service Principal
* One for the JIRA Secret
Create a new Key Vault or deploy an existing one and add the different secrets to it.
The names will need to be provided when deploying the ARM Templates from the Logic Apps.
Edit the Access Policy and assign 'Secret - Get' permissions to the Key Vault Service Principal.
## 4. Deploy Logic Apps
The solution consists of four different Logic Apps:
* Sync Incidents from Sentinel to JIRA (Sync-Incidents.json)
* Sync status from JIRA to Sentinel (Sync-Status.json)
* Sync assigned user from JIRA to Sentinel (Sync-AssignedUser.json)
* Add a link to the JIRA incident to the Sentinel incident (Add-JiraLinkComment.json)
This will enable a two way synchronization between JIRA and Sentinel. Not all Logic Apps are mandatory, you can deploy the ones your organization needs.
Each Logic App can be deployed using the provided ARM templates.
After deploying the Logic Apps, you can copy the HTTP trigger URLs and paste them in the JIRA Automation Rules.
### Custom Fields Configuration
A lot of JIRA Custom fields are used within these Logic Apps. It's important to create these custom fields in your own JIRA environment and change the correct ID's in the Logic Apps.
For more information about the different custom fields used, please check the JIRA Configuration.
### Sync Incidents from Sentinel to JIRA
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
This Logic App will create a new incident in JIRA when an incident in Sentinel is created.
It uses the 'Incident Trigger' from Sentinel and is triggered by an Automation Rule (see Sentinel Configuration).
This Logic App does the following:
* Retrieve all the incident information
* Retrieve the Tactics in this incident
* Retrieve the details from the Account Entity
* Check which customer this incident is coming from (to add the right organization in JIRA)
* Create JIRA ticket through an API call
It uses two connections:
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the JIRA API Key (Managed Identity)
In order to correlate the right add the incident in JIRA to the correct Organization, we use a switch and determine the correct organization based on the originate Subscription ID.
Add a case per customer and add the right Subscription ID, Customer name and Organization ID.
If you do not use organizations in JIRA, you can remove the switch.
![Switch](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Azure%20-%20Switch%20Organization.png)
### Sync status from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
This Logic App will change the status in Sentinel when the status has been changed in JIRA.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It's important you use the same closure reason in JIRA as the ones in Sentinel, otherwise the sync will fail.
It uses one connections:
* One connection to Sentinel through a Managed Identity.
### Sync assigned user from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-AssignedUser%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-AssignedUser%2Fazuredeploy.json)
When a incident is assigned in JIRA, this will assign the correct user inside of Microsoft Sentinel.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule when the assigned user of an incident is changed.
It will retrieve the client secret for the service principal with permissions to retrieve users in your Microsoft Entra ID. With this, it will query the user and retrieve the Microsoft Entra ID Object ID from that user. Wit this information, we will update the incident in Microsoft Sentinel.
There is a check built-in to make sure that JIRA provides the assigned user. Sometimes it does not and then we don't need to update the incident in Sentinel.
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the Secret for the Service Principal with Microsoft Entra ID permissions (also configured when deploying the Logic App)
### Add a link to the JIRA incident to the Sentinel incident
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
This Logic App will add a URL to the JIRA incident as a comment to the Sentinel Incident.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It will add the link to the JIRA Customer Portal, which enables a customer to view the details of an incident inside JIRA.
It uses one connections:
* One connection to Sentinel through a Managed Identity
## 5. Deploy Azure Function
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-CommentsFunctionApp%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-CommentsFunctionApp%2Fazuredeploy.json)
To sync incident comments from JIRA to Microsoft Sentinel an Azure Function is used. This Function App contains one Powershell Function.
There are two types of comments in JIRA: internal and public comments. This script will only sync the public comments, so that customers don't have access to the internal ones.
The code for this function can be found [in this repository](Sync-Comments/Sync-Comment.ps1).
This Function uses a managed identity to authenticate to the Key Vault.
Either deployment the Function App through the ARM template linked above or deploy a Function app manually and paste the ps1 code
After deployment, configure the parameters in the Powershell file.
* jiraUser => Used for authentication to JIRA
* jiraSecretURL => The URL to the JIRA Secret in our Key Vault
* sentinelSecretURL => The URL to the Sentinel Secret in our Key Vault
* tenantID => Tenant ID for the Sentinel Service Principals
* clientID => Client ID for the Sentinel Service Principal
Enable the Managed Identity (Identity => System Assigned).
Provide 'Secret - Get' permissions to the Function app in the Access Policies of the Key Vault.
## 6. Sentinel Automation Rule
In order to trigger the Logic App that creates incidents in JIRA, we use an Automation Rule in Sentinel.
This will enable us to trigger a Logic App (Playbook) each time an incident is created.
Navigate to your Sentinel workspace and choose 'Automation', after this click 'Create Rule'.
Provide a name for the rule and for conditions choose 'Analytics Rule Name contains All'. This will trigger out Logic app each time an incident is created.
If you only want to sync certain incidents, choose the right condition.
For actions, choose 'Run Playbook' and select the 'Sync-Incidents' Playbook.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Sentinel%20-%20Automation%20Rule.png)
## Conclusion
After this solution, you are able to work on Microsoft Sentinel incidents while staying in your trusted ITSM tool.
This tool should take care of any previous synchronization issues between the JIRA and Sentinel.
# Synchronization Tool for Sentinel and JIRA
Author: Thijs Lecomte
## Overview
This tool will synchronize incidents between Microsoft Sentinel and JIRA Service Management using the following tools:
* Azure Logic Apps
* Azure Functions
* Automation for JIRA
* Microsoft Sentinel Automation Rules
* Azure Key Vault
This tool will do the following:
* Create an incident in JIRA when an incident is created in Sentinel
* Sync the assigned user from JIRA to Sentinel
* Sync the status from JIRA to Sentinel
* Add the URL to the JIRA incident as a comment in Sentinel
* Sync public comments from JIRA to Sentinel
![Overview](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Solution%20overview.png)
[Blog post with more background information](https://www.thecollective.eu/en/insights/setting-up-a-bidirectional-sync-between-sentinel-and-jira)
## Implementation
To implement this solution, a few different steps need to be done:
1. Create necessary Service Principals
2. JIRA Configuration
1. Custom fields
2. Deploy Automation for JIRA rules (used for sync from JIRA to Microsoft Sentinel)
3. Deploy the Key Vault and add secrets
4. Deploy Azure Logic Apps (4) through ARM deployment
5. Deploy Azure Function for comment sychronization and add the Powershell code (check the Functions)
6. Create Sentinel Automation Rule
## 1. Create Service Principal
The tool requires a service principals for authentication to different services:
* Authentication to Microsoft Entra ID to retrieve user ID's (for assigning incidents in Sentinel)
### Microsoft Entra ID Service Principal
This Service Principal needs to have User.Read.All application permissions.
This Service Principal is used in the Logic app 'Sync-AssignedUser.
## 2. JIRA Configuration
### JIRA Custom Fields
#### Introduction
A lot of the Sentinel specific information is stored inside of Custom Fields in JIRA which need to be created.
This document contains an overview of the different custom fields that are used in the Logic Apps.
All Logic Apps need to be updated with the correct ID's of the fields.
#### Custom Fields overview
| **Field Name** | **Field ID** | **Field Type**|
| --- | --- | --- |
| Organizations | customfield_10002 | Built-in |
| Sentinel Incident URL | customfield_10144 | Url Field |
| Incident ID | customfield_10145 | Text Field (Single line) |
| Closure Comment | customfield_10146 | Text Field (Multiline) |
| Closure Reason | customfield_10047 | Select List (Single choice) |
| Tenant Name | customfield_10149 | Select List (Single Choice) |
| Created At | customfield_10154 | Date Time Picker |
| Att&ck Tactics | customfield_10155 | Select List (Multiple choices) |
| Affected User | customfield_10158 | Text Field (Multiline) |
| Subscription ID | customfield_10162 | Text Field (Singline) |
| Sentinel Resource Group | customfield_10169 | Text Field (Singline) |
| Sentinel Workspace Name | customfield_10170 | Text Field (Singline) |
| Sentinel Workspace ID | customfield_10172 | Text Field (Singline) |
| Sentinel Incident ID | customfield_10173 | Text Field (Singline) |
| Sentinel Incident ARM ID | customfield_10175 | Text Field (Singline) |
The Att&ck Tactics list contains all Sentinel Tactics.
The Closure Reason contains all valid Sentinel Closure Reasons
### JIRA Automation Rules
In order to synchronize changes from JIRA to Sentinel, Automation for JIRA is used to trigger Logic Apps when certain conditions are met.
Automation for JIRA is an integrated plugin that is free to use for JIRA Service Management.
This document will describe the different automation rules that are necessary to trigger the correct Logic Apps/Functions.
In almost every rule, the step 're-fetch issue data' is used. This will make sure we are using the most up to date information in our Logic Apps.
If you are not using this, you might encouter failures.
Navigate to the project settings, then go to Automation to create rules.
#### Sync Status
This automation rule has a trigger 'Issue Transitioned' and will trigger the Logic App 'Sync-Status'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Status.png)
#### Sync Assigned User
This automation rule has a trigger 'Issue Assigned' and will trigger the Logic App 'Sync-AssignedUser'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Assigned%20User.png)
#### Create Link
This automation rule has a trigger 'Issue created' and will trigger the Logic App 'Add-JIRALinkComment'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Create%20Link.png)
#### Sync comment
This automation rule will trigger the function app to sync public comments to Microsoft Sentinel.
Provide the POST URL of the Sync Comment Function in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Comment.png)
## 3. Deploy Key Vault
The Key Vault is used to store three secrets:
* One for the Microsoft Entra ID Service Principal
* One for the Microsoft Sentinel Service Principal
* One for the JIRA Secret
Create a new Key Vault or deploy an existing one and add the different secrets to it.
The names will need to be provided when deploying the ARM Templates from the Logic Apps.
Edit the Access Policy and assign 'Secret - Get' permissions to the Key Vault Service Principal.
## 4. Deploy Logic Apps
The solution consists of four different Logic Apps:
* Sync Incidents from Sentinel to JIRA (Sync-Incidents.json)
* Sync status from JIRA to Sentinel (Sync-Status.json)
* Sync assigned user from JIRA to Sentinel (Sync-AssignedUser.json)
* Add a link to the JIRA incident to the Sentinel incident (Add-JiraLinkComment.json)
This will enable a two way synchronization between JIRA and Sentinel. Not all Logic Apps are mandatory, you can deploy the ones your organization needs.
Each Logic App can be deployed using the provided ARM templates.
After deploying the Logic Apps, you can copy the HTTP trigger URLs and paste them in the JIRA Automation Rules.
### Custom Fields Configuration
A lot of JIRA Custom fields are used within these Logic Apps. It's important to create these custom fields in your own JIRA environment and change the correct ID's in the Logic Apps.
For more information about the different custom fields used, please check the JIRA Configuration.
### Sync Incidents from Sentinel to JIRA
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
This Logic App will create a new incident in JIRA when an incident in Sentinel is created.
It uses the 'Incident Trigger' from Sentinel and is triggered by an Automation Rule (see Sentinel Configuration).
This Logic App does the following:
* Retrieve all the incident information
* Retrieve the Tactics in this incident
* Retrieve the details from the Account Entity
* Check which customer this incident is coming from (to add the right organization in JIRA)
* Create JIRA ticket through an API call
It uses two connections:
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the JIRA API Key (Managed Identity)
In order to correlate the right add the incident in JIRA to the correct Organization, we use a switch and determine the correct organization based on the originate Subscription ID.
Add a case per customer and add the right Subscription ID, Customer name and Organization ID.
If you do not use organizations in JIRA, you can remove the switch.
![Switch](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Playbooks/Sync-IncidentsWithJIRA/Images/Azure%20-%20Switch%20Organization.png)
### Sync status from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
This Logic App will change the status in Sentinel when the status has been changed in JIRA.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It's important you use the same closure reason in JIRA as the ones in Sentinel, otherwise the sync will fail.
It uses one connections:
* One connection to Sentinel through a Managed Identity.
### Sync assigned user from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-AssignedUser%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-AssignedUser%2Fazuredeploy.json)
When a incident is assigned in JIRA, this will assign the correct user inside of Microsoft Sentinel.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule when the assigned user of an incident is changed.
It will retrieve the client secret for the service principal with permissions to retrieve users in your Microsoft Entra ID. With this, it will query the user and retrieve the Microsoft Entra ID Object ID from that user. Wit this information, we will update the incident in Microsoft Sentinel.
There is a check built-in to make sure that JIRA provides the assigned user. Sometimes it does not and then we don't need to update the incident in Sentinel.
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the Secret for the Service Principal with Microsoft Entra ID permissions (also configured when deploying the Logic App)
### Add a link to the JIRA incident to the Sentinel incident
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FSync-IncidentsWithJIRA%2FAdd-JiraLinkComment%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FSync-IncidentsWithJIRA%2FAdd-JiraLinkCommnet%2Fazuredeploy.json)
This Logic App will add a URL to the JIRA incident as a comment to the Sentinel Incident.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It will add the link to the JIRA Customer Portal, which enables a customer to view the details of an incident inside JIRA.
It uses one connections:
* One connection to Sentinel through a Managed Identity
## 5. Deploy Azure Function
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-CommentsFunctionApp%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-CommentsFunctionApp%2Fazuredeploy.json)
To sync incident comments from JIRA to Microsoft Sentinel an Azure Function is used. This Function App contains one Powershell Function.
There are two types of comments in JIRA: internal and public comments. This script will only sync the public comments, so that customers don't have access to the internal ones.
The code for this function can be found [in this repository](Sync-Comments/Sync-Comment.ps1).
This Function uses a managed identity to authenticate to the Key Vault.
Either deployment the Function App through the ARM template linked above or deploy a Function app manually and paste the ps1 code
After deployment, configure the parameters in the Powershell file.
* jiraUser => Used for authentication to JIRA
* jiraSecretURL => The URL to the JIRA Secret in our Key Vault
* sentinelSecretURL => The URL to the Sentinel Secret in our Key Vault
* tenantID => Tenant ID for the Sentinel Service Principals
* clientID => Client ID for the Sentinel Service Principal
Enable the Managed Identity (Identity => System Assigned).
Provide 'Secret - Get' permissions to the Function app in the Access Policies of the Key Vault.
## 6. Sentinel Automation Rule
In order to trigger the Logic App that creates incidents in JIRA, we use an Automation Rule in Sentinel.
This will enable us to trigger a Logic App (Playbook) each time an incident is created.
Navigate to your Sentinel workspace and choose 'Automation', after this click 'Create Rule'.
Provide a name for the rule and for conditions choose 'Analytics Rule Name contains All'. This will trigger out Logic app each time an incident is created.
If you only want to sync certain incidents, choose the right condition.
For actions, choose 'Run Playbook' and select the 'Sync-Incidents' Playbook.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Sentinel%20-%20Automation%20Rule.png)
## Conclusion
After this solution, you are able to work on Microsoft Sentinel incidents while staying in your trusted ITSM tool.
This tool should take care of any previous synchronization issues between the JIRA and Sentinel.
For any issues with the tool or requested improvements, feel free to create an issue on Github or contact me through [Twitter](https://twitter.com/thijslecomte).

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,233 +1,233 @@
# Synchronization Tool for Sentinel and JIRA
Author: Thijs Lecomte
## Overview
This tool will synchronize incidents between Microsoft Sentinel and JIRA Service Management using the following tools:
* Azure Logic Apps
* Azure Functions
* Automation for JIRA
* Microsoft Sentinel Automation Rules
* Azure Key Vault
This tool will do the following:
* Create an incident in JIRA when an incident is created in Sentinel
* Sync the assigned user from JIRA to Sentinel
* Sync the status from JIRA to Sentinel
* Add the URL to the JIRA incident as a comment in Sentinel
* Sync public comments from JIRA to Sentinel
![Overview](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Solution%20overview.png)
[Blog post with more background information](https://www.thecollective.eu/en/insights/setting-up-a-bidirectional-sync-between-sentinel-and-jira)
## Implementation
To implement this solution, a few different steps need to be done:
1. Create necessary Service Principals
2. JIRA Configuration
1. Custom fields
2. Deploy Automation for JIRA rules (used for sync from JIRA to Microsoft Sentinel)
3. Deploy the Key Vault and add secrets
4. Deploy Azure Logic Apps (4) through ARM deployment
5. Deploy Azure Function for comment sychronization and add the Powershell code (check the Functions)
6. Create Sentinel Automation Rule
## 1. Create Service Principal
The tool requires a service principals for authentication to different services:
* Authentication to Microsoft Entra ID to retrieve user ID's (for assigning incidents in Sentinel)
### Microsoft Entra ID Service Principal
This Service Principal needs to have User.Read.All application permissions.
This Service Principal is used in the Logic app 'Sync-AssignedUser.
## 2. JIRA Configuration
### JIRA Custom Fields
#### Introduction
A lot of the Sentinel specific information is stored inside of Custom Fields in JIRA which need to be created.
This document contains an overview of the different custom fields that are used in the Logic Apps.
All Logic Apps need to be updated with the correct ID's of the fields.
#### Custom Fields overview
| **Field Name** | **Field ID** | **Field Type**|
| --- | --- | --- |
| Organizations | customfield_10002 | Built-in |
| Sentinel Incident URL | customfield_10144 | Url Field |
| Incident ID | customfield_10145 | Text Field (Single line) |
| Closure Comment | customfield_10146 | Text Field (Multiline) |
| Closure Reason | customfield_10047 | Select List (Single choice) |
| Tenant Name | customfield_10149 | Select List (Single Choice) |
| Created At | customfield_10154 | Date Time Picker |
| Att&ck Tactics | customfield_10155 | Select List (Multiple choices) |
| Affected User | customfield_10158 | Text Field (Multiline) |
| Subscription ID | customfield_10162 | Text Field (Singline) |
| Sentinel Resource Group | customfield_10169 | Text Field (Singline) |
| Sentinel Workspace Name | customfield_10170 | Text Field (Singline) |
| Sentinel Workspace ID | customfield_10172 | Text Field (Singline) |
| Sentinel Incident ID | customfield_10173 | Text Field (Singline) |
| Sentinel Incident ARM ID | customfield_10175 | Text Field (Singline) |
The Att&ck Tactics list contains all Sentinel Tactics.
The Closure Reason contains all valid Sentinel Closure Reasons
### JIRA Automation Rules
In order to synchronize changes from JIRA to Sentinel, Automation for JIRA is used to trigger Logic Apps when certain conditions are met.
Automation for JIRA is an integrated plugin that is free to use for JIRA Service Management.
This document will describe the different automation rules that are necessary to trigger the correct Logic Apps/Functions.
In almost every rule, the step 're-fetch issue data' is used. This will make sure we are using the most up to date information in our Logic Apps.
If you are not using this, you might encouter failures.
Navigate to the project settings, then go to Automation to create rules.
#### Sync Status
This automation rule has a trigger 'Issue Transitioned' and will trigger the Logic App 'Sync-Status'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Status.png)
#### Sync Assigned User
This automation rule has a trigger 'Issue Assigned' and will trigger the Logic App 'Sync-AssignedUser'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Assigned%20User.png)
#### Create Link
This automation rule has a trigger 'Issue created' and will trigger the Logic App 'Add-JIRALinkComment'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Create%20Link.png)
#### Sync comment
This automation rule will trigger the function app to sync public comments to Microsoft Sentinel.
Provide the POST URL of the Sync Comment Function in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Comment.png)
## 3. Deploy Key Vault
The Key Vault is used to store three secrets:
* One for the Microsoft Entra ID Service Principal
* One for the Microsoft Sentinel Service Principal
* One for the JIRA Secret
Create a new Key Vault or deploy an existing one and add the different secrets to it.
The names will need to be provided when deploying the ARM Templates from the Logic Apps.
Edit the Access Policy and assign 'Secret - Get' permissions to the Key Vault Service Principal.
## 4. Deploy Logic Apps
The solution consists of four different Logic Apps:
* Sync Incidents from Sentinel to JIRA (Sync-Incidents.json)
* Sync status from JIRA to Sentinel (Sync-Status.json)
* Sync assigned user from JIRA to Sentinel (Sync-AssignedUser.json)
* Add a link to the JIRA incident to the Sentinel incident (Add-JiraLinkComment.json)
This will enable a two way synchronization between JIRA and Sentinel. Not all Logic Apps are mandatory, you can deploy the ones your organization needs.
Each Logic App can be deployed using the provided ARM templates.
After deploying the Logic Apps, you can copy the HTTP trigger URLs and paste them in the JIRA Automation Rules.
### Custom Fields Configuration
A lot of JIRA Custom fields are used within these Logic Apps. It's important to create these custom fields in your own JIRA environment and change the correct ID's in the Logic Apps.
For more information about the different custom fields used, please check the JIRA Configuration.
### Sync Incidents from Sentinel to JIRA
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
This Logic App will create a new incident in JIRA when an incident in Sentinel is created.
It uses the 'Incident Trigger' from Sentinel and is triggered by an Automation Rule (see Sentinel Configuration).
This Logic App does the following:
* Retrieve all the incident information
* Retrieve the Tactics in this incident
* Retrieve the details from the Account Entity
* Check which customer this incident is coming from (to add the right organization in JIRA)
* Create JIRA ticket through an API call
It uses two connections:
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the JIRA API Key (Managed Identity)
In order to correlate the right add the incident in JIRA to the correct Organization, we use a switch and determine the correct organization based on the originate Subscription ID.
Add a case per customer and add the right Subscription ID, Customer name and Organization ID.
If you do not use organizations in JIRA, you can remove the switch.
![Switch](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Azure%20-%20Switch%20Organization.png)
### Sync status from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
This Logic App will change the status in Sentinel when the status has been changed in JIRA.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It's important you use the same closure reason in JIRA as the ones in Sentinel, otherwise the sync will fail.
It uses one connections:
* One connection to Sentinel through a Managed Identity.
### Sync assigned user from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-AssignedUser%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-AssignedUser%2Fazuredeploy.json)
When a incident is assigned in JIRA, this will assign the correct user inside of Microsoft Sentinel.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule when the assigned user of an incident is changed.
It will retrieve the client secret for the service principal with permissions to retrieve users in your Microsoft Entra ID. With this, it will query the user and retrieve the Microsoft Entra ID Object ID from that user. Wit this information, we will update the incident in Microsoft Sentinel.
There is a check built-in to make sure that JIRA provides the assigned user. Sometimes it does not and then we don't need to update the incident in Sentinel.
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the Secret for the Service Principal with Microsoft Entra ID permissions (also configured when deploying the Logic App)
### Add a link to the JIRA incident to the Sentinel incident
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FAdd-JiraLinkComment%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FAdd-JiraLinkComment%2Fazuredeploy.json)
This Logic App will add a URL to the JIRA incident as a comment to the Sentinel Incident.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It will add the link to the JIRA Customer Portal, which enables a customer to view the details of an incident inside JIRA.
It uses one connections:
* One connection to Sentinel through a Managed Identity
## 5. Deploy Azure Function
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-CommentsFunctionApp%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-CommentsFunctionApp%2Fazuredeploy.json)
To sync incident comments from JIRA to Microsoft Sentinel an Azure Function is used. This Function App contains one Powershell Function.
There are two types of comments in JIRA: internal and public comments. This script will only sync the public comments, so that customers don't have access to the internal ones.
The code for this function can be found [in this repository](Sync-Comments/Sync-Comment.ps1).
This Function uses a managed identity to authenticate to the Key Vault.
Either deployment the Function App through the ARM template linked above or deploy a Function app manually and paste the ps1 code
After deployment, configure the parameters in the Powershell file.
* jiraUser => Used for authentication to JIRA
* jiraSecretURL => The URL to the JIRA Secret in our Key Vault
* sentinelSecretURL => The URL to the Sentinel Secret in our Key Vault
* tenantID => Tenant ID for the Sentinel Service Principals
* clientID => Client ID for the Sentinel Service Principal
Enable the Managed Identity (Identity => System Assigned).
Provide 'Secret - Get' permissions to the Function app in the Access Policies of the Key Vault.
## 6. Sentinel Automation Rule
In order to trigger the Logic App that creates incidents in JIRA, we use an Automation Rule in Sentinel.
This will enable us to trigger a Logic App (Playbook) each time an incident is created.
Navigate to your Sentinel workspace and choose 'Automation', after this click 'Create Rule'.
Provide a name for the rule and for conditions choose 'Analytics Rule Name contains All'. This will trigger out Logic app each time an incident is created.
If you only want to sync certain incidents, choose the right condition.
For actions, choose 'Run Playbook' and select the 'Sync-Incidents' Playbook.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Sentinel%20-%20Automation%20Rule.png)
## Conclusion
After this solution, you are able to work on Microsoft Sentinel incidents while staying in your trusted ITSM tool.
This tool should take care of any previous synchronization issues between the JIRA and Sentinel.
# Synchronization Tool for Sentinel and JIRA
Author: Thijs Lecomte
## Overview
This tool will synchronize incidents between Microsoft Sentinel and JIRA Service Management using the following tools:
* Azure Logic Apps
* Azure Functions
* Automation for JIRA
* Microsoft Sentinel Automation Rules
* Azure Key Vault
This tool will do the following:
* Create an incident in JIRA when an incident is created in Sentinel
* Sync the assigned user from JIRA to Sentinel
* Sync the status from JIRA to Sentinel
* Add the URL to the JIRA incident as a comment in Sentinel
* Sync public comments from JIRA to Sentinel
![Overview](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Solution%20overview.png)
[Blog post with more background information](https://www.thecollective.eu/en/insights/setting-up-a-bidirectional-sync-between-sentinel-and-jira)
## Implementation
To implement this solution, a few different steps need to be done:
1. Create necessary Service Principals
2. JIRA Configuration
1. Custom fields
2. Deploy Automation for JIRA rules (used for sync from JIRA to Microsoft Sentinel)
3. Deploy the Key Vault and add secrets
4. Deploy Azure Logic Apps (4) through ARM deployment
5. Deploy Azure Function for comment sychronization and add the Powershell code (check the Functions)
6. Create Sentinel Automation Rule
## 1. Create Service Principal
The tool requires a service principals for authentication to different services:
* Authentication to Microsoft Entra ID to retrieve user ID's (for assigning incidents in Sentinel)
### Microsoft Entra ID Service Principal
This Service Principal needs to have User.Read.All application permissions.
This Service Principal is used in the Logic app 'Sync-AssignedUser.
## 2. JIRA Configuration
### JIRA Custom Fields
#### Introduction
A lot of the Sentinel specific information is stored inside of Custom Fields in JIRA which need to be created.
This document contains an overview of the different custom fields that are used in the Logic Apps.
All Logic Apps need to be updated with the correct ID's of the fields.
#### Custom Fields overview
| **Field Name** | **Field ID** | **Field Type**|
| --- | --- | --- |
| Organizations | customfield_10002 | Built-in |
| Sentinel Incident URL | customfield_10144 | Url Field |
| Incident ID | customfield_10145 | Text Field (Single line) |
| Closure Comment | customfield_10146 | Text Field (Multiline) |
| Closure Reason | customfield_10047 | Select List (Single choice) |
| Tenant Name | customfield_10149 | Select List (Single Choice) |
| Created At | customfield_10154 | Date Time Picker |
| Att&ck Tactics | customfield_10155 | Select List (Multiple choices) |
| Affected User | customfield_10158 | Text Field (Multiline) |
| Subscription ID | customfield_10162 | Text Field (Singline) |
| Sentinel Resource Group | customfield_10169 | Text Field (Singline) |
| Sentinel Workspace Name | customfield_10170 | Text Field (Singline) |
| Sentinel Workspace ID | customfield_10172 | Text Field (Singline) |
| Sentinel Incident ID | customfield_10173 | Text Field (Singline) |
| Sentinel Incident ARM ID | customfield_10175 | Text Field (Singline) |
The Att&ck Tactics list contains all Sentinel Tactics.
The Closure Reason contains all valid Sentinel Closure Reasons
### JIRA Automation Rules
In order to synchronize changes from JIRA to Sentinel, Automation for JIRA is used to trigger Logic Apps when certain conditions are met.
Automation for JIRA is an integrated plugin that is free to use for JIRA Service Management.
This document will describe the different automation rules that are necessary to trigger the correct Logic Apps/Functions.
In almost every rule, the step 're-fetch issue data' is used. This will make sure we are using the most up to date information in our Logic Apps.
If you are not using this, you might encouter failures.
Navigate to the project settings, then go to Automation to create rules.
#### Sync Status
This automation rule has a trigger 'Issue Transitioned' and will trigger the Logic App 'Sync-Status'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Status.png)
#### Sync Assigned User
This automation rule has a trigger 'Issue Assigned' and will trigger the Logic App 'Sync-AssignedUser'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Assigned%20User.png)
#### Create Link
This automation rule has a trigger 'Issue created' and will trigger the Logic App 'Add-JIRALinkComment'.
Provide the POST URL of the Logic App in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Create%20Link.png)
#### Sync comment
This automation rule will trigger the function app to sync public comments to Microsoft Sentinel.
Provide the POST URL of the Sync Comment Function in the 'Send Web Request' Step. As webhook data, specify 'issue data'.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/JIRA%20-%20Automation%20-%20Sync%20Comment.png)
## 3. Deploy Key Vault
The Key Vault is used to store three secrets:
* One for the Microsoft Entra ID Service Principal
* One for the Microsoft Sentinel Service Principal
* One for the JIRA Secret
Create a new Key Vault or deploy an existing one and add the different secrets to it.
The names will need to be provided when deploying the ARM Templates from the Logic Apps.
Edit the Access Policy and assign 'Secret - Get' permissions to the Key Vault Service Principal.
## 4. Deploy Logic Apps
The solution consists of four different Logic Apps:
* Sync Incidents from Sentinel to JIRA (Sync-Incidents.json)
* Sync status from JIRA to Sentinel (Sync-Status.json)
* Sync assigned user from JIRA to Sentinel (Sync-AssignedUser.json)
* Add a link to the JIRA incident to the Sentinel incident (Add-JiraLinkComment.json)
This will enable a two way synchronization between JIRA and Sentinel. Not all Logic Apps are mandatory, you can deploy the ones your organization needs.
Each Logic App can be deployed using the provided ARM templates.
After deploying the Logic Apps, you can copy the HTTP trigger URLs and paste them in the JIRA Automation Rules.
### Custom Fields Configuration
A lot of JIRA Custom fields are used within these Logic Apps. It's important to create these custom fields in your own JIRA environment and change the correct ID's in the Logic Apps.
For more information about the different custom fields used, please check the JIRA Configuration.
### Sync Incidents from Sentinel to JIRA
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Incidents%2Fazuredeploy.json)
This Logic App will create a new incident in JIRA when an incident in Sentinel is created.
It uses the 'Incident Trigger' from Sentinel and is triggered by an Automation Rule (see Sentinel Configuration).
This Logic App does the following:
* Retrieve all the incident information
* Retrieve the Tactics in this incident
* Retrieve the details from the Account Entity
* Check which customer this incident is coming from (to add the right organization in JIRA)
* Create JIRA ticket through an API call
It uses two connections:
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the JIRA API Key (Managed Identity)
In order to correlate the right add the incident in JIRA to the correct Organization, we use a switch and determine the correct organization based on the originate Subscription ID.
Add a case per customer and add the right Subscription ID, Customer name and Organization ID.
If you do not use organizations in JIRA, you can remove the switch.
![Switch](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Playbooks/Sync-IncidentsWithJIRA/Images/Azure%20-%20Switch%20Organization.png)
### Sync status from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-Status%2Fazuredeploy.json)
This Logic App will change the status in Sentinel when the status has been changed in JIRA.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It's important you use the same closure reason in JIRA as the ones in Sentinel, otherwise the sync will fail.
It uses one connections:
* One connection to Sentinel through a Managed Identity.
### Sync assigned user from JIRA to Sentinel
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-AssignedUser%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-AssignedUser%2Fazuredeploy.json)
When a incident is assigned in JIRA, this will assign the correct user inside of Microsoft Sentinel.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule when the assigned user of an incident is changed.
It will retrieve the client secret for the service principal with permissions to retrieve users in your Microsoft Entra ID. With this, it will query the user and retrieve the Microsoft Entra ID Object ID from that user. Wit this information, we will update the incident in Microsoft Sentinel.
There is a check built-in to make sure that JIRA provides the assigned user. Sometimes it does not and then we don't need to update the incident in Sentinel.
* One connection to Sentinel through a Managed Identity
* One connection to a Key Vault to retrieve the Secret for the Service Principal with Microsoft Entra ID permissions (also configured when deploying the Logic App)
### Add a link to the JIRA incident to the Sentinel incident
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FSync-IncidentsWithJIRA%2FAdd-JiraLinkComment%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure%2FAzure-Sentinel%2Fmaster%2FPlaybooks%2FSync-IncidentsWithJIRA%2FAdd-JiraLinkCommnet%2Fazuredeploy.json)
This Logic App will add a URL to the JIRA incident as a comment to the Sentinel Incident.
It uses an HTTP trigger which is triggered from a JIRA Automation Rule.
It will add the link to the JIRA Customer Portal, which enables a customer to view the details of an incident inside JIRA.
It uses one connections:
* One connection to Sentinel through a Managed Identity
## 5. Deploy Azure Function
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-CommentsFunctionApp%2Fazuredeploy.json)
[![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FAzure-Sentinel%2Fmaster%2FSolutions%2FAtlassianJiraAudit%2FPlaybooks%2FSync-CommentsFunctionApp%2Fazuredeploy.json)
To sync incident comments from JIRA to Microsoft Sentinel an Azure Function is used. This Function App contains one Powershell Function.
There are two types of comments in JIRA: internal and public comments. This script will only sync the public comments, so that customers don't have access to the internal ones.
The code for this function can be found [in this repository](Sync-Comments/Sync-Comment.ps1).
This Function uses a managed identity to authenticate to the Key Vault.
Either deployment the Function App through the ARM template linked above or deploy a Function app manually and paste the ps1 code
After deployment, configure the parameters in the Powershell file.
* jiraUser => Used for authentication to JIRA
* jiraSecretURL => The URL to the JIRA Secret in our Key Vault
* sentinelSecretURL => The URL to the Sentinel Secret in our Key Vault
* tenantID => Tenant ID for the Sentinel Service Principals
* clientID => Client ID for the Sentinel Service Principal
Enable the Managed Identity (Identity => System Assigned).
Provide 'Secret - Get' permissions to the Function app in the Access Policies of the Key Vault.
## 6. Sentinel Automation Rule
In order to trigger the Logic App that creates incidents in JIRA, we use an Automation Rule in Sentinel.
This will enable us to trigger a Logic App (Playbook) each time an incident is created.
Navigate to your Sentinel workspace and choose 'Automation', after this click 'Create Rule'.
Provide a name for the rule and for conditions choose 'Analytics Rule Name contains All'. This will trigger out Logic app each time an incident is created.
If you only want to sync certain incidents, choose the right condition.
For actions, choose 'Run Playbook' and select the 'Sync-Incidents' Playbook.
![Automation Rule](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/AtlassianJiraAudit/Playbooks/Images/Sentinel%20-%20Automation%20Rule.png)
## Conclusion
After this solution, you are able to work on Microsoft Sentinel incidents while staying in your trusted ITSM tool.
This tool should take care of any previous synchronization issues between the JIRA and Sentinel.
For any issues with the tool or requested improvements, feel free to create an issue on Github or contact me through [Twitter](https://twitter.com/thijslecomte).

Просмотреть файл

@ -1,15 +1,15 @@
{
"publisherId": "azuresentinel",
"offerId": "azure-sentinel-solution-atlassianjiraaudit",
"firstPublishDate": "2022-01-10",
"providers": ["Atlassian"],
"categories": {
"domains" : ["DevOps", "Security - Automation (SOAR)"]
},
"support": {
"name": "Microsoft Corporation",
"email": "support@microsoft.com",
"tier": "Microsoft",
"link": "https://support.microsoft.com"
}
{
"publisherId": "azuresentinel",
"offerId": "azure-sentinel-solution-atlassianjiraaudit",
"firstPublishDate": "2022-01-10",
"providers": ["Atlassian"],
"categories": {
"domains" : ["DevOps", "Security - Automation (SOAR)"]
},
"support": {
"name": "Microsoft Corporation",
"email": "support@microsoft.com",
"tier": "Microsoft",
"link": "https://support.microsoft.com"
}
}

Просмотреть файл

@ -1,419 +1,419 @@
{
"version": "Notebook/1.0",
"items": [
{
"type": 1,
"content": {
"json": "**NOTE**: This data connector depends on a parser based on Kusto Function **JiraAudit** to work as expected. [Follow steps to get this Kusto Function](https://aka.ms/sentinel-jiraauditapi-parser)"
},
"name": "text - 8"
},
{
"type": 9,
"content": {
"version": "KqlParameterItem/1.0",
"parameters": [
{
"id": "cd8447d9-b096-4673-92d8-2a1e8291a125",
"version": "KqlParameterItem/1.0",
"name": "TimeRange",
"type": 4,
"description": "Sets the time name for analysis",
"value": {
"durationMs": 2592000000
},
"typeSettings": {
"selectableValues": [
{
"durationMs": 900000
},
{
"durationMs": 3600000
},
{
"durationMs": 86400000
},
{
"durationMs": 604800000
},
{
"durationMs": 2592000000
},
{
"durationMs": 7776000000
}
]
},
"timeContext": {
"durationMs": 86400000
}
}
],
"style": "pills",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces"
},
"name": "parameters - 11"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| make-series TotalEvents = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain};",
"size": 0,
"title": "Events Over Time",
"timeContext": {
"durationMs": 7776000000
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "timechart",
"graphSettings": {
"type": 0
}
},
"customWidth": "55",
"name": "query - 12",
"styleSettings": {
"maxWidth": "55"
}
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where isnotempty(EventCategoryType) \r\n| summarize count() by EventCategoryType\r\n| join kind = inner (JiraAudit \r\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by EventCategoryType) on EventCategoryType\r\n| project-away EventCategoryType1, TimeGenerated\r\n| project count_, EventCategory = case(EventCategoryType =~ 'user management', 'User Management',\r\n EventCategoryType =~ 'projects', 'Projects Management',\r\n EventCategoryType =~ 'group management', 'Group Management',\r\n EventCategoryType =~ 'workflows', 'Workflow Management',\r\n EventCategoryType =~ 'permissions', 'Permissions Management',\r\n EventCategoryType =~ 'status', 'Task Status',\r\n 'Other'), Trend\r\n",
"size": 3,
"title": "Event Categories",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "tiles",
"tileSettings": {
"titleContent": {
"columnMatch": "EventCategory",
"formatter": 1
},
"leftContent": {
"columnMatch": "count_",
"formatter": 12,
"formatOptions": {
"palette": "auto"
},
"numberFormat": {
"unit": 17,
"options": {
"style": "decimal",
"maximumFractionDigits": 2,
"maximumSignificantDigits": 3
}
}
},
"secondaryContent": {
"columnMatch": "Trend",
"formatter": 21,
"formatOptions": {
"palette": "blue"
}
},
"showBorder": false
}
},
"customWidth": "30",
"name": "query - 0",
"styleSettings": {
"maxWidth": "30"
}
},
{
"type": 12,
"content": {
"version": "NotebookGroup/1.0",
"groupType": "editable",
"items": [
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where EventCategoryType =~ 'projects'\r\n| where ObjectItemTypeName =~ 'PROJECT'\r\n| summarize dcount(ObjectItemName)",
"size": 3,
"title": "Projects",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "card",
"tileSettings": {
"showBorder": false
},
"graphSettings": {
"type": 0
},
"mapSettings": {
"locInfo": "LatLong",
"sizeSettings": "DstPortNumber",
"sizeAggregation": "Sum",
"legendMetric": "DstPortNumber",
"legendAggregation": "Sum",
"itemColorSettings": {
"type": "heatmap",
"colorAggregation": "Sum",
"nodeColorField": "DstPortNumber",
"heatmapPalette": "greenRed"
}
},
"textSettings": {
"style": "bignumber"
}
},
"name": "query - 14"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where EventCategoryType =~ 'workflows'\r\n| where ObjectItemTypeName =~ 'WORKFLOW'\r\n| summarize dcount(ObjectItemName)\r\n",
"size": 3,
"title": "Workflows",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "card",
"textSettings": {
"style": "bignumber"
}
},
"name": "query - 12"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\n| where isnotempty(UserName)\n| summarize dcount(UserName)",
"size": 3,
"title": "Users",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "card",
"textSettings": {
"style": "bignumber"
}
},
"name": "query - 2"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\n| count",
"size": 3,
"title": "Operations",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "card",
"textSettings": {
"style": "bignumber"
}
},
"name": "query - 3"
}
]
},
"customWidth": "15",
"name": "group - 13"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where isnotempty(EventMessage) \r\n| summarize count() by EventMessage\r\n",
"size": 3,
"title": "Event types",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "piechart",
"tileSettings": {
"showBorder": false,
"titleContent": {
"columnMatch": "EventMessage",
"formatter": 1
},
"leftContent": {
"columnMatch": "count_",
"formatter": 12,
"formatOptions": {
"palette": "auto"
},
"numberFormat": {
"unit": 17,
"options": {
"maximumSignificantDigits": 3,
"maximumFractionDigits": 2
}
}
}
}
},
"customWidth": "27",
"name": "query - 3",
"styleSettings": {
"margin": "10",
"padding": "10"
}
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": " JiraAudit\r\n | where isnotempty(SrcIpAddr) \r\n | summarize count() by SrcIpAddr\r\n | top 10 by SrcIpAddr",
"size": 3,
"title": "Top sources",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "piechart"
},
"customWidth": "27",
"name": "query - 9"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where isnotempty(UserName) \r\n| summarize count() by UserName, EventMessage\r\n| project User=UserName, Operation=EventMessage, EventCount=count_\r\n",
"size": 0,
"title": "User activity",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "table"
},
"customWidth": "46",
"name": "query - 15",
"styleSettings": {
"maxWidth": "30"
}
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where isnotempty(UserName)\r\n| where isnotempty(SrcIpAddr) \r\n| summarize IPAddresses = makeset(SrcIpAddr) by UserName\r\n",
"size": 0,
"title": "Document types",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "table"
},
"customWidth": "35",
"name": "query - 10",
"styleSettings": {
"maxWidth": "30"
}
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where EventCategoryType =~ 'projects'\r\n| where ObjectItemTypeName =~ 'PROJECT'\r\n| summarize count() by ObjectItemName",
"size": 0,
"title": "Top projects",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "barchart"
},
"customWidth": "55",
"name": "query - 13",
"styleSettings": {
"maxWidth": "50"
}
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where EventCategoryType =~ 'workflows'\r\n| where ObjectItemTypeName =~ 'WORKFLOW'\r\n| summarize count() by ObjectItemName\r\n",
"size": 3,
"title": "Workflows by activity",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "piechart",
"gridSettings": {
"rowLimit": 100,
"filter": true
}
},
"customWidth": "30",
"name": "query - 12"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\n| where isnotempty(UserName) \n| summarize count() by UserName",
"size": 3,
"title": "Users' activity",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "piechart"
},
"customWidth": "30",
"name": "query - 11"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\n| where isnotempty(UserName) \n| summarize count() by UserName\n| order by count_\n| project User=UserName, EventCount=count_",
"size": 0,
"title": "Events by user",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "table"
},
"customWidth": "40",
"name": "query - 12"
}
],
"fromTemplateId": "sentinel-AtlasianJiraAuditWorkbook",
"$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json"
{
"version": "Notebook/1.0",
"items": [
{
"type": 1,
"content": {
"json": "**NOTE**: This data connector depends on a parser based on Kusto Function **JiraAudit** to work as expected. [Follow steps to get this Kusto Function](https://aka.ms/sentinel-jiraauditapi-parser)"
},
"name": "text - 8"
},
{
"type": 9,
"content": {
"version": "KqlParameterItem/1.0",
"parameters": [
{
"id": "cd8447d9-b096-4673-92d8-2a1e8291a125",
"version": "KqlParameterItem/1.0",
"name": "TimeRange",
"type": 4,
"description": "Sets the time name for analysis",
"value": {
"durationMs": 2592000000
},
"typeSettings": {
"selectableValues": [
{
"durationMs": 900000
},
{
"durationMs": 3600000
},
{
"durationMs": 86400000
},
{
"durationMs": 604800000
},
{
"durationMs": 2592000000
},
{
"durationMs": 7776000000
}
]
},
"timeContext": {
"durationMs": 86400000
}
}
],
"style": "pills",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces"
},
"name": "parameters - 11"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| make-series TotalEvents = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain};",
"size": 0,
"title": "Events Over Time",
"timeContext": {
"durationMs": 7776000000
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "timechart",
"graphSettings": {
"type": 0
}
},
"customWidth": "55",
"name": "query - 12",
"styleSettings": {
"maxWidth": "55"
}
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where isnotempty(EventCategoryType) \r\n| summarize count() by EventCategoryType\r\n| join kind = inner (JiraAudit \r\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by EventCategoryType) on EventCategoryType\r\n| project-away EventCategoryType1, TimeGenerated\r\n| project count_, EventCategory = case(EventCategoryType =~ 'user management', 'User Management',\r\n EventCategoryType =~ 'projects', 'Projects Management',\r\n EventCategoryType =~ 'group management', 'Group Management',\r\n EventCategoryType =~ 'workflows', 'Workflow Management',\r\n EventCategoryType =~ 'permissions', 'Permissions Management',\r\n EventCategoryType =~ 'status', 'Task Status',\r\n 'Other'), Trend\r\n",
"size": 3,
"title": "Event Categories",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "tiles",
"tileSettings": {
"titleContent": {
"columnMatch": "EventCategory",
"formatter": 1
},
"leftContent": {
"columnMatch": "count_",
"formatter": 12,
"formatOptions": {
"palette": "auto"
},
"numberFormat": {
"unit": 17,
"options": {
"style": "decimal",
"maximumFractionDigits": 2,
"maximumSignificantDigits": 3
}
}
},
"secondaryContent": {
"columnMatch": "Trend",
"formatter": 21,
"formatOptions": {
"palette": "blue"
}
},
"showBorder": false
}
},
"customWidth": "30",
"name": "query - 0",
"styleSettings": {
"maxWidth": "30"
}
},
{
"type": 12,
"content": {
"version": "NotebookGroup/1.0",
"groupType": "editable",
"items": [
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where EventCategoryType =~ 'projects'\r\n| where ObjectItemTypeName =~ 'PROJECT'\r\n| summarize dcount(ObjectItemName)",
"size": 3,
"title": "Projects",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "card",
"tileSettings": {
"showBorder": false
},
"graphSettings": {
"type": 0
},
"mapSettings": {
"locInfo": "LatLong",
"sizeSettings": "DstPortNumber",
"sizeAggregation": "Sum",
"legendMetric": "DstPortNumber",
"legendAggregation": "Sum",
"itemColorSettings": {
"type": "heatmap",
"colorAggregation": "Sum",
"nodeColorField": "DstPortNumber",
"heatmapPalette": "greenRed"
}
},
"textSettings": {
"style": "bignumber"
}
},
"name": "query - 14"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where EventCategoryType =~ 'workflows'\r\n| where ObjectItemTypeName =~ 'WORKFLOW'\r\n| summarize dcount(ObjectItemName)\r\n",
"size": 3,
"title": "Workflows",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "card",
"textSettings": {
"style": "bignumber"
}
},
"name": "query - 12"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\n| where isnotempty(UserName)\n| summarize dcount(UserName)",
"size": 3,
"title": "Users",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "card",
"textSettings": {
"style": "bignumber"
}
},
"name": "query - 2"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\n| count",
"size": 3,
"title": "Operations",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "card",
"textSettings": {
"style": "bignumber"
}
},
"name": "query - 3"
}
]
},
"customWidth": "15",
"name": "group - 13"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where isnotempty(EventMessage) \r\n| summarize count() by EventMessage\r\n",
"size": 3,
"title": "Event types",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "piechart",
"tileSettings": {
"showBorder": false,
"titleContent": {
"columnMatch": "EventMessage",
"formatter": 1
},
"leftContent": {
"columnMatch": "count_",
"formatter": 12,
"formatOptions": {
"palette": "auto"
},
"numberFormat": {
"unit": 17,
"options": {
"maximumSignificantDigits": 3,
"maximumFractionDigits": 2
}
}
}
}
},
"customWidth": "27",
"name": "query - 3",
"styleSettings": {
"margin": "10",
"padding": "10"
}
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": " JiraAudit\r\n | where isnotempty(SrcIpAddr) \r\n | summarize count() by SrcIpAddr\r\n | top 10 by SrcIpAddr",
"size": 3,
"title": "Top sources",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "piechart"
},
"customWidth": "27",
"name": "query - 9"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where isnotempty(UserName) \r\n| summarize count() by UserName, EventMessage\r\n| project User=UserName, Operation=EventMessage, EventCount=count_\r\n",
"size": 0,
"title": "User activity",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "table"
},
"customWidth": "46",
"name": "query - 15",
"styleSettings": {
"maxWidth": "30"
}
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where isnotempty(UserName)\r\n| where isnotempty(SrcIpAddr) \r\n| summarize IPAddresses = makeset(SrcIpAddr) by UserName\r\n",
"size": 0,
"title": "Document types",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "table"
},
"customWidth": "35",
"name": "query - 10",
"styleSettings": {
"maxWidth": "30"
}
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where EventCategoryType =~ 'projects'\r\n| where ObjectItemTypeName =~ 'PROJECT'\r\n| summarize count() by ObjectItemName",
"size": 0,
"title": "Top projects",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "barchart"
},
"customWidth": "55",
"name": "query - 13",
"styleSettings": {
"maxWidth": "50"
}
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\r\n| where EventCategoryType =~ 'workflows'\r\n| where ObjectItemTypeName =~ 'WORKFLOW'\r\n| summarize count() by ObjectItemName\r\n",
"size": 3,
"title": "Workflows by activity",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "piechart",
"gridSettings": {
"rowLimit": 100,
"filter": true
}
},
"customWidth": "30",
"name": "query - 12"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\n| where isnotempty(UserName) \n| summarize count() by UserName",
"size": 3,
"title": "Users' activity",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "piechart"
},
"customWidth": "30",
"name": "query - 11"
},
{
"type": 3,
"content": {
"version": "KqlItem/1.0",
"query": "JiraAudit\n| where isnotempty(UserName) \n| summarize count() by UserName\n| order by count_\n| project User=UserName, EventCount=count_",
"size": 0,
"title": "Events by user",
"timeContext": {
"durationMs": 0
},
"timeContextFromParameter": "TimeRange",
"queryType": 0,
"resourceType": "microsoft.operationalinsights/workspaces",
"visualization": "table"
},
"customWidth": "40",
"name": "query - 12"
}
],
"fromTemplateId": "sentinel-AtlasianJiraAuditWorkbook",
"$schema": "https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json"
}

Двоичный файл не отображается.

Просмотреть файл

@ -20,7 +20,9 @@ FILE_SHARE_CONNECTION_STRING = os.environ['AzureWebJobsStorage']
LOG_TYPE = 'Auth0AM'
MAX_SCRIPT_EXEC_TIME_MINUTES = 5
logging.getLogger('azure.core.pipeline.policies.http_logging_policy').setLevel(logging.ERROR)
FIELD_SIZE_LIMIT_BYTES = 1000 * 32
logging.getLogger(
'azure.core.pipeline.policies.http_logging_policy').setLevel(logging.ERROR)
LOG_ANALYTICS_URI = os.environ.get('logAnalyticsUri')
@ -39,27 +41,32 @@ CLIENT_ID = os.environ['CLIENT_ID']
CLIENT_SECRET = os.environ['CLIENT_SECRET']
AUDIENCE = DOMAIN + '/api/v2/'
retry = 3
error=False
error = False
def main(mytimer: func.TimerRequest):
logging.info('Script started.')
script_start_time = int(time.time())
state_manager = StateManager(FILE_SHARE_CONNECTION_STRING, file_path='auth0_confing.json')
state_manager = StateManager(
FILE_SHARE_CONNECTION_STRING, file_path='auth0_confing.json')
config_string = state_manager.get()
if config_string:
config = json.loads(config_string)
else:
config = json.loads('{"last_log_id": "","last_date": ""}')
logging.info(f'Config loaded\n\t{config}')
connector = Auth0Connector(DOMAIN, API_PATH, CLIENT_ID, CLIENT_SECRET, AUDIENCE)
connector = Auth0Connector(
DOMAIN, API_PATH, CLIENT_ID, CLIENT_SECRET, AUDIENCE)
connector.get_log_events(script_start_time, config)
logging.info(f'Finish script.')
class Auth0Connector:
def __init__(self, domain, api_path, client_id, client_secret, audience):
self.state_manager = StateManager(FILE_SHARE_CONNECTION_STRING, file_path='auth0_confing.json')
self.sentinel = AzureSentinelConnector(LOG_ANALYTICS_URI, WORKSPACE_ID, SHARED_KEY, LOG_TYPE, queue_size=1000)
self.state_manager = StateManager(
FILE_SHARE_CONNECTION_STRING, file_path='auth0_confing.json')
self.sentinel = AzureSentinelConnector(
LOG_ANALYTICS_URI, WORKSPACE_ID, SHARED_KEY, LOG_TYPE, queue_size=1000)
self.domain = domain
self.api_path = api_path
self.client_id = client_id
@ -68,98 +75,122 @@ class Auth0Connector:
self.uri = self.domain + self.api_path
self.token = None
self.header = None
self.retry = retry
self.retry = retry
"""This method is used to process and post the results to Log Analytics Workspace
Returns:
last_log_id : last processed eventId
events: last processed Events
"""
def get_log_events(self, script_start_time, config: dict) -> Tuple[str, List]:
self.token = self._get_token()
logging.info(f'Token provided.')
self.header = self._get_header()
last_log_id = self._get_last_log_id(config)
#last_log_id = "90020230126121002244690048186607762971591195832157732866"
# last_log_id = "90020230126121002244690048186607762971591195832157732866"
logging.info(f'\tLast log id extracted: {last_log_id}.')
if last_log_id is None:
#return '', []
# return '', []
self.update_statemarker_file(config, '', [])
return
# first request
params = {'from': last_log_id, 'take': '100'}
count = 0
error=True
error = True
while error:
try:
error=False
resp = requests.get(self.uri, headers=self.header, params=params)
error = False
resp = requests.get(
self.uri, headers=self.header, params=params)
if not resp.json():
self.update_statemarker_file(config, last_log_id, [])
return
events = resp.json()
if 'statusCode' in events:
raise Exception(events['error'])
except Exception as err:
error = True
count+=1
logging.error("Something wrong. Exception error text: {}".format(err))
count += 1
if (err == 'Too Many Requests'):
time.sleep(1)
logging.error(
"Something wrong. Exception error text: {}".format(err))
if count > self.retry:
logging.error("Exceeded maximum Retries")
break
logging.info('\tFirst request executed.')
if not resp.json():
#return last_log_id, []
# return last_log_id, []
self.update_statemarker_file(config, last_log_id, [])
return
events = resp.json()
logging.info('\t response object : {events}')
logging.info(f'Response Object : {events}')
events.sort(key=lambda item: item['date'], reverse=True)
last_log_id = events[0]['log_id']
for el in events:
self.customize_event(el)
self.sentinel.send(el)
self.sentinel.flush()
logging.info('Events sent to Sentinel.')
self.update_statemarker_file(config, last_log_id , events)
self.update_statemarker_file(config, last_log_id, events)
if "Link" in resp.headers :
if "Link" in resp.headers:
next_link = resp.headers['Link']
next_uri = next_link[next_link.index('<') + 1:next_link.index('>')]
page_num = 1
while resp.json() and len(events)!=0:
while resp.json() and len(events) != 0:
count = 0
error=True
error = True
while error:
try:
error=False
error = False
resp = requests.get(next_uri, headers=self.header)
events = resp.json()
if 'statusCode' in events:
raise Exception(events['error'])
except Exception as err:
error = True
count+=1
logging.error("Something wrong. Exception error text: {}".format(err))
count += 1
if (err == 'Too Many Requests'):
time.sleep(1)
logging.error(
"Something wrong. Exception error text: {}".format(err))
if count > self.retry:
logging.error("Exceeded maximum Retries")
break
#logging.info(f'\t Response message {resp.headers}')
# logging.info(f'\t Response message {resp.headers}')
try:
next_link = resp.headers['Link']
next_uri = next_link[next_link.index('<') + 1:next_link.index('>')]
next_uri = next_link[next_link.index(
'<') + 1:next_link.index('>')]
events = resp.json()
logging.info(f'\t#{page_num} extracted')
page_num += 1
if page_num % 9 == 0:
time.sleep(1)
if len(events)!=0:
events.sort(key=lambda item: item['date'], reverse=True)
if len(events) != 0:
events.sort(
key=lambda item: item['date'], reverse=True)
last_log_id = events[0]['log_id']
for el in events:
self.customize_event(el)
self.sentinel.send(el)
self.sentinel.flush()
self.update_statemarker_file(config, last_log_id , events)
self.update_statemarker_file(
config, last_log_id, events)
if self.check_if_script_runs_too_long(script_start_time):
logging.info(f'Script is running too long. Stop processing new events. Finish script.')
logging.info(
f'Script is running too long. Stop processing new events. Finish script.')
break
except Exception as err:
logging.error("Something wrong. Exception error text: {}".format(err))
break
#logging.info(f'\t New last log id: {last_log_id}\n at date {events[0]["date"]}. Events extracted.')
logging.error(
"Something wrong. Exception error text: {}".format(err))
break
# logging.info(f'\t New last log id: {last_log_id}\n at date {events[0]["date"]}. Events extracted.')
return last_log_id, events
def _get_last_log_id(self, config: dict) -> Union[str, None]:
@ -178,40 +209,171 @@ class Auth0Connector:
def _get_token(self):
params = {
'grant_type': 'client_credentials',
'client_id': self.client_id,
'client_secret': self.client_secret,
'audience': self.audience
}
'grant_type': 'client_credentials',
'client_id': self.client_id,
'client_secret': self.client_secret,
'audience': self.audience
}
header = {'content-type': "application/x-www-form-urlencoded"}
count = 0
error=True
error = True
while error:
try:
error=False
resp = requests.post(self.domain + '/oauth/token', headers=header, data=params)
error = False
resp = requests.post(
self.domain + '/oauth/token', headers=header, data=params)
try:
token = resp.json()['access_token']
except KeyError:
raise Exception('Token not provided.')
except Exception as err:
error = True
count+=1
count += 1
if count > self.retry:
break
return token
def _get_header(self):
return {'Authorization': 'Bearer ' + self.token}
def check_if_script_runs_too_long(self, script_start_time: int) -> bool:
now = int(time.time())
duration = now - script_start_time
max_duration = int(MAX_SCRIPT_EXEC_TIME_MINUTES * 60 * 0.80)
return duration > max_duration
"""This method is used to limit the column count
Returns:
events: Updated Events
"""
def customize_event(self, el):
if "details" in el:
if "body" in el["details"]:
myjson = str(el["details"]["body"])
if (myjson.startswith("{")):
if "app" in el["details"]["body"]:
if "metadata" in el["details"]["body"]["app"]:
el["details"]["body"]["app"]["metadata"] = json.dumps(
el["details"]["body"]["app"]["metadata"])
if "transaction" in el["details"]["body"]:
el["details"]["body"]["transaction"] = json.dumps(
el["details"]["body"]["transaction"])
if "user" in el["details"]["body"]:
if "metadata" in el["details"]["body"]["user"]:
el["details"]["body"]["user"]["metadata"] = json.dumps(
el["details"]["body"]["user"]["metadata"])
if "request" in el["details"]:
if "auth" in el["details"]["request"]:
el["details"]["request"]["auth"] = json.dumps(
el["details"]["request"]["auth"])
if "body" in el["details"]["request"]:
myjson = str(el["details"]["request"]["body"])
if (myjson.startswith("{")):
if "app" in el["details"]["request"]["body"]:
if "metadata" in el["details"]["request"]["body"]["app"]:
el["details"]["request"]["body"]["app"]["metadata"] = json.dumps(
el["details"]["request"]["body"]["app"]["metadata"])
if "client" in el["details"]["request"]["body"]:
el["details"]["request"]["body"]["client"] = json.dumps(
el["details"]["request"]["body"]["client"])
if "refresh" in el["details"]["request"]["body"]:
if "token" in el["details"]["request"]["body"]["refresh"]:
el["details"]["request"]["body"]["refresh"]["token"] = json.dumps(
el["details"]["request"]["body"]["refresh"]["token"])
if "template" in el["details"]["request"]["body"]:
el["details"]["request"]["body"]["template"] = json.dumps(
el["details"]["request"]["body"]["template"])
details_request_body_template = el["details"]["request"]["body"]["template"]
if (len(json.dumps(details_request_body_template).encode()) > FIELD_SIZE_LIMIT_BYTES):
queue_list = self._split_big_request(
details_request_body_template)
count = 1
for q in queue_list:
columnname = 'templatePart' + str(count)
el['details']['request']['body'][columnname] = q
count += 1
if 'templatePart2' in el['details']['request']['body']:
del el["details"]["request"]["body"]["template"]
if "user" in el["details"]["request"]["body"]:
if "metadata" in el["details"]["request"]["body"]["user"]:
el["details"]["request"]["body"]["user"]["metadata"] = json.dumps(
el["details"]["request"]["body"]["user"]["metadata"])
if "response" in el["details"]:
if "body" in el["details"]["response"]:
myjson = str(el["details"]["response"]["body"])
if (myjson.startswith("{")):
if "app" in el["details"]["response"]["body"]:
if "metadata" in el["details"]["response"]["body"]["app"]:
el["details"]["response"]["body"]["app"]["metadata"] = json.dumps(
el["details"]["response"]["body"]["app"]["metadata"])
if "flags" in el["details"]["response"]["body"]:
el["details"]["response"]["body"]["flags"] = json.dumps(
el["details"]["response"]["body"]["flags"])
if "refresh" in el["details"]["response"]["body"]:
if "token" in el["details"]["response"]["body"]["refresh"]:
el["details"]["response"]["body"]["refresh"]["token"] = json.dumps(
el["details"]["response"]["body"]["refresh"]["token"])
if "universal" in el["details"]["response"]["body"]:
if "login" in el["details"]["response"]["body"]["universal"]:
el["details"]["response"]["body"]["universal"]["login"] = json.dumps(
el["details"]["response"]["body"]["universal"]["login"])
if "user" in el["details"]["response"]["body"]:
if "metadata" in el["details"]["response"]["body"]["user"]:
el["details"]["response"]["body"]["user"]["metadata"] = json.dumps(
el["details"]["response"]["body"]["user"]["metadata"])
if "bindings" in el['details']['response']['body']:
el['details']['response']['body']['bindings'] = json.dumps(
el['details']['response']['body']['bindings'])
details_response_body_bindings = el['details']['response']['body']['bindings']
if (len(json.dumps(details_response_body_bindings).encode()) > FIELD_SIZE_LIMIT_BYTES):
queue_list = self._split_big_request(
details_response_body_bindings)
count = 1
for q in queue_list:
columnname = 'bindingsPart' + str(count)
el['details']['response']['body'][columnname] = q
count += 1
if 'bindingsPart2' in el['details']['response']['body']:
del el['details']['response']['body']['bindings']
return el
def _check_size(self, queue):
data_bytes_len = len(json.dumps(queue).encode())
return data_bytes_len < FIELD_SIZE_LIMIT_BYTES
def _split_big_request(self, queue):
if self._check_size(queue):
return [queue]
else:
middle = int(len(queue) / 2)
queues_list = [queue[:middle], queue[middle:]]
return self._split_big_request(queues_list[0]) + self._split_big_request(queues_list[1])
def clear_event(self, el):
if 'details' in el and 'response' in el['details'] and 'body' in el['details']['response'] and 'bindingsPart2' in el['details']['response']['body']:
del el['details']['response']['body']['bindings']
if 'details' in el and 'request' in el['details'] and 'body' in el['details']['request'] and 'templatePart2' in el['details']['request']['body']:
del el["details"]["request"]["body"]["template"]
return el
"""This method is used to update the statemareker file with lastprocessed event details
"""
def update_statemarker_file(self, config, last_log_id, events):
config['last_log_id'] = last_log_id
try:
@ -220,6 +382,3 @@ class Auth0Connector:
logging.info('Known Indexing Scenario. Proceed with execution')
logging.info("new config" + str(config))
self.state_manager.post(json.dumps(config))

Просмотреть файл

@ -15,7 +15,7 @@ query: |
let opValues = dynamic(["Microsoft.SecurityInsights/alertRules/write", "Microsoft.SecurityInsights/alertRules/delete"]);
// Microsoft Sentinel Analytics - Rule Create / Update / Delete
AzureActivity
| where Category =~ "Administrative"
| where CategoryValue =~ "Administrative"
| where OperationNameValue in~ (opValues)
| where ActivitySubstatusValue in~ ("Created", "OK")
| sort by TimeGenerated desc
@ -34,4 +34,4 @@ entityMappings:
fieldMappings:
- identifier: Address
columnName: CallerIpAddress
version: 2.0.1
version: 2.0.2

Просмотреть файл

@ -31,7 +31,7 @@
"Data Connectors/BitSightDataConnector/BitSight_API_FunctionApp.json"
],
"BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\BitSight",
"Version": "3.0.1",
"Version": "3.0.2",
"Metadata": "SolutionMetadata.json",
"TemplateSpec": true,
"Is1PConnector": false

Двоичные данные
Solutions/BitSight/Package/3.0.1.zip

Двоичный файл не отображается.

Двоичные данные
Solutions/BitSight/Package/3.0.2.zip Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -41,8 +41,8 @@
"email": "ariela.silberstein@bitsighttech.com",
"_email": "[variables('email')]",
"_solutionName": "BitSight",
"_solutionVersion": "3.0.1",
"solutionId": "bitsight_technologies_inc.bitsight_sentinel",
"_solutionVersion": "3.0.2",
"solutionId": "bitsighttechnologiesinc1695119434818.bitsight_v1",
"_solutionId": "[variables('solutionId')]",
"workbookVersion1": "1.0.0",
"workbookContentId1": "BitSightWorkbook",
@ -3172,7 +3172,7 @@
"apiVersion": "2023-04-01-preview",
"location": "[parameters('workspace-location')]",
"properties": {
"version": "3.0.1",
"version": "3.0.2",
"kind": "Solution",
"contentSchemaVersion": "3.0.0",
"displayName": "BitSight",

Просмотреть файл

@ -1,6 +1,6 @@
{
"publisherId": "bitsight_technologies_inc",
"offerId": "bitsight_sentinel",
"publisherId": "bitsighttechnologiesinc1695119434818",
"offerId": "bitsight_v1",
"firstPublishDate": "2023-02-20",
"lastPublishDate": "2024-02-20",
"providers": [

Просмотреть файл

@ -25,7 +25,7 @@
{
"type": "IsConnectedQuery",
"value": [
"\nCommonSecurityLog \n| where DeviceVendor =~ \"Cisco\"\n| where DeviceProduct == \"ASA\"\n\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)"
"\nCommonSecurityLog \n| where DeviceVendor =~ \"Cisco\"\n| where DeviceProduct == \"ASA\"\n\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(3d)"
]
}
],
@ -37,7 +37,7 @@
],
"availability": {
"status": 2,
"isPreview": false,
"isPreview": false,
"featureFlag": {
"feature": "CiscoASAConnector",
"featureStates": {
@ -144,4 +144,4 @@
"tier": "developer"
}
}
}
}

Двоичные данные
Solutions/CiscoASA/Package/3.0.4.zip Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -41,7 +41,7 @@
"email": "support@microsoft.com",
"_email": "[variables('email')]",
"_solutionName": "CiscoASA",
"_solutionVersion": "3.0.3",
"_solutionVersion": "3.0.4",
"solutionId": "azuresentinel.azure-sentinel-solution-ciscoasa",
"_solutionId": "[variables('solutionId')]",
"workbookVersion1": "1.1.0",
@ -103,18 +103,18 @@
"playbookTemplateSpecName4": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId4'))))]",
"_playbookcontentProductId4": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId4'),'-', variables('playbookVersion4'))))]",
"analyticRuleObject1": {
"analyticRuleVersion1": "1.0.1",
"analyticRuleVersion1": "1.0.2",
"_analyticRulecontentId1": "795edf2d-cf3e-45b5-8452-fe6c9e6a582e",
"analyticRuleId1": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '795edf2d-cf3e-45b5-8452-fe6c9e6a582e')]",
"analyticRuleTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('795edf2d-cf3e-45b5-8452-fe6c9e6a582e')))]",
"_analyticRulecontentProductId1": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','795edf2d-cf3e-45b5-8452-fe6c9e6a582e','-', '1.0.1')))]"
"_analyticRulecontentProductId1": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','795edf2d-cf3e-45b5-8452-fe6c9e6a582e','-', '1.0.2')))]"
},
"analyticRuleObject2": {
"analyticRuleVersion2": "1.0.1",
"analyticRuleVersion2": "1.0.2",
"_analyticRulecontentId2": "79f29feb-6a9d-4cdf-baaa-2daf480a5da1",
"analyticRuleId2": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', '79f29feb-6a9d-4cdf-baaa-2daf480a5da1')]",
"analyticRuleTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring('79f29feb-6a9d-4cdf-baaa-2daf480a5da1')))]",
"_analyticRulecontentProductId2": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','79f29feb-6a9d-4cdf-baaa-2daf480a5da1','-', '1.0.1')))]"
"_analyticRulecontentProductId2": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-','79f29feb-6a9d-4cdf-baaa-2daf480a5da1','-', '1.0.2')))]"
},
"_solutioncontentProductId": "[concat(take(variables('_solutionId'),50),'-','sl','-', uniqueString(concat(variables('_solutionId'),'-','Solution','-',variables('_solutionId'),'-', variables('_solutionVersion'))))]"
},
@ -128,7 +128,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "Cisco Workbook with template version 3.0.3",
"description": "Cisco Workbook with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('workbookVersion1')]",
@ -216,7 +216,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "CiscoASA data connector with template version 3.0.3",
"description": "CiscoASA data connector with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('dataConnectorVersion1')]",
@ -257,7 +257,7 @@
{
"type": "IsConnectedQuery",
"value": [
"\nCommonSecurityLog \n| where DeviceVendor =~ \"Cisco\"\n| where DeviceProduct == \"ASA\"\n\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)"
"\nCommonSecurityLog \n| where DeviceVendor =~ \"Cisco\"\n| where DeviceProduct == \"ASA\"\n\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(3d)"
]
}
],
@ -478,7 +478,7 @@
{
"type": "IsConnectedQuery",
"value": [
"\nCommonSecurityLog \n| where DeviceVendor =~ \"Cisco\"\n| where DeviceProduct == \"ASA\"\n\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)"
"\nCommonSecurityLog \n| where DeviceVendor =~ \"Cisco\"\n| where DeviceProduct == \"ASA\"\n\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(3d)"
]
}
],
@ -598,7 +598,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "CiscoASA data connector with template version 3.0.3",
"description": "CiscoASA data connector with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('dataConnectorVersion2')]",
@ -903,7 +903,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "CiscoASAConnector Playbook with template version 3.0.3",
"description": "CiscoASAConnector Playbook with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('playbookVersion1')]",
@ -3062,7 +3062,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "CiscoASA-AddIPtoNetworkObjectGroup Playbook with template version 3.0.3",
"description": "CiscoASA-AddIPtoNetworkObjectGroup Playbook with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('playbookVersion2')]",
@ -3829,7 +3829,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "CiscoASA-CreateACEInACL Playbook with template version 3.0.3",
"description": "CiscoASA-CreateACEInACL Playbook with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('playbookVersion3')]",
@ -4610,7 +4610,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "CiscoASA-CreateInboundAccessRuleOnInterface Playbook with template version 3.0.3",
"description": "CiscoASA-CreateInboundAccessRuleOnInterface Playbook with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('playbookVersion4')]",
@ -5391,7 +5391,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "CiscoASA-ThreatDetectionMessage_AnalyticalRules Analytics Rule with template version 3.0.3",
"description": "CiscoASA-ThreatDetectionMessage_AnalyticalRules Analytics Rule with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject1').analyticRuleVersion1]",
@ -5408,7 +5408,7 @@
"description": "Identifies when the Cisco ASA Threat Detection engine fired an alert based on malicious activity occurring on the network inicated by DeviceEventClassID 733101-733105\nResources: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html\nDetails on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html",
"displayName": "Cisco ASA - threat detection message fired",
"enabled": false,
"query": "CommonSecurityLog\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID in (\"733101\",\"733102\",\"733103\",\"733104\",\"733105\")\n| extend timestamp = TimeGenerated, IPCustomEntity = SourceIP, HostCustomEntity = DeviceName\n",
"query": "CommonSecurityLog\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID in (\"733101\",\"733102\",\"733103\",\"733104\",\"733105\")\n| extend HostName = tostring(split(DeviceName, \".\")[0]), DomainIndex = toint(indexof(DeviceName, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)\n",
"queryFrequency": "PT1H",
"queryPeriod": "PT1H",
"severity": "Medium",
@ -5435,22 +5435,22 @@
],
"entityMappings": [
{
"entityType": "Host",
"fieldMappings": [
{
"columnName": "HostCustomEntity",
"identifier": "FullName"
"identifier": "FullName",
"columnName": "DeviceName"
}
],
"entityType": "Host"
]
},
{
"entityType": "IP",
"fieldMappings": [
{
"columnName": "IPCustomEntity",
"identifier": "Address"
"identifier": "Address",
"columnName": "SourceIP"
}
],
"entityType": "IP"
]
}
]
}
@ -5506,7 +5506,7 @@
"[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]"
],
"properties": {
"description": "CiscoASA-AvgAttackDetectRateIncrease_AnalyticalRules Analytics Rule with template version 3.0.3",
"description": "CiscoASA-AvgAttackDetectRateIncrease_AnalyticalRules Analytics Rule with template version 3.0.4",
"mainTemplate": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "[variables('analyticRuleObject2').analyticRuleVersion2]",
@ -5523,7 +5523,7 @@
"description": "This will help you determine if Cisco ASA devices are under heavier attack than normal over the last hour versus the previous 6 hours based on DeviceEventClassID 733100\nReferences: https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/syslogs9.html\nDetails on how to further troubleshoot/investigate: https://www.cisco.com/c/en/us/support/docs/security/asa-5500-x-series-next-generation-firewalls/113685-asa-threat-detection.html",
"displayName": "Cisco ASA - average attack detection rate increase",
"enabled": false,
"query": "let timeframe = 1h;\nlet last1h = CommonSecurityLog\n| where TimeGenerated >= ago(timeframe)\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID == \"733100\"\n| extend SourceOfDropRateCount = tostring(split(tostring(split(Message, \"]\")[0]),\"[ \")[1])\n| extend splitMessage = split(Message, \".\")\n| extend DropRate = tostring(split(tostring(splitMessage[0]),\"] \")[1])\n| extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),\" \")[0]),\"is \")\n| extend CurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1]),\" \")[0])\n| extend MaxConfiguredBurstRate = toint(CurrentBurstRate[2])\n| extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),\" \")[1]),\"is \")\n| extend CurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1]),\" \")[0])\n| extend MaxConfiguredAvgRate = toint(CurrentAvgRate[2])\n| extend CumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),\" \")[2]),\"is \")[1])\n| summarize last1hCumTotal = sum(CumulativeTotal), last1hAvgRatePerSec = avg(CurrentAvgRatePerSec), last1hAvgBurstRatePerSec = avg(CurrentBurstRatePerSec) by DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate;\nlet prev6h = CommonSecurityLog\n| where TimeGenerated between (ago(6h) .. ago(1h))\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID == \"733100\"\n| extend SourceOfDropRateCount = tostring(split(tostring(split(Message, \"]\")[0]),\"[ \")[1])\n| extend splitMessage = split(Message, \".\")\n| extend DropRate = tostring(split(tostring(splitMessage[0]),\"] \")[1])\n| extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),\" \")[0]),\"is \")\n| extend prevCurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1]),\" \")[0])\n| extend prevMaxConfiguredBurstRate = toint(CurrentBurstRate[2])\n| extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),\" \")[1]),\"is \")\n| extend prevCurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1]),\" \")[0])\n| extend prevMaxConfiguredAvgRate = toint(CurrentAvgRate[2])\n| extend prevCumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),\" \")[2]),\"is \")[1])\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), prev6hCumTotal = sum(prevCumulativeTotal), prev6hAvgRatePerSec = avg(prevCurrentAvgRatePerSec), prev6hAvgBurstRatePerSec = avg(prevCurrentBurstRatePerSec)\nby DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate;\nlast1h | join (\n prev6h\n) on DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate\n| project StartTimeUtc, EndTimeUtc, DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate, last1hCumTotal, prev6hCumTotal, prev6hAvgCumTotal = prev6hCumTotal/6, last1hAvgRatePerSec, prev6hAvgRatePerSec, last1hAvgBurstRatePerSec, prev6hAvgBurstRatePerSec\n// Select only events that indicate a doubling of the expected rate in the last hour over the previous 6 hours\n| where last1hCumTotal > 2*prev6hAvgCumTotal or last1hAvgRatePerSec > 2*prev6hAvgRatePerSec or last1hAvgBurstRatePerSec > 2*prev6hAvgBurstRatePerSec\n| extend timestamp = StartTimeUtc, IPCustomEntity = SourceIP, HostCustomEntity = DeviceName\n",
"query": "let timeframe = 1h;\nlet last1h = CommonSecurityLog\n| where TimeGenerated >= ago(timeframe)\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID == \"733100\"\n| extend SourceOfDropRateCount = tostring(split(tostring(split(Message, \"]\")[0]),\"[ \")[1])\n| extend splitMessage = split(Message, \".\")\n| extend DropRate = tostring(split(tostring(splitMessage[0]),\"] \")[1])\n| extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),\" \")[0]),\"is \")\n| extend CurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1]),\" \")[0])\n| extend MaxConfiguredBurstRate = toint(CurrentBurstRate[2])\n| extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),\" \")[1]),\"is \")\n| extend CurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1]),\" \")[0])\n| extend MaxConfiguredAvgRate = toint(CurrentAvgRate[2])\n| extend CumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),\" \")[2]),\"is \")[1])\n| summarize last1hCumTotal = sum(CumulativeTotal), last1hAvgRatePerSec = avg(CurrentAvgRatePerSec), last1hAvgBurstRatePerSec = avg(CurrentBurstRatePerSec) by DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate;\nlet prev6h = CommonSecurityLog\n| where TimeGenerated between (ago(6h) .. ago(1h))\n| where isempty(CommunicationDirection)\n| where DeviceEventClassID == \"733100\"\n| extend SourceOfDropRateCount = tostring(split(tostring(split(Message, \"]\")[0]),\"[ \")[1])\n| extend splitMessage = split(Message, \".\")\n| extend DropRate = tostring(split(tostring(splitMessage[0]),\"] \")[1])\n| extend CurrentBurstRate = split(tostring(split(tostring(splitMessage[1]),\" \")[0]),\"is \")\n| extend prevCurrentBurstRatePerSec = toint(split(tostring(CurrentBurstRate[1]),\" \")[0])\n| extend prevMaxConfiguredBurstRate = toint(CurrentBurstRate[2])\n| extend CurrentAvgRate = split(tostring(split(tostring(splitMessage[1]),\" \")[1]),\"is \")\n| extend prevCurrentAvgRatePerSec = toint(split(tostring(CurrentAvgRate[1]),\" \")[0])\n| extend prevMaxConfiguredAvgRate = toint(CurrentAvgRate[2])\n| extend prevCumulativeTotal = toint(split(tostring(split(tostring(splitMessage[1]),\" \")[2]),\"is \")[1])\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), prev6hCumTotal = sum(prevCumulativeTotal), prev6hAvgRatePerSec = avg(prevCurrentAvgRatePerSec), prev6hAvgBurstRatePerSec = avg(prevCurrentBurstRatePerSec)\nby DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate;\nlast1h | join (\n prev6h\n) on DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate\n| project StartTimeUtc, EndTimeUtc, DeviceName, DeviceEventClassID, SourceIP, SourceOfDropRateCount, DropRate, last1hCumTotal, prev6hCumTotal, prev6hAvgCumTotal = prev6hCumTotal/6, last1hAvgRatePerSec, prev6hAvgRatePerSec, last1hAvgBurstRatePerSec, prev6hAvgBurstRatePerSec\n// Select only events that indicate a doubling of the expected rate in the last hour over the previous 6 hours\n| where last1hCumTotal > 2*prev6hAvgCumTotal or last1hAvgRatePerSec > 2*prev6hAvgRatePerSec or last1hAvgBurstRatePerSec > 2*prev6hAvgBurstRatePerSec\n| extend HostName = tostring(split(DeviceName, \".\")[0]), DomainIndex = toint(indexof(DeviceName, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(DeviceName, DomainIndex + 1), DeviceName)\n",
"queryFrequency": "PT1H",
"queryPeriod": "PT6H",
"severity": "Low",
@ -5550,22 +5550,30 @@
],
"entityMappings": [
{
"entityType": "Host",
"fieldMappings": [
{
"columnName": "HostCustomEntity",
"identifier": "FullName"
"identifier": "FullName",
"columnName": "DeviceName"
},
{
"identifier": "HostName",
"columnName": "HostName"
},
{
"identifier": "DnsDomain",
"columnName": "HostNameDomain"
}
],
"entityType": "Host"
]
},
{
"entityType": "IP",
"fieldMappings": [
{
"columnName": "IPCustomEntity",
"identifier": "Address"
"identifier": "Address",
"columnName": "SourceIP"
}
],
"entityType": "IP"
]
}
]
}
@ -5617,12 +5625,12 @@
"apiVersion": "2023-04-01-preview",
"location": "[parameters('workspace-location')]",
"properties": {
"version": "3.0.3",
"version": "3.0.4",
"kind": "Solution",
"contentSchemaVersion": "3.0.0",
"displayName": "CiscoASA",
"publisherDisplayName": "Microsoft Sentinel, Microsoft Corporation",
"descriptionHtml": "<p><strong>Note:</strong> Please refer to the following before installing the solution:</p>\n<p>• Review the solution <a href=\"https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/CiscoASA/ReleaseNotes.md\">Release Notes</a></p>\n<p>• There may be <a href=\"https://aka.ms/sentinelsolutionsknownissues\">known issues</a> pertaining to this Solution, please refer to them before installing.</p>\n<p>The <a href=\"https://www.cisco.com/c/en_in/products/security/adaptive-security-appliance-asa-software/index.html\">Cisco ASA</a> solution for Microsoft Sentinel enables you to ingest <a href=\"https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/messages-listed-by-severity-level.html\">Cisco ASA logs</a> into Microsoft Sentinel. This solution includes two (2) data connectors to help ingest the logs.</p>\n<ol>\n<li><p><strong>Cisco ASA/FTD via AMA</strong> - This data connector helps in ingesting Cisco ASA logs into your Log Analytics Workspace using the new Azure Monitor Agent. Learn more about ingesting using the new Azure Monitor Agent <a href=\"https://learn.microsoft.com/azure/sentinel/connect-cef-ama\">here</a>. <strong>Microsoft recommends using this Data Connector</strong></p>\n</li>\n<li><p><strong>Cisco ASA via Legacy Agent</strong> - This data connector helps in ingesting Cisco ASA logs into your Log Analytics Workspace using the legacy Log Analytics agent.</p>\n</li>\n</ol>\n<P style=\"color:red\">**NOTE:** Microsoft recommends Installation of Cisco ASA/FTD via AMA Connector. Legacy connector uses the Log Analytics agent which is about to be deprecated by **Aug 31, 2024** and thus should only be installed where AMA is not supported.</p>\n<p><strong>Underlying Microsoft Technologies used:</strong></p>\n<p>This solution takes a dependency on the following technologies, and some of these dependencies either may be in <a href=\"https://azure.microsoft.com/support/legal/preview-supplemental-terms/\">Preview</a> state or might result in additional ingestion or operational costs:</p>\n<ol type=\"a\">\n<li><a href=\"https://docs.microsoft.com/azure/sentinel/connect-syslog\">Agent-based log collection (Syslog)</a></li>\n</ol>\n<p><strong>Data Connectors:</strong> 2, <strong>Workbooks:</strong> 1, <strong>Analytic Rules:</strong> 2, <strong>Custom Azure Logic Apps Connectors:</strong> 1, <strong>Playbooks:</strong> 3</p>\n<p><a href=\"https://aka.ms/azuresentinel\">Learn more about Microsoft Sentinel</a> | <a href=\"https://aka.ms/azuresentinelsolutionsdoc\">Learn more about Solutions</a></p>\n",
"descriptionHtml": "<p><strong>Note:</strong> Please refer to the following before installing the solution:</p>\n<p>• Review the solution <a href=\"https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/CiscoASA/ReleaseNotes.md\">Release Notes</a></p>\n<p>• There may be <a href=\"https://aka.ms/sentinelsolutionsknownissues\">known issues</a> pertaining to this Solution, please refer to them before installing.</p>\n<p>The <a href=\"https://www.cisco.com/c/en_in/products/security/adaptive-security-appliance-asa-software/index.html\">Cisco ASA</a> solution for Microsoft Sentinel enables you to ingest <a href=\"https://www.cisco.com/c/en/us/td/docs/security/asa/syslog/b_syslog/messages-listed-by-severity-level.html\">Cisco ASA logs</a> into Microsoft Sentinel. This solution includes two (2) data connectors to help ingest the logs.</p>\n<ol>\n<li><p><strong>Cisco ASA/FTD via AMA</strong> - This data connector helps in ingesting Cisco ASA logs into your Log Analytics Workspace using the new Azure Monitor Agent. Learn more about ingesting using the new Azure Monitor Agent <a href=\"https://learn.microsoft.com/azure/sentinel/connect-cef-ama\">here</a>. <strong>Microsoft recommends using this Data Connector</strong></p>\n</li>\n<li><p><strong>Cisco ASA via Legacy Agent</strong> - This data connector helps in ingesting Cisco ASA logs into your Log Analytics Workspace using the legacy Log Analytics agent.</p>\n</li>\n</ol>\n<P style=\"color:red\">**NOTE:** Microsoft recommends Installation of Cisco ASA/FTD via AMA Connector. Legacy connector uses the Log Analytics agent which is about to be deprecated by **Aug 31,2024** and thus should only be installed where AMA is not supported.</p>\n<p><strong>Underlying Microsoft Technologies used:</strong></p>\n<p>This solution takes a dependency on the following technologies, and some of these dependencies either may be in <a href=\"https://azure.microsoft.com/support/legal/preview-supplemental-terms/\">Preview</a> state or might result in additional ingestion or operational costs:</p>\n<ol type=\"a\">\n<li><a href=\"https://docs.microsoft.com/azure/sentinel/connect-syslog\">Agent-based log collection (Syslog)</a></li>\n</ol>\n<p><strong>Data Connectors:</strong> 2, <strong>Workbooks:</strong> 1, <strong>Analytic Rules:</strong> 2, <strong>Custom Azure Logic Apps Connectors:</strong> 1, <strong>Playbooks:</strong> 3</p>\n<p><a href=\"https://aka.ms/azuresentinel\">Learn more about Microsoft Sentinel</a> | <a href=\"https://aka.ms/azuresentinelsolutionsdoc\">Learn more about Solutions</a></p>\n",
"contentKind": "Solution",
"contentProductId": "[variables('_solutioncontentProductId')]",
"id": "[variables('_solutioncontentProductId')]",

Просмотреть файл

@ -1,5 +1,6 @@
| **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** |
|-------------|--------------------------------|------------------------------------------------------------------------------|
| 3.0.4 | 22-05-2024 | Updated connectivity criteria for **Data Connector** |
| 3.0.3 | 14-03-2024 | Change the connectivity criteria to use the resource graph and not LA data |
| 3.0.2 | 07-03-2024 | New AMA based connector is now in public preview |
| 3.0.1 | 31-01-2023 | Added new **Data Connector** Cisco ASA/FTD via AMA (Preview) to the solution |

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше