Package: panther-sdk
Panther SDKThe Panther SDK module allows you to configure detections for yourPantherinstance.Getting StartedInstallThe Panther SDK can be installed using PIP.pip3installpanther-sdk==0.0.24Writing a detectionYou can use thedetectionmodule in Panther SDK to configure detections. The example below shows a detection that processing an HTTP log.Assuming we have a log typeInternal.HTTP.Trafficthat has the following shape:{"method":"POST","useSSL":false,"path":"/api/some/endpoint","host":"internal.megacorp.com"}We can write a detection to check for insecurePOSTandPUTrequests:# import the "detection" module, as we'll be creating a rule.frompanther_sdkimportdetection# The next four functions are used in the detection definition that follows. Panther# detections allow for parts of a detection to be defined with custom Python code.# "filter_insecure" is an example of python function that will be used to create# a detection.PythonFilter that only matches insecure events. The event argument will# have a python dict object corresponding to the JSON event.deffilter_insecure(event,params):returnevent["useSSL"]==False# "filter_http_methods" is a slightly more complicated python function that we will use# to create a detection.PythonFilter later. This function uses the second "params" argument# to make the function's logic reusable.deffilter_http_methods(event,params):allowed_methods=params["methods"]actual_method=event["method"]returnactual_methodinallowed_methods# "reference_generator" is another example where we will use some python code to dynamically# change the information Panther presents on an Alert resulting from a Detection match. In# this example, we're populating a query param with some relevant information from# the contextual event.defreference_generator(event):origin=event["origin"]returnf"https://wiki.internal.megacorp.com/hosts_db?host={origin}"# "make_context" will be used to attach arbitrary data to the resulting Alert. This# can be used to simply change how data is presented or be used to push machine readable information# to a downstream Alert Destination.defmake_context(event):# The Panther SDK's hooks to arbitrary python come with some restrictions. When the# detection is saved, the Panther backend will capture the source of provided function to use# in realtime log data processing and other backend processes. Because of this, functions used# to define a detection must not have references that are not local to the function body. Therefore,# imports targeting any of the below _must_ be included in the function body:##   - The python standard library#   - Libraries that are enabled on your Panther instance#   - Panther "Global Helpers" that you have configured on your instanceimportfnmatchpath=event["path"]return{"is_api_path":fnmatch.fnmatch(path,"/api/*")}# "pick_severity" is a custom function we are using to define the severity of Alerts based on# the data present in the current log. The detection.Rule declaration below shows how this method# is registered with the definition of our Rule.defpick_severity(event)->str:frompanther_sdkimportdetection# required. see notes in comment above "make_context"ifevent["origin"]!="internal.megacorp.com":returndetection.SeverityInforeturndetection.SeverityInfo# Declare a rule. Every call to "detection.Rule" in your repo will create a Rule in the Panther backend.# This example uses a subset of the fields available to define a Rule. See "Full Dataclass API" for# all the available fields.detection.Rule(# Give the Rule an id. This name must be unique on your Panther# instance. Dot separated names following "namespace" pattern is recommended.rule_id="Internal.HTTP.Traffic.Insecure",# Pick a human friendly name for the rule. This will be used# to present the Rule in the Panther Console UIname="Detect insecure internal HTTP traffic",# Specify one or more log types for your Rule. This setting is what# tells the Panther backend to run this Rule against the log data depicted above.log_types=["Internal.HTTP.Traffic"],# Specify an enabled state for the Rule. Detections can be uploaded in a# disabled state and will not begin processing log data until enabled.enabled=True,# Optionally, you can specify a list of tags to associate with the detection.tags=["internal"],# The "filters" list defines the sequence of matching logic that an event# will be tested against to determine whether there is a match. Returning "True" proceeds to the# next check. If the final check returns "True", there is a match.filters=[# If the HTTP transaction was secure, we're not interested in that log in this detection.# Therefore, the first filter uses the "filter_insecure" function we defined to filter to only# events that have useSSL set to "false".detection.PythonFilter(func=filter_insecure),# For now, we're only interested in getting alerted for insecure POST and PUT requests.# We therefore define the second filter step using "filter_http_methods". Unlike "filter_insecure",# we pass some parameters to this function.detection.PythonFilter(func=filter_http_methods,params={'methods':["POST","PUT"]}),],# On this line, we're defining the severity that should be associated with any resulting alerts.# We have the option of defining a static severity (simply: severity="INFO") but, in this case, we want# to make the severity dynamic based on data from the event. To do this, we reference the "pick_severity"# function we defined at the top of the file. We also provide a fallback value in case the dynamic function# cannot be processed. This fallback will also be the Severity value displayed in the Panther Console UIseverity=detection.DynamicStringField(func=pick_severity,fallback=detection.SeverityInfo,),# Below we specify the "reference" field. This optional field is used to attach a link to any Alerts# resulting from this detection. Similar to "severity" we can make this field dynamic based on# event data. There is also a fallback value specified.reference=detection.DynamicStringField(func=reference_generator,fallback="https://wiki.internal.megacorp.com/hosts_db",),# Fields like "runbook" and "description" are also available to further customize how any# resulting Alerts will be displayed. These can have dynamic handlers defined, but in this# example static string values will work just fine.runbook="Optional runbook content",description="A helpful description",# Finally, we use the optional "alert_context" field to tell the Panther backend to use our# "make_context" function to generate custom data that will be attached to any resulting Alerts.alert_context=make_context,)There is support for override behavior that can be very helpful for writing factory functions for your detections.
You can provide defaults for your detection while letting customizations be set when the function is called. For example:frompanther_sdkimportdetection# This is an example of a factory rule function that might live in panther_detections or your own library of detections.# This function accepts an optional overrides object, which is passed through to the Rule instantiation. Any attributes# set on the RuleOverrides object will override the attributes defined for the rule.deffactory_rule_func(overrides:Optional[detection.RuleOverrides]=None)->detection.Rule:returndetection.Rule(rule_id="default.rule.id",filters=[...],log_types=["AWS.ALB"],severity=detection.SeverityMedium,overrides=overrides,)# Here is an example of using the rule factory function.defmake_detections()->None:# We can pass no overrides at all, and it will be the default rule the function createsr=factory_rule_func()print(r)# We can override the id and severity to create a more customized rule using our function from abover=factory_rule_func(overrides=detection.RuleOverrides(rule_id="not.important.rule",severity=detection.SeverityInfo,))print(r)r=factory_rule_func(overrides=detection.RuleOverrides(rule_id="very.important.rule",severity=detection.SeverityHigh,))print(r)# Now we call our main detection making function to execute it when running this python scriptmake_detections()Similar to overrides, you have the ability to add extensions to your Panther content.
These can be used the same way as overrides on fields that have lists.frompanther_sdkimportdetection# This is an example of a factory rule function that might live in panther_detections or your own library of detections.# This function accepts an optional extensions object, which is passed through to the Rule instantiation. Any attributes# set on the RuleExtensions object will override the attributes defined for the rule.deffactory_rule_func(extensions:Optional[detection.RuleExtensions]=None)->detection.Rule:returndetection.Rule(rule_id="default.rule.id",filters=[...],log_types=["AWS.ALB"],severity=detection.SeverityMedium,extensions=extensions,)# Here is an example of using the rule factory function.defmake_detections()->None:# We can pass no extensions at all, and it will be the default rule the function createsr=factory_rule_func()print(r)# We can extend filters to add logic to the ruler=factory_rule_func(extensions=detection.RuleExtensions(filters=[detection.PythonFilter(func=my_very_important_filter)],))print(r)# Now we call our main detection making function to execute it when running this python scriptmake_detections()Full Dataclass APIdetection moduleDynamicStringFieldMake a field dynamic based on the detection inputFieldDescriptionTypefallbackFallback value in case the dynamic handler failsstrfuncDynamic handlerOptional[Callable[[PantherEvent], str]]DynamicDestinationsMake destinations dynamic based on the detection inputFieldDescriptionTypefallbackFallback value in case the dynamic handler failsOptional[List[str]]funcDynamic handlerCallable[[PantherEvent], List[str]]AlertGroupingConfiguration for how an alert is groupedFieldDescriptionTypeperiod_minutesHow long should matches be grouped into an alert after the first matchintgroup_byFunction to generate a key for grouping matchesOptional[Callable[[PantherEvent], str]]PythonFilterCreate a filter by referencing a python functionFieldDescriptionTypefuncProvide a function whose python source will be used as the filter definitionCallable[[PantherEvent], bool]UnitTestMockMock for a unit testFieldDescriptionTypenamename of the object to mockstrreturn_valuestring to assign as the return value for the mockstrJSONUnitTestUnit test with json contentFieldDescriptionTypenamename of the unit teststrexpect_matchwhether the data should match and trigger an alertbooldatajson stringstrmockslist of mocks to use in the testOptional[List[UnitTestMock]]PolicyDefine a Policy-type detection to execute against log data in your Panther instanceFieldDescriptionTypepolicy_idID for the Policystrignore_patternsPatterns of resource ids to ignore for the policyOptional[Union[str, List[str]]]destinationsAlert destinations for the policyOptional[Union[str, List[str], DynamicDestinations]]filtersDefine event filters for the policyUnion[Union[PythonFilter], List[Union[PythonFilter]]]enabledWhether the policy is enabled or notboolresource_typesWhat resource types this policy will apply toUnion[str, List[str]]severityWhat severity alerts generated from this policy get assignedUnion[str, DynamicStringField]nameWhat name to display in the UI and alerts. The PolicyID will be displayed if this field is not set.Optional[str]descriptionDescription for the policyOptional[Union[str, DynamicStringField]]referenceThe reason this policy exists, often a link to documentationOptional[Union[str, DynamicStringField]]reportsA mapping of framework or report names to values this policy covers for that frameworkOptional[Dict[str, List[str]]]runbookThe actions to be carried out if this policy fails, often a link to documentationOptional[Union[str, DynamicStringField]]tagsTags used to categorize this policyOptional[Union[str, List[str]]]unit_testsUnit tests for this policyOptional[Union[Union[JSONUnitTest], List[Union[JSONUnitTest]]]]alert_titleTitle to use in the alertOptional[Callable[[PantherEvent], str]]alert_contextOptional JSON to attach to alerts generated by this policyOptional[Callable[[PantherEvent], Dict[str, Any]]]alert_groupingConfiguration for how an alert is groupedOptional[AlertGrouping]RuleDefine a Rule-type detection to execute against log data in your Panther instanceFieldDescriptionTyperule_idID for the rulestrseveritySeverity for the ruleUnion[str, DynamicStringField]thresholdNumber of matches received before an alert is triggeredintnameDisplay name for the ruleOptional[str]log_typesLog Types to associate with this ruleUnion[str, List[str]]filtersDefine event filters for the ruleUnion[Union[PythonFilter], List[Union[PythonFilter]]]enabledWhether the rule is enabled or notboolunit_testsDefine event filters for the ruleOptional[Union[Union[JSONUnitTest], List[Union[JSONUnitTest]]]]tagsTags for the ruleOptional[Union[str, List[str]]]referenceReference for the ruleOptional[Union[str, DynamicStringField]]runbookRunbook for the ruleOptional[Union[str, DynamicStringField]]descriptionDescription for the ruleOptional[Union[str, DynamicStringField]]summary_attrsSummary Attributes for the ruleOptional[List[str]]reportsReport mappings for the ruleOptional[Dict[str, List[str]]]destinationsAlert destinations for the ruleOptional[Union[str, List[str], DynamicDestinations]]alert_titleTitle to use in the alertOptional[Callable[[PantherEvent], str]]alert_contextOptional JSON to attach to alerts generated by this ruleOptional[Callable[[PantherEvent], Dict[str, Any]]]alert_groupingConfiguration for how an alert is groupedOptional[AlertGrouping]ScheduledRuleDefine a ScheduledRule-type detection to execute against query results in your Panther instanceFieldDescriptionTyperule_idID for the scheduled rulestrseverityWhat severity alerts generated from this scheduled rule get assignedUnion[str, DynamicStringField]thresholdNumber of matches received before an alert is triggeredintnameDisplay name for the scheduled ruleOptional[str]scheduled_queriesScheduled queries to associate with this scheduled ruleUnion[str, List[str]]filtersDefine event filters for the scheduled ruleUnion[Union[PythonFilter], List[Union[PythonFilter]]]enabledShort description for the scheduled ruleboolunit_testsDefine event filters for the scheduled ruleOptional[Union[Union[JSONUnitTest], List[Union[JSONUnitTest]]]]tagsTags for the scheduled ruleOptional[Union[str, List[str]]]referenceReference for the scheduled ruleOptional[Union[str, DynamicStringField]]runbookRunbook for the scheduled ruleOptional[Union[str, DynamicStringField]]descriptionDescription for the scheduled ruleOptional[Union[str, DynamicStringField]]summary_attrsSummary Attributes for the scheduled ruleOptional[List[str]]reportsReport mappings for the scheduled ruleOptional[Dict[str, List[str]]]destinationsAlert destinations for the scheduled ruleOptional[Union[str, List[str], DynamicDestinations]]alert_titleTitle to use in the alertOptional[Callable[[PantherEvent], str]]alert_contextOptional JSON to attach to alerts generated by this ruleOptional[Callable[[PantherEvent], Dict[str, Any]]]alert_groupingConfiguration for how an alert is groupedOptional[AlertGrouping]query moduleCronScheduleCron expression based schedule definition for a queryFieldDescriptionTypeexpressionDefines how often queries using this schedule runstrtimeout_minutesDefines the timeout applied to queries with this scheduleintIntervalScheduleInterval based schedule definition for a queryFieldDescriptionTyperate_minutesDefines how often queries using this schedule runinttimeout_minutesDefines the timeout applied to queries with this scheduleintQueryA saved or scheduled queryFieldDescriptionTypenameUnique name for the querystrdescriptionShort description for the querystrdefault_databaseDefault database for the querystrsqlSQL statementstrenabledWhether the query is enabled or notbooltagsTags for the queryOptional[Union[str, List[str]]]scheduleSchedule attached to the queryOptional[Union[IntervalSchedule, CronSchedule]]schema moduleDataModelMappingFieldDescriptionTypenameName of the data model field. This will be the name used when accessing the field from within detections.strpathPath to the target value in the Panther Event. This can be a simple field name or complete JSON path starting with a$. JSON path syntax must be compatible with thejsonpath-ngPython package.Optional[str]funcA Python function to access the target value. The input is the Panther Event and output is the target value in the Panther Event.Optional[Callable[[PantherEvent], Any]]DataModelData Models provide a way to configure a set of unified fields across all log types.FieldDescriptionTypedata_model_idThe unique identifier of the data model.strnameWhat name to display in the UI and alerts. Thedata_model_idwill be displayed if this field is not set.Optional[str]enabledWhether this data model is enabled.Optional[bool]log_typeWhat log type this data model will apply to.strmappingsMapping from source field name or method to unified data model field name.Union[DataModelMapping, List[DataModelMapping]]