PFI25 - Agari data connector fixes (#1315)
* PFI-25: Agari Data Connector - Added support for fetching /revoking bearer tokens for Agari Phishing Defense (APD) - Added support for fetching /revoking bearer tokens for Agari Phishing Response (APR) - Added support for fetching /revoking bearer tokens for Agari Brand Protection (BP) - Added support Microsoft Security Graph via OAuth - Added support for fetching Policy Hits and Threat Categories for APD into Sentinel Log Analytics - Added support for Brand Protection alert logs to Sentinel Log Analytics. - Added support for Brand Protection Threat Feeds to feed URL data to the Security Graph - Added support for Phishing Response IoCs to be fed to the Security Graph API - Added error checking on API responses - Added support for pagination of API responses - Added instructions for fetching the Agari Client ID / Secret - Added instructions about the Security Graph API - Added instructions for manual deployment * PFI-25: Agari Data Connector (continued - fixes) - fixed typo in token gen if statement - fixed header variable in APD call - added x-header to API call to identify Sentinel - added if statements for APD push to Sentinel to verify if there is data to push - removed en-us from URLs - added BP logs to deployment template - added log samples - raw is data from the API call, formatted is what is used to push to Sentinel - added approprtiate files to the zip archive - functionapp.json-- - removed Preview from the title - added preview to the availability section --deploy.json-- - removed "description" tag from the boolean variables - fixed typos in the descriptions - fixed alignment of paramaters - added new resources to capture function, resource groups, subscriptionid for writing to the evironment variables - added 3 new variables for LastLogtTime per product --run.ps1 changes-- - added new variables to take read environment variables - added new function SetLastLogTime. This function stamps the new startdate to be used on the next run of the script. This was done to satisfy the case where if the script failed to run there would be no gap in the logs vs relying on the timer function - added UserAgent Strings - moved startdate into if statements per product to read the latest time in the respective variables - added varaiables to be populated if the API call was successfule, used in the function above to signal a new startdate should be populated - call the function last as it resets the current app session --zip file-- - created new zip with updated app - added version of powershell progamatically to the UA String - per product UA strings - Set the the first run start-date once - moved to per product startdate variables - modified queries to use per-product startdates - Update agari.zip * Update Agari_API_FunctionApp.json -Updated instructions for additonal steps around permissions to make both the automated and manual deployments have the correct permissions. -added BP logs to the query section * Updated additonal instructions and samples Cleaned up the instructions further added samples in json format removed old zip samples * Updated role type Changed text to Contirbutor vs owner * Update azuredeploy_Agari_API_FunctionApp.json Updated as per guidance from @nazang * Update azuredeploy_Agari_API_FunctionApp.json - Added the ?raw=true to the link. * Update Agari_API_FunctionApp.json @nazang I'll need a shortened link for the FunctionAPP.json as well * Links and Logo Update - added short links to json files - added Agari logo
This commit is contained in:
Родитель
30d61e126d
Коммит
58cff9dbdc
|
@ -0,0 +1,172 @@
|
|||
{
|
||||
"id": "Agari",
|
||||
"title": "Agari Phishing Defense and Brand Protection",
|
||||
"publisher": "Agari",
|
||||
"descriptionMarkdown": "This connector uses a Agari REST API connection to push data into Azure Sentinel Log Analytics.",
|
||||
"graphQueries": [
|
||||
{
|
||||
"metricName": "Total data received",
|
||||
"legend": "Agari Brand Protection Logs",
|
||||
"baseQuery": "agari_bpalerts_log_CL"
|
||||
},
|
||||
{
|
||||
"metricName": "Total data received",
|
||||
"legend": "Agari Phishing Defense Policy Hits",
|
||||
"baseQuery": "agari_apdpolicy_log_CL"
|
||||
},
|
||||
{
|
||||
"metricName": "Total data received",
|
||||
"legend": "Agari Phishing Defense Threat Categories",
|
||||
"baseQuery": "agari_apdtc_log_CL"
|
||||
}
|
||||
],
|
||||
"sampleQueries": [
|
||||
{
|
||||
"description" : "Summary by Attack Type",
|
||||
"query": "agari_apdtc_log_CL\n | summarize Count=count() by attack_types_s"
|
||||
},
|
||||
{
|
||||
"description" : "Summary of Policy Hits",
|
||||
"query": "agari_apdpolicy_log_CL\n | summarize Count=count() by alert_definition_name_s"
|
||||
}
|
||||
],
|
||||
"dataTypes": [
|
||||
{
|
||||
"name": "agari_bpalerts_log_CL",
|
||||
"lastDataReceivedQuery": "agari_bpalerts_log_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
|
||||
},
|
||||
{
|
||||
"name": "agari_apdtc_log_CL",
|
||||
"lastDataReceivedQuery": "agari_apdtc_log_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
|
||||
},
|
||||
{
|
||||
"name": "agari_apdpolicy_log_CL",
|
||||
"lastDataReceivedQuery": "agari_apdpolicy_log_CL\n | summarize Time = max(TimeGenerated)\n| where isnotempty(Time)"
|
||||
}
|
||||
],
|
||||
|
||||
"connectivityCriterias": [
|
||||
{
|
||||
"type": "IsConnectedQuery",
|
||||
"value": [
|
||||
"agari_bpalerts_log_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(30d)",
|
||||
"agari_apdtc_log_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(30d)",
|
||||
"agari_apdpolicy_log_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(30d)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"availability": {
|
||||
"status": 1,
|
||||
"isPreview": true
|
||||
},
|
||||
"permissions": {
|
||||
"resourceProvider": [
|
||||
{
|
||||
"provider": "Microsoft.OperationalInsights/workspaces",
|
||||
"permissionsDisplayText": "read and write permissions are required.",
|
||||
"providerDisplayName": "Workspace",
|
||||
"scope": "Workspace",
|
||||
"requiredPermissions": {
|
||||
"write": true,
|
||||
"read": true,
|
||||
"delete": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
|
||||
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key)",
|
||||
"providerDisplayName": "Keys",
|
||||
"scope": "Workspace",
|
||||
"requiredPermissions": {
|
||||
"action": true
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"customs": [
|
||||
{
|
||||
"name": "Microsoft.Web/sites permissions",
|
||||
"description": "Read and write permissions to Azure Functions to create a Function App is required. [See the documentation to learn more about Azure Functions](https://docs.microsoft.com/azure/azure-functions/)."
|
||||
},
|
||||
|
||||
{
|
||||
"name": "Agari Phishing Defense, Phishing Response or Brand Protection API Client ID and Secret",
|
||||
"description": "Ensure you have your Client ID and Secret keys. Instructions can be found on the [Agari Developers Site](https://developers.agari.com/agari-platform/docs/quick-start)."
|
||||
},
|
||||
{
|
||||
"name": "(Optional) Microsoft Security Graph API",
|
||||
"description": "The Agari Function App has the ability to share threat intelleigence with Sentinel via the Security Graph API. To use this feature, you will need to enable the [Sentinel Threat Intelligence Platforms connector](https://docs.microsoft.com/azure/sentinel/connect-threat-intelligence) as well as register an application in Azure Active Directory. "
|
||||
}
|
||||
]
|
||||
},
|
||||
"instructionSteps": [
|
||||
{
|
||||
"title": "",
|
||||
"description": ">**NOTE:** This connector uses Azure Functions to connect to the Agari APIs to pull its logs into Azure Sentinel. This might result in additional data ingestion costs. Check the [Azure Functions pricing page](https://azure.microsoft.com/pricing/details/functions/) for details."
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"description": ">**(Optional Step)** Securely store workspace and API authorization key(s) or token(s) in Azure Key Vault. Azure Key Vault provides a secure mechanism to store and retrieve key values. [Follow these instructions](https://docs.microsoft.com/azure/app-service/app-service-key-vault-references) to use Azure Key Vault with an Azure Function App."
|
||||
},
|
||||
{
|
||||
"title": "STEP 1 - Get your Agari API credentials",
|
||||
"description": "\n1. Log into any Agari product (Client ID and Secret are the same for all applications) \n2. Click on your username in the upper right and select **Settings**\n3. Click on the **Generate API Secret** link to generate an API client_id and client_secret (the link will read **Regenerate API Secret** if you have already generated an API client ID/secret previously)\n4. Copy both the client_id and client_secret that are generated"
|
||||
},
|
||||
|
||||
{
|
||||
"title": "STEP 2 - (Optional) Enable the Security Graph API",
|
||||
"description": "Follow the instrcutions found on article [Connect Azure Sentinel to your threat intelligence platform](https://docs.microsoft.com/azure/sentinel/connect-threat-intelligence#connect-azure-sentinel-to-your-threat-intelligence-platform). Once the application is created you will need to record the Tenant ID, Client ID and Client Secret."
|
||||
},
|
||||
{
|
||||
"title": "STEP 3 - Deploy the connector and the associated Azure Function",
|
||||
"description": "\n>**IMPORTANT:** Before deploying the Agari Connector, have the Workspace ID and Workspace Primary Key (can be copied from the following), as well as the Agari API credentials from the previous step.",
|
||||
"instructions": [
|
||||
{
|
||||
"parameters": {
|
||||
"fillWith": [
|
||||
"WorkspaceId"
|
||||
],
|
||||
"label": "Workspace ID"
|
||||
},
|
||||
"type": "CopyableLabel"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"fillWith": [
|
||||
"PrimaryKey"
|
||||
],
|
||||
"label": "Primary Key"
|
||||
},
|
||||
"type": "CopyableLabel"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Choose a deployement option",
|
||||
"description": ""
|
||||
},
|
||||
{ "title": "Option 1: Deploy using the Azure Resource Manager (ARM) Template",
|
||||
"description": "1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinel-agari-azuredeploy) \n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the **Workspace ID**, **Workspace Key**, **Agari Client ID**, **Agari Client Secret**, select `True` or `False` for the products you subscribe to, and if you wish to share IoCs with Sentinel, select `True` For **Enable Security Graph Sharing**, and enter the required IDs from the Azure Application.\n> - The Function App will request data from the Agari APIs every 5 minutes, corresponding to the Funciton App Timer.\n> - Note: If using Azure Key Vault secrets for any of the values above, use the`@Microsoft.KeyVault(SecretUri={Security Identifier})`schema in place of the string values. Refer to [Key Vault references documentation](https://docs.microsoft.com/azure/app-service/app-service-key-vault-references) for further details. \n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**. \n5. Click **Purchase** to deploy.\n6. **NOTE:** Due to the use of Environment Variables to store log access times, the App requires 1 additonal manual step. In the Function App, select the Function App Name and select Click on **Identity** and for System assigned Identity, click on **Azure role assignments** and **Add Role assignment**. Select **Subscription** as the scope, select your subscription and set the Role to **Contributor**. Click on **Save**."
|
||||
},
|
||||
{
|
||||
"title": "Option 2: Manual Deployment of Azure Functions",
|
||||
"description": "**1. Create a Function App**\n\n1. From the Azure Portal, navigate to [Function App](https://portal.azure.com/#blade/HubsExtension/BrowseResource/resourceType/Microsoft.Web%2Fsites/kind/functionapp), and select **+ Add**.\n2. In the **Basics** tab, ensure Runtime stack is set to **Powershell Core**. \n3. In the **Hosting** tab, ensure the **Consumption (Serverless)** plan type is selected.\n4. Make other preferrable configuration changes, if needed, then click **Create**."
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"description": "**2. Import Function App Code**\n\n1. In the newly created Function App, select **Functions** on the left pane and click **+ Add**.\n2. Click on **Code + Test** on the left pane. \n3. Copy the [Function App Code](https://aka.ms/sentinelagariazurefunctioncode) and paste into the Function App `run.ps1` editor.\n3. Click **Save**."
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"description": "**3. 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 eight to eleven (11-14) application settings individually, with their respective string values (case-sensitive): \n\t\tclientID\n\t\tclientSecret\n\t\tworkspaceID\n\t\tworkspaceKey\n\t\tenableBrandProtectionAPI\n\t\tenablePhishingResponseAPI\n\t\tenablePhishingDefenseAPI\n\t\tresGroup\n\t\tfunctionName\n\t\tsubId\n\t\tenableSecurityGraphSharing\n\t\t<--- Required if enableSecurityGraphSharing is set to true --->\n\t\tGraphTenantId\n\t\tGraphClientId\n\t\tGraphClientSecret\n> - Enter your Agari ClientID and Secret in 'clientId' and 'clientSecret'\n> - Enter 'true' or 'false' for 'enablePhishingDefense', 'enableBrandProtection', 'enablePhishingResponse' as per your product subscriptions.\n> - Enter your Resource Group name in resGroup, the name of the Function (from previous step) in functionName and your Subscription ID in subId.\n> - Enter 'true' or 'false' for 'enableSecurtyGraphAPI'. If you are enabling the Security Graph, the 'GraphTenantId','GraphClientId', and 'GraphClientSecret' is required.\n>\n"
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"description": "**4. Set Permissions for the App**\n\n1. In the Function App, select the Function App Name and select Click on **Identity** and for System assigned Identity, set the status to On. \n\n2. Next, click on **Azure role assignments** and **Add Role assignment**. Select **Subscription** as the scope, select your subscription and set the Role to **Contributor**. Click on **Save**."
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"description": "**5. Complete Setup.**\n\n1. Once all application settings have been entered, click **Save**. Note that it will take some time to have the required dependencies download, so you may see some inital failure messages."
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"bindings": [
|
||||
{
|
||||
"type": "timerTrigger",
|
||||
"name": "Timer",
|
||||
"schedule": "0 */5 * * * *",
|
||||
"direction": "in"
|
||||
}
|
||||
],
|
||||
"disabled": false
|
||||
}
|
|
@ -0,0 +1,450 @@
|
|||
# Input bindings are passed in via param block.
|
||||
param($Timer)
|
||||
|
||||
# Get the current universal time in the default string format
|
||||
$currentUTCtime = (Get-Date).ToUniversalTime()
|
||||
|
||||
# The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled
|
||||
if ($Timer.IsPastDue) {
|
||||
Write-Host "PowerShell timer is running late!"
|
||||
}
|
||||
|
||||
# Write an information log with the current time.
|
||||
Write-Host "PowerShell timer trigger function ran! TIME: $currentUTCtime"
|
||||
|
||||
# Get ENV parameters
|
||||
|
||||
# Agari Client ID and Secret
|
||||
$client_id = $env:clientID
|
||||
$client_secret = $env:clientSecret
|
||||
|
||||
# Define the Log Analytics Workspace ID and Keys
|
||||
$CustomerId = $env:workspaceId
|
||||
$SharedKey = $env:workspaceKey
|
||||
|
||||
# Define the Graph API credentials
|
||||
$GraphTenantId = $env:GraphTenantId
|
||||
$GraphClientId = $env:GraphClientId
|
||||
$GraphClientSecret = $env:GraphClientSecret
|
||||
|
||||
#Define Product(s) Enabled
|
||||
$bpEnabled = $env:enableBrandProtectionAPI
|
||||
$aprEnabled = $env:enablePhishingResponseAPI
|
||||
$apdEnabled = $env:enablePhishingDefenseAPI
|
||||
$sgEnabled = $env:enableSecurityGraphSharing
|
||||
|
||||
#Function App Configuration for Timer Functions
|
||||
$resGrp = $env:resGroup
|
||||
$appName = $env:functionName
|
||||
$subid = $env:subId
|
||||
$bplastLog = $env:BPlastLogTime
|
||||
$apdlastLog = $env:APDlastLogTime
|
||||
$aprlastLog = $env:APRlastLogTime
|
||||
|
||||
# Function to build the Authorization signature for the Log Analytics Data Connector API
|
||||
Function Build-Signature ($customerId, $sharedKey, $date, $contentLength, $method, $contentType, $resource)
|
||||
{
|
||||
$xHeaders = "x-ms-date:" + $date
|
||||
$stringToHash = $method + "`n" + $contentLength + "`n" + $contentType + "`n" + $xHeaders + "`n" + $resource
|
||||
|
||||
$bytesToHash = [Text.Encoding]::UTF8.GetBytes($stringToHash)
|
||||
$keyBytes = [Convert]::FromBase64String($sharedKey)
|
||||
|
||||
$sha256 = New-Object System.Security.Cryptography.HMACSHA256
|
||||
$sha256.Key = $keyBytes
|
||||
$calculatedHash = $sha256.ComputeHash($bytesToHash)
|
||||
$encodedHash = [Convert]::ToBase64String($calculatedHash)
|
||||
$authorization = 'SharedKey {0}:{1}' -f $customerId,$encodedHash
|
||||
|
||||
# Dispose SHA256 from heap before return.
|
||||
$sha256.Dispose()
|
||||
|
||||
return $authorization
|
||||
}
|
||||
|
||||
# Function to create and invoke an API POST request to the Log Analytics Data Connector API
|
||||
Function Post-LogAnalyticsData($customerId, $sharedKey, $body, $logType)
|
||||
{
|
||||
$method = "POST"
|
||||
$contentType = "application/json"
|
||||
$resource = "/api/logs"
|
||||
$rfc1123date = [DateTime]::UtcNow.ToString("r")
|
||||
$contentLength = $body.Length
|
||||
$signature = Build-Signature `
|
||||
-customerId $customerId `
|
||||
-sharedKey $sharedKey `
|
||||
-date $rfc1123date `
|
||||
-contentLength $contentLength `
|
||||
-method $method `
|
||||
-contentType $contentType `
|
||||
-resource $resource
|
||||
$uri = "https://" + $customerId + ".ods.opinsights.azure.com" + $resource + "?api-version=2016-04-01"
|
||||
|
||||
$headers = @{
|
||||
"Authorization" = $signature;
|
||||
"Log-Type" = $logType;
|
||||
"x-ms-date" = $rfc1123date;
|
||||
"time-generated-field" = $TimeStampField;
|
||||
}
|
||||
|
||||
$response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Headers $headers -Body $body -UseBasicParsing
|
||||
return $response.StatusCode
|
||||
}
|
||||
|
||||
# Timer Function to stamp the last successful log into the environment variable
|
||||
Function SetLastLogTime ($subid,$resGrp,$appName,$nextStartDate,$apdLogSuccess,$aprLogSuccess,$bpLogSuccess)
|
||||
{
|
||||
#Get the subscription
|
||||
Select-AzSubscription -Subscriptionid $subid
|
||||
#Getting WebApp info
|
||||
$webApp = Get-AzWebApp -ResourceGroupName $resGrp -Name $appName
|
||||
|
||||
# Read App Settings and load into Hash Table
|
||||
$appSettingList = $webApp.SiteConfig.AppSettings
|
||||
$newAppSettingList = @{}
|
||||
ForEach ($kvp in $appSettingList) {
|
||||
$newAppSettingList[$kvp.Name] = $kvp.Value
|
||||
}
|
||||
|
||||
# Add in new value for last log time NOTE: have to mangle the date with a "t" prefix due to issue Set-AzWebApp #8277
|
||||
if ($apdLogSuccess){
|
||||
$newAppSettingList['APDlastLogTime'] = "t$nextStartDate"
|
||||
}
|
||||
if ($aprLogSuccess){
|
||||
$newAppSettingList['APRlastLogTime'] = "t$nextStartDate"
|
||||
}
|
||||
if ($bpLogSuccess){
|
||||
$newAppSettingList['BPlastLogTime'] = "t$nextStartDate"
|
||||
}
|
||||
# Write to App Settings if there are changes
|
||||
if(($apdLogSuccess) -or ($aprLogSuccess) -or ($bpLogSuccess)){
|
||||
Set-AzWebApp -ResourceGroupName $resGrp -Name $appName -AppSettings $newAppSettingList
|
||||
}
|
||||
}
|
||||
|
||||
# Function to get Agari product bearer token
|
||||
Function GetToken($client_id,$client_secret,$TokenURI) {
|
||||
$GetTokenHeaders=@{
|
||||
'accept'='application/json'
|
||||
'content-type'='application/x-www-form-urlencoded'
|
||||
}
|
||||
$result = Try {Invoke-WebRequest -uri $TokenURI -Method 'POST' -Headers $GetTokenHeaders -Body "grant_type=client_credentials&client_id=$client_id&client_secret=$client_secret"} catch {Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__}
|
||||
# Really simple error check, if we get a 200 return the bearer token, ortherwise return false
|
||||
if ($result.StatusCode -eq 200) {
|
||||
return ($result.Content | ConvertFrom-Json).access_token
|
||||
} else {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
# Function to revoke the Agari bearer token
|
||||
Function RevokeToken($revokeToken_uri, $token) {
|
||||
$RevokeTokenHeaders=@{
|
||||
'accept'='application/json'
|
||||
'content-type'='application/x-www-form-urlencoded'
|
||||
'authorization'="Bearer $token"
|
||||
}
|
||||
Invoke-WebRequest -uri $revokeToken_uri -Method POST -Headers $RevokeTokenHeaders -Body "token=$token" | Out-Null
|
||||
}
|
||||
|
||||
# Function for creating the Threat Indicators body based on threat type
|
||||
Function Body-SentinelTI($GraphTenantId,$IoC_Type,$IoC,$Product,$expiry){
|
||||
$body=@{
|
||||
'action' = "alert"
|
||||
'azureTenantId' = $GraphTenantId
|
||||
'description' = "$IoC_Type IoC from Agari $Product"
|
||||
'expirationDateTime'= $expiry
|
||||
'targetProduct' = 'Azure Sentinel'
|
||||
'tlpLevel' = "Amber"
|
||||
'vendorInformation'= 'Agari'
|
||||
}
|
||||
switch ($IoC_Type) {
|
||||
'Domain' {$body.Add("emailSourceDomain", "$IoC")}
|
||||
'Domain' {$body.Add('threatType','Phishing')}
|
||||
'IP' {$body.Add('networkDestinationIPv4',"$IoC")}
|
||||
'IP'{$body.Add('threatType','Phishing')}
|
||||
'URL' {$body.Add('url',"$IoC")}
|
||||
'URL'{$body.Add('threatType','MaliciousURL')}
|
||||
'File'{$body.Add('fileHashValue',"$IoC")}
|
||||
'File'{$body.Add('fileHashType','sha256')}
|
||||
'File'{$body.Add('threatType','Malware')}
|
||||
}
|
||||
$sg_body = $body | ConvertTo-Json
|
||||
return $sg_body
|
||||
}
|
||||
|
||||
# Setup the SGAPI call
|
||||
if ($sgEnabled){
|
||||
# Set a 10 day expiry for the IoC
|
||||
$expiry=(Get-Date (get-date).addDays(10) -UFormat "+%Y-%m-%dT%H:00:00.00Z")
|
||||
#Get the token for the Securty Graph API calls
|
||||
$uri = "https://login.microsoftonline.com/$GraphTenantId/oauth2/v2.0/token"
|
||||
$body = @{
|
||||
client_id = $GraphClientId
|
||||
scope = "https://graph.microsoft.com/.default"
|
||||
client_secret = $GraphClientSecret
|
||||
grant_type = "client_credentials"
|
||||
}
|
||||
# Get OAuth 2.0 Token
|
||||
$tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing
|
||||
# Unpack Access Token if we get a success
|
||||
if ($tokenRequest.StatusCode -eq 200) {
|
||||
$sgapi_token = ($tokenRequest.Content | ConvertFrom-Json).access_token
|
||||
# Base URL
|
||||
$sgapi_uri = 'https://graph.microsoft.com/beta/security/tiIndicators'
|
||||
$sgapi_headers = @{
|
||||
'Authorization' = "Bearer $sgapi_token"
|
||||
'ContentType' = 'application/json'
|
||||
}
|
||||
} else {
|
||||
$sgEnabled = $false
|
||||
Write-Host "Error fetching token for the Security Graph API call"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#Set uris for get/revoke bearer tokens
|
||||
$get_apd_token_uri='https://api.agari.com/v1/ep/token'
|
||||
$get_bp_token_uri='https://api.agari.com/v1/cp/oauth/token'
|
||||
$get_apr_token_uri='https://api.agari.com/v1/apr/token'
|
||||
$revoke_apd_token_uri='https://api.agari.com/v1/ep/revoke'
|
||||
$revoke_apr_token_uri='https://api.agari.com/v1/apr/revoke'
|
||||
$revoke_bp_token_uri='https://api.agari.com/v1/cp/oauth/revoke'
|
||||
|
||||
|
||||
# Get the Bearer Tokens
|
||||
if ($bpEnabled){
|
||||
#Get the bearer token
|
||||
$bpToken = GetToken $client_id $client_secret $get_bp_token_uri
|
||||
# set the headers
|
||||
if ($bpToken){
|
||||
$bpHeaders = @{
|
||||
'Authorization' = "Bearer $bpToken"
|
||||
'ContentType' = 'application/json'
|
||||
'UserAgent' = "AgariSentinel BP_Integration/v1.0 SentinelPowerShellCore/v$PSVersionTable.PSVersion.major"
|
||||
}
|
||||
} else {
|
||||
$bpToken = $false
|
||||
Write-Host "Error Fetching BP Token"
|
||||
}
|
||||
}
|
||||
if ($apdEnabled){
|
||||
#Get the bearer token
|
||||
$apdToken = GetToken $client_id $client_secret $get_apd_token_uri
|
||||
# set the headers
|
||||
if ($apdToken){
|
||||
$apdHeaders = @{
|
||||
'Authorization'="Bearer $apdToken"
|
||||
'ContentType' = 'application/json'
|
||||
'UserAgent' = "AgariSentinel APD_Integration/v1.0 SentinelPowerShellCore/v$PSVersionTable.PSVersion.major"
|
||||
}
|
||||
} else {
|
||||
$apdToken = $false
|
||||
Write-Host "Error Fetching APD Token"
|
||||
}
|
||||
}
|
||||
if ($aprEnabled){
|
||||
#Get the bearer token
|
||||
$aprToken = GetToken $client_id $client_secret $get_apr_token_uri
|
||||
# set the headers
|
||||
if ($aprToken){
|
||||
$aprHeaders = @{
|
||||
'Authorization'="Bearer $aprToken"
|
||||
'ContentType' = 'application/json'
|
||||
'UserAgent' = "AgariSentinel APR_Integration/v1.0 SentinelPowerShellCore/v$PSVersionTable.PSVersion.major"
|
||||
}
|
||||
} else {
|
||||
$aprToken = $false
|
||||
Write-Host "Error Fetching APR Token"
|
||||
}
|
||||
}
|
||||
|
||||
#Set global api variables
|
||||
#set first run startdate
|
||||
$fr_startdate=(Get-Date (get-date).addMinutes(-6) -UFormat "+%Y-%m-%dT%H:%M:00:001Z")
|
||||
#set the enddate
|
||||
$enddate=(Get-Date (get-date).addMinutes(-1) -UFormat "+%Y-%m-%dT%H:%M:00.000Z")
|
||||
#if successful, we'll popoulate the environment variable with the end date + 1ms
|
||||
$nextStartDate = (Get-Date (get-date).addMinutes(-1) -UFormat "+%Y-%m-%dT%H:%M:00:001Z")
|
||||
$limit = 200
|
||||
$offset = 0
|
||||
$TimeStampField = "DateValue"
|
||||
|
||||
# --------------------------------------------------- #
|
||||
# Below is for loading BP Logs and TIs into Sentinel. #
|
||||
# --------------------------------------------------- #
|
||||
|
||||
#Check if BP is enabled and we got a token
|
||||
if (($bpEnabled) -and ($bpToken)) {
|
||||
#Check to see if start time empty - usally first run, otherwise set the time from the env variable
|
||||
if ($BPlastLog){
|
||||
$BPstartdate = $BPlastLog.substring(1)
|
||||
} else {
|
||||
$BPstartdate = $fr_startdate
|
||||
}
|
||||
$offset = 0
|
||||
do {
|
||||
$BPAlertsListAPI = "https://api.agari.com/v1/cp/alert_events?start_date=$BPstartdate&end_date=$enddate&fields=id%2C&limit=$limit&offset=$offset&sort=created_at%20ASC"
|
||||
Invoke-RestMethod -Uri $BPAlertsListAPI -Method 'GET' -Headers $bpHeaders | ForEach-Object {
|
||||
$ids += $_.alert_events | Select-Object -ExpandProperty id
|
||||
$count = $_.count
|
||||
$bpLogSuccess = $true
|
||||
}
|
||||
$offset += $limit
|
||||
} while ($count -eq $limit)
|
||||
|
||||
#Loop through each ID and add to the bp_alert log
|
||||
foreach ($id in $ids) {
|
||||
$GetIDAPI="https://api.agari.com:443/v1/cp/alert_events/$id"
|
||||
Invoke-RestMethod -Uri $GetIDAPI -Method 'GET' -Headers $bpHeaders | ForEach-Object {
|
||||
$id_data = $_.alert_event
|
||||
$id_log = $id_data | ConvertTo-Json
|
||||
Post-LogAnalyticsData -customerId $customerId -sharedKey $sharedKey -body ([System.Text.Encoding]::UTF8.GetBytes($id_log)) -logType "agari_bpalerts_log"
|
||||
}
|
||||
}
|
||||
# Load the URLs from the BP Threat Feed to Security Graph if enabled
|
||||
if ($sgEnabled){
|
||||
$Product = 'Brand Protection'
|
||||
#Get the Threat Feed ID
|
||||
$BP_TF_Url = "https://api.agari.com/v1/cp/threat_feeds"
|
||||
Invoke-RestMethod -Uri $BP_TF_Url -Method 'GET' -Headers $bpHeaders | Out-Null
|
||||
# If there is a Threat ID, get the URIs in the feed
|
||||
if ($_.threat_feeds.id){
|
||||
$IoC_Type = 'URL'
|
||||
foreach ($sub_id in $_.threat_feeds.id){
|
||||
$BP_SubmissionUrl = "https://api.agari.com/v1/cp/threat_feeds/$sub_id/submissions?start_date=$BPstartdate&end_date=$enddate"
|
||||
Invoke-RestMethod -Uri $BP_SubmissionUrl -Method 'GET' -Headers $bpHeaders | ForEach-Object {
|
||||
$bpBody = (Body-SentinelTI $GraphTenantId $IoC_Type $_.threat_feed_submissions.uri $Product $expiry)
|
||||
Invoke-WebRequest -Method POST -Uri $sgapi_uri -Headers $sgapi_headers -Body $bpBody
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# -------------------------------------------- #
|
||||
# Below is for loading APD Logs into Sentinel. #
|
||||
# -------------------------------------------- #
|
||||
|
||||
#Check if APD is enabled
|
||||
if (($apdEnabled) -and ($apdToken)){
|
||||
#Check to see if start time empty - usally first run, otherwise set the time from the env variable
|
||||
if ($apdlastLog){
|
||||
$APDstartdate = $APDlastLog.substring(1)
|
||||
} else {
|
||||
$APDstartdate = $fr_startdate
|
||||
}
|
||||
#Reset the Offset
|
||||
$offset = 0
|
||||
#Get the APD policy hits with the offset for paging
|
||||
do {
|
||||
$APDPolicyAPI = "https://api.agari.com/v1/ep/policy_events?limit=$limit&offset=$offset&sort=created_at%20DESC&policy_enabled=true&start_date=$APDstartdate&end_date=$enddate"
|
||||
Invoke-RestMethod -Uri $APDPolicyAPI -Method 'GET' -Headers $apdHeaders | ForEach-Object {
|
||||
$APDPolicyData += $_.alert_events | Select-Object -Property created_at, id, alert_definition_name
|
||||
$count = $_.count
|
||||
}
|
||||
$offset += $limit
|
||||
} while ($count -eq $limit)
|
||||
|
||||
# If there are results, convert log to JSON and Post the data to log analytics API
|
||||
if ($APDPolicyData){
|
||||
$APDPolicyLog = $APDPolicyData | ConvertTo-JSON
|
||||
Post-LogAnalyticsData -customerId $customerId -sharedKey $sharedKey -body ([System.Text.Encoding]::UTF8.GetBytes($APDPolicyLog)) -logType "agari_apdpolicy_log"
|
||||
}
|
||||
#Get the Threat Categories and push to Sentinel
|
||||
#Reset the Offset
|
||||
$offset = 0
|
||||
#Get the APD Threat Categories API call with the offset for paging
|
||||
do {
|
||||
$APDThreatCatAPI = "https://api.agari.com/v1/ep/messages?start_date=$APDstartdate&end_date=$enddate&fields=attack_types%2Cto%2Cfrom%2Cid%2Cfrom_domain%2Ctimestamp_ms&limit=$limit&offset=$offset&sort=timestamp_ms%20DESC&search=attack_types%20is%20not%20empty"
|
||||
Invoke-RestMethod -Uri $APDThreatCatAPI -Method 'GET' -Headers $apdHeaders | ForEach-Object {
|
||||
$APDThreatCatData += $_.messages | Select-Object -Property to, from, from_domain, attack_types,id,timestamp_ms
|
||||
$count = $_.count
|
||||
$apdLogSuccess = $true
|
||||
}
|
||||
$offset += $limit
|
||||
} while ($count -eq $limit)
|
||||
# If there are results, convert log to JSON and Post the data to log analytics API
|
||||
if ($APDThreatCatData){
|
||||
$APDThreatCatLog = $APDThreatCatData | ConvertTo-Json
|
||||
Post-LogAnalyticsData -customerId $customerId -sharedKey $sharedKey -body ([System.Text.Encoding]::UTF8.GetBytes($APDThreatCatLog)) -logType "agari_apdtc_log"
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
# Below is for loading APR TIs into Sentinel via the Security Graph API. #
|
||||
# ---------------------------------------------------------------------- #
|
||||
|
||||
if ($sgEnabled){
|
||||
# If APR enabled, get all malicious IoC verdicts from investigations
|
||||
if (($aprEnabled) -and ($aprToken)){
|
||||
#Check to see if start time empty - usally first run, otherwise set the time from the env variable
|
||||
if ($aprlastLog){
|
||||
$APRstartdate = $APRlastLog.substring(1)
|
||||
} else {
|
||||
$APRstartdate = $fr_startdate
|
||||
}
|
||||
$Product = 'Phishing Response'
|
||||
#Query the latest investigations that are malicious and get the TIs
|
||||
$APRUrl = "https://api.agari.com/v1/apr/investigations?start_date=$APRstartdate&end_date=$enddate&classification=malicious"
|
||||
Invoke-RestMethod -Uri $APRUrl -Method 'GET' -Headers $aprHeaders | ForEach-Object {
|
||||
#Get the IDs of the investigations, we'll need these to get file hash values
|
||||
$inv_id = $_.investigations.id
|
||||
#Get the unique IoCs from the investigations
|
||||
$TI_DOMAIN = $_.investigations.indicators.domain.summary.resource | Select-Object -Unique
|
||||
$TI_URI = $_.investigations.indicators.uri.summary.resource | Select-Object -Unique
|
||||
$TI_IP = $_.investigations.indicators.ip.summary.resource | Select-Object -Unique
|
||||
$aprLogSuccess = $true
|
||||
}
|
||||
#Load the Domain IoCs
|
||||
if ($TI_DOMAIN) {
|
||||
$IoC_Type = "Domain"
|
||||
foreach ($domain_ioc in $TI_DOMAIN) {
|
||||
$domainBody = Body-SentinelTI $GraphTenantId $IoC_Type $domain_ioc $Product $expiry
|
||||
Invoke-WebRequest -Method POST -Uri $sgapi_uri -Headers $sgapi_headers -Body $domainBody
|
||||
}
|
||||
}
|
||||
#Load the URL IoCs
|
||||
if ($TI_URI) {
|
||||
$IoC_Type = "URL"
|
||||
foreach ($url_ioc in $TI_URL) {
|
||||
$urlBody = Body-SentinelTI $GraphTenantId $IoC_Type $url_ioc $Product $expiry
|
||||
Invoke-WebRequest -Method POST -Uri $sgapi_uri -Headers $sgapi_headers -Body $urlBody
|
||||
}
|
||||
}
|
||||
#Load the IP IoCs
|
||||
if ($TI_IP) {
|
||||
$IoC_Type = "IP"
|
||||
foreach ($ip_ioc in $TI_IP) {
|
||||
$ipBody = Body-SentinelTI $GraphTenantId $IoC_Type $ip_ioc $Product $expiry
|
||||
Invoke-WebRequest -Method POST -Uri $sgapi_uri -Headers $sgapi_headers -Body $ipBody
|
||||
}
|
||||
}
|
||||
#Files are special, need to go by ID to fetch the SHA values
|
||||
foreach ($hash_byid in $inv_id) {
|
||||
$GetHashAPI = "https://api.agari.com/v1/apr/investigations/$hash_byid/attachments?fields=hash_sha256"
|
||||
$HashAPIcall = Invoke-RestMethod -Uri $GetHashAPI -Method 'GET' -Headers $aprHeaders
|
||||
if ($HashAPIcall.attachments.hash_sha256) {
|
||||
$IoC_Type = "File"
|
||||
foreach ($file_ioc in $HashAPIcall.attachments.hash_sha256) {
|
||||
$hashBody = Body-SentinelTI $GraphTenantId $IoC_Type $file_ioc $Product $expiry
|
||||
Invoke-WebRequest -Method POST -Uri $sgapi_uri -Headers $sgapi_headers -Body $hashBody
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# We done, revoke the Tokens!
|
||||
if (($bpEnabled) -and ($bpToken)){
|
||||
RevokeToken $revoke_bp_token_uri $bpToken
|
||||
}
|
||||
if (($apdEnabled) -and ($apdToken)){
|
||||
RevokeToken $revoke_apd_token_uri $apdToken
|
||||
}
|
||||
if (($aprEnabled) -and ($aprToken)){
|
||||
RevokeToken $revoke_apr_token_uri $aprToken
|
||||
}
|
||||
|
||||
# Write the environment variable for the next startdate
|
||||
SetLastLogTime $subid $resGrp $appName $nextStartDate $apdLogSuccess $aprLogSuccess $bpLogSuccess
|
Двоичный файл не отображается.
|
@ -0,0 +1,302 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"FunctionName": {
|
||||
"defaultValue": "agari",
|
||||
"type": "string"
|
||||
},
|
||||
"clientID": {
|
||||
"type": "string",
|
||||
"defaultValue": "Enter Agari Client ID"
|
||||
},
|
||||
"clientSecret": {
|
||||
"type": "string",
|
||||
"defaultValue": "Enter Agari Client Secret"
|
||||
},
|
||||
"workspaceID": {
|
||||
"type": "string",
|
||||
"defaultValue": "<workspaceID>"
|
||||
},
|
||||
"workspaceKey": {
|
||||
"type": "string",
|
||||
"defaultValue": "<workspaceKey>"
|
||||
},
|
||||
"enableBrandProtectionAPI": {
|
||||
"type": "bool"
|
||||
},
|
||||
"enablePhishingDefenseAPI": {
|
||||
"type": "bool"
|
||||
},
|
||||
"enablePhishingResponseAPI": {
|
||||
"type": "bool"
|
||||
},
|
||||
"enableSecurityGraphSharing": {
|
||||
"type": "bool"
|
||||
},
|
||||
"GraphTenantID": {
|
||||
"type": "string",
|
||||
"defaultValue": "Enter MS Graph Tenant ID"
|
||||
},
|
||||
"GraphClientID": {
|
||||
"type": "string",
|
||||
"defaultValue": "Enter MS Graph Client ID"
|
||||
},
|
||||
"GraphClientSecret": {
|
||||
"type": "string",
|
||||
"defaultValue": "Enter MS Graph Client Secret"
|
||||
}
|
||||
|
||||
},
|
||||
"variables": {
|
||||
"FunctionName": "[concat(toLower(parameters('FunctionName')), uniqueString(resourceGroup().id))]"
|
||||
},
|
||||
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.Insights/components",
|
||||
"apiVersion": "2015-05-01",
|
||||
"name": "[parameters('FunctionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"kind": "web",
|
||||
"properties": {
|
||||
"Application_Type": "web",
|
||||
"ApplicationId": "[parameters('FunctionName')]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.KeyVault/vaults",
|
||||
"apiVersion": "2016-10-01",
|
||||
"name": "[parameters('FunctionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"properties": {
|
||||
"sku": {
|
||||
"family": "A",
|
||||
"name": "standard"
|
||||
},
|
||||
"tenantId": "[subscription().tenantId]",
|
||||
"enabledForDeployment": false,
|
||||
"enabledForDiskEncryption": false,
|
||||
"enabledForTemplateDeployment": true,
|
||||
"enableSoftDelete": true,
|
||||
"accessPolicies": [
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.KeyVault/vaults/secrets",
|
||||
"apiVersion": "2016-10-01",
|
||||
"name": "[concat(parameters('FunctionName'), '/workspaceKey')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.KeyVault/vaults', parameters('FunctionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"value": "[parameters('workspaceKey')]",
|
||||
"contentType": "string",
|
||||
"attributes": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[tolower(parameters('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.Web/serverfarms",
|
||||
"apiVersion": "2018-02-01",
|
||||
"name": "[parameters('FunctionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"sku": {
|
||||
"name": "Y1",
|
||||
"tier": "Dynamic"
|
||||
},
|
||||
"kind": "functionapp",
|
||||
"properties": {
|
||||
"name": "[parameters('FunctionName')]",
|
||||
"workerSize": "0",
|
||||
"workerSizeId": "0",
|
||||
"numberOfWorkers": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[concat(parameters('FunctionName'), '/default')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', tolower(parameters('FunctionName')))]"
|
||||
],
|
||||
"sku": {
|
||||
"name": "Standard_LRS",
|
||||
"tier": "Standard"
|
||||
},
|
||||
"properties": {
|
||||
"cors": {
|
||||
"corsRules": [
|
||||
]
|
||||
},
|
||||
"deleteRetentionPolicy": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts/fileServices",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[concat(parameters('FunctionName'), '/default')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', tolower(parameters('FunctionName')))]"
|
||||
],
|
||||
"sku": {
|
||||
"name": "Standard_LRS",
|
||||
"tier": "Standard"
|
||||
},
|
||||
"properties": {
|
||||
"cors": {
|
||||
"corsRules": [
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Web/sites",
|
||||
"apiVersion": "2018-11-01",
|
||||
"name": "[parameters('FunctionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', tolower(parameters('FunctionName')))]",
|
||||
"[resourceId('Microsoft.Web/serverfarms', parameters('FunctionName'))]",
|
||||
"[resourceId('Microsoft.KeyVault/vaults', parameters('FunctionName'))]",
|
||||
"[resourceId('Microsoft.Insights/components', parameters('FunctionName'))]"
|
||||
],
|
||||
"kind": "functionapp",
|
||||
"identity": {
|
||||
"type": "SystemAssigned"
|
||||
},
|
||||
"properties": {
|
||||
"name": "[parameters('FunctionName')]",
|
||||
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('FunctionName'))]",
|
||||
"httpsOnly": true,
|
||||
"clientAffinityEnabled": true
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "2018-11-01",
|
||||
"type": "config",
|
||||
"name": "appsettings",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Web/sites/', parameters('FunctionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"FUNCTIONS_EXTENSION_VERSION": "~3",
|
||||
"FUNCTIONS_WORKER_RUNTIME": "powershell",
|
||||
"APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(resourceId('Microsoft.insights/components', parameters('FunctionName')), '2015-05-01').InstrumentationKey]",
|
||||
"APPLICATIONINSIGHTS_CONNECTION_STRING": "[reference(resourceId('microsoft.insights/components', parameters('FunctionName')), '2015-05-01').ConnectionString]",
|
||||
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(parameters('FunctionName')),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(parameters('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=core.windows.net')]",
|
||||
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(parameters('FunctionName')),';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(parameters('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=core.windows.net')]",
|
||||
"WEBSITE_CONTENTSHARE": "[toLower(parameters('FunctionName'))]",
|
||||
"clientID": "[parameters('clientID')]",
|
||||
"clientSecret": "[parameters('clientSecret')]",
|
||||
"workspaceID": "[parameters('workspaceID')]",
|
||||
"workspaceKey": "[concat('@Microsoft.KeyVault(SecretUri=', reference(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('FunctionName'), 'workspaceKey')).SecretUriWithVersion, ')')]",
|
||||
"GraphTenantID": "[parameters('GraphTenantID')]",
|
||||
"GraphClientID": "[parameters('GraphClientID')]",
|
||||
"GraphClientSecret": "[parameters('GraphClientSecret')]",
|
||||
"enablePhishingDefenseAPI": "[parameters('enablePhishingDefenseAPI')]",
|
||||
"enableBrandProtectionAPI": "[parameters('enableBrandProtectionAPI')]",
|
||||
"enablePhishingResponseAPI": "[parameters('enablePhishingResponseAPI')]",
|
||||
"enableSecurityGraphSharing": "[parameters('enableSecurityGraphSharing')]",
|
||||
"functionName": "[parameters('FunctionName')]",
|
||||
"resGroup": "[resourceGroup().name]",
|
||||
"subId": "[subscription().subscriptionId]",
|
||||
"APRlastLogTime": "",
|
||||
"APDlastLogTime": "",
|
||||
"BPlastLogTime": "",
|
||||
"WEBSITE_RUN_FROM_PACKAGE": "https://aka.ms/sentinel-agari-functionapp"
|
||||
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Web/sites/hostNameBindings",
|
||||
"apiVersion": "2018-11-01",
|
||||
"name": "[concat(parameters('FunctionName'), '/', parameters('FunctionName'), '.azurewebsites.net')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Web/sites', parameters('FunctionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"siteName": "[parameters('FunctionName')]",
|
||||
"hostNameType": "Verified"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[concat(parameters('FunctionName'), '/default/azure-webjobs-hosts')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('FunctionName'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('FunctionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"publicAccess": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[concat(parameters('FunctionName'), '/default/azure-webjobs-secrets')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('FunctionName'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('FunctionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"publicAccess": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts/fileServices/shares",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[concat(parameters('FunctionName'), '/default/', tolower(parameters('FunctionName')))]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('FunctionName'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', parameters('FunctionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"shareQuota": 5120
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": "2.0",
|
||||
"managedDependency": {
|
||||
"Enabled": true
|
||||
},
|
||||
"extensionBundle": {
|
||||
"id": "Microsoft.Azure.Functions.ExtensionBundle",
|
||||
"version": "[1.*, 2.0.0)"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
# Azure Functions profile.ps1
|
||||
#
|
||||
# This profile.ps1 will get executed every "cold start" of your Function App.
|
||||
# "cold start" occurs when:
|
||||
#
|
||||
# * A Function App starts up for the very first time
|
||||
# * A Function App starts up after being de-allocated due to inactivity
|
||||
#
|
||||
# You can define helper functions, run commands, or specify environment variables
|
||||
# NOTE: any variables defined that are not environment variables will get reset after the first execution
|
||||
# Authenticate with Azure PowerShell using MSI.
|
||||
# Remove this if you are not planning on using MSI or Azure PowerShell.
|
||||
|
||||
if ($env:MSI_SECRET -and (Get-Module -ListAvailable Az.Accounts)) {
|
||||
Connect-AzAccount -Identity
|
||||
}
|
||||
|
||||
# Uncomment the next line to enable legacy AzureRm alias in Azure PowerShell.
|
||||
# Enable-AzureRmAlias
|
||||
# You can also define functions or aliases that can be referenced in any of your PowerShell functions.
|
|
@ -0,0 +1,7 @@
|
|||
# This file enables modules to be automatically managed by the Functions service.
|
||||
# See https://aka.ms/functionsmanageddependency for additional information.
|
||||
#
|
||||
@{
|
||||
# For latest supported version, go to 'https://www.powershellgallery.com/packages/Az'.
|
||||
'Az' = '4.*'
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<svg id="LogoFullColorRGB" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 393.03 211.14"><defs><style>.cls-1{fill:#f68d2e;}.cls-2{fill:#474c56;}</style></defs><title>Agari_Logos_RGB</title><path class="cls-1" d="M213.21,79.47H203.07L182.8,132h18l3.85-12.34a7.5,7.5,0,1,1,6.87,0L215.4,132h18Z"/><path class="cls-2" d="M246.09,78.91h18.29a43.6,43.6,0,0,1,12.39,1.55C293,85.26,293,111.66,275,116.14l13.26,15.5H277.32l-12.63-14.39h-8.6v14.39h-10Zm10,28.46h11.18c3.19,0,11.31.08,11.31-9.44,0-9.13-9-9.28-11.69-9.28h-10.8Z"/><rect class="cls-2" x="303.97" y="79.09" width="9.93" height="52.55"/><path class="cls-2" d="M92.85,93l8.48,22.42H84.71ZM87.78,78.9,67.46,131.64H78.58l2.44-6.8h23.65l2.64,6.8h10.76L97.92,78.9Z"/><path class="cls-2" d="M177,102.4H151.53v9.11h14.75a11.33,11.33,0,0,1-5.56,9.1,16.18,16.18,0,0,1-8.48,2.12,17.88,17.88,0,0,1-13-5.13A16.76,16.76,0,0,1,134,105.1,16.37,16.37,0,0,1,139,93a17.28,17.28,0,0,1,12.61-5,19.46,19.46,0,0,1,12,4l4.78-8.85c-5.56-4-13.08-4.68-16.82-4.68q-12.71,0-20.64,8.89a25.53,25.53,0,0,0-6.7,17.61,27.52,27.52,0,0,0,3.62,13.76,25.4,25.4,0,0,0,9.85,9.82A28.65,28.65,0,0,0,151.87,132a25.58,25.58,0,0,0,12.92-3.16,24.2,24.2,0,0,0,9-9.14c2.32-4,3.46-10.71,3.46-15.17l-.06-2.09Z"/><path class="cls-2" d="M323.33,128.54h.48a1.43,1.43,0,0,0,.38,0,.58.58,0,0,0,.26-.13.48.48,0,0,0,.14-.2.8.8,0,0,0,0-.28,1,1,0,0,0,0-.26.55.55,0,0,0-.15-.19.42.42,0,0,0-.22-.11,1.71,1.71,0,0,0-.36,0h-.54Zm0,.47v1.45h-.63V126.8h1.17a1.88,1.88,0,0,1,1.06.25,1,1,0,0,1,.33.77,1,1,0,0,1-.21.65,1.16,1.16,0,0,1-.66.38.53.53,0,0,1,.12.1.44.44,0,0,1,.1.15l.93,1.36h-.6a.2.2,0,0,1-.2-.1l-.83-1.24a.38.38,0,0,0-.09-.09l-.15,0Zm-2-.37a2.38,2.38,0,0,0,.11.7,2.65,2.65,0,0,0,.25.64,2.83,2.83,0,0,0,.39.52,3.22,3.22,0,0,0,.52.41,2.47,2.47,0,0,0,.63.26,2.68,2.68,0,0,0,.69.1,2.63,2.63,0,0,0,1.85-.77,2.51,2.51,0,0,0,.55-.83,2.79,2.79,0,0,0,.11-1.74,3,3,0,0,0-.26-.64,4.09,4.09,0,0,0-.4-.53,2.41,2.41,0,0,0-.54-.41,2.13,2.13,0,0,0-.61-.27,2.74,2.74,0,0,0-.7-.09,2.47,2.47,0,0,0-1,.21,2.62,2.62,0,0,0-1.58,2.44m-.41,0a2.63,2.63,0,0,1,.12-.8,3.19,3.19,0,0,1,.29-.72,3.15,3.15,0,0,1,.48-.61,2.87,2.87,0,0,1,.61-.46,2.14,2.14,0,0,1,.71-.3,2.66,2.66,0,0,1,.79-.12,2.74,2.74,0,0,1,.81.12,2.34,2.34,0,0,1,.71.3,3.41,3.41,0,0,1,.6.46,2.53,2.53,0,0,1,.48.61,3.23,3.23,0,0,1,.3.72,3,3,0,0,1,.12.8,2.9,2.9,0,0,1-.12.79,3.12,3.12,0,0,1-.3.73,2.26,2.26,0,0,1-.48.59,2.71,2.71,0,0,1-.6.47,2.64,2.64,0,0,1-.71.31,3.1,3.1,0,0,1-.81.11,3,3,0,0,1-.79-.11,2.39,2.39,0,0,1-.71-.31,2.36,2.36,0,0,1-.61-.47,2.75,2.75,0,0,1-.48-.59,3.09,3.09,0,0,1-.29-.73,2.56,2.56,0,0,1-.12-.79"/></svg>
|
После Ширина: | Высота: | Размер: 2.5 KiB |
|
@ -0,0 +1,44 @@
|
|||
[
|
||||
{
|
||||
"TenantId": "27201ba9-a494-40b0-bca0-364028a854c5",
|
||||
"SourceSystem": "RestAPI",
|
||||
"MG": "",
|
||||
"ManagementGroupName": "",
|
||||
"TimeGenerated [UTC]": "11/17/2020, 10:05:20.561 PM",
|
||||
"Computer": "",
|
||||
"RawData": "",
|
||||
"created_at_t [UTC]": "11/17/2020, 10:01:21.000 PM",
|
||||
"id_d": 541047785,
|
||||
"alert_definition_name_s": "Policy 1",
|
||||
"Type": "agari_apdpolicy_log_CL",
|
||||
"_ResourceId": ""
|
||||
},
|
||||
{
|
||||
"TenantId": "27201ba9-a494-40b0-bca0-364028a854c5",
|
||||
"SourceSystem": "RestAPI",
|
||||
"MG": "",
|
||||
"ManagementGroupName": "",
|
||||
"TimeGenerated [UTC]": "11/17/2020, 10:10:19.001 PM",
|
||||
"Computer": "",
|
||||
"RawData": "",
|
||||
"created_at_t [UTC]": "11/17/2020, 10:06:32.000 PM",
|
||||
"id_d": 541051040,
|
||||
"alert_definition_name_s": "Policy 2",
|
||||
"Type": "agari_apdpolicy_log_CL",
|
||||
"_ResourceId": ""
|
||||
},
|
||||
{
|
||||
"TenantId": "27201ba9-a494-40b0-bca0-364028a854c5",
|
||||
"SourceSystem": "RestAPI",
|
||||
"MG": "",
|
||||
"ManagementGroupName": "",
|
||||
"TimeGenerated [UTC]": "11/18/2020, 12:10:02.750 AM",
|
||||
"Computer": "",
|
||||
"RawData": "",
|
||||
"created_at_t [UTC]": "11/18/2020, 12:08:08.000 AM",
|
||||
"id_d": 541098663,
|
||||
"alert_definition_name_s": "Policy 3",
|
||||
"Type": "agari_apdpolicy_log_CL",
|
||||
"_ResourceId": ""
|
||||
}
|
||||
]
|
|
@ -0,0 +1,59 @@
|
|||
[
|
||||
{
|
||||
"TenantId": "27201ba9-a494-40b0-bca0-364028a854c5",
|
||||
"SourceSystem": "RestAPI",
|
||||
"MG": "",
|
||||
"ManagementGroupName": "",
|
||||
"TimeGenerated [UTC]": "11/17/2020, 3:40:19.942 PM",
|
||||
"Computer": "",
|
||||
"RawData": "",
|
||||
"id_g": "52289fcc-28ea-11eb-8461-0242ac140004",
|
||||
"timestamp_ms_s": 1605627243000,
|
||||
"to_s": "user1@mydomain.com",
|
||||
"from_s": "User A <usera@domaina.com>",
|
||||
"from_domain_s": "domaina.com",
|
||||
"attack_types_s": [
|
||||
"low_trust (Low trust domain)"
|
||||
],
|
||||
"Type": "agari_apdtc_log_CL",
|
||||
"_ResourceId": ""
|
||||
},
|
||||
{
|
||||
"TenantId": "27201ba9-a494-40b0-bca0-364028a854c5",
|
||||
"SourceSystem": "RestAPI",
|
||||
"MG": "",
|
||||
"ManagementGroupName": "",
|
||||
"TimeGenerated [UTC]": "11/17/2020, 4:20:22.724 PM",
|
||||
"Computer": "",
|
||||
"RawData": "",
|
||||
"id_g": "2d801dca-28f0-11eb-90ff-0242ac130004",
|
||||
"timestamp_ms_s": 1605629758000,
|
||||
"to_s": "user2@mydomain.com",
|
||||
"from_s": "User B <userb@domainb.com>",
|
||||
"from_domain_s": "domainb.com",
|
||||
"attack_types_s": [
|
||||
"low_trust (Low trust domain)"
|
||||
],
|
||||
"Type": "agari_apdtc_log_CL",
|
||||
"_ResourceId": ""
|
||||
},
|
||||
{
|
||||
"TenantId": "27201ba9-a494-40b0-bca0-364028a854c5",
|
||||
"SourceSystem": "RestAPI",
|
||||
"MG": "",
|
||||
"ManagementGroupName": "",
|
||||
"TimeGenerated [UTC]": "11/17/2020, 3:35:21.972 PM",
|
||||
"Computer": "",
|
||||
"RawData": "",
|
||||
"id_g": "483cc29a-28ea-11eb-90ff-0242ac130004",
|
||||
"timestamp_ms_s": 1605627226000,
|
||||
"to_s": "user3@mydomain.com",
|
||||
"from_s": "User C <userc@domainc.com>",
|
||||
"from_domain_s": "domainc.com",
|
||||
"attack_types_s": [
|
||||
"low_trust (Low trust domain)"
|
||||
],
|
||||
"Type": "agari_apdtc_log_CL",
|
||||
"_ResourceId": ""
|
||||
}
|
||||
]
|
|
@ -0,0 +1,82 @@
|
|||
[
|
||||
{
|
||||
"TenantId": "27201ba9-a494-40b0-bca0-364028a854c5",
|
||||
"SourceSystem": "RestAPI",
|
||||
"MG": "",
|
||||
"ManagementGroupName": "",
|
||||
"TimeGenerated [UTC]": "11/16/2020, 8:40:20.842 PM",
|
||||
"Computer": "",
|
||||
"RawData": "",
|
||||
"new_dmarc_record_s": "v=DMARC1; p=reject; fo=1; ri=3600; rua=mailto:rua@domain.com; ruf=mailto:ruf@domain.com",
|
||||
"old_spf_tree_domain_s": "",
|
||||
"old_spf_tree_record_s": "",
|
||||
"old_dmarc_record_s": "v=DMARC1; p=reject; fo=1; ri=3600; rua=mailto:rua@domain.com; ruf=mailto:ruf@domain.com",
|
||||
"top_hosts_s": "",
|
||||
"top_subjects_s": "",
|
||||
"top_uris_s": "",
|
||||
"links_failure_stats_by_subject_s": "",
|
||||
"links_failure_stats_by_ip_s": "",
|
||||
"old_spf_tree_s": "",
|
||||
"new_spf_tree_domain_s": "",
|
||||
"new_spf_tree_record_s": "",
|
||||
"spf_errors_s": "",
|
||||
"alert_data_s": "",
|
||||
"recent_messages_s": "",
|
||||
"recent_start_ts_t [UTC]": "1/1/1970, 12:00:00.000 AM",
|
||||
"id_d": 10142058,
|
||||
"alert_type_s": "dmarc_record_changed",
|
||||
"resolved_at_t [UTC]": "11/16/2020, 8:36:15.782 PM",
|
||||
"created_at_t [UTC]": "11/16/2020, 8:36:15.783 PM",
|
||||
"updated_at_t [UTC]": "11/16/2020, 8:36:15.783 PM",
|
||||
"summary_s": "The DMARC record for domain.com has changed.",
|
||||
"domain_s": "domain.com",
|
||||
"Type": "agari_bpalerts_log_CL",
|
||||
"_ResourceId": ""
|
||||
},
|
||||
{
|
||||
"TenantId": "27201ba9-a494-40b0-bca0-364028a854c5",
|
||||
"SourceSystem": "RestAPI",
|
||||
"MG": "",
|
||||
"ManagementGroupName": "",
|
||||
"TimeGenerated [UTC]": "11/11/2020, 7:25:03.210 PM",
|
||||
"Computer": "",
|
||||
"RawData": "",
|
||||
"new_dmarc_record_s": "",
|
||||
"old_spf_tree_domain_s": "",
|
||||
"old_spf_tree_record_s": "",
|
||||
"old_dmarc_record_s": "",
|
||||
"top_hosts_s": "",
|
||||
"top_subjects_s": "",
|
||||
"top_uris_s": "",
|
||||
"links_failure_stats_by_subject_s": "",
|
||||
"links_failure_stats_by_ip_s": "",
|
||||
"old_spf_tree_s": "",
|
||||
"new_spf_tree_domain_s": "",
|
||||
"new_spf_tree_record_s": "",
|
||||
"spf_errors_s": "",
|
||||
"alert_data_s": "",
|
||||
"recent_messages_s": [
|
||||
{
|
||||
"subject": "subject",
|
||||
"hdr_from": "from.domain.com",
|
||||
"from": "\"Someone\" <no-reply@domain.com>",
|
||||
"count": 1,
|
||||
"start_ts": "2020-11-11T18:14:25Z",
|
||||
"end_ts": "2020-11-11T18:14:25Z",
|
||||
"threat_message_ids": "2070332012",
|
||||
"brand_identifiers": "",
|
||||
"failure_samples_link": "https://smaple.com"
|
||||
}
|
||||
],
|
||||
"recent_start_ts_t [UTC]": "11/11/2020, 6:14:25.000 PM",
|
||||
"id_d": 10122376,
|
||||
"alert_type_s": "brand_spoofing",
|
||||
"resolved_at_t [UTC]": "1/1/1970, 12:00:00.000 AM",
|
||||
"created_at_t [UTC]": "11/11/2020, 7:23:14.608 PM",
|
||||
"updated_at_t [UTC]": "11/11/2020, 7:23:14.608 PM",
|
||||
"summary_s": "domain was detected spoofing your brand",
|
||||
"domain_s": "",
|
||||
"Type": "agari_bpalerts_log_CL",
|
||||
"_ResourceId": ""
|
||||
}
|
||||
]
|
Загрузка…
Ссылка в новой задаче