Merge pull request #2939 from NikitaGrunskyHolm/holmsecurity

Files to deploy azure function
This commit is contained in:
v-jayakal 2021-10-26 23:30:00 -07:00 коммит произвёл GitHub
Родитель 93d6372ee7 d2adf64ce6
Коммит 149427e1aa
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
12 изменённых файлов: 3669 добавлений и 0 удалений

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

@ -0,0 +1,13 @@
{
"Name": "net_assets_CL",
"Properties": [
{
"Name": "ip",
"Type": "String"
},
{
"Name": "severity",
"Type": "String"
}
]
}

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

@ -0,0 +1,13 @@
{
"Name": "web_assets_CL",
"Properties": [
{
"Name": "uri",
"Type": "String"
},
{
"Name": "severity",
"Type": "String"
}
]
}

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

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

@ -0,0 +1,90 @@
[
{
"uuid": "7e05288b-d153-437b-a148-f735f47a796d",
"severity": "info"
},
{
"uuid": "868a79da-4df1-4a6d-8589-a198450dc5e1",
"severity": "info"
},
{
"uuid": "4230782c-9d64-41b6-8753-435bba6626f2",
"severity": "info"
},
{
"uuid": "abb7b4bf-d1bc-4a62-93e9-fde0db578d0d",
"severity": "info"
},
{
"uuid": "bef4fad8-380b-4435-8c3f-fe78d5864877",
"severity": "info"
},
{
"uuid": "fcfd2ec4-dae8-404f-ab64-a7798809af55",
"severity": "info"
},
{
"uuid": "7e05288b-d153-437b-a148-f735f47a796d",
"severity": "low"
},
{
"uuid": "868a79da-4df1-4a6d-8589-a198450dc5e1",
"severity": "low"
},
{
"uuid": "4230782c-9d64-41b6-8753-435bba6626f2",
"severity": "low"
},
{
"uuid": "abb7b4bf-d1bc-4a62-93e9-fde0db578d0d",
"severity": "low"
},
{
"uuid": "bef4fad8-380b-4435-8c3f-fe78d5864877",
"severity": "low"
},
{
"uuid": "fcfd2ec4-dae8-404f-ab64-a7798809af55",
"severity": "low"
},
{
"uuid": "7e05288b-d153-437b-a148-f735f47a796d",
"severity": "high"
},
{
"uuid": "868a79da-4df1-4a6d-8589-a198450dc5e1",
"severity": "high"
},
{
"uuid": "4230782c-9d64-41b6-8753-435bba6626f2",
"severity": "high"
},
{
"uuid": "bef4fad8-380b-4435-8c3f-fe78d5864877",
"severity": "high"
},
{
"uuid": "7e05288b-d153-437b-a148-f735f47a796d",
"severity": "medium"
},
{
"uuid": "868a79da-4df1-4a6d-8589-a198450dc5e1",
"severity": "medium"
},
{
"uuid": "4230782c-9d64-41b6-8753-435bba6626f2",
"severity": "medium"
},
{
"uuid": "abb7b4bf-d1bc-4a62-93e9-fde0db578d0d",
"severity": "medium"
},
{
"uuid": "bef4fad8-380b-4435-8c3f-fe78d5864877",
"severity": "medium"
},
{
"uuid": "fcfd2ec4-dae8-404f-ab64-a7798809af55",
"severity": "medium"
}
]

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

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

@ -0,0 +1,125 @@
import json
import datetime
import logging
import requests
import hashlib
import hmac
import base64
import os
import re
import azure.functions as func
SEVERITY_LIST = ("info", "low", "high", "medium", "critical")
TOKEN = os.environ['token']
CUSTOMER_ID = os.environ['workspaceId']
SHARED_KEY = os.environ['workspaceKey']
BASE_URL = os.environ['api_url']
logAnalyticsUri = os.environ.get('logAnalyticsUri')
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.")
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).encode('utf-8')
decoded_key = base64.b64decode(shared_key)
encoded_hash = base64.b64encode(hmac.new(decoded_key, bytes_to_hash, digestmod=hashlib.sha256).digest())
authorization = "SharedKey {}:{}".format(customer_id,encoded_hash)
return authorization
def post_data(customer_id, shared_key, body, log_type):
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
}
try:
response = requests.post(uri, data=body, headers=headers)
except Exception as err:
print("Error during sending logs to Azure Sentinel: {}".format(err))
else:
if (response.status_code >= 200 and response.status_code <= 299):
print("logs have been successfully sent to Azure Sentinel.")
else:
print("Error during sending logs to Azure Sentinel. Response code: {}".format(response.status_code))
def send_net_assets():
for severity in SEVERITY_LIST:
response = requests.request(
'GET',
url=BASE_URL + f"/net-assets?severity={severity}&limit=600",
headers={
"Authorization": f"Token {TOKEN}", "Content-Type": "application/json"
}
)
json_response = response.json()
json_data = []
for result in json_response.get("results"):
ip = result.get("ip")
json_data.append(
{
"ip": ip,
"severity": severity,
}
)
body = json.dumps(json_data)
post_data(CUSTOMER_ID, SHARED_KEY, body, "net_assets")
def send_web_assets():
for severity in SEVERITY_LIST:
response = requests.request(
'GET',
url=BASE_URL + f"/web-assets?severity={severity}&limit=600",
headers={
"Authorization": f"Token {TOKEN}", "Content-Type": "application/json"
}
)
json_response = response.json()
json_data = []
for result in json_response.get("results"):
uuid = result.get("uuid")
json_data.append(
{
"uuid": uuid,
"severity": severity,
}
)
body = json.dumps(json_data)
post_data(CUSTOMER_ID, SHARED_KEY, body, "web_assets")
def main(mytimer: func.TimerRequest) -> None:
utc_timestamp = datetime.datetime.utcnow().replace(
tzinfo=datetime.timezone.utc).isoformat()
if mytimer.past_due:
logging.info('The timer is past due!')
send_net_assets()
send_web_assets()
logging.info('Python timer trigger function ran at %s', utc_timestamp)

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

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

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

