diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/README.md b/Solutions/RubrikSecurityCloud/Data Connectors/README.md deleted file mode 100644 index e3f3f72f5ae..00000000000 --- a/Solutions/RubrikSecurityCloud/Data Connectors/README.md +++ /dev/null @@ -1,87 +0,0 @@ -# Rubrik Security Cloud data connector - -## Introduction - -This folder contains the Azure function http trigger code for 3 azure functions of Rubrik's Microsoft Sentinel connector. The connector will run when any of the events(Anomaly, Ransomware Investigation Analysis or ThreatHunt) data will be pushed via webhook and ingest the triggered event data into the respective Microsoft Sentinel logs custom table `Rubrik_Anomaly_Data_CL`,`Rubrik_Ransomware_Data_CL` and `Rubrik_ThreatHunt_Data_CL`. - -## Description - -The Rubrik Security Cloud data connector enables security operations teams to integrate insights from Rubrik’s Data Observability services into Microsoft Sentinel. The insights include identification of anomalous filesystem behavior associated with ransomware and mass deletion, assess the blast radius of a ransomware attack, and sensitive data operators to prioritize and more rapidly investigate potential incidents. - -## Folders - -1. `RubrikWebhookEventsApp/` - This contains the package, requirements, ARM JSON file, connector page template JSON, and other dependencies. -2. `RubrikAnomalyEvent/` - This contains the Azure function source code to receive Anomaly event data via rubrik webhook and post into Microsoft Sentinel along with sample data. -3. `RubrikRansomwareAnalysisEvent/` - This contains the Azure function source code to receive Ransomware Analysis event data via rubrik webhook and post into Microsoft Sentinel along with sample data. -4. `RubrikThreatHuntEvent/` - This contains the Azure function source code to receive ThreatHunt event data via rubrik webhook and post into Microsoft Sentinel along with sample data. - - -## Installing for the users - -After the solution is published, we can find the connector in the connector gallery of Microsoft Sentinel among other connectors in Data connectors section of Microsoft Sentinel. - -i. Go to Microsoft Sentinel -> Data Connectors - -ii. Click on the SecurityScorecard connector, connector page will open. - -iii. Click on the blue `Deploy to Azure` button. - - -It will lead to a custom deployment page where after user need to select **Subscription**, **Resource Group** and **Location**. -And need to enter below information to configure Rubrik data connector for Microsoft Sentinel. -```Function Name - Workspace ID - Workspace Key - Anomalies_table_name - RansomwareAnalysis_table_name - ThreatHunts_table_name -``` - -## **Post Deployment Steps** - -* Steps to Configure the webhook using function url. - -1. Note down the Function App URL and Function access key - -2. Follow the Rubrik User Guide instructions to [Add a Webhook](https://docs.rubrik.com/en-us/saas/saas/common/adding_webhook.html) to begin receiving event information related to Ransomware Anomalies. - - Select the Generic as the webhook Provider - - This will use CEF formatted event information - - Enter the Function App URL as the webhook URL endpoint for the Rubrik Solution for Microsoft Sentinel - - Select the Custom Authentication option - - Enter x-function-key as the HTTP header - - Enter the Function access key as the HTTP value -Note: if you change this function access key in Microsoft Sentinel in the future you will need to update this webhook configuration -3. Select the following Event types: - - Anomaly - - Ransomware Investigation Analysis - - Threat Hunt -4. Select the following severity levels: - - Critical - - Warning - - Informational - - -The connector should ingest the data into the logs when it receives data from webhook via Http request. - - -## Installing for testing - - -i. Log in to Azure portal using the URL - [https://preview.portal.azure.com/?feature.BringYourOwnConnector=true](https://preview.portal.azure.com/?feature.BringYourOwnConnector=true). - -ii. Go to Microsoft Sentinel -> Data Connectors - -iii. Click the “import” button at the top and select the json file `RubrikWebhookEvents_API_FunctionApp.json` downloaded on your local machine from Github. - -iv. This will load the connector page and rest of the process will be same as the Installing for users guideline above. - - -Each invocation and its logs of the function can be seen in Function App service of Azure, available in the Azure Portal outside of Microsoft Sentinel. - -i. Go to Function App and click on the function which you have deployed, identified with the given name at the deployment stage. - -ii. Go to Functions -> RubrikAnomalyEvent -> Monitor - -iii. By clicking on invocation time, you can see all the logs for that run. - -**Note: Furthermore we can check logs in Application Insights of the given function in detail if needed. We can search the logs by operation ID in Transaction search section.** diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/__init__.py b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/__init__.py new file mode 100644 index 00000000000..1bd28fa7f0d --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/__init__.py @@ -0,0 +1,45 @@ +"""This __init__ file will be called by Orchastrator function to ingest data in Sentinel.""" +import inspect +import time +from shared_code.logger import applogger +from shared_code.consts import LOGS_STARTS_WITH +from shared_code.rubrik_exception import RubrikException +from .rubrik import Rubrik + + +def main(name) -> str: + """Start Execution of Activity Function. + + Args: + name (dict): data received via Rubrik Webhook. + + Returns: + str: status message of activity function. + """ + __method_name = inspect.currentframe().f_code.co_name + try: + applogger.info( + "{}(method={}) Activity function called!".format( + LOGS_STARTS_WITH, __method_name + ) + ) + start = time.time() + rubrik_obj = Rubrik() + rubrik_obj.post_data_to_sentinel(name) + end = time.time() + applogger.info( + "{}(method={}) time taken for data ingestion is {} sec".format( + LOGS_STARTS_WITH, __method_name, int(end - start) + ) + ) + applogger.info( + "{}(method={}) Activity function Completed!".format( + LOGS_STARTS_WITH, __method_name + ) + ) + except RubrikException as err: + return err + except Exception as err: + applogger.error("{}(method={}) {}".format(LOGS_STARTS_WITH, __method_name, err)) + return err + return "Data Posted successfully to {}".format(name.get("log_type")) diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/function.json b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/function.json new file mode 100644 index 00000000000..97685a81bbc --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/function.json @@ -0,0 +1,10 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "name", + "type": "activityTrigger", + "direction": "in" + } + ] +} \ No newline at end of file diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/rubrik.py b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/rubrik.py new file mode 100644 index 00000000000..812bb861976 --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/rubrik.py @@ -0,0 +1,88 @@ +"""This file contains implementation to ingest Dataminr RTAP alert data into sentinel.""" +import inspect +from .sentinel import MicrosoftSentinel +from shared_code.consts import ( + LOGS_STARTS_WITH, + ANOMALY_LOG_TYPE, + RANSOMWARE_LOG_TYPE, + THREATHUNT_LOG_TYPE, +) +from shared_code.rubrik_exception import RubrikException +from shared_code.logger import applogger + + +class Rubrik: + """This class contains methods to get data from request body pushed via Rubrik Webhook and ingest into Sentinel.""" + + def __init__(self) -> None: + """Initialize instance variables for class.""" + self.logs_starts_with = LOGS_STARTS_WITH + self.microsoftsentinel = MicrosoftSentinel() + self.error_logs = "{}(method={}) {}" + self.check_environment_var_existance() + + def check_environment_var_existance(self): + """To verify that all required environment variables exist. + + Raises: + RubrikException: raise exception if any of the required environment variable is not set. + """ + __method_name = inspect.currentframe().f_code.co_name + env_var = [ + {"Anomalies_table_name": ANOMALY_LOG_TYPE}, + {"RansomwareAnalysis_table_name": RANSOMWARE_LOG_TYPE}, + {"ThreatHunts_table_name": THREATHUNT_LOG_TYPE}, + ] + try: + applogger.debug( + "{}(method={}) Checking environment variables are exist or not.".format( + self.logs_starts_with, __method_name + ) + ) + for i in env_var: + key, val = next(iter(i.items())) + if val is None: + raise RubrikException( + "{} is not set in the environment please set the environment variable.".format( + key + ) + ) + applogger.debug( + "{}(method={}) All custom environment variables exist.".format( + self.logs_starts_with, __method_name + ) + ) + except RubrikException as err: + applogger.error( + "{}".format( + self.error_logs.format(self.logs_starts_with, __method_name, err) + ) + ) + raise RubrikException(err) + except Exception as err: + applogger.error( + "{}".format( + self.error_logs.format(self.logs_starts_with, __method_name, err) + ) + ) + raise RubrikException(err) + + def post_data_to_sentinel(self, data): + """To post data received via Rubrik Webhook into Sentinel. + + Args: + data (dict): data received via Rubrik Webhook. + """ + __method_name = inspect.currentframe().f_code.co_name + try: + sentinel_obj = MicrosoftSentinel() + body = data.get("data") + log_type = data.get("log_type") + sentinel_obj.post_data(body, log_type) + except Exception as err: + applogger.error( + "{}".format( + self.error_logs.format(self.logs_starts_with, __method_name, err) + ) + ) + raise RubrikException(err) diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/AzureSentinel.py b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/sentinel.py similarity index 67% rename from Solutions/RubrikSecurityCloud/Data Connectors/shared_code/AzureSentinel.py rename to Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/sentinel.py index d33bbe2861a..93287166268 100644 --- a/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/AzureSentinel.py +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikActivity/sentinel.py @@ -3,18 +3,21 @@ import datetime import hashlib import hmac -import logging -import os import requests -from .RubrikException import RubrikException +from ..shared_code.consts import LOGS_STARTS_WITH, WORKSPACE_ID, WORKSPACE_KEY +from ..shared_code.logger import applogger +from ..shared_code.rubrik_exception import RubrikException -customer_id = os.environ.get("WorkspaceID") -shared_key = os.environ.get("WorkspaceKey") - -class AzureSentinel: +class MicrosoftSentinel: """AzureSentinel class is used to post data into log Analytics workspace.""" + def __init__(self) -> None: + """Intialize instance variables for MicrosoftSentinel class.""" + self.logs_start_with = "{}(MicrosoftSentinel)".format(LOGS_STARTS_WITH) + self.customer_id = WORKSPACE_ID + self.shared_key = WORKSPACE_KEY + def build_signature( self, date, @@ -37,11 +40,11 @@ def build_signature( + resource ) bytes_to_hash = bytes(string_to_hash, encoding="utf-8") - decoded_key = base64.b64decode(shared_key) + decoded_key = base64.b64decode(self.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) + authorization = "SharedKey {}:{}".format(self.customer_id, encoded_hash) return authorization # Build and send a request to the POST API @@ -69,13 +72,13 @@ def post_data(self, body, log_type): resource, ) except Exception as err: - logging.error("Error occurred: {}".format(err)) + applogger.error("{} Error occurred: {}".format(self.logs_start_with, err)) raise RubrikException( "Error while generating signature for posting data into log analytics." ) uri = ( "https://" - + customer_id + + self.customer_id + ".ods.opinsights.azure.com" + resource + "?api-version=2016-04-01" @@ -90,20 +93,27 @@ def post_data(self, body, log_type): try: response = requests.post(uri, data=body, headers=headers) if response.status_code >= 200 and response.status_code <= 299: - logging.info(response.status_code) - logging.info("Accepted: Data Posted Successfully to microsoft sentinel.") + applogger.info( + "{} Data posted successfully to {} table in Log Analytics Workspace.".format( + self.logs_start_with, log_type + ) + ) else: + applogger.info( + "Response code: {} from posting data to log analytics.\nError: {}".format( + response.status_code, response.content + ) + ) raise RubrikException( "Response code: {} from posting data to log analytics.\nError: {}".format( response.status_code, response.content ) ) - except RubrikException as err: - logging.error(err) + except RubrikException as error: + applogger.error("{} Error:{}".format(self.logs_start_with, error)) raise RubrikException( "RubrikException: Error while posting data to sentinel." ) except Exception as error: - logging.error(error) - raise RubrikException("Exception: Error while posting data to sentinel.") - return response.status_code + applogger.error("{} Error:{}".format(self.logs_start_with, error)) + raise RubrikException() diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyEvent/__init__.py b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyEvent/__init__.py deleted file mode 100644 index 08cc4aef75c..00000000000 --- a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyEvent/__init__.py +++ /dev/null @@ -1,67 +0,0 @@ -"""This __init__ file will be called once data is generated in webhook and it creates trigger.""" -import json -import logging -import os -from datetime import datetime - -from ..shared_code.AzureSentinel import AzureSentinel -from ..shared_code.RubrikException import RubrikException - -import azure.functions as func - -# fetch data from os environment -sentinel_log_type = os.environ.get("Anomalies_table_name") - - -def main(request: func.HttpRequest) -> func.HttpResponse: - """ - Start the execution. - - Args: - request (func.HttpRequest): To get data from request body pushed by webhook - - Returns: - func.HttpResponse: Status of Http request process (successful/failed). - """ - logging.info("RubrikAnomalyEvent({}): Start processing...".format(datetime.now())) - try: - logging.info("({}): Start getting data.".format(datetime.now())) - webhook_data = request.get_json() - logging.info("({}): Got data Successfully.".format(datetime.now())) - except ValueError as value_error: - logging.error("Value Error in RubrikAnomalyEvent: {}".format(value_error)) - return func.HttpResponse( - "Value Error - RubrikAnomalyEvent: {}".format(value_error) - ) - except Exception as error: - logging.error("Error in RubrikAnomalyEvent: {}".format(error)) - return func.HttpResponse("Error in RubrikAnomalyEvent: {}".format(error)) - else: - if webhook_data: - body = json.dumps(webhook_data) - logging.info("Got data of Anomaly event via webhook.") - try: - logging.info( - "({}) Try to post the webhook data from AnomalyEvent.".format( - datetime.now() - ) - ) - azuresentinel = AzureSentinel() - status_code = azuresentinel.post_data( - body, - sentinel_log_type, - ) - except RubrikException as error: - logging.error(error) - return func.HttpResponse(error) - else: - if status_code >= 200 and status_code <= 299: - return func.HttpResponse( - "Data posted successfully to log analytics from RubrikAnomalyEvent." - ) - return func.HttpResponse( - "Failed to post data from RubrikAnomalyEvent into sentinel." - ) - else: - logging.info("No required data found.") - return func.HttpResponse("No required data found for this trigger.") diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyEvent/function.json b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyEvent/function.json deleted file mode 100644 index ea6e3f1c11c..00000000000 --- a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyEvent/function.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "scriptFile": "__init__.py", - "bindings": [ - { - "authLevel": "function", - "type": "httpTrigger", - "direction": "in", - "name": "request", - "methods": [ - "get", - "post" - ], - "webHookType": "genericJson" - }, - { - "type": "http", - "direction": "out", - "name": "$return" - } - ] -} diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyOrchestrator/__init__.py b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyOrchestrator/__init__.py new file mode 100644 index 00000000000..225c85297c9 --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyOrchestrator/__init__.py @@ -0,0 +1,27 @@ +"""This __init__ file will be called by Http Starter function to pass the Anomaly data to activity function.""" +import azure.durable_functions as df +from shared_code.consts import ANOMALY_LOG_TYPE, LOGS_STARTS_WITH +from shared_code.logger import applogger + + +def orchestrator_function(context: df.DurableOrchestrationContext): + """Get Anomaly data from durable orchestration context and schedule an activity for execution. + + Args: + context (df.DurableOrchestrationContext): Context of the durable orchestration execution. + + Returns: + str: result of Activity function + """ + applogger.debug("{} AnomalyOrchestrator function called!".format(LOGS_STARTS_WITH)) + json_data = context.get_input() + result1 = yield context.call_activity( + "RubrikActivity", {"data": json_data, "log_type": ANOMALY_LOG_TYPE} + ) + applogger.debug( + "{} AnomalyOrchestrator function completed!".format(LOGS_STARTS_WITH) + ) + return result1 + + +main = df.Orchestrator.create(orchestrator_function) diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyOrchestrator/function.json b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyOrchestrator/function.json new file mode 100644 index 00000000000..82fabb9a853 --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikAnomalyOrchestrator/function.json @@ -0,0 +1,10 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "context", + "type": "orchestrationTrigger", + "direction": "in" + } + ] +} \ No newline at end of file diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikConnector.zip b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikConnector.zip deleted file mode 100644 index 6ace0197e25..00000000000 Binary files a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikConnector.zip and /dev/null differ diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikHttpStarter/__init__.py b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikHttpStarter/__init__.py new file mode 100644 index 00000000000..18e3f5265d9 --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikHttpStarter/__init__.py @@ -0,0 +1,83 @@ +"""This __init__ file will be called once data is generated in webhook and it creates trigger.""" +import inspect +import json +import azure.functions as func +import azure.durable_functions as df +from shared_code.consts import LOGS_STARTS_WITH +from shared_code.logger import applogger +from shared_code.rubrik_exception import RubrikException + + +def get_data_from_request_body(request): + """Get data from request body. + + Args: + request (func.HttpRequest): Azure function HttpRequest class object + + Raises: + RubrikException: raises when an error occurs. + """ + __method_name = inspect.currentframe().f_code.co_name + try: + data = request.get_json() + json_data = json.dumps(data) + return json_data + except ValueError as value_error: + applogger.error( + "{}(method={}) {}".format(LOGS_STARTS_WITH, __method_name, value_error) + ) + raise RubrikException(value_error) + except Exception as err: + applogger.error("{}(method={}) {}".format(LOGS_STARTS_WITH, __method_name, err)) + raise RubrikException(err) + + +async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse: + """ + Start the execution. + + Args: + req (func.HttpRequest): To get data from request body pushed by webhook + + Returns: + func.HttpResponse: Status of Http request process (successful/failed). + """ + __method_name = inspect.currentframe().f_code.co_name + try: + applogger.debug("{} HttpStarter Function Called.".format(LOGS_STARTS_WITH)) + data = get_data_from_request_body(req) + if data: + client = df.DurableOrchestrationClient(starter) + instance_id = await client.start_new( + req.route_params["functionName"], client_input=data + ) + applogger.info( + "{} Started orchestration with ID = '{}'.".format( + LOGS_STARTS_WITH, instance_id + ) + ) + body = "Data Received successfully via Rubrik Webhook." + return func.HttpResponse( + body=body, + status_code=200, + headers={"Content-Length": str(len(body))}, + ) + else: + applogger.info( + "{}(method={})No required data found.".format( + LOGS_STARTS_WITH, __method_name + ) + ) + body = "No required data found." + return func.HttpResponse( + body=body, + status_code=202, + headers={"Content-Length": str(len(body))}, + ) + except RubrikException as err: + body = "Error: {}".format(err) + return func.HttpResponse( + body=body, + status_code=400, + headers={"Content-Length": str(len(body))}, + ) diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikHttpStarter/function.json b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikHttpStarter/function.json new file mode 100644 index 00000000000..e3619cfb5ad --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikHttpStarter/function.json @@ -0,0 +1,26 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "authLevel": "function", + "name": "req", + "type": "httpTrigger", + "direction": "in", + "route": "orchestrators/{functionName}", + "methods": [ + "post", + "get" + ] + }, + { + "name": "$return", + "type": "http", + "direction": "out" + }, + { + "name": "starter", + "type": "durableClient", + "direction": "in" + } + ] +} \ No newline at end of file diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareAnalysisEvent/__init__.py b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareAnalysisEvent/__init__.py deleted file mode 100644 index df8e9595660..00000000000 --- a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareAnalysisEvent/__init__.py +++ /dev/null @@ -1,75 +0,0 @@ -"""This __init__ file will be called once data is generated in webhook and it creates trigger.""" -import json -import logging -import os -from datetime import datetime - -from ..shared_code.AzureSentinel import AzureSentinel -from ..shared_code.RubrikException import RubrikException - -import azure.functions as func - -# fetch data from os environment -sentinel_log_type = os.environ.get("RansomwareAnalysis_table_name") - - -def main(request: func.HttpRequest) -> func.HttpResponse: - """ - Start the execution. - - Args: - request (func.HttpRequest): To get data from request body pushed - by webhook - - Returns: - func.HttpResponse: Status of Http request process (successful/failed). - """ - logging.info( - "RubrikRansomwareAnalysisEvent({}): Start processing...".format(datetime.now()) - ) - - try: - logging.info("({}): Start getting data.".format(datetime.now())) - webhook_data = request.get_json() - logging.info("({}): Got data Successfully.".format(datetime.now())) - except ValueError as value_error: - logging.error( - "Value Error in RubrikRansomwareAnalysisEvent: {}".format(value_error) - ) - return func.HttpResponse( - "Value Error - RubrikRansomwareAnalysisEvent: {}".format(value_error) - ) - except Exception as error: - logging.error("Error in RubrikRansomwareAnalysisEvent: {}".format(error)) - return func.HttpResponse( - "Error in RubrikRansomwareAnalysisEvent: {}".format(error) - ) - else: - if webhook_data: - body = json.dumps(webhook_data) - logging.info("Got data of RansomwareAnalysis event via webhook.") - try: - logging.info( - "({}) Try to post the webhook data from RansomwareAnalysisEvent.".format( - datetime.now() - ) - ) - azuresentinel = AzureSentinel() - status_code = azuresentinel.post_data( - body, - sentinel_log_type, - ) - except RubrikException as error: - logging.error(error) - return func.HttpResponse(error) - else: - if status_code >= 200 and status_code <= 299: - return func.HttpResponse( - "Data posted successfully to log analytics from RubrikRansomwareAnalysisEvent." - ) - return func.HttpResponse( - "Failed to post data from RubrikRansomwareAnalysis into sentinel." - ) - else: - logging.info("No required data found.") - return func.HttpResponse("No required data found for this trigger.") diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareAnalysisEvent/function.json b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareAnalysisEvent/function.json deleted file mode 100644 index ea6e3f1c11c..00000000000 --- a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareAnalysisEvent/function.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "scriptFile": "__init__.py", - "bindings": [ - { - "authLevel": "function", - "type": "httpTrigger", - "direction": "in", - "name": "request", - "methods": [ - "get", - "post" - ], - "webHookType": "genericJson" - }, - { - "type": "http", - "direction": "out", - "name": "$return" - } - ] -} diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareOrchestrator/__init__.py b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareOrchestrator/__init__.py new file mode 100644 index 00000000000..3dcd02232a5 --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareOrchestrator/__init__.py @@ -0,0 +1,29 @@ +"""This __init__ file will be called by Http Starter function to pass the Ransomware data to activity function.""" +import azure.durable_functions as df +from shared_code.consts import RANSOMWARE_LOG_TYPE, LOGS_STARTS_WITH +from shared_code.logger import applogger + + +def orchestrator_function(context: df.DurableOrchestrationContext): + """Get Ransomware data from durable orchestration context and schedule an activity for execution. + + Args: + context (df.DurableOrchestrationContext): Context of the durable orchestration execution. + + Returns: + str: result of Activity function + """ + applogger.debug( + "{} RansomwareOrchestrator function called!".format(LOGS_STARTS_WITH) + ) + json_data = context.get_input() + result1 = yield context.call_activity( + "RubrikActivity", {"data": json_data, "log_type": RANSOMWARE_LOG_TYPE} + ) + applogger.debug( + "{} RansomwareOrchestrator function completed!".format(LOGS_STARTS_WITH) + ) + return result1 + + +main = df.Orchestrator.create(orchestrator_function) diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareOrchestrator/function.json b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareOrchestrator/function.json new file mode 100644 index 00000000000..82fabb9a853 --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikRansomwareOrchestrator/function.json @@ -0,0 +1,10 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "context", + "type": "orchestrationTrigger", + "direction": "in" + } + ] +} \ No newline at end of file diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreatHuntEvent/__init__.py b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreatHuntEvent/__init__.py deleted file mode 100644 index 809f779e25d..00000000000 --- a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreatHuntEvent/__init__.py +++ /dev/null @@ -1,70 +0,0 @@ -"""This __init__ file will be called once data is generated in webhook and it creates trigger.""" -import json -import logging -import os -from datetime import datetime - -from ..shared_code.AzureSentinel import AzureSentinel -from ..shared_code.RubrikException import RubrikException - -import azure.functions as func - -# fetch data from os environment -sentinel_log_type = os.environ.get("ThreatHunts_table_name") - - -def main(request: func.HttpRequest) -> func.HttpResponse: - """ - Start the execution. - - Args: - request (func.HttpRequest): To get data from request body pushed by webhook - - Returns: - func.HttpResponse: Status of Http request process (successful/failed). - """ - logging.info( - "RubrikThreatHuntEvent({}): Start processing...".format(datetime.now()) - ) - - try: - logging.info("({}): Start getting data.".format(datetime.now())) - webhook_data = request.get_json() - logging.info("({}): Got data Successfully.".format(datetime.now())) - except ValueError as value_error: - logging.error("Value Error in RubrikThreatHuntEvent: {}".format(value_error)) - return func.HttpResponse( - "Value Error - RubrikThreatHuntEvent: {}".format(value_error) - ) - except Exception as error: - logging.error("Error in RubrikThreatHuntEvent: {}".format(error)) - return func.HttpResponse("Error in RubrikThreatHuntEvent: {}".format(error)) - else: - if webhook_data: - body = json.dumps(webhook_data) - logging.info("Got data of ThreatHunt event via webhook.") - try: - logging.info( - "({}) Try to post the webhook data from RubrikThreatHuntEvent.".format( - datetime.now() - ) - ) - azuresentinel = AzureSentinel() - status_code = azuresentinel.post_data( - body, - sentinel_log_type, - ) - except RubrikException as error: - logging.error(error) - return func.HttpResponse(error) - else: - if status_code >= 200 and status_code <= 299: - return func.HttpResponse( - "Data posted successfully to log analytics from RubrikThreatHuntEvent." - ) - return func.HttpResponse( - "Failed to post data from RubrikThreatHuntEvent into sentinel" - ) - else: - logging.info("No required data found.") - return func.HttpResponse("No required data found for this trigger.") diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreatHuntEvent/function.json b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreatHuntEvent/function.json deleted file mode 100644 index ea6e3f1c11c..00000000000 --- a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreatHuntEvent/function.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "scriptFile": "__init__.py", - "bindings": [ - { - "authLevel": "function", - "type": "httpTrigger", - "direction": "in", - "name": "request", - "methods": [ - "get", - "post" - ], - "webHookType": "genericJson" - }, - { - "type": "http", - "direction": "out", - "name": "$return" - } - ] -} diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreathuntOrchestrator/__init__.py b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreathuntOrchestrator/__init__.py new file mode 100644 index 00000000000..b8f31d04aec --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreathuntOrchestrator/__init__.py @@ -0,0 +1,29 @@ +"""This __init__ file will be called by Http Starter function to pass the ThreatHunt data to activity function.""" +import azure.durable_functions as df +from shared_code.consts import THREATHUNT_LOG_TYPE, LOGS_STARTS_WITH +from shared_code.logger import applogger + + +def orchestrator_function(context: df.DurableOrchestrationContext): + """Get ThreatHunt data from durable orchestration context and schedule an activity for execution. + + Args: + context (df.DurableOrchestrationContext): Context of the durable orchestration execution. + + Returns: + str: result of Activity function + """ + applogger.debug( + "{} ThreatHuntOrchestrator function called!".format(LOGS_STARTS_WITH) + ) + json_data = context.get_input() + result1 = yield context.call_activity( + "RubrikActivity", {"data": json_data, "log_type": THREATHUNT_LOG_TYPE} + ) + applogger.debug( + "{} ThreatHuntOrchestrator function completed!".format(LOGS_STARTS_WITH) + ) + return result1 + + +main = df.Orchestrator.create(orchestrator_function) diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreathuntOrchestrator/function.json b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreathuntOrchestrator/function.json new file mode 100644 index 00000000000..82fabb9a853 --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikThreathuntOrchestrator/function.json @@ -0,0 +1,10 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "name": "context", + "type": "orchestrationTrigger", + "direction": "in" + } + ] +} \ No newline at end of file diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikWebhookEvents.zip b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikWebhookEvents.zip new file mode 100644 index 00000000000..ca8377b4874 Binary files /dev/null and b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikWebhookEvents.zip differ diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikWebhookEvents_API_FunctionApp.json b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikWebhookEvents_FunctionApp.json similarity index 77% rename from Solutions/RubrikSecurityCloud/Data Connectors/RubrikWebhookEvents_API_FunctionApp.json rename to Solutions/RubrikSecurityCloud/Data Connectors/RubrikWebhookEvents_FunctionApp.json index 2f26292d391..c79b8167326 100644 --- a/Solutions/RubrikSecurityCloud/Data Connectors/RubrikWebhookEvents_API_FunctionApp.json +++ b/Solutions/RubrikSecurityCloud/Data Connectors/RubrikWebhookEvents_FunctionApp.json @@ -2,7 +2,7 @@ "id": "RubrikSecurityCloudAzureFunctions", "title": "Rubrik Security Cloud data connector", "publisher": "Rubrik, Inc", - "descriptionMarkdown": "The Rubrik Security Cloud data connector enables security operations teams to integrate insights from Rubrik’s Data Observability services into Microsoft Sentinel. The insights include identification of anomalous filesystem behavior associated with ransomware and mass deletion, assess the blast radius of a ransomware attack, and sensitive data operators to prioritize and more rapidly investigate potential incidents.", + "descriptionMarkdown": "The Rubrik Security Cloud data connector enables security operations teams to integrate insights from Rubrik's Data Observability services into Microsoft Sentinel. The insights include identification of anomalous filesystem behavior associated with ransomware and mass deletion, assess the blast radius of a ransomware attack, and sensitive data operators to prioritize and more rapidly investigate potential incidents.", "graphQueries": [ { "metricName": "Total Anomaly Event data received", @@ -137,7 +137,7 @@ }, { "title": "Option 1 - Azure Resource Manager (ARM) Template", - "description": "Use this method for automated deployment of the Rubrik connector.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinel-RubrikWebhookEvents-azuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the below information : \n\t\tFunction Name \n\t\tWorkspace ID \n\t\tWorkspace Key \n\t\tAnomalies_table_name \n\t\tRansomwareAnalysis_table_name \n\t\tThreatHunts_table_name \n \n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**. \n5. Click **Purchase** to deploy." + "description": "Use this method for automated deployment of the Rubrik connector.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinel-RubrikWebhookEvents-azuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the below information : \n\t\tFunction Name \n\t\tWorkspace ID \n\t\tWorkspace Key \n\t\tAnomalies_table_name \n\t\tRansomwareAnalysis_table_name \n\t\tThreatHunts_table_name\n\t\tLogLevel \n \n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**. \n5. Click **Purchase** to deploy." }, { "title": "Option 2 - Manual Deployment of Azure Functions", @@ -149,23 +149,23 @@ }, { "title": "", - "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 values (case-sensitive): \n\t\tWorkspaceID\n\t\tWorkspaceKey\n\t\tAnomalies_table_name\n\t\tRansomwareAnalysis_table_name\n\t\tThreatHunts_table_name\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://.ods.opinsights.azure.us. \n4. Once all application settings have been entered, click **Save**." + "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 values (case-sensitive): \n\t\tWorkspaceID\n\t\tWorkspaceKey\n\t\tAnomalies_table_name\n\t\tRansomwareAnalysis_table_name\n\t\tThreatHunts_table_name\n\t\tLogLevel\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://.ods.opinsights.azure.us. \n4. Once all application settings have been entered, click **Save**." }, { "title": "", "description": "**Post Deployment steps**\n\n" }, { - "title": "", - "description": "**STEP 1 - To get the Azure Function url**\n\n 1. Go to Azure function Overview page and Click on \"Functions\" in the left blade.\n 2. Click on the Rubrik defined function for the event.\n 3. Go to \"GetFunctionurl\" and copy the function url." + "title": "1) Get the Function app endpoint", + "description": "1. Go to Azure function Overview page and Click on **\"Functions\"** tab.\n2. Click on the function called **\"RubrikHttpStarter\"**.\n3. Go to **\"GetFunctionurl\"** and copy the function url." }, { - "title": "", - "description": "**STEP 2 - Follow the Rubrik User Guide instructions to [Add a Webhook](https://docs.rubrik.com/en-us/saas/saas/common/adding_webhook.html) to begin receiving event information related to Ransomware Anomalies.**\n\n 1. Select the Generic as the webhook Provider(This will use CEF formatted event information)\n 2. Enter the Function App URL as the webhook URL endpoint for the Rubrik Microsoft Sentinel Solution\n 3. Select the Custom Authentication option \n 4. Enter x-functions-key as the HTTP header \n 5. Enter the Function access key as the HTTP value(Note: if you change this function access key in Microsoft Sentinel in the future you will need to update this webhook configuration)\n 6. Select the following Event types: Anomaly, Ransomware Investigation Analysis, Threat Hunt \n 7. Select the following severity levels: Critical, Warning, Informational" + "title": "2) Add a webhook in RubrikSecurityCloud to send data to Microsoft Sentinel.", + "description": "Follow the Rubrik User Guide instructions to [Add a Webhook](https://docs.rubrik.com/en-us/saas/saas/common/adding_webhook.html) to begin receiving event information related to Ransomware Anomalies \n 1. Select the Generic as the webhook Provider(This will use CEF formatted event information)\n 2. Enter the URL part from copied Function-url as the webhook URL endpoint and replace **{functionname}** with **\"RubrikAnomalyOrchestrator\"**, for the Rubrik Microsoft Sentinel Solution \n 3. Select the Advanced or Custom Authentication option \n 4. Enter x-functions-key as the HTTP header \n 5. Enter the Function access key(value of code parameter from copied function-url) as the HTTP value(Note: if you change this function access key in Microsoft Sentinel in the future you will need to update this webhook configuration) \n 6. Select the EventType as Anomaly \n 7. Select the following severity levels: Critical, Warning, Informational \n 8. Repeat the same steps to add webhooks for Ransomware Investigation Analysis and Threat Hunt. \n\n NOTE: while adding webhooks for Ransomware Investigation Analysis and Threat Hunt, replace **{functionname}** with **\"RubrikRansomwareOrchestrator\"** and **\"RubrikThreatHuntOrchestrator\"** respectively in copied function-url." }, { "title": "", - "description": "*Now we are done with the rubrik Webhook configuration. Once the webhook events triggered , you should be able to see the Anomaly, Ransomware Analysis, ThreatHunt events from the Rubrik into respective LogAnalytics workspace table called \"Rubrik_Anomaly_Data_CL\", \"Rubrik_Ransomware_Data_CL\", \"Rubrik_ThreatHunt_Data_CL\".*\n\n" + "description": "*Now we are done with the rubrik Webhook configuration. Once the webhook events triggered , you should be able to see the Anomaly, Ransomware Investigation Analysis, Threat Hunt events from the Rubrik into respective LogAnalytics workspace table called \"Rubrik_Anomaly_Data_CL\", \"Rubrik_Ransomware_Data_CL\", \"Rubrik_ThreatHunt_Data_CL\".*\n\n" } ] } diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/azuredeploy_RubrikWebhookEvents_API_FunctionApp.json b/Solutions/RubrikSecurityCloud/Data Connectors/azuredeploy_Connector_RubrikWebhookEvents_AzureFunction.json similarity index 91% rename from Solutions/RubrikSecurityCloud/Data Connectors/azuredeploy_RubrikWebhookEvents_API_FunctionApp.json rename to Solutions/RubrikSecurityCloud/Data Connectors/azuredeploy_Connector_RubrikWebhookEvents_AzureFunction.json index 83ddbe46828..18937c93c7f 100644 --- a/Solutions/RubrikSecurityCloud/Data Connectors/azuredeploy_RubrikWebhookEvents_API_FunctionApp.json +++ b/Solutions/RubrikSecurityCloud/Data Connectors/azuredeploy_Connector_RubrikWebhookEvents_AzureFunction.json @@ -8,14 +8,6 @@ "maxLength": 11, "type": "string" }, - "WorkspaceID": { - "type": "securestring", - "defaultValue": "" - }, - "WorkspaceKey": { - "type": "securestring", - "defaultValue": "" - }, "Anomalies_table_name":{ "type": "string", "defaultValue": "Rubrik_Anomaly_Data_CL" @@ -27,6 +19,33 @@ "ThreatHunts_table_name":{ "type": "string", "defaultValue": "Rubrik_ThreatHunt_Data_CL" + }, + "WorkspaceID": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Enter Workspace ID of log analytics Workspace." + } + }, + "WorkspaceKey": { + "type": "securestring", + "minLength": 1, + "metadata": { + "description": "Enter Workspace Key of log analytics Workspace." + } + }, + "LogLevel": { + "type": "string", + "allowedValues": [ + "Debug", + "Info", + "Error", + "Warning" + ], + "defaultValue": "Info", + "metadata": { + "description": "Select log level or log severity value from Debug, Info, Error, Warning. By default it is set to Info." + } } }, "variables": { @@ -159,6 +178,7 @@ "RansomwareAnalysis_table_name": "[parameters('RansomwareAnalysis_table_name')]", "ThreatHunts_table_name": "[parameters('ThreatHunts_table_name')]", "Anomalies_table_name": "[parameters('Anomalies_table_name')]", + "LogLevel": "[parameters('LogLevel')]", "WEBSITE_RUN_FROM_PACKAGE": "https://aka.ms/sentinel-RubrikWebhookEvents-functionapp" } } diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/host.json b/Solutions/RubrikSecurityCloud/Data Connectors/host.json index 519fe11b518..bb92b402912 100644 --- a/Solutions/RubrikSecurityCloud/Data Connectors/host.json +++ b/Solutions/RubrikSecurityCloud/Data Connectors/host.json @@ -6,10 +6,23 @@ "isEnabled": true, "excludedTypes": "Request" } + }, + "logLevel": { + "default": "Trace", + "Host.Results": "Trace", + "Function": "Trace", + "Host.Aggregator": "Trace" } }, "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[3.*, 4.0.0)" + }, + "extensions": { + "durableTask": { + "storageProvider": { + "type": "AzureStorage" + } + } } -} +} \ No newline at end of file diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/proxies.json b/Solutions/RubrikSecurityCloud/Data Connectors/proxies.json index b385252f5ed..b20e0c7f210 100644 --- a/Solutions/RubrikSecurityCloud/Data Connectors/proxies.json +++ b/Solutions/RubrikSecurityCloud/Data Connectors/proxies.json @@ -1,4 +1,4 @@ { - "$schema": "http://json.schemastore.org/proxies", - "proxies": {} + "$schema": "http://json.schemastore.org/proxies", + "proxies": {} } diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/requirements.txt b/Solutions/RubrikSecurityCloud/Data Connectors/requirements.txt index 5d145b32137..eaa2c3a65a9 100644 --- a/Solutions/RubrikSecurityCloud/Data Connectors/requirements.txt +++ b/Solutions/RubrikSecurityCloud/Data Connectors/requirements.txt @@ -3,4 +3,5 @@ # Manually managing azure-functions-worker may cause unexpected issues azure-functions -requests +azure-functions-durable +requests \ No newline at end of file diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/__init__.py b/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/__init__.py deleted file mode 100644 index 6bf843002cc..00000000000 --- a/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""This is init file to consider shared_code as package.""" diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/consts.py b/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/consts.py new file mode 100644 index 00000000000..c3bf5967b4a --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/consts.py @@ -0,0 +1,11 @@ +"""This file contains all constants.""" +import os + +LOGS_STARTS_WITH = "Rubrik:" +DEFAULT_LOG_LEVEL = "INFO" +LOG_LEVEL = os.environ.get("LogLevel", "") +WORKSPACE_ID = os.environ.get("WorkspaceID") +WORKSPACE_KEY = os.environ.get("WorkspaceKey") +ANOMALY_LOG_TYPE = os.environ.get("Anomalies_table_name") +RANSOMWARE_LOG_TYPE = os.environ.get("RansomwareAnalysis_table_name") +THREATHUNT_LOG_TYPE = os.environ.get("ThreatHunts_table_name") diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/logger.py b/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/logger.py new file mode 100644 index 00000000000..a9c099e7668 --- /dev/null +++ b/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/logger.py @@ -0,0 +1,14 @@ +"""Handle the logger.""" +import logging +import sys +from .consts import DEFAULT_LOG_LEVEL, LOG_LEVEL + +default_log_level = DEFAULT_LOG_LEVEL +log_level = LOG_LEVEL +applogger = None +applogger = logging.getLogger("azure") +log_level = log_level.upper() +numeric_level = getattr(logging, log_level, default_log_level) +applogger.setLevel(level=numeric_level) +handler = logging.StreamHandler(stream=sys.stdout) +applogger.addHandler(handler) diff --git a/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/RubrikException.py b/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/rubrik_exception.py similarity index 83% rename from Solutions/RubrikSecurityCloud/Data Connectors/shared_code/RubrikException.py rename to Solutions/RubrikSecurityCloud/Data Connectors/shared_code/rubrik_exception.py index 14b164a9eca..4f5d5e3cc0a 100644 --- a/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/RubrikException.py +++ b/Solutions/RubrikSecurityCloud/Data Connectors/shared_code/rubrik_exception.py @@ -1,4 +1,4 @@ -"""This File contains custom Exception class foe Rubrik.""" +"""This File contains custom Exception class for Rubrik.""" class RubrikException(Exception): diff --git a/Solutions/RubrikSecurityCloud/Data/Solution_RubrikSecurityCloud.json b/Solutions/RubrikSecurityCloud/Data/Solution_RubrikSecurityCloud.json index ec254d80067..39cec9b4df7 100644 --- a/Solutions/RubrikSecurityCloud/Data/Solution_RubrikSecurityCloud.json +++ b/Solutions/RubrikSecurityCloud/Data/Solution_RubrikSecurityCloud.json @@ -15,10 +15,10 @@ "Playbooks/RubrikRansomwareDiscoveryAndVMRecovery/azuredeploy.json" ], "Data Connectors": [ - "Data Connectors/RubrikWebhookEvents_API_FunctionApp.json" + "Data Connectors/RubrikDataConnector/Rubrik_FunctionApp.json" ], - "BasePath": "C:\\Github\\Azure-Sentinel\\Solutions\\RubrikSecurityCloud", - "Version": "3.0.0", + "BasePath": "C:\\Azure-Sentinel\\Solutions\\RubrikSecurityCloud", + "Version": "3.1.0", "Metadata": "SolutionMetadata.json", "TemplateSpec": true, "Is1PConnector": false diff --git a/Solutions/RubrikSecurityCloud/Package/3.1.0.zip b/Solutions/RubrikSecurityCloud/Package/3.1.0.zip new file mode 100644 index 00000000000..348e56f851a Binary files /dev/null and b/Solutions/RubrikSecurityCloud/Package/3.1.0.zip differ diff --git a/Solutions/RubrikSecurityCloud/Package/mainTemplate.json b/Solutions/RubrikSecurityCloud/Package/mainTemplate.json index b023fae146f..8eebee5f7af 100644 --- a/Solutions/RubrikSecurityCloud/Package/mainTemplate.json +++ b/Solutions/RubrikSecurityCloud/Package/mainTemplate.json @@ -30,12 +30,12 @@ } }, "variables": { - "solutionId": "rubrik_inc.rubrik_sentinel", - "_solutionId": "[variables('solutionId')]", "email": "ben.meadowcroft@rubrik.com", "_email": "[variables('email')]", "_solutionName": "RubrikSecurityCloud", - "_solutionVersion": "3.0.0", + "_solutionVersion": "3.1.0", + "solutionId": "rubrik_inc.rubrik_sentinel", + "_solutionId": "[variables('solutionId')]", "RubrikCustomConnector": "RubrikCustomConnector", "_RubrikCustomConnector": "[variables('RubrikCustomConnector')]", "TemplateEmptyArray": "[json('[]')]", @@ -142,7 +142,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RubrikCustomConnector Playbook with template version 3.0.0", + "description": "RubrikCustomConnector Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion1')]", @@ -290,7 +290,7 @@ "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", + "contentSchemaVersion": "3.1.0", "contentId": "[variables('_playbookContentId1')]", "contentKind": "LogicAppsCustomConnector", "displayName": "RubrikCustomConnector", @@ -308,7 +308,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RubrikAnomalyAnalysis Playbook with template version 3.0.0", + "description": "RubrikAnomalyAnalysis Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion2')]", @@ -2629,7 +2629,7 @@ "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", + "contentSchemaVersion": "3.1.0", "contentId": "[variables('_playbookContentId2')]", "contentKind": "Playbook", "displayName": "RubrikAnomalyAnalysis", @@ -2647,7 +2647,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RubrikAnomalyIncidentResponse Playbook with template version 3.0.0", + "description": "RubrikAnomalyIncidentResponse Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion3')]", @@ -3123,7 +3123,7 @@ "body": { "BaseUrl": "@variables('BaseUrl')", "ClusterId": "@variables('ClusterId')", - "IncidentStartTime": "@variables('IncidentStartTime')", + "IncidentStartTime": "@triggerBody()?['object']?['properties']?['createdTimeUtc']", "ObjectName": "@variables('ObjectName')" }, "host": { @@ -3300,7 +3300,7 @@ "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", + "contentSchemaVersion": "3.1.0", "contentId": "[variables('_playbookContentId3')]", "contentKind": "Playbook", "displayName": "RubrikAnomalyIncidentResponse", @@ -3318,7 +3318,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RubrikDataObjectDiscovery Playbook with template version 3.0.0", + "description": "RubrikDataObjectDiscovery Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion4')]", @@ -5911,7 +5911,7 @@ "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", + "contentSchemaVersion": "3.1.0", "contentId": "[variables('_playbookContentId4')]", "contentKind": "Playbook", "displayName": "RubrikDataObjectDiscovery", @@ -5929,7 +5929,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RubrikFilesetRansomwareDiscovery Playbook with template version 3.0.0", + "description": "RubrikFilesetRansomwareDiscovery Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion5')]", @@ -6557,7 +6557,7 @@ "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", + "contentSchemaVersion": "3.1.0", "contentId": "[variables('_playbookContentId5')]", "contentKind": "Playbook", "displayName": "RubrikFilesetRansomwareDiscovery", @@ -6575,7 +6575,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RubrikIOCScan Playbook with template version 3.0.0", + "description": "RubrikIOCScan Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion6')]", @@ -8563,6 +8563,8 @@ "maximumSizeInBytes": 10000000 }, "pathFilter": { + "exceptions": "[[variables('blanks')]", + "excludes": "[[variables('blanks')]", "includes": [ "**" ] @@ -9009,7 +9011,7 @@ "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", + "contentSchemaVersion": "3.1.0", "contentId": "[variables('_playbookContentId6')]", "contentKind": "Playbook", "displayName": "RubrikIOCScan", @@ -9027,7 +9029,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RubrikPollAsyncResult Playbook with template version 3.0.0", + "description": "RubrikPollAsyncResult Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion7')]", @@ -9873,7 +9875,7 @@ "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", + "contentSchemaVersion": "3.1.0", "contentId": "[variables('_playbookContentId7')]", "contentKind": "Playbook", "displayName": "RubrikPollAsyncResult", @@ -9891,7 +9893,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RubrikRansomwareDiscoveryAndFileRecovery Playbook with template version 3.0.0", + "description": "RubrikRansomwareDiscoveryAndFileRecovery Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion8')]", @@ -11228,8 +11230,11 @@ "value": { "destObjectId": "@body('Collect_Recovery_Data')?['data']?['destination object ID to restore file']", "domainName": "[variables('blanks')]", + "guestCredentialId": "[[variables('blanks')]", + "ignoreErrors": "[[variables('blanks')]", "password": "[variables('blanks')]", "restoreConfig": "@variables('RestoreConfig')", + "shouldRestoreXAttrs": "[[variables('blanks')]", "shouldSaveCredentials": false, "shouldUseAgent": true, "username": "[variables('blanks')]" @@ -11801,7 +11806,7 @@ "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", + "contentSchemaVersion": "3.1.0", "contentId": "[variables('_playbookContentId8')]", "contentKind": "Playbook", "displayName": "RubrikRansomwareDiscoveryAndFileRecovery", @@ -11819,7 +11824,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RubrikRansomwareDiscoveryAndVMRecovery Playbook with template version 3.0.0", + "description": "RubrikRansomwareDiscoveryAndVMRecovery Playbook with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('playbookVersion9')]", @@ -14102,14 +14107,18 @@ "body": { "query": "\r\n mutation vSphereLiveMountMutation($snappableId: String!, $hostId: String, $clusterId: String, $resourcePoolId: String, $snapshotFid: String, $shouldRecoverTags: Boolean!, $keepMacAddresses: Boolean!, $powerOn: Boolean!, $removeNetworkDevices: Boolean!, $vmName: String, $vNicBindings: [VmwareVnicBindingInfoV2Input!], $recoveryPoint: DateTime, $shouldMigrateImmediately: Boolean!, $migrationConfig: RelocateMountConfigV2Input) {\r\n vsphereVmInitiateLiveMountV2(\r\n input: {\r\n id: $snappableId, config: { hostId: $hostId, resourcePoolId: $resourcePoolId, clusterId: $clusterId, shouldRecoverTags: $shouldRecoverTags, vNicBindings: $vNicBindings, requiredRecoveryParameters: { snapshotId: $snapshotFid, recoveryPoint: $recoveryPoint}mountExportSnapshotJobCommonOptionsV2: { keepMacAddresses: $keepMacAddresses, powerOn: $powerOn, removeNetworkDevices: $removeNetworkDevices, vmName: $vmName}, shouldMigrateImmediately: $shouldMigrateImmediately, migrationConfig: $migrationConfig}}\r\n ) {\r\n id\r\n status\r\n __typename\r\n }\r\n }\r\n", "variables": { + "clusterId": "[[variables('blanks')]", "hostId": "@variables('HostId')", "keepMacAddresses": false, + "migrationConfig": "[[variables('blanks')]", "powerOn": false, "removeNetworkDevices": false, + "resourcePoolId": "[[variables('blanks')]", "shouldMigrateImmediately": false, "shouldRecoverTags": true, "snappableId": "@{triggerBody()?['ObjectId']}", "snapshotFid": "@{body('Response_RubrikIOCScan')?['RecoverableSnapshotid']}", + "vNicBindings": "[[variables('blanks')]", "vmName": "@body('Collect_recovery_data_for_live-mounting_VM')?['data']?['live-mounted VM name']" } }, @@ -15951,7 +15960,7 @@ "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", + "contentSchemaVersion": "3.1.0", "contentId": "[variables('_playbookContentId9')]", "contentKind": "Playbook", "displayName": "RubrikRansomwareDiscoveryAndVMRecovery", @@ -15969,7 +15978,7 @@ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RubrikSecurityCloud data connector with template version 3.0.0", + "description": "RubrikSecurityCloud data connector with template version 3.1.0", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "[variables('dataConnectorVersion1')]", @@ -16118,7 +16127,7 @@ ] }, { - "description": "Use this method for automated deployment of the Rubrik connector.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinel-RubrikWebhookEvents-azuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the below information : \n\t\tFunction Name \n\t\tWorkspace ID \n\t\tWorkspace Key \n\t\tAnomalies_table_name \n\t\tRansomwareAnalysis_table_name \n\t\tThreatHunts_table_name \n \n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**. \n5. Click **Purchase** to deploy.", + "description": "Use this method for automated deployment of the Rubrik connector.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinel-RubrikWebhookEvents-azuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the below information : \n\t\tFunction Name \n\t\tWorkspace ID \n\t\tWorkspace Key \n\t\tAnomalies_table_name \n\t\tRansomwareAnalysis_table_name \n\t\tThreatHunts_table_name\n\t\tLogLevel \n \n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**. \n5. Click **Purchase** to deploy.", "title": "Option 1 - Azure Resource Manager (ARM) Template" }, { @@ -16129,19 +16138,21 @@ "description": "**1. Deploy a Function App**\n\n> **NOTE:** You will need to [prepare VS code](https://docs.microsoft.com/azure/azure-functions/functions-create-first-function-python#prerequisites) for Azure function development.\n\n1. Download the [Azure Function App](https://aka.ms/sentinel-RubrikWebhookEvents-functionapp) file. Extract archive to your local development computer.\n2. Start VS Code. Choose File in the main menu and select Open Folder.\n3. Select the top level folder from extracted files.\n4. Choose the Azure icon in the Activity bar, then in the **Azure: Functions** area, choose the **Deploy to function app** button.\nIf you aren't already signed in, choose the Azure icon in the Activity bar, then in the **Azure: Functions** area, choose **Sign in to Azure**\nIf you're already signed in, go to the next step.\n5. Provide the following information at the prompts:\n\n\ta. **Select folder:** Choose a folder from your workspace or browse to one that contains your function app.\n\n\tb. **Select Subscription:** Choose the subscription to use.\n\n\tc. Select **Create new Function App in Azure** (Don't choose the Advanced option)\n\n\td. **Enter a globally unique name for the function app:** Type a name that is valid in a URL path. The name you type is validated to make sure that it's unique in Azure Functions. (e.g. RubrikXXXXX).\n\n\te. **Select a runtime:** Choose Python 3.8 or above.\n\n\tf. Select a location for new resources. For better performance and lower costs choose the same [region](https://azure.microsoft.com/regions/) where Microsoft Sentinel is located.\n\n6. Deployment will begin. A notification is displayed after your function app is created and the deployment package is applied.\n7. Go to Azure Portal for the Function App configuration." }, { - "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 values (case-sensitive): \n\t\tWorkspaceID\n\t\tWorkspaceKey\n\t\tAnomalies_table_name\n\t\tRansomwareAnalysis_table_name\n\t\tThreatHunts_table_name\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://.ods.opinsights.azure.us. \n4. Once all application settings have been entered, click **Save**." + "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 values (case-sensitive): \n\t\tWorkspaceID\n\t\tWorkspaceKey\n\t\tAnomalies_table_name\n\t\tRansomwareAnalysis_table_name\n\t\tThreatHunts_table_name\n\t\tLogLevel\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://.ods.opinsights.azure.us. \n4. Once all application settings have been entered, click **Save**." }, { "description": "**Post Deployment steps**\n\n" }, { - "description": "**STEP 1 - To get the Azure Function url**\n\n 1. Go to Azure function Overview page and Click on \"Functions\" in the left blade.\n 2. Click on the Rubrik defined function for the event.\n 3. Go to \"GetFunctionurl\" and copy the function url." + "description": "1. Go to Azure function Overview page and Click on **\"Functions\"** tab.\n2. Click on the function called **\"RubrikHttpStarter\"**.\n3. Go to **\"GetFunctionurl\"** and copy the function url.", + "title": "1) Get the Function app endpoint" }, { - "description": "**STEP 2 - Follow the Rubrik User Guide instructions to [Add a Webhook](https://docs.rubrik.com/en-us/saas/saas/common/adding_webhook.html) to begin receiving event information related to Ransomware Anomalies.**\n\n 1. Select the Generic as the webhook Provider(This will use CEF formatted event information)\n 2. Enter the Function App URL as the webhook URL endpoint for the Rubrik Microsoft Sentinel Solution\n 3. Select the Custom Authentication option \n 4. Enter x-functions-key as the HTTP header \n 5. Enter the Function access key as the HTTP value(Note: if you change this function access key in Microsoft Sentinel in the future you will need to update this webhook configuration)\n 6. Select the following Event types: Anomaly, Ransomware Investigation Analysis, Threat Hunt \n 7. Select the following severity levels: Critical, Warning, Informational" + "description": "Follow the Rubrik User Guide instructions to [Add a Webhook](https://docs.rubrik.com/en-us/saas/saas/common/adding_webhook.html) to begin receiving event information related to Ransomware Anomalies \n 1. Select the Generic as the webhook Provider(This will use CEF formatted event information)\n 2. Enter the URL part from copied Function-url as the webhook URL endpoint and replace **{functionname}** with **\"RubrikAnomalyOrchestrator\"**, for the Rubrik Microsoft Sentinel Solution \n 3. Select the Advanced or Custom Authentication option \n 4. Enter x-functions-key as the HTTP header \n 5. Enter the Function access key(value of code parameter from copied function-url) as the HTTP value(Note: if you change this function access key in Microsoft Sentinel in the future you will need to update this webhook configuration) \n 6. Select the EventType as Anomaly \n 7. Select the following severity levels: Critical, Warning, Informational \n 8. Repeat the same steps to add webhooks for Ransomware Investigation Analysis and Threat Hunt. \n\n NOTE: while adding webhooks for Ransomware Investigation Analysis and Threat Hunt, replace **{functionname}** with **\"RubrikRansomwareOrchestrator\"** and **\"RubrikThreatHuntOrchestrator\"** respectively in copied function-url.", + "title": "2) Add a webhook in RubrikSecurityCloud to send data to Microsoft Sentinel." }, { - "description": "*Now we are done with the rubrik Webhook configuration. Once the webhook events triggered , you should be able to see the Anomaly, Ransomware Analysis, ThreatHunt events from the Rubrik into respective LogAnalytics workspace table called \"Rubrik_Anomaly_Data_CL\", \"Rubrik_Ransomware_Data_CL\", \"Rubrik_ThreatHunt_Data_CL\".*\n\n" + "description": "*Now we are done with the rubrik Webhook configuration. Once the webhook events triggered , you should be able to see the Anomaly, Ransomware Investigation Analysis, ThreatHunt events from the Rubrik into respective LogAnalytics workspace table called \"Rubrik_Anomaly_Data_CL\", \"Rubrik_Ransomware_Data_CL\", \"Rubrik_ThreatHunt_Data_CL\".*\n\n" } ] } @@ -16179,7 +16190,7 @@ "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", + "contentSchemaVersion": "3.1.0", "contentId": "[variables('_dataConnectorContentId1')]", "contentKind": "DataConnector", "displayName": "Rubrik Security Cloud data connector (using Azure Functions)", @@ -16359,7 +16370,7 @@ ] }, { - "description": "Use this method for automated deployment of the Rubrik connector.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinel-RubrikWebhookEvents-azuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the below information : \n\t\tFunction Name \n\t\tWorkspace ID \n\t\tWorkspace Key \n\t\tAnomalies_table_name \n\t\tRansomwareAnalysis_table_name \n\t\tThreatHunts_table_name \n \n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**. \n5. Click **Purchase** to deploy.", + "description": "Use this method for automated deployment of the Rubrik connector.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sentinel-RubrikWebhookEvents-azuredeploy)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the below information : \n\t\tFunction Name \n\t\tWorkspace ID \n\t\tWorkspace Key \n\t\tAnomalies_table_name \n\t\tRansomwareAnalysis_table_name \n\t\tThreatHunts_table_name\n\t\tLogLevel \n \n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**. \n5. Click **Purchase** to deploy.", "title": "Option 1 - Azure Resource Manager (ARM) Template" }, { @@ -16370,19 +16381,21 @@ "description": "**1. Deploy a Function App**\n\n> **NOTE:** You will need to [prepare VS code](https://docs.microsoft.com/azure/azure-functions/functions-create-first-function-python#prerequisites) for Azure function development.\n\n1. Download the [Azure Function App](https://aka.ms/sentinel-RubrikWebhookEvents-functionapp) file. Extract archive to your local development computer.\n2. Start VS Code. Choose File in the main menu and select Open Folder.\n3. Select the top level folder from extracted files.\n4. Choose the Azure icon in the Activity bar, then in the **Azure: Functions** area, choose the **Deploy to function app** button.\nIf you aren't already signed in, choose the Azure icon in the Activity bar, then in the **Azure: Functions** area, choose **Sign in to Azure**\nIf you're already signed in, go to the next step.\n5. Provide the following information at the prompts:\n\n\ta. **Select folder:** Choose a folder from your workspace or browse to one that contains your function app.\n\n\tb. **Select Subscription:** Choose the subscription to use.\n\n\tc. Select **Create new Function App in Azure** (Don't choose the Advanced option)\n\n\td. **Enter a globally unique name for the function app:** Type a name that is valid in a URL path. The name you type is validated to make sure that it's unique in Azure Functions. (e.g. RubrikXXXXX).\n\n\te. **Select a runtime:** Choose Python 3.8 or above.\n\n\tf. Select a location for new resources. For better performance and lower costs choose the same [region](https://azure.microsoft.com/regions/) where Microsoft Sentinel is located.\n\n6. Deployment will begin. A notification is displayed after your function app is created and the deployment package is applied.\n7. Go to Azure Portal for the Function App configuration." }, { - "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 values (case-sensitive): \n\t\tWorkspaceID\n\t\tWorkspaceKey\n\t\tAnomalies_table_name\n\t\tRansomwareAnalysis_table_name\n\t\tThreatHunts_table_name\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://.ods.opinsights.azure.us. \n4. Once all application settings have been entered, click **Save**." + "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 values (case-sensitive): \n\t\tWorkspaceID\n\t\tWorkspaceKey\n\t\tAnomalies_table_name\n\t\tRansomwareAnalysis_table_name\n\t\tThreatHunts_table_name\n\t\tLogLevel\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://.ods.opinsights.azure.us. \n4. Once all application settings have been entered, click **Save**." }, { "description": "**Post Deployment steps**\n\n" }, { - "description": "**STEP 1 - To get the Azure Function url**\n\n 1. Go to Azure function Overview page and Click on \"Functions\" in the left blade.\n 2. Click on the Rubrik defined function for the event.\n 3. Go to \"GetFunctionurl\" and copy the function url." + "description": "1. Go to Azure function Overview page and Click on **\"Functions\"** tab.\n2. Click on the function called **\"RubrikHttpStarter\"**.\n3. Go to **\"GetFunctionurl\"** and copy the function url.", + "title": "1) Get the Function app endpoint" }, { - "description": "**STEP 2 - Follow the Rubrik User Guide instructions to [Add a Webhook](https://docs.rubrik.com/en-us/saas/saas/common/adding_webhook.html) to begin receiving event information related to Ransomware Anomalies.**\n\n 1. Select the Generic as the webhook Provider(This will use CEF formatted event information)\n 2. Enter the Function App URL as the webhook URL endpoint for the Rubrik Microsoft Sentinel Solution\n 3. Select the Custom Authentication option \n 4. Enter x-functions-key as the HTTP header \n 5. Enter the Function access key as the HTTP value(Note: if you change this function access key in Microsoft Sentinel in the future you will need to update this webhook configuration)\n 6. Select the following Event types: Anomaly, Ransomware Investigation Analysis, Threat Hunt \n 7. Select the following severity levels: Critical, Warning, Informational" + "description": "Follow the Rubrik User Guide instructions to [Add a Webhook](https://docs.rubrik.com/en-us/saas/saas/common/adding_webhook.html) to begin receiving event information related to Ransomware Anomalies \n 1. Select the Generic as the webhook Provider(This will use CEF formatted event information)\n 2. Enter the URL part from copied Function-url as the webhook URL endpoint and replace **{functionname}** with **\"RubrikAnomalyOrchestrator\"**, for the Rubrik Microsoft Sentinel Solution \n 3. Select the Advanced or Custom Authentication option \n 4. Enter x-functions-key as the HTTP header \n 5. Enter the Function access key(value of code parameter from copied function-url) as the HTTP value(Note: if you change this function access key in Microsoft Sentinel in the future you will need to update this webhook configuration) \n 6. Select the EventType as Anomaly \n 7. Select the following severity levels: Critical, Warning, Informational \n 8. Repeat the same steps to add webhooks for Ransomware Investigation Analysis and Threat Hunt. \n\n NOTE: while adding webhooks for Ransomware Investigation Analysis and Threat Hunt, replace **{functionname}** with **\"RubrikRansomwareOrchestrator\"** and **\"RubrikThreatHuntOrchestrator\"** respectively in copied function-url.", + "title": "2) Add a webhook in RubrikSecurityCloud to send data to Microsoft Sentinel." }, { - "description": "*Now we are done with the rubrik Webhook configuration. Once the webhook events triggered , you should be able to see the Anomaly, Ransomware Analysis, ThreatHunt events from the Rubrik into respective LogAnalytics workspace table called \"Rubrik_Anomaly_Data_CL\", \"Rubrik_Ransomware_Data_CL\", \"Rubrik_ThreatHunt_Data_CL\".*\n\n" + "description": "*Now we are done with the rubrik Webhook configuration. Once the webhook events triggered , you should be able to see the Anomaly, Ransomware Investigation Analysis, ThreatHunt events from the Rubrik into respective LogAnalytics workspace table called \"Rubrik_Anomaly_Data_CL\", \"Rubrik_Ransomware_Data_CL\", \"Rubrik_ThreatHunt_Data_CL\".*\n\n" } ], "id": "[variables('_uiConfigId1')]" @@ -16394,9 +16407,9 @@ "apiVersion": "2023-04-01-preview", "location": "[parameters('workspace-location')]", "properties": { - "version": "3.0.0", + "version": "3.1.0", "kind": "Solution", - "contentSchemaVersion": "3.0.0", + "contentSchemaVersion": "3.1.0", "displayName": "RubrikSecurityCloud", "publisherDisplayName": "Rubrik", "descriptionHtml": "

Note: There may be known issues pertaining to this Solution, please refer to them before installing.

\n

The Rubrik Security Cloud solution enables security operations teams to integrate insights from Rubrik’s Data Observability services into Microsoft Sentinel.

\n

Underlying Microsoft Technologies used:

\n

This solution takes a dependency on the following technologies, and some of these dependencies either may be in Preview state or might result in additional ingestion or operational costs:

\n

a.Azure Monitor HTTP Data Collector API

\n

b.Azure Functions

\n

Data Connectors: 1, Custom Azure Logic Apps Connectors: 1, Playbooks: 8

\n

Learn more about Microsoft Sentinel | Learn more about Solutions

\n", @@ -16491,4 +16504,4 @@ } ], "outputs": {} -} \ No newline at end of file +} diff --git a/Solutions/RubrikSecurityCloud/ReleaseNotes.md b/Solutions/RubrikSecurityCloud/ReleaseNotes.md index 9fd3014272b..f8876aca52a 100644 --- a/Solutions/RubrikSecurityCloud/ReleaseNotes.md +++ b/Solutions/RubrikSecurityCloud/ReleaseNotes.md @@ -1,3 +1,4 @@ | **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | |-------------|--------------------------------|---------------------------------------------| -| 3.0.0 | 14-07-2023 | Updated the title in such a way that user can identify the adaptive card based on incident. | +| 3.1.0 | 20-10-2023 | Updated the DataConnector code by implementing Durable Function App. | +| 3.0.0 | 14-07-2023 | Updated the title in such a way that user can identify the adaptive card based on incident. | \ No newline at end of file