@ -0,0 +1,149 @@
{
"id": "HolmSecurityAssets",
"title": "Holm Security Asset Data",
"publisher": "Holm Security",
"descriptionMarkdown": "The connector provides the capability to poll data from Holm Security Center into Azure Sentinel.",
"graphQueries": [
{
"metricName": "Total data received",
"legend": "net_assets_CL",
"baseQuery": "net_assets_CL"
},
{
"metricName": "Total data received",
"legend": "web_assets_CL",
"baseQuery": "web_assets_CL"
}
],
"sampleQueries": [
{
"description" : "All low net assets",
"query": "net_assets_Cl\n | where severity_s == 'low'"
},
{
"description" : "All low web assets",
"query": "web_assets_Cl\n | where severity_s == 'low'"
}
],
"dataTypes": [
{
"name": "net_assets_CL",
"lastDataReceivedQuery": "net_assets_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
},
{
"name": "web_assets_CL",
"lastDataReceivedQuery": "web_assets_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
}
],
"connectivityCriterias": [
{
"type": "IsConnectedQuery",
"value": [
"net_assets_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(30d)"
]
},
{
"type": "IsConnectedQuery",
"value": [
"web_assets_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 on the workspace 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": "Holm Security API Token",
"description": "Holm Security API Token is required. [Holm Security API Token](https://support.holmsecurity.com/hc/en-us)"
}
]
},
"instructionSteps": [
{
"title": "",
"description": ">**NOTE:** This connector uses Azure Functions to connect to a Holm Security Assets 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": "",
"description": "**STEP 1 - Configuration steps for the Holm Security API**\n\n [Follow these instructions](https://support.holmsecurity.com/hc/en-us/articles/360027651591-How-do-I-set-up-an-API-token-) to create an API authentication token."
},
{
"title": "",
"description": "**STEP 2 - Use the below deployment option to deploy the connector and the associated Azure Function**\n\n>**IMPORTANT:** Before deploying the Holm Security connector, have the Workspace ID and Workspace Primary Key (can be copied from the following), as well as the Holm Security API authorization Token, readily available.",
"instructions": [
{
"parameters": {
"fillWith": [
"WorkspaceId"
],
"label": "Workspace ID"
},
"type": "CopyableLabel"
},
{
"parameters": {
"fillWith": [
"PrimaryKey"
],
"label": "Primary Key"
},
"type": "CopyableLabel"
}
]
},
{
"title": "Azure Resource Manager (ARM) Template Deployment",
"description": "**Option 1 - Azure Resource Manager (ARM) Template**\n\nUse this method for automated deployment of the Holm Security connector.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinel-holmsecurityassets-azuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the **Workspace ID**, **Workspace Key**, **API Username**, **API Password**, 'and/or Other required fields'. \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."
}
],
"metadata": {
"id": "Unique Identifier (GUID) used to identify dependencies and content from solutions or community.",
"version": "1.0.0",
"kind": "dataConnector",
"source": {
"kind": "community",
"name": "Holm Security"
},
"author": {
"name": "Holm Security"
},
"support": {
"tier": "developer",
"name": "Holm Security",
"link":"https://support.holmsecurity.com/hc/en-us"
}
}
}

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

@ -0,0 +1,201 @@
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"FunctionName": {
"defaultValue": "HolmSec",
"minLength": 1,
"maxLength": 11,
"type": "String"
},
"WorkspaceID": {
"defaultValue": "<workspaceID>",
"type": "String"
},
"WorkspaceKey": {
"defaultValue": "<workspaceKey>",
"type": "String"
},
"API Token": {
"defaultValue": "<Holm Security Token>",
"type": "String"
},
"API URL": {
"defaultValue": "<URL address to Holm Security Center API>",
"type": "String"
}
},
"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": "2015-05-01",
"name": "[variables('FunctionName')]",
"location": "[resourceGroup().location]",
"kind": "web",
"properties": {
"Application_Type": "web",
"ApplicationId": "[variables('FunctionName')]"
}
},
{
"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": [
{
"type": "config",
"apiVersion": "2018-11-01",
"name": "appsettings",
"dependsOn": [
"[concat('Microsoft.Web/sites/', variables('FunctionName'))]"
],
"properties": {
"FUNCTIONS_EXTENSION_VERSION": "~3",
"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')))]",
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[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')))]",
"WEBSITE_CONTENTSHARE": "[toLower(variables('FunctionName'))]",
"workspaceId": "[parameters('WorkspaceID')]",
"workspaceKey": "[parameters('WorkspaceKey')]",
"logAnalyticsUri": "[variables('LogAnaltyicsUri')]",
"token": "[parameters('API Token')]",
"api_url": "[parameters('API URL')]",
"WEBSITE_RUN_FROM_PACKAGE": "https://aka.ms/sentinel-holmsecurityassets-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
}
}
]
}

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

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

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

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

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

@ -0,0 +1,2 @@
azure-functions
requests