Merge pull request #9802 from FortiNDR-Integration/FortiNDR-Cloud-Sentinel-initialization
Fortinet FortiNDR Cloud Initialization
|
@ -0,0 +1,126 @@
|
|||
{
|
||||
"Name": "FncEventsDetections_CL",
|
||||
"Properties": [
|
||||
{
|
||||
"Name": "vendor_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "product_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "signal_version_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "event_type_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "subject_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "timestamp_t",
|
||||
"Type": "DateTime"
|
||||
},
|
||||
{
|
||||
"Name": "device_ip_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "name_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "severity_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "confidence_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "sensor_id_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "muted_b",
|
||||
"Type": "Boolean"
|
||||
},
|
||||
{
|
||||
"Name": "muted_rule_b",
|
||||
"Type": "Boolean"
|
||||
},
|
||||
{
|
||||
"Name": "rule_uuid_g",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "muted_comment_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "first_seen_t",
|
||||
"Type": "DateTime"
|
||||
},
|
||||
{
|
||||
"Name": "last_seen_t",
|
||||
"Type": "DateTime"
|
||||
},
|
||||
{
|
||||
"Name": "created_t",
|
||||
"Type": "DateTime"
|
||||
},
|
||||
{
|
||||
"Name": "updated_t",
|
||||
"Type": "DateTime"
|
||||
},
|
||||
{
|
||||
"Name": "uuid_g",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "status_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "indicators_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "customer_id_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "primary_pdns_hostnames_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "other_pdns_hostnames_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "primary_dhcp_machost_pairs_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "other_dhcp_machost_pairs_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "Category",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "Type",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "TimeGenerated",
|
||||
"Type": "DateTime"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
{
|
||||
"Name": "FncEventsObservation_CL",
|
||||
"Properties": [
|
||||
{
|
||||
"Name": "timestamp_t",
|
||||
"Type": "DateTime"
|
||||
},
|
||||
{
|
||||
"Name": "uuid_g",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "event_type_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "customer_id_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "sensor_id_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "source_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "evidence_start_timestamp_t",
|
||||
"Type": "DateTime"
|
||||
},
|
||||
{
|
||||
"Name": "evidence_end_timestamp_t",
|
||||
"Type": "DateTime"
|
||||
},
|
||||
{
|
||||
"Name": "observation_uuid_g",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "title_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "confidence_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_internal_b",
|
||||
"Type": "Boolean"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_geo_location_lat_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_geo_location_lon_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_geo_country_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_geo_subdivision_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_geo_city_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_asn_asn_d",
|
||||
"Type": "Int"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_asn_org_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_asn_isp_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_asn_asn_org_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_applications_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_environments_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_locations_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_owners_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_roles_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_tags_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_internal_b",
|
||||
"Type": "Boolean"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_geo_location_lat_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_geo_location_lon_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_geo_country_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_geo_subdivision_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_geo_city_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_asn_asn_d",
|
||||
"Type": "Int"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_asn_org_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_asn_isp_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_asn_asn_org_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_applications_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_environments_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_locations_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_owners_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_roles_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_tags_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "geo_distance_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "sensor_ids_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "evidence_iql_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "description_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "context_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "class_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "intel_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "Category",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "Type",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "TimeGenerated",
|
||||
"Type": "DateTime"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,330 @@
|
|||
{
|
||||
"Name": "FncEventsSuricata_CL",
|
||||
"Properties": [
|
||||
{
|
||||
"Name": "timestamp_t",
|
||||
"Type": "DateTime"
|
||||
},
|
||||
{
|
||||
"Name": "uuid_g",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "event_type_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "customer_id_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "sensor_id_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "source_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_port_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "dest_ip_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dest_port_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "proto_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "alert_signature_id_d",
|
||||
"Type": "Int"
|
||||
},
|
||||
{
|
||||
"Name": "alert_rev_d",
|
||||
"Type": "Int"
|
||||
},
|
||||
{
|
||||
"Name": "alert_signature_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "alert_category_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "alert_severity_d",
|
||||
"Type": "Int"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_internal_b",
|
||||
"Type": "Boolean"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_geo_location_lat_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_geo_location_lon_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_geo_country_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_geo_subdivision_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_geo_city_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_asn_asn_d",
|
||||
"Type": "Int"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_asn_org_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_asn_isp_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_asn_asn_org_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_applications_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_environments_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_locations_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_owners_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_roles_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "src_ip_enrichments_annotations_tags_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_internal_b",
|
||||
"Type": "Boolean"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_geo_location_lat_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_geo_location_lon_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_geo_country_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_geo_subdivision_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_geo_city_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_asn_asn_d",
|
||||
"Type": "Int"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_asn_org_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_asn_isp_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_asn_asn_org_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_applications_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_environments_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_locations_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_owners_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_roles_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "dst_ip_enrichments_annotations_tags_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "geo_distance_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "http_status_d",
|
||||
"Type": "Int"
|
||||
},
|
||||
{
|
||||
"Name": "http_protocol_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_url_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_internal_b",
|
||||
"Type": "Boolean"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_geo_location_lat_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_geo_location_lon_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_geo_subdivision_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_geo_city_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_asn_asn_d",
|
||||
"Type": "Int"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_asn_org_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_asn_isp_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_asn_asn_org_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_geo_country_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_annotations_applications_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_annotations_environments_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_annotations_locations_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_annotations_owners_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_annotations_roles_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_ip_enrichments_annotations_tags_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_hostname_enrichments_domain_enrichments_domain_entropy_d",
|
||||
"Type": "Double"
|
||||
},
|
||||
{
|
||||
"Name": "http_length_d",
|
||||
"Type": "Int"
|
||||
},
|
||||
{
|
||||
"Name": "http_http_method_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_http_content_type_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_http_refer_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_http_user_agent_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_redirect_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "http_xtf_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "payload_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "intel_s",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "Type",
|
||||
"Type": "String"
|
||||
},
|
||||
{
|
||||
"Name": "TimeGenerated",
|
||||
"Type": "DateTime"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
[{
|
||||
"vendor": "FortiNDRCloudExample",
|
||||
"product": "FNC",
|
||||
"signal_version": "1",
|
||||
"event_type": "detection",
|
||||
"subject": "none",
|
||||
"timestamp": "1970-01-01T15:05:01.139Z",
|
||||
"device_ip": "192.80.44.123",
|
||||
"name": "Sample Rule Name",
|
||||
"category": "Sample Rule Detection Category",
|
||||
"severity": "low",
|
||||
"confidence": "high",
|
||||
"sensor_id": "bob999",
|
||||
"muted": false,
|
||||
"muted_rule": false,
|
||||
"rule_uuid": "65ca67e0-5a28-4eb6-912e-577b93bb3b7f",
|
||||
"muted_comment": "",
|
||||
"first_seen": "1970-01-01T14:58:45.447Z",
|
||||
"last_seen": "1970-01-01T14:59:05.536Z",
|
||||
"created": "1970-01-01T14:58:45.447Z",
|
||||
"updated": "1970-01-01T14:58:45.447Z",
|
||||
"uuid": "2a497a81-3706-42be-8c04-da9f3b66e625",
|
||||
"status": "active",
|
||||
"indicators": [
|
||||
{
|
||||
"field": "dst.ip",
|
||||
"values": [
|
||||
"123.234.456.78"
|
||||
]
|
||||
},
|
||||
{
|
||||
"field": "ssl:issuer",
|
||||
"values": [
|
||||
"Sample usdrasdfkl;jzfg;nmadfg;jdfgSDRESRWERzdfgadf"
|
||||
]
|
||||
},
|
||||
{
|
||||
"field": "ssl:server_name_indication",
|
||||
"values": [
|
||||
"123-234-345-56.fortinet.sample.com"
|
||||
]
|
||||
},
|
||||
{
|
||||
"field": "ssl:subject",
|
||||
"values": [
|
||||
"CN=*.fortinet.sample.com"
|
||||
]
|
||||
}
|
||||
],
|
||||
"customer_id": "fortindrcloud",
|
||||
"primary_dhcp_machost_pairs": [
|
||||
"c1:2a:b3:df:45:46/ENEDEF5EW3"
|
||||
],
|
||||
"other_dhcp_machost_pairs": [
|
||||
"12:3c:0a:g5:12:dc/H1789-9Rp1-12DC",
|
||||
"12:3c:0a:g5:21:b8/H1789-9Rp1-21B8",
|
||||
"12:3c:0a:g5:11:34/H1789-9Rp1-1134",
|
||||
"12:3c:0a:67:3b:14/H1789-9M64-3B14",
|
||||
"12:3c:0a:67:07:54/H1789-9M64-0754",
|
||||
"a1:b2:3c:67:tt:po/FOFPL2M0KS2"
|
||||
]
|
||||
}]
|
|
@ -0,0 +1,128 @@
|
|||
[{
|
||||
"timestamp": "2023-12-22T20:03:51.544000Z",
|
||||
"uuid": "6b7aabaf-82c0-4fbf-a930-01e6f6c0d62e",
|
||||
"event_type": "observation",
|
||||
"customer_id": "hws",
|
||||
"sensor_id": "Yli76C",
|
||||
"source": "Fortinet",
|
||||
"evidence_start_timestamp": "2024-01-15T05:12:57.608000Z",
|
||||
"evidence_end_timestamp": "2024-01-15T05:14:57.611000Z",
|
||||
"observation_uuid": "dd4365b9-7a92-4604-b36b-4c185cacf234",
|
||||
"title": "Sample Observation Title",
|
||||
"category": "relationship",
|
||||
"confidence": "moderate",
|
||||
"src_ip": "238.74.93.79",
|
||||
"src_ip_enrichments": {
|
||||
"internal": true,
|
||||
"geo": {
|
||||
"location": {
|
||||
"lat": 15.313723083291551,
|
||||
"lon": -52.82257173318456
|
||||
},
|
||||
"country": "ZJXNonrYAhqqgftpkVtXbTJPaCVbyV",
|
||||
"subdivision": "jh5c66RDSlPfWkgAwWksySOxQjJYQk",
|
||||
"city": "AfyKJjpctINlQWaJkfDmmwxLSkPXTy"
|
||||
},
|
||||
"asn": {
|
||||
"asn": 1765414505,
|
||||
"org": "SSTargdmXymzkbRjupYpgjWAETwbJw",
|
||||
"isp": "oqRoFXJmrnUtBUUQUaFXPYLknxTTKr",
|
||||
"asn_org": "LqdiMMJGYnARWyvqRJiWrmhrqQdcEe"
|
||||
},
|
||||
"annotations": {
|
||||
"applications": [
|
||||
"XG2IdiPIN",
|
||||
"RgIrnZu"
|
||||
],
|
||||
"environments": [
|
||||
"UorQ",
|
||||
"wsQt0q",
|
||||
"Fx1",
|
||||
"gWso047"
|
||||
],
|
||||
"locations": [
|
||||
"ik",
|
||||
"KUB7CKL",
|
||||
"HvKFh4FF",
|
||||
"ggV0a8"
|
||||
],
|
||||
"owners": [
|
||||
"ijvNwJeTO",
|
||||
"gwlGhZ12w"
|
||||
],
|
||||
"roles": [
|
||||
"wRjs",
|
||||
"TupofYtPH",
|
||||
"SkBnO",
|
||||
"TvfZL",
|
||||
"bY6HOx2"
|
||||
],
|
||||
"tags": [
|
||||
"Dz",
|
||||
"qXyXh7"
|
||||
]
|
||||
}
|
||||
},
|
||||
"dst_ip": "230.109.63.180",
|
||||
"dst_ip_enrichments": {
|
||||
"internal": true,
|
||||
"geo": {
|
||||
"location": {
|
||||
"lat": 38.77745079152252,
|
||||
"lon": -77.15990374931947
|
||||
},
|
||||
"country": "aooaXFefIledlOAnIXNIiFaYmOHMtF",
|
||||
"subdivision": "VbYdMDTP93M6NhuZcAzDWJ64qFukws",
|
||||
"city": "jzBejuNViIzoTaKyMZPEtgcICGcQjD"
|
||||
},
|
||||
"asn": {
|
||||
"asn": 75605248,
|
||||
"org": "kcbbCpqCgxEIrFtukNqKlIfVuDqFxo",
|
||||
"isp": "jtvIFfdUwjeHnCNmKiuJoHBGSzuJhT",
|
||||
"asn_org": "zUVYmVHprxEAfEDgiUZMsbTxXSaEuo"
|
||||
},
|
||||
"annotations": {
|
||||
"applications": [
|
||||
"KB"
|
||||
],
|
||||
"environments": [
|
||||
"qSZ8scjI",
|
||||
"exty",
|
||||
"8s8"
|
||||
],
|
||||
"locations": [
|
||||
"IJvj9E",
|
||||
"LEhIP7lT"
|
||||
],
|
||||
"owners": [
|
||||
"B",
|
||||
"4kWqAO",
|
||||
"5",
|
||||
"twJzpSZx",
|
||||
"jhwdjR"
|
||||
],
|
||||
"roles": [
|
||||
"jRyJ69N6F",
|
||||
"Rx05P",
|
||||
"s"
|
||||
],
|
||||
"tags": [
|
||||
"aOuuId0A"
|
||||
]
|
||||
}
|
||||
},
|
||||
"geo_distance": 7.969739952125808E307,
|
||||
"sensor_ids": [
|
||||
"Yli76C"
|
||||
],
|
||||
"evidence_iql": "src.ip = \"123.234.345.456\" AND dst.ip = \"654.543.432.321\" AND src.port = 123 AND dst.port = 456",
|
||||
"context": "{\"Operations\":[\"CreateServiceA\",\"StartServiceA\",\"DeleteService\"]}",
|
||||
"intel": [
|
||||
{"indicator": "12.34.567.890", "indicator_type": "ip_address", "timestamp": "2023-12-10T16:02:22.898252Z", "confidence": "high", "severity": "moderate", "feed": "sdfgklhjrthbfgUIHHRFahgdfgh", "is_malicious": true, "customer_ids": ["bob123"], "aggregator": null, "meta": "asdofijkadfgDFLjasdl;fS:dfSDFl;kjasdfkl;asdjadfghzvioOISDfjODFJOSDFJdf"},
|
||||
{"indicator": "23.45.678.901", "indicator_type": "ip_address", "timestamp": "2023-12-11T16:02:22.898252Z", "confidence": "moderate", "severity": "low", "feed": "SDFjSDOIFfasdjfasodfjasdfadf", "is_malicious": true, "customer_ids": ["bob123"], "aggregator": null, "meta": "bjsdfgjkadfl;gjwergijIOFJSDFJr;lgkjadofigjasrgioajdfopigsjdfg"},
|
||||
{"indicator": "34.56.789.012", "indicator_type": "ip_address", "timestamp": "2023-12-12T16:02:22.898252Z", "confidence": "low", "severity": "moderate", "feed": "OSDIFUERdfjsdfg;FSDDFFDDflkd", "is_malicious": false, "customer_ids": ["bob123"], "aggregator": null, "meta": "werpoituwkl;sjnbskldfgjnl;iojcv;alksdfg'asdfnkfvafga';sdfao"},
|
||||
{"indicator": "56.78.901.234", "indicator_type": "ip_address", "timestamp": "2023-12-13T16:02:22.898252Z", "confidence": "moderate", "severity": "high", "feed": "zcvijadifopaiDSIDJOISJ23423", "is_malicious": true, "customer_ids": ["bob123"], "aggregator": null, "meta": "kl;cvbnmsdftigjOISDjfIOFjradoifgjaodfgjruighjadfgskdfglija;lkdfjg;"}
|
||||
],
|
||||
"description": "Sample Observation Description.",
|
||||
"class": "specific"
|
||||
}]
|
|
@ -0,0 +1,159 @@
|
|||
[{
|
||||
"timestamp": "2023-12-22T20:03:51.544000Z",
|
||||
"uuid": "6b7aabaf-82c0-4fbf-a930-01e6f6c0d62e",
|
||||
"event_type": "suricata",
|
||||
"customer_id": "hws",
|
||||
"sensor_id": "Yli76C",
|
||||
"source": "Suricata",
|
||||
"src_ip": "238.74.93.79",
|
||||
"src_ip_enrichments": {
|
||||
"internal": true,
|
||||
"geo": {
|
||||
"location": {
|
||||
"lat": 15.313723083291551,
|
||||
"lon": -52.82257173318456
|
||||
},
|
||||
"country": "ZJXNonrYAhqqgftpkVtXbTJPaCVbyV",
|
||||
"subdivision": "jh5c66RDSlPfWkgAwWksySOxQjJYQk",
|
||||
"city": "AfyKJjpctINlQWaJkfDmmwxLSkPXTy"
|
||||
},
|
||||
"asn": {
|
||||
"asn": 1765414505,
|
||||
"org": "SSTargdmXymzkbRjupYpgjWAETwbJw",
|
||||
"isp": "oqRoFXJmrnUtBUUQUaFXPYLknxTTKr",
|
||||
"asn_org": "LqdiMMJGYnARWyvqRJiWrmhrqQdcEe"
|
||||
},
|
||||
"annotations": {
|
||||
"applications": [
|
||||
"XG2IdiPIN",
|
||||
"RgIrnZu"
|
||||
],
|
||||
"environments": [
|
||||
"UorQ",
|
||||
"wsQt0q",
|
||||
"Fx1",
|
||||
"gWso047"
|
||||
],
|
||||
"locations": [
|
||||
"ik",
|
||||
"KUB7CKL",
|
||||
"HvKFh4FF",
|
||||
"ggV0a8"
|
||||
],
|
||||
"owners": [
|
||||
"ijvNwJeTO",
|
||||
"gwlGhZ12w"
|
||||
],
|
||||
"roles": [
|
||||
"wRjs",
|
||||
"TupofYtPH",
|
||||
"SkBnO",
|
||||
"TvfZL",
|
||||
"bY6HOx2"
|
||||
],
|
||||
"tags": [
|
||||
"Dz",
|
||||
"qXyXh7"
|
||||
]
|
||||
}
|
||||
},
|
||||
"src_port": 12569,
|
||||
"dest_ip": "230.109.63.180",
|
||||
"dst_ip_enrichments": {
|
||||
"internal": true,
|
||||
"geo": {
|
||||
"location": {
|
||||
"lat": 38.77745079152252,
|
||||
"lon": -77.15990374931947
|
||||
},
|
||||
"country": "aooaXFefIledlOAnIXNIiFaYmOHMtF",
|
||||
"subdivision": "VbYdMDTP93M6NhuZcAzDWJ64qFukws",
|
||||
"city": "jzBejuNViIzoTaKyMZPEtgcICGcQjD"
|
||||
},
|
||||
"asn": {
|
||||
"asn": 75605248,
|
||||
"org": "kcbbCpqCgxEIrFtukNqKlIfVuDqFxo",
|
||||
"isp": "jtvIFfdUwjeHnCNmKiuJoHBGSzuJhT",
|
||||
"asn_org": "zUVYmVHprxEAfEDgiUZMsbTxXSaEuo"
|
||||
},
|
||||
"annotations": {
|
||||
"applications": [
|
||||
"KB"
|
||||
],
|
||||
"environments": [
|
||||
"qSZ8scjI",
|
||||
"exty",
|
||||
"8s8"
|
||||
],
|
||||
"locations": [
|
||||
"IJvj9E",
|
||||
"LEhIP7lT"
|
||||
],
|
||||
"owners": [
|
||||
"B",
|
||||
"4kWqAO",
|
||||
"5",
|
||||
"twJzpSZx",
|
||||
"jhwdjR"
|
||||
],
|
||||
"roles": [
|
||||
"jRyJ69N6F",
|
||||
"Rx05P",
|
||||
"s"
|
||||
],
|
||||
"tags": [
|
||||
"aOuuId0A"
|
||||
]
|
||||
}
|
||||
},
|
||||
"geo_distance": 7.969739952125808E307,
|
||||
"dest_port": 27567,
|
||||
"proto": "gr6C1a2gRVoyc6XVmr2W",
|
||||
"alert": {
|
||||
"gid": 2121495645,
|
||||
"signature_id": 2843301883188533248,
|
||||
"rev": 1204256967,
|
||||
"signature": "1zxcM49pPaWQaXvRoxvF",
|
||||
"category": "uxqXdYR5AtF71Qv0ss1l",
|
||||
"severity": 596603172
|
||||
},
|
||||
"http": {
|
||||
"status": 2142954575,
|
||||
"protocol": "WidPnn3Wh6dgFJWtg76J",
|
||||
"url": "Vm3mNRW1MVlFLR6Qcgz4",
|
||||
"hostname": "vyNEAwnvr1J0zWbye5AD",
|
||||
"hostname_enrichments": {
|
||||
"ip_enrichments": null,
|
||||
"domain_enrichments": {
|
||||
"domain_entropy": 1.6027313483366948E308
|
||||
}
|
||||
},
|
||||
"length": 2509176891212047360,
|
||||
"http_method": "WWMFjeIvsVl0UgSsB2Et",
|
||||
"http_content_type": "3Mik1hKDUUBDFxT1TAnJ",
|
||||
"http_refer": "pirALwUM90ArBV1ozWiO",
|
||||
"http_user_agent": "aB2bGN3r2xb77dkDdWCz",
|
||||
"redirect": "UNEImrJLYEJ31WxFarFq",
|
||||
"xff": "uGTG6tcYRvZpPa09mKhI"
|
||||
},
|
||||
"payload": "DKM1pVbM1SDnWnIYyyqp",
|
||||
"intel": [
|
||||
{
|
||||
"indicator": "http://UcEQISIgTbWCsBvjcEcCuMIQhxYDhZhwzElwIOZddCfklhFJ.WJNWNtVAvbYinLIXpJe.SdkDewBDMaBcoiLlegQMVhfUrihDrKgaplPrIEhNcjbt.gRPjiDATneCR.IJNreZjOCebWrSvXZIFgAAXXvWncYAGpceUBRbRCJoHeebHUQMIeICQtzcXEvPd.BOifnwfUruejtkKJoNXP?UqGuJkebGGoGvrxVkRxCxogrjJDeaV=3SDQJZ0j8EmFhxXnlcseJqHQxMTvVm",
|
||||
"indicator_type": "url",
|
||||
"timestamp": "1970-01-24T00:25:03.731000Z",
|
||||
"confidence": "high",
|
||||
"severity": "moderate",
|
||||
"feed": "94",
|
||||
"is_malicious": true,
|
||||
"customer_ids": [
|
||||
"guokN59jSlYJ5bouFn9Fyc36tmLJv0",
|
||||
"5pJvH0cw240ZGIcbToyiaJIVePg2Xr",
|
||||
"aSy5MWlvhRGyUBnG2xE6FBErFQEgrW",
|
||||
"vGKqpD9I6BJzqJWql3ftRrEu32Iou8"
|
||||
],
|
||||
"aggregator": "9bniCI45031Ye01WwhFhoi2vBZhNmY",
|
||||
"meta": "GEPlZeEAIZymjKss5EYQbpBwj5Gy6H"
|
||||
}
|
||||
]
|
||||
}]
|
|
@ -0,0 +1,200 @@
|
|||
[{
|
||||
"timestamp": "2024-01-03T15:17:32.537000Z",
|
||||
"uuid": "fa42c375-a313-437a-8d30-5a498d787693",
|
||||
"event_type": "suricata",
|
||||
"customer_id": "kep",
|
||||
"sensor_id": "618Fly",
|
||||
"source": "Suricata",
|
||||
"src_ip": "7.70.40.168",
|
||||
"src_ip_enrichments": {
|
||||
"internal": false,
|
||||
"geo": {
|
||||
"location": {
|
||||
"lat": -56.58733456686193,
|
||||
"lon": -132.7164747659492
|
||||
},
|
||||
"country": "uPLnDOHtEGjTLnaTweeDKBoPzgqEYb",
|
||||
"subdivision": "0s9wnbsjpUH6qv4AyMWa6MHdugK87y",
|
||||
"city": "fhjtlvWTETtjYLrXgWSyZAfUqfxFhO"
|
||||
},
|
||||
"asn": {
|
||||
"asn": 1579573468,
|
||||
"org": "hObohPbedoEsJFnrSjpOjhmrTJBfQT",
|
||||
"isp": "LwdwmCRSdJnOWjHQLbNsnrOSeNKNQu",
|
||||
"asn_org": "qvQjCeBbmNBRTcRVCAAhYkOWIQbZQz"
|
||||
},
|
||||
"annotations": {
|
||||
"applications": [
|
||||
"8N9rwf",
|
||||
"L",
|
||||
"SHV6SuSfm"
|
||||
],
|
||||
"environments": [
|
||||
"EIy6Rqy",
|
||||
"zU"
|
||||
],
|
||||
"locations": [
|
||||
"h9rmc",
|
||||
"whctigB",
|
||||
"BelZyc"
|
||||
],
|
||||
"owners": [
|
||||
"fXp4iRU",
|
||||
"w",
|
||||
"Fsc1aC",
|
||||
"s",
|
||||
"4UUqws6H"
|
||||
],
|
||||
"roles": [
|
||||
"OmFp08pdZ",
|
||||
"QIC",
|
||||
"PbMJBcvs",
|
||||
"IJiymzt"
|
||||
],
|
||||
"tags": [
|
||||
"oLrpApMK5"
|
||||
]
|
||||
}
|
||||
},
|
||||
"src_port": 44961,
|
||||
"dest_ip": "195.153.43.186",
|
||||
"dst_ip_enrichments": {
|
||||
"internal": true,
|
||||
"geo": {
|
||||
"location": {
|
||||
"lat": 16.051329125427948,
|
||||
"lon": 31.744029699611797
|
||||
},
|
||||
"country": "UsVqwowturHLEaoskCEJCGktAfqDkV",
|
||||
"subdivision": "nWLowh9qXx1EIxRToJ0VozQBXYtANY",
|
||||
"city": "OyGxPtJUBFcSxEIEthEYzoFJvGyvRg"
|
||||
},
|
||||
"asn": {
|
||||
"asn": 675464323,
|
||||
"org": "lkZuoSEUIDFSMCozonxWRqKukxJrtQ",
|
||||
"isp": "hxBBfKFzojTVozMWhLOwoTakIQEymU",
|
||||
"asn_org": "qbUGKjpRxhTEkDZlIROuDDHvjOPNbs"
|
||||
},
|
||||
"annotations": {
|
||||
"applications": [
|
||||
"guThX",
|
||||
"Foh"
|
||||
],
|
||||
"environments": [
|
||||
"HFBT",
|
||||
"D08O5lBQB"
|
||||
],
|
||||
"locations": [
|
||||
"R8Uqtk",
|
||||
"E4L3X",
|
||||
"g6"
|
||||
],
|
||||
"owners": [
|
||||
"CdOM4P7r",
|
||||
"5M",
|
||||
"n",
|
||||
"20j",
|
||||
"ie9Qg"
|
||||
],
|
||||
"roles": [
|
||||
"Reug6",
|
||||
"D7I"
|
||||
],
|
||||
"tags": [
|
||||
"7j",
|
||||
"Rby",
|
||||
"q"
|
||||
]
|
||||
}
|
||||
},
|
||||
"geo_distance": 3.843256997016675E306,
|
||||
"dest_port": 45347,
|
||||
"proto": "9JCamj2bhPDVfbWeuyaz",
|
||||
"alert": {
|
||||
"gid": 807114439,
|
||||
"signature_id": 6980346026415599616,
|
||||
"rev": 1881245527,
|
||||
"signature": "VbFF6W8KFvFMgdWtHg0v",
|
||||
"category": "u22N835x9Rkz1geeAfmu",
|
||||
"severity": 1561098741
|
||||
},
|
||||
"http": {
|
||||
"status": 16169864,
|
||||
"protocol": "TiX7UWD17nyOEj5VZ8PE",
|
||||
"url": "yAwpyhWdXflR5iXI5iLX",
|
||||
"hostname": "10.1.25.26",
|
||||
"hostname_enrichments": {
|
||||
"ip_enrichments": {
|
||||
"internal": true,
|
||||
"geo": {
|
||||
"location": {
|
||||
"lat": 30.3985599356892,
|
||||
"lon": 95.85731456777427
|
||||
},
|
||||
"country": "gWNKKjBwaodFYUxMiPIMebssgBMpxG",
|
||||
"subdivision": "KSDTxgXXJEXihPDZBfRuqTo9TjblvF",
|
||||
"city": "YfhBldthxooCdYNPkiPqjJZbxqrhFX"
|
||||
},
|
||||
"asn": {
|
||||
"asn": 2064822871,
|
||||
"org": "mZgrHibcGtDXwZZGxEoeeypyeKXNjS",
|
||||
"isp": "ktSKKTyPaTBlTKGvnXBgtJThzdDZjd",
|
||||
"asn_org": "QLxDmVHaiKihJEVpxEEZXwwjWLoHle"
|
||||
},
|
||||
"annotations": {
|
||||
"applications": [
|
||||
"RbnD9qIYY",
|
||||
"gI51sSYLg"
|
||||
],
|
||||
"environments": [
|
||||
"0mivVw",
|
||||
"m9wPswnJS",
|
||||
"brl",
|
||||
"YWDFei"
|
||||
],
|
||||
"locations": [
|
||||
"vJztDx",
|
||||
"jE",
|
||||
"DSLRCN",
|
||||
"gT",
|
||||
"1n"
|
||||
],
|
||||
"owners": [
|
||||
"qxsY"
|
||||
],
|
||||
"roles": [
|
||||
"DXz"
|
||||
],
|
||||
"tags": [
|
||||
"nxBj"
|
||||
]
|
||||
}
|
||||
},
|
||||
"domain_enrichments": null
|
||||
},
|
||||
"length": 3787690537907247104,
|
||||
"http_method": "zu7rToinmmNgd52cmEYh",
|
||||
"http_content_type": "VODGhG7DHup65eNvQzhU",
|
||||
"http_refer": "kjIOSp5isxUzAstHxxeH",
|
||||
"http_user_agent": "Ho3kgsmsQmT0GuIkGEg2",
|
||||
"redirect": "Qoor9U16hba0nI9ajbPA",
|
||||
"xff": "31L9NVpqdO7CBlPQZvdv"
|
||||
},
|
||||
"payload": "SsmQ1i318x6N07kT7DBo",
|
||||
"intel": [
|
||||
{
|
||||
"indicator": "191.132.127.119",
|
||||
"indicator_type": "cidr",
|
||||
"timestamp": "1970-01-05T05:43:26.246000Z",
|
||||
"confidence": "high",
|
||||
"severity": "high",
|
||||
"feed": "4217508",
|
||||
"is_malicious": true,
|
||||
"customer_ids": [
|
||||
"P9kuMHc3CTHNFdTKrNvfWekeMvJS9v"
|
||||
],
|
||||
"aggregator": "9vtKfV9cMtoHfZrsOO8FgdxBcu2lIl",
|
||||
"meta": "AanYoutCTr2VYpK3LT8slWCyRJYZaL"
|
||||
}
|
||||
]
|
||||
}]
|
|
@ -0,0 +1,167 @@
|
|||
{
|
||||
"id": "3a7ee0fe-ba5e-4588-a0b2-9818a67746f8",
|
||||
"title": "Fortinet FortiNDR Cloud",
|
||||
"publisher": "Fortinet",
|
||||
"descriptionMarkdown": "The Fortinet FortiNDR Cloud data connector provides the capability to ingest [Fortinet FortiNDR Cloud](https://docs.fortinet.com/product/fortindr-cloud) events stored in Amazon S3 into Microsoft Sentinel using the Amazon S3 REST API.",
|
||||
"additionalRequirementBanner": "These queries and workbooks are dependent on a parser based on Kusto to work as expected. Follow the steps to use this Kusto functions alias **Fortinet_FortiNDR_Cloud** in queries and workbooks. [Follow steps to get this Kusto functions>]() ",
|
||||
"graphQueries": [
|
||||
{
|
||||
"metricName": "Fortinet FortiNDR Cloud Suricata Logs",
|
||||
"legend": "FncEventsSuricata_CL",
|
||||
"baseQuery": "FncEventsSuricata_CL"
|
||||
},
|
||||
{
|
||||
"metricName": "Fortinet FortiNDR Cloud Observation Logs",
|
||||
"legend": "FncEventsObservation_CL",
|
||||
"baseQuery": "FncEventsObservation_CL"
|
||||
},
|
||||
{
|
||||
"metricName": "Fortinet FortiNDR Cloud Detections Logs",
|
||||
"legend": "FncEventsDetections_CL",
|
||||
"baseQuery": "FncEventsDetections_CL"
|
||||
}
|
||||
],
|
||||
"sampleQueries": [
|
||||
{
|
||||
"description" : "Fortinet FortiNDR Cloud Suricata Logs",
|
||||
"query": "FncEventsSuricata_CL\n | sort by TimeGenerated desc"
|
||||
},
|
||||
{
|
||||
"description" : "Fortinet FortiNDR Cloud Observation Logs",
|
||||
"query": "FncEventsObservation_CL\n | sort by TimeGenerated desc"
|
||||
},
|
||||
{
|
||||
"description" : "Fortinet FortiNDR Cloud Detections Logs",
|
||||
"query": "FncEventsDetections_CL\n | sort by TimeGenerated desc"
|
||||
}
|
||||
],
|
||||
"dataTypes": [
|
||||
{
|
||||
"name": "FncEventsSuricata_CL",
|
||||
"lastDataReceivedQuery": "FncEventsSuricata_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
|
||||
},
|
||||
{
|
||||
"name": "FncEventsObservation_CL",
|
||||
"lastDataReceivedQuery": "FncEventsObservation_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
|
||||
},
|
||||
{
|
||||
"name": "FncEventsDetections_CL",
|
||||
"lastDataReceivedQuery": "FncEventsDetections_CL\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)"
|
||||
}
|
||||
],
|
||||
"connectivityCriterias": [
|
||||
{
|
||||
"type": "IsConnectedQuery",
|
||||
"value": [
|
||||
"FncEventsSuricata_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)",
|
||||
"FncEventsObservation_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)",
|
||||
"FncEventsDetections_CL\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(1d)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"availability": {
|
||||
"status": 1,
|
||||
"isPreview": true
|
||||
},
|
||||
"permissions": {
|
||||
"resourceProvider": [
|
||||
{
|
||||
"provider": "Microsoft.OperationalInsights/workspaces",
|
||||
"permissionsDisplayText": "read and write permissions on the workspace are required.",
|
||||
"providerDisplayName": "Workspace",
|
||||
"scope": "Workspace",
|
||||
"requiredPermissions": {
|
||||
"write": true,
|
||||
"read": true,
|
||||
"delete": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"provider": "Microsoft.OperationalInsights/workspaces/sharedKeys",
|
||||
"permissionsDisplayText": "read permissions to shared keys for the workspace are required. [See the documentation to learn more about workspace keys](https://docs.microsoft.com/azure/azure-monitor/platform/agent-windows#obtain-workspace-id-and-key).",
|
||||
"providerDisplayName": "Keys",
|
||||
"scope": "Workspace",
|
||||
"requiredPermissions": {
|
||||
"action": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"customs": [
|
||||
{
|
||||
"name": "Microsoft.Web/sites permissions",
|
||||
"description": "Read and write permissions to Azure Functions to create a Function App is required. [See the documentation to learn more about Azure Functions](https://docs.microsoft.com/azure/azure-functions/)."
|
||||
},
|
||||
{
|
||||
"name": "Amazon S3 REST API Credentials/permissions",
|
||||
"description": "**AWS Access Key Id**, **AWS Secret Access Key**, **FortiNDR Cloud Account Code** are required for Amazon S3 REST API."
|
||||
}
|
||||
]
|
||||
},
|
||||
"instructionSteps": [
|
||||
{
|
||||
"title": "",
|
||||
"description": ">**NOTE:** This connector uses Azure Functions to connect to the Amazon S3 REST API to pull logs into Microsoft Sentinel. This might result in additional data ingestion costs. Check the [Azure Functions pricing page](https://azure.microsoft.com/pricing/details/functions/) for details."
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"description": ">**(Optional Step)** Securely store workspace and API authorization key(s) or token(s) in Azure Key Vault. Azure Key Vault provides a secure mechanism to store and retrieve key values. [Follow these instructions](https://docs.microsoft.com/azure/app-service/app-service-key-vault-references) to use Azure Key Vault with an Azure Function App."
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"description": ">**NOTE:** This connector uses a parser based on a Kusto Function to normalize fields. [Follow these steps](https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Fortinet FortiNDR Cloud/Parsers/Fortinet_FortiNDR_Cloud) to create the Kusto function alias **Fortinet_FortiNDR_Cloud**."
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"description": "**STEP 1 - Configuration steps for the Fortinet FortiNDR Cloud Logs Collection**\n\nThe provider should provide or link to detailed steps to configure the 'PROVIDER NAME APPLICATION NAME' API endpoint so that the Azure Function can authenticate to it successfully, get its authorization key or token, and pull the appliance's logs into Azure Sentinel."
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"description": "**STEP 2 - Choose ONE from the following two deployment options to deploy the connector and the associated Azure Function**\n\n>**IMPORTANT:** Before deploying the Fortinet FortiNDR Cloud connector, have the Workspace ID and Workspace Primary Key (can be copied from the following), as well as the as well as the Amazon S3 REST API Authorization credentials, readily available.",
|
||||
"instructions": [
|
||||
{
|
||||
"parameters": {
|
||||
"fillWith": [
|
||||
"WorkspaceId"
|
||||
],
|
||||
"label": "Workspace ID"
|
||||
},
|
||||
"type": "CopyableLabel"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"fillWith": [
|
||||
"PrimaryKey"
|
||||
],
|
||||
"label": "Primary Key"
|
||||
},
|
||||
"type": "CopyableLabel"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"description": "**Option 1 - Azure Resource Manager (ARM) Template**\n\nUse this method for automated deployment of the Fortinet FortiNDR Cloud connector.\n\n1. Click the **Deploy to Azure** button below. \n\n\t[![Deploy To Azure](https://aka.ms/deploytoazurebutton)](<Add Link to ARM Template on https://aka.ms/threathunter GitHub repo, name template as azuredeploy_Connector_PROVIDER_NAME_APPLIANCE_NAME_AzureFunction.json>)\n2. Select the preferred **Subscription**, **Resource Group** and **Location**. \n3. Enter the **Workspace ID**, **Workspace Key**, **AwsAccessKeyId**, **AwsSecretAccessKey**, and/or Other required fields. \n4. Mark the checkbox labeled **I agree to the terms and conditions stated above**. \n5. Click **Purchase** to deploy."
|
||||
},
|
||||
{
|
||||
"title": "",
|
||||
"description": "**Option 2 - Manual Deployment of Azure Functions**\n\n Use the following step-by-step instructions to deploy the Fortinet FortiNDR Cloud connector manually with Azure Functions(Deployment via Visual Studio Code).",
|
||||
"instructions": [
|
||||
{
|
||||
"parameters": {
|
||||
"instructionSteps": [
|
||||
{
|
||||
"title": "Step 1 - Deploy a Function App",
|
||||
"description": "**NOTE:** You will need to [prepare VS code](https://docs.microsoft.com/azure/azure-functions/create-first-function-vs-code-python) for Azure Functions development.\n\n1. Download the [Azure Functions App]() file. Extract archive to your local development computer.\n2. Follow the [function app manual deployment instructions](https://github.com/Azure/Azure-Sentinel/blob/master/DataConnectors/AzureFunctionsManualDeployment.md#function-app-manual-deployment-instructions) to deploy the Azure Functions app using VSCode.\n3. After successful deployment of the function app, follow next steps for configuring it."
|
||||
},
|
||||
{
|
||||
"title": "Step 2 - Configure the Function App",
|
||||
"description": "1. In the Function App, select the Function App Name and select **Configuration**.\n2. In the **Application settings** tab, select **+ New application setting**.\n3. Add each of the following application settings individually, with their respective string values (case-sensitive): \n\t\tWorkspaceId\n\t\tWorkspaceKey\n\t\tAWSAccessKeyId\n\t\tAWSSecretAccessKey\n\t\tFncAccountCode\n\t\tFncEvents (optional default: observation,detections)\n\t\tFncTerminateApp (optional default: false)\n\t\tFncDaysToCollect(optional default: 7)\n\t\tFncIntervalMinutes (optional, default 5)\n\t\tlogAnalyticsUri (optional)\n> - Use logAnalyticsUri to override the log analytics API endpoint for dedicated cloud. For example, for public cloud, leave the value empty; for Azure GovUS cloud environment, specify the value in the following format: `https://<CustomerId>.ods.opinsights.azure.us`.\n3. Once all application settings have been entered, click **Save**."
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "InstructionStepsGroup"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"FunctionName": {
|
||||
"defaultValue": "FortiNDR Cloud",
|
||||
"minLength": 1,
|
||||
"maxLength": 20,
|
||||
"type": "string"
|
||||
},
|
||||
"WorkspaceId": {
|
||||
"type": "string",
|
||||
"defaultValue": "<WorkspaceId>"
|
||||
},
|
||||
"WorkspaceKey": {
|
||||
"type": "securestring",
|
||||
"defaultValue": "<workspaceKey>"
|
||||
},
|
||||
"AwsAccessKeyId": {
|
||||
"type": "string",
|
||||
"defaultValue": "<AwsAccessKeyId>"
|
||||
},
|
||||
"AwsSecretAccessKey": {
|
||||
"type": "securestring",
|
||||
"defaultValue": "<AwsSecretAccessKey>"
|
||||
},
|
||||
"FncAccountCode": {
|
||||
"type": "string",
|
||||
"defaultValue": "<enter the FortiNDR Cloud account code here>"
|
||||
},
|
||||
"FncEvents": {
|
||||
"type": "string",
|
||||
"defaultValue": "observation,detections"
|
||||
},
|
||||
"FncTerminateApp": {
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
"FncDaysToCollect": {
|
||||
"type": "int",
|
||||
"defaultValue": 7
|
||||
},
|
||||
"FncIntervalMinutes": {
|
||||
"type": "int",
|
||||
"defaultValue": 5
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"FunctionName": "[concat(toLower(parameters('FunctionName')), uniqueString(resourceGroup().id))]",
|
||||
"StorageSuffix": "[environment().suffixes.storage]",
|
||||
"LogAnalyticsUri": "[replace(environment().portal, 'https://portal', concat('https://', toLower(parameters('WorkspaceId')), '.ods.opinsights'))]"
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"type": "Microsoft.Insights/components",
|
||||
"apiVersion": "2015-05-01",
|
||||
"name": "[variables('FunctionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"kind": "web",
|
||||
"properties": {
|
||||
"Application_Type": "web",
|
||||
"ApplicationId": "[variables('FunctionName')]"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[tolower(variables('FunctionName'))]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"sku": {
|
||||
"name": "Standard_LRS",
|
||||
"tier": "Standard"
|
||||
},
|
||||
"kind": "StorageV2",
|
||||
"properties": {
|
||||
"networkAcls": {
|
||||
"bypass": "AzureServices",
|
||||
"virtualNetworkRules": [
|
||||
],
|
||||
"ipRules": [
|
||||
],
|
||||
"defaultAction": "Allow"
|
||||
},
|
||||
"supportsHttpsTrafficOnly": true,
|
||||
"encryption": {
|
||||
"services": {
|
||||
"file": {
|
||||
"keyType": "Account",
|
||||
"enabled": true
|
||||
},
|
||||
"blob": {
|
||||
"keyType": "Account",
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"keySource": "Microsoft.Storage"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Web/serverfarms",
|
||||
"apiVersion": "2018-02-01",
|
||||
"name": "[variables('FunctionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"sku": {
|
||||
"name": "Y1",
|
||||
"tier": "Dynamic"
|
||||
},
|
||||
"kind": "functionapp",
|
||||
"properties": {
|
||||
"name": "[variables('FunctionName')]",
|
||||
"workerSize": "0",
|
||||
"workerSizeId": "0",
|
||||
"numberOfWorkers": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[concat(variables('FunctionName'), '/default')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
|
||||
],
|
||||
"sku": {
|
||||
"name": "Standard_LRS",
|
||||
"tier": "Standard"
|
||||
},
|
||||
"properties": {
|
||||
"cors": {
|
||||
"corsRules": [
|
||||
]
|
||||
},
|
||||
"deleteRetentionPolicy": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts/fileServices",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[concat(variables('FunctionName'), '/default')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]"
|
||||
],
|
||||
"sku": {
|
||||
"name": "Standard_LRS",
|
||||
"tier": "Standard"
|
||||
},
|
||||
"properties": {
|
||||
"cors": {
|
||||
"corsRules": [
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Web/sites",
|
||||
"apiVersion": "2018-11-01",
|
||||
"name": "[variables('FunctionName')]",
|
||||
"location": "[resourceGroup().location]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', tolower(variables('FunctionName')))]",
|
||||
"[resourceId('Microsoft.Web/serverfarms', variables('FunctionName'))]",
|
||||
"[resourceId('Microsoft.Insights/components', variables('FunctionName'))]"
|
||||
],
|
||||
"kind": "functionapp",
|
||||
"identity": {
|
||||
"type": "SystemAssigned"
|
||||
},
|
||||
"properties": {
|
||||
"name": "[variables('FunctionName')]",
|
||||
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('FunctionName'))]",
|
||||
"httpsOnly": true,
|
||||
"clientAffinityEnabled": true,
|
||||
"alwaysOn": true,
|
||||
"reserved": true,
|
||||
"siteConfig": {
|
||||
"linuxFxVersion": "python|3.9"
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "2018-11-01",
|
||||
"type": "config",
|
||||
"name": "appsettings",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Web/sites/', variables('FunctionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"FUNCTIONS_EXTENSION_VERSION": "~4",
|
||||
"FUNCTIONS_WORKER_RUNTIME": "python",
|
||||
"APPINSIGHTS_INSTRUMENTATIONKEY": "[reference(resourceId('Microsoft.insights/components', variables('FunctionName')), '2015-05-01').InstrumentationKey]",
|
||||
"APPLICATIONINSIGHTS_CONNECTION_STRING": "[reference(resourceId('microsoft.insights/components', variables('FunctionName')), '2015-05-01').ConnectionString]",
|
||||
"AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=',toLower(variables('StorageSuffix')))]",
|
||||
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('DefaultEndpointsProtocol=https;AccountName=', toLower(variables('FunctionName')),';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', toLower(variables('FunctionName'))), '2019-06-01').keys[0].value, ';EndpointSuffix=',toLower(variables('StorageSuffix')))]",
|
||||
"WEBSITE_CONTENTSHARE": "[toLower(variables('FunctionName'))]",
|
||||
"WorkspaceId": "[parameters('WorkspaceID')]",
|
||||
"WorkspaceKey": "[parameters('WorkspaceKey')]",
|
||||
"AwsAccessKeyId": "[parameters('AwsAccessKeyId')]",
|
||||
"AwsSecretAccessKey": "[parameters('AwsSecretAccessKey')]",
|
||||
"FncAccountCode":"[parameters('FncAccountCode')]",
|
||||
"FncEvents": "[parameters('FncEvents')]",
|
||||
"FncTerminateApp": "[parameters('FncTerminateApp')]",
|
||||
"FncDaysToCollect": "[parameters('FncDaysToCollect')]",
|
||||
"FncIntervalMinutes": "[parameters('FncIntervalMinutes')]",
|
||||
"logAnalyticsUri": "[variables('LogAnalyticsUri')]",
|
||||
"WEBSITE_RUN_FROM_PACKAGE": "<add link to zip>"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-hosts')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"publicAccess": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[concat(variables('FunctionName'), '/default/azure-webjobs-secrets')]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('FunctionName'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"publicAccess": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Microsoft.Storage/storageAccounts/fileServices/shares",
|
||||
"apiVersion": "2019-06-01",
|
||||
"name": "[concat(variables('FunctionName'), '/default/', tolower(variables('FunctionName')))]",
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Storage/storageAccounts/fileServices', variables('FunctionName'), 'default')]",
|
||||
"[resourceId('Microsoft.Storage/storageAccounts', variables('FunctionName'))]"
|
||||
],
|
||||
"properties": {
|
||||
"shareQuota": 5120
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Двоичные данные
Solutions/Fortinet FortiNDR Cloud/Data Connectors/fortinetFortiNdrCloudDataConn.zip
Normal file
|
@ -0,0 +1,80 @@
|
|||
import logging
|
||||
import os
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from metastream import fetch_detections, fetch_events
|
||||
from metastream.s3_client import Context
|
||||
from sentinel import post_data
|
||||
from globalVariables import SUPPORTED_EVENT_TYPES
|
||||
|
||||
AWS_ACCESS_KEY = os.environ.get('AwsAccessKeyId')
|
||||
AWS_SECRET_KEY = os.environ.get('AwsSecretAccessKey') # is this encrypted
|
||||
ACCOUNT_CODE = os.environ.get("FncAccountCode")
|
||||
|
||||
|
||||
def main(args: dict) -> str:
|
||||
validate_args(args)
|
||||
|
||||
event_type = args.get('event_type', '')
|
||||
checkpoint = args.get('checkpoint', '')
|
||||
|
||||
if not checkpoint:
|
||||
return ""
|
||||
|
||||
logging.info(
|
||||
f'FetchAndSendActivity: event type: {event_type} checkpoint: {checkpoint}')
|
||||
|
||||
ctx = Context()
|
||||
start_date = datetime.fromisoformat(checkpoint).replace(tzinfo=timezone.utc)
|
||||
try:
|
||||
if event_type == 'detections':
|
||||
fetch_and_send_detections(ctx, event_type, start_date)
|
||||
else:
|
||||
fetch_and_send_events(ctx, event_type, start_date)
|
||||
|
||||
new_checkpoint = ctx.checkpoint.isoformat()
|
||||
|
||||
except Exception as ex:
|
||||
logging.error(
|
||||
f"Failure: FetchAcndSendActivity: event: {event_type} checkpoint: {checkpoint} error: {str(ex)}")
|
||||
raise Exception(
|
||||
f"Failure: FetchAcndSendActivity: event: {event_type} error: {str(ex)}")
|
||||
|
||||
return new_checkpoint
|
||||
|
||||
|
||||
def validate_args(args: dict):
|
||||
event_type = args.get('event_type', '')
|
||||
|
||||
if not event_type or not event_type in SUPPORTED_EVENT_TYPES:
|
||||
raise AttributeError(
|
||||
"Event type was not provided or it is not supported. Event type must be one of (Observation | Suricata | Detection).")
|
||||
|
||||
def post_events_inc(events, event_type):
|
||||
limit = 5000
|
||||
count = len(events)
|
||||
start = 0
|
||||
while start < count:
|
||||
end = count if count - start <= limit else start + limit
|
||||
post_data(events[start:end], event_type)
|
||||
start = start + limit
|
||||
|
||||
def fetch_and_send_events(ctx: Context, event_type: str, start_date: datetime):
|
||||
for events in fetch_events(context=ctx,
|
||||
name='sentinel',
|
||||
event_types=[event_type],
|
||||
account_code=ACCOUNT_CODE,
|
||||
start_date=start_date,
|
||||
access_key=AWS_ACCESS_KEY,
|
||||
secret_key=AWS_SECRET_KEY):
|
||||
post_events_inc(events, event_type)
|
||||
|
||||
|
||||
def fetch_and_send_detections(ctx: Context, event_type: str, start_date: datetime):
|
||||
for events in fetch_detections(context=ctx,
|
||||
name='sentinel',
|
||||
account_code=ACCOUNT_CODE,
|
||||
start_date=start_date,
|
||||
access_key=AWS_ACCESS_KEY,
|
||||
secret_key=AWS_SECRET_KEY):
|
||||
post_events_inc(events, event_type)
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"scriptFile": "__init__.py",
|
||||
"bindings": [
|
||||
{
|
||||
"name": "args",
|
||||
"type": "activityTrigger",
|
||||
"direction": "in"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
import logging
|
||||
import os
|
||||
from datetime import date, datetime, timedelta, timezone
|
||||
|
||||
from metastream import fetch_detections_by_day, fetch_events_by_day
|
||||
from metastream.s3_client import Context
|
||||
from sentinel.sentinel import post_data
|
||||
from globalVariables import SUPPORTED_EVENT_TYPES
|
||||
|
||||
AWS_ACCESS_KEY = os.environ.get('AwsAccessKeyId')
|
||||
AWS_SECRET_KEY = os.environ.get('AwsSecretAccessKey')
|
||||
ACCOUNT_CODE = os.environ.get("FncAccountCode")
|
||||
|
||||
|
||||
def main(args: dict) -> str:
|
||||
validate_args(args)
|
||||
|
||||
event_type = args.get('event_type', '')
|
||||
day: int = args.get('day', '')
|
||||
|
||||
try:
|
||||
ctx = Context()
|
||||
start_day = datetime.now(tz=timezone.utc) - timedelta(days=day)
|
||||
logging.info(
|
||||
f'FetchAndSendByDayActivity: event: {event_type} day: {start_day.date()}')
|
||||
|
||||
if event_type == 'detections':
|
||||
fetch_and_post_detections(ctx, event_type, start_day.date())
|
||||
else:
|
||||
fetch_and_post_events(ctx, event_type, start_day)
|
||||
|
||||
# it's required to return something that is json serializable
|
||||
return 'success'
|
||||
except Exception as ex:
|
||||
logging.error(
|
||||
f'Failure: FetchAndSendByDayActivity: event: {event_type} day: {start_day.date()} error: {str(ex)}')
|
||||
raise Exception(
|
||||
f"Failure: FetchAndSendByDayActivity failed. Event: {event_type} error: {str(ex)}")
|
||||
|
||||
|
||||
def validate_args(args: dict):
|
||||
event_type = args.get('event_type', '').lower()
|
||||
day: int = args.get('day', '')
|
||||
|
||||
if not event_type or not event_type in SUPPORTED_EVENT_TYPES:
|
||||
raise AttributeError(
|
||||
"Event type was not provided or it is not supported. Event type must be one of (Observation | Suricata | Detection).")
|
||||
if not day:
|
||||
raise AttributeError(
|
||||
"The day for which to retrieve event is required for the FetchAndSendByDayActivity.")
|
||||
|
||||
def post_events_inc(events, event_type):
|
||||
limit = 5000
|
||||
count = len(events)
|
||||
start = 0
|
||||
while start < count:
|
||||
end = count if count - start <= limit else start + limit
|
||||
post_data(events[start:end], event_type)
|
||||
start = start + limit
|
||||
|
||||
def fetch_and_post_events(ctx: Context, event_type: str, start_day: datetime):
|
||||
for events in fetch_events_by_day(context=ctx,
|
||||
name='sentinel',
|
||||
event_type=event_type,
|
||||
account_code=ACCOUNT_CODE,
|
||||
day=start_day,
|
||||
access_key=AWS_ACCESS_KEY,
|
||||
secret_key=AWS_SECRET_KEY):
|
||||
post_events_inc(events, event_type)
|
||||
|
||||
|
||||
|
||||
def fetch_and_post_detections(ctx: Context, event_type: str, start_day: date):
|
||||
for events in fetch_detections_by_day(context=ctx,
|
||||
name='sentinel',
|
||||
account_code=ACCOUNT_CODE,
|
||||
day=start_day,
|
||||
access_key=AWS_ACCESS_KEY,
|
||||
secret_key=AWS_SECRET_KEY):
|
||||
post_events_inc(events, event_type)
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"scriptFile": "__init__.py",
|
||||
"bindings": [
|
||||
{
|
||||
"name": "args",
|
||||
"type": "activityTrigger",
|
||||
"direction": "in"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
import logging
|
||||
import os
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from azure.durable_functions.models import DurableOrchestrationStatus
|
||||
import azure.durable_functions as df
|
||||
import azure.functions as func
|
||||
|
||||
from metastream.errors import InputError
|
||||
from globalVariables import ORCHESTRATION_NAME, SUPPORTED_EVENT_TYPES
|
||||
|
||||
NOT_RUNNING_FUNCTION_STATES = [
|
||||
df.OrchestrationRuntimeStatus.Completed,
|
||||
df.OrchestrationRuntimeStatus.Failed,
|
||||
df.OrchestrationRuntimeStatus.Terminated,
|
||||
None
|
||||
]
|
||||
|
||||
EVENT_TYPES = (os.environ.get("FncEvents") or "observation").split(",")
|
||||
EVENT_TYPES = [event.strip() for event in EVENT_TYPES if event]
|
||||
TERMINATE_APP = os.environ.get("FncTerminateApp").strip().lower() == 'true'
|
||||
|
||||
try:
|
||||
DAYS_TO_COLLECT = int(os.environ.get("FncDaysToCollect") or 7)
|
||||
except ValueError:
|
||||
DAYS_TO_COLLECT = None
|
||||
|
||||
try:
|
||||
INTERVAL = int(os.environ.get("FncIntervalMinutes") or "5")
|
||||
except ValueError:
|
||||
INTERVAL = None
|
||||
|
||||
|
||||
def validate_configuration():
|
||||
if EVENT_TYPES and not SUPPORTED_EVENT_TYPES.issuperset(EVENT_TYPES):
|
||||
raise InputError(
|
||||
f"FncEvents must be one or more of {SUPPORTED_EVENT_TYPES}")
|
||||
|
||||
sentinel_shared_key = (os.environ.get('WorkspaceKey') or '').strip()
|
||||
if not sentinel_shared_key:
|
||||
raise InputError(f'WorkspaceKey is required.')
|
||||
|
||||
if INTERVAL is None or INTERVAL < 1 or INTERVAL > 60:
|
||||
raise InputError(f'FncIntervalMinutes must be a number 1-60')
|
||||
|
||||
if DAYS_TO_COLLECT and (DAYS_TO_COLLECT < 0 or DAYS_TO_COLLECT > 7):
|
||||
raise InputError(f'FncDaysToCollect must be a number 0-7')
|
||||
|
||||
|
||||
async def main(mytimer: func.TimerRequest, starter: str) -> None:
|
||||
client = df.DurableOrchestrationClient(starter)
|
||||
instance_id = "FncIntegrationSentinelStaticInstanceId"
|
||||
|
||||
existing_instance = await client.get_status(instance_id)
|
||||
logging.info(
|
||||
f'OrchestratorWatchdog: {ORCHESTRATION_NAME} status: {existing_instance.runtime_status}')
|
||||
|
||||
if TERMINATE_APP:
|
||||
reason = f'FncTerminateApp set to {TERMINATE_APP}'
|
||||
await terminate_app(client, existing_instance.runtime_status, instance_id, reason)
|
||||
return
|
||||
|
||||
# Only start the orchestrator if it's not already running.
|
||||
if existing_instance.runtime_status in NOT_RUNNING_FUNCTION_STATES:
|
||||
validate_configuration()
|
||||
await client.start_new(ORCHESTRATION_NAME, instance_id, create_args())
|
||||
logging.info(f"OrchestratorWatchdog: Started {ORCHESTRATION_NAME}")
|
||||
|
||||
|
||||
async def terminate_app(client, status, instance_id, reason: str):
|
||||
if status not in NOT_RUNNING_FUNCTION_STATES:
|
||||
await client.terminate(instance_id=instance_id, reason=reason)
|
||||
logging.info(
|
||||
f'OrchestrationWatchdog: Termination request sent to {ORCHESTRATION_NAME}.')
|
||||
|
||||
|
||||
def create_args():
|
||||
timestamp = datetime.now(tz=timezone.utc)
|
||||
days_to_collect = DAYS_TO_COLLECT if DAYS_TO_COLLECT else 0
|
||||
|
||||
if DAYS_TO_COLLECT:
|
||||
start_date = timestamp.replace(hour=0, minute=0, second=0).isoformat()
|
||||
else:
|
||||
start_date = (timestamp - timedelta(minutes=INTERVAL)).isoformat()
|
||||
|
||||
args = {}
|
||||
args['event_types'] = {
|
||||
event_type.strip(): {
|
||||
"checkpoint": start_date,
|
||||
"days_to_collect": days_to_collect
|
||||
}
|
||||
for event_type in EVENT_TYPES
|
||||
}
|
||||
args['interval'] = INTERVAL
|
||||
return args
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"scriptFile": "__init__.py",
|
||||
"bindings": [
|
||||
{
|
||||
"name": "mytimer",
|
||||
"type": "timerTrigger",
|
||||
"direction": "in",
|
||||
"schedule": "0 0 */6 * * *",
|
||||
"runOnStartup": true
|
||||
},
|
||||
{
|
||||
"type": "orchestrationClient",
|
||||
"direction": "in",
|
||||
"name": "starter"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
import azure.durable_functions as df
|
||||
|
||||
def orchestrator_function(context: df.DurableOrchestrationContext):
|
||||
args: dict = context.get_input()
|
||||
event_types: dict = args.get('event_types')
|
||||
interval: int = args.get('interval')
|
||||
|
||||
logging.info(
|
||||
f'SingletonEternalOrchestrator: event_types: {list(event_types)} instance_id: {context.instance_id}')
|
||||
|
||||
if not event_types:
|
||||
return
|
||||
|
||||
# Retrieving full days for each event_type one by one
|
||||
failing = args.get('failing', [])
|
||||
for event_type, event_type_args in event_types.items():
|
||||
if event_type in failing:
|
||||
continue
|
||||
attempt = event_type_args.get('attempt', 0)
|
||||
remaining_days = event_type_args['days_to_collect']
|
||||
if remaining_days > 0 and attempt <= 3:
|
||||
try:
|
||||
yield context.call_activity('FetchAndSendByDayActivity', {'day': remaining_days, 'event_type': event_type})
|
||||
event_types[event_type]['days_to_collect'] = remaining_days-1
|
||||
event_type_args['attempt'] = 0
|
||||
except Exception as ex:
|
||||
logging.error(f'Error when fetching events by day with event_type => {event_type} error => {ex}')
|
||||
attempt += 1
|
||||
event_types[event_type]['attempt'] = attempt
|
||||
if attempt <= 3:
|
||||
logging.info(f"Retrying attempt {attempt}.")
|
||||
else:
|
||||
failing.append(event_type)
|
||||
args['failing'] = failing
|
||||
|
||||
# Run the orchastrator new for each day to help avoid timeouts.
|
||||
args['event_types'] = event_types
|
||||
context.continue_as_new(args)
|
||||
return
|
||||
|
||||
# Retrieving piece of a day for each event_type one by one
|
||||
retrieved = args.get('retrieved', [])
|
||||
for event_type, event_type_args in event_types.items():
|
||||
attempt = event_type_args.get('attempt', 0)
|
||||
if event_type in failing or event_type in retrieved or attempt > 3:
|
||||
continue
|
||||
|
||||
try:
|
||||
checkpoint = event_type_args['checkpoint']
|
||||
next_checkpoint = yield context.call_activity('FetchAndSendActivity', {'checkpoint': checkpoint, 'event_type': event_type})
|
||||
event_types[event_type]['checkpoint'] = next_checkpoint
|
||||
retrieved.append(event_type)
|
||||
args['retrieved'] = retrieved
|
||||
event_type_args['attempt'] = 0
|
||||
except Exception as ex:
|
||||
logging.error(f'Error when fetching events by checkpoints with event_type => {event_type} error => {ex}')
|
||||
attempt += 1
|
||||
event_types[event_type]['attempt'] = attempt
|
||||
if attempt <= 3:
|
||||
logging.info(f"Retrying attempt {attempt}.")
|
||||
else:
|
||||
failing.append(event_type)
|
||||
args['failing'] = failing
|
||||
|
||||
args['event_types'] = event_types
|
||||
context.continue_as_new(args)
|
||||
return
|
||||
|
||||
retrieved_events = args.get('retrieved', 'none')
|
||||
failed_events = args.get('failing', 'none')
|
||||
logging.info(f'Fech events finished. Retrieved Events: {retrieved_events}, Failed Events: {failed_events}')
|
||||
args.pop('retrieved', None)
|
||||
args.pop('failing', None)
|
||||
for event_type_args in event_types.values():
|
||||
event_type_args['attempt'] = 0
|
||||
args['event_types'] = event_types
|
||||
|
||||
# sleep
|
||||
logging.info(
|
||||
f'SingletonEternalOrchestrator: Sleeping for {interval} minutes')
|
||||
yield context.create_timer(context.current_utc_datetime + timedelta(minutes=interval))
|
||||
logging.info(
|
||||
f'SingletonEternalOrchestrator: Woke up and will continue as new.')
|
||||
context.continue_as_new(args)
|
||||
|
||||
main = df.Orchestrator.create(orchestrator_function)
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"scriptFile": "__init__.py",
|
||||
"bindings": [
|
||||
{
|
||||
"name": "context",
|
||||
"type": "orchestrationTrigger",
|
||||
"direction": "in"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
SUPPORTED_EVENT_TYPES = set(['observation', 'suricata', 'detections'])
|
||||
|
||||
ORCHESTRATION_NAME = 'SingletonEternalOrchestrator'
|
||||
|
||||
AUTH_URLS = {
|
||||
"production": "auth.icebrg.io",
|
||||
"uat": "auth-uat.icebrg.io"
|
||||
}
|
||||
|
||||
BUCKETS = {
|
||||
"production": "fortindr-cloud-metastream",
|
||||
"uat": "fortindr-cloud-metastream-uat"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
from .metastream import fetch_events_by_day, fetch_events, fetch_event_types, fetch_detections, fetch_detections_by_day
|
|
@ -0,0 +1,56 @@
|
|||
import http.client
|
||||
import json
|
||||
|
||||
from globalVariables import AUTH_URLS
|
||||
from .errors import InputError
|
||||
|
||||
def _get_auth_url(env):
|
||||
auth_url = AUTH_URLS.get(env)
|
||||
if not auth_url:
|
||||
raise InputError(f"no auth url defined for environment '{env}'")
|
||||
return auth_url
|
||||
|
||||
|
||||
class Auth:
|
||||
def __init__(self, token, env):
|
||||
self.token = token
|
||||
self.env = env
|
||||
|
||||
def __enter__(self):
|
||||
self.connection = _Auth(self.token).connect(self.env)
|
||||
return self.connection
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.connection.conn.close()
|
||||
|
||||
|
||||
class _Auth:
|
||||
def __init__(self, token):
|
||||
self.conn = None
|
||||
self._headers = {"Authorization": f"IBToken {token}"}
|
||||
|
||||
def connect(self, env: str):
|
||||
auth_url = _get_auth_url(env)
|
||||
self.conn = http.client.HTTPSConnection(auth_url)
|
||||
return self
|
||||
|
||||
def user(self) -> dict:
|
||||
url = "/v1/authenticate/self"
|
||||
user = self._get(url).get("user")
|
||||
if not user:
|
||||
raise InputError("unable to get user from auth")
|
||||
return user
|
||||
|
||||
def account(self, account_uuid: str) -> dict:
|
||||
url = f"/v1/account/{account_uuid}"
|
||||
account = self._get(url).get("account")
|
||||
if not account:
|
||||
raise InputError("unable to get account from auth")
|
||||
return account
|
||||
|
||||
def _get(self, url: str) -> dict:
|
||||
self.conn.request("GET", url, headers=self._headers)
|
||||
r = self.conn.getresponse()
|
||||
if 200 > r.status > 300:
|
||||
raise InputError(f"unable to contact auth: {r.status} {r.reason}")
|
||||
return json.loads(r.read())
|
|
@ -0,0 +1,18 @@
|
|||
class BaseError(Exception):
|
||||
"""Base class for metastream client errors"""
|
||||
|
||||
def __init__(self, code, message):
|
||||
self.code = code
|
||||
self.message = message
|
||||
super().__init__(message)
|
||||
|
||||
|
||||
class InputError(BaseError):
|
||||
"""Exception raised for user input errors"""
|
||||
def __init__(self, message):
|
||||
super().__init__(code=0, message=message)
|
||||
|
||||
|
||||
class ServerError(BaseError):
|
||||
"""Exception raised for server side errors"""
|
||||
pass
|
|
@ -0,0 +1,255 @@
|
|||
import os.path
|
||||
from datetime import datetime, timedelta, timezone, date
|
||||
from typing import List
|
||||
|
||||
from globalVariables import SUPPORTED_EVENT_TYPES, BUCKETS
|
||||
from .s3_client import S3Client, Context
|
||||
from .auth_client import Auth
|
||||
from .errors import InputError, ServerError
|
||||
|
||||
def _validate_start_date(start_date: datetime, checkpoint: datetime):
|
||||
if start_date > checkpoint:
|
||||
raise InputError(message="start_date must be at least 1 second in the past")
|
||||
|
||||
delta = checkpoint - start_date
|
||||
if delta > timedelta(days=1):
|
||||
raise InputError(message="start_date must be within the last 24 hours")
|
||||
|
||||
|
||||
def _validate_day(day: date):
|
||||
if (datetime.now(timezone.utc).date() - day).days > 7:
|
||||
raise InputError(message="day must be within 7 days")
|
||||
|
||||
|
||||
def _validate_event_types(event_types):
|
||||
if not all(e in SUPPORTED_EVENT_TYPES for e in event_types):
|
||||
raise InputError(f'event_types must be of the following: {", ".join(SUPPORTED_EVENT_TYPES)}')
|
||||
|
||||
|
||||
def _validate_limit(limit: int):
|
||||
if limit < 1 or limit > 10_000:
|
||||
raise InputError('limit must be between 1 and 10,000')
|
||||
|
||||
|
||||
def _basename(prefix):
|
||||
return os.path.basename(prefix.rstrip('/'))
|
||||
|
||||
|
||||
def _prefix_to_datetime(date_prefix: str) -> datetime:
|
||||
"""
|
||||
Converts a S3 bucket key prefix to a datetime.
|
||||
:param date_prefix: assumes the last element is a date in YYYYMMDD format
|
||||
:return: UTC datetime
|
||||
"""
|
||||
date = _basename(date_prefix)
|
||||
if date.startswith("date_partition="):
|
||||
date = date[15:]
|
||||
try:
|
||||
return datetime.strptime(date + '+0000', "%Y%m%d%z")
|
||||
except ValueError:
|
||||
raise ServerError(message=f'unknown format for date_prefix: {date_prefix}', code=0) from None
|
||||
|
||||
|
||||
def _ts_to_datetime(timestamp: str) -> datetime:
|
||||
"""Converts an ISO 8601 formatted timestamp to a datetime"""
|
||||
if not timestamp:
|
||||
return datetime.min
|
||||
return datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f%z')
|
||||
|
||||
|
||||
def _get_customer_prefix(account_code: str, env: str) -> str:
|
||||
"""returns the bucket key prefix up to the account_code"""
|
||||
if env.lower() == "uat":
|
||||
account_code = f'uat-{account_code}'
|
||||
return f'v1/customer/cust-{account_code}'
|
||||
|
||||
|
||||
def _get_bucket(env: str):
|
||||
if env.lower() == "production":
|
||||
return BUCKETS["production"]
|
||||
else:
|
||||
return BUCKETS["uat"]
|
||||
|
||||
|
||||
def _fetch_account_code(env: str, account_code: str = None, api_token: str = None) -> str:
|
||||
"""returns account_code if given or else attempts to fetch the account code from the auth API"""
|
||||
if not any([account_code, api_token]):
|
||||
raise InputError(f"one of 'account_code' or 'api_token' is required")
|
||||
if account_code:
|
||||
return account_code
|
||||
|
||||
with Auth(api_token, env) as auth:
|
||||
user = auth.user()
|
||||
account_uuid = user.get("account_uuid")
|
||||
account = auth.account(account_uuid)
|
||||
account_code = account.get("code")
|
||||
if account_code is None:
|
||||
raise InputError("unable to get account code from auth")
|
||||
return account_code
|
||||
|
||||
|
||||
def _create_user_agent_extra(name, account_code):
|
||||
user_agent_extra = f'integrations-{name}-{account_code}'
|
||||
return user_agent_extra
|
||||
|
||||
|
||||
def fetch_events(name: str, event_types: List[str], account_code: str = None, api_token: str = None,
|
||||
start_date: datetime = datetime.now(timezone.utc) - timedelta(minutes=5),
|
||||
access_key: str = None, secret_key: str = None, limit: int = 0, env: str = "production",
|
||||
context: Context = None):
|
||||
"""fetches events from metastream. See README.md for full details"""
|
||||
checkpoint = datetime.now(tz=timezone.utc).replace(microsecond=0)
|
||||
if context:
|
||||
context.checkpoint = checkpoint
|
||||
|
||||
account_code = _fetch_account_code(env, account_code, api_token)
|
||||
_validate_event_types(event_types)
|
||||
_validate_start_date(start_date, checkpoint)
|
||||
|
||||
start_day = start_date.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc)
|
||||
|
||||
if not event_types:
|
||||
event_types = SUPPORTED_EVENT_TYPES
|
||||
|
||||
num_events = 0
|
||||
cut_off = checkpoint - timedelta(seconds=1)
|
||||
|
||||
user_agent_extra = _create_user_agent_extra(name, account_code)
|
||||
|
||||
with S3Client(_get_bucket(env), access_key, secret_key, user_agent_extra, context=context) as s3:
|
||||
for sensor_prefix in s3.fetch_common_prefixes(_get_customer_prefix(account_code, env)):
|
||||
if _basename(sensor_prefix) in ['devices', 'signals']:
|
||||
continue
|
||||
|
||||
for date_prefix in s3.fetch_common_prefixes(sensor_prefix):
|
||||
if start_day > _prefix_to_datetime(date_prefix):
|
||||
continue
|
||||
|
||||
for event_type_prefix in s3.fetch_common_prefixes(date_prefix):
|
||||
if _basename(event_type_prefix) not in event_types:
|
||||
continue
|
||||
|
||||
for obj in s3.fetch_file_objects(f'{event_type_prefix}v1/'):
|
||||
if start_date > obj.get('LastModified'):
|
||||
continue
|
||||
if obj.get('LastModified') > cut_off:
|
||||
continue
|
||||
|
||||
events = s3.fetch_gzipped_json_lines_file(obj.get('Key'))
|
||||
if limit:
|
||||
yield events[:limit - num_events]
|
||||
num_events += len(events)
|
||||
if num_events >= limit:
|
||||
return
|
||||
else:
|
||||
yield events
|
||||
|
||||
|
||||
def fetch_events_by_day(name: str, day: datetime, event_type: str, account_code: str, api_token: str = None,
|
||||
access_key: str = None, secret_key: str = None, limit: int = 0, env: str = "production",
|
||||
context: Context = None) -> List[dict]:
|
||||
"""fetches events from metastream for an entire day. See README.md for full details"""
|
||||
account_code = _fetch_account_code(env, account_code, api_token)
|
||||
_validate_day(day.date())
|
||||
start_day = day.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc)
|
||||
|
||||
user_agent_extra = _create_user_agent_extra(name, account_code)
|
||||
num_events = 0
|
||||
with S3Client(_get_bucket(env), access_key, secret_key, user_agent_extra, context=context) as s3:
|
||||
for sensor_prefix in s3.fetch_common_prefixes(_get_customer_prefix(account_code, env)):
|
||||
if _basename(sensor_prefix) in ['devices', 'signals']:
|
||||
continue
|
||||
|
||||
for date_prefix in s3.fetch_common_prefixes(sensor_prefix):
|
||||
if start_day != _prefix_to_datetime(date_prefix):
|
||||
continue
|
||||
|
||||
for event_type_prefix in s3.fetch_common_prefixes(date_prefix):
|
||||
if _basename(event_type_prefix) != event_type:
|
||||
continue
|
||||
|
||||
for obj in s3.fetch_file_objects(f'{event_type_prefix}v1/'):
|
||||
events = s3.fetch_gzipped_json_lines_file(obj.get('Key'))
|
||||
if limit:
|
||||
yield events[:limit - num_events]
|
||||
num_events += len(events)
|
||||
if num_events >= limit:
|
||||
return
|
||||
else:
|
||||
yield events
|
||||
|
||||
|
||||
def fetch_detections_by_day(name: str, day: date, account_code: str, access_key: str = None, secret_key: str = None,
|
||||
limit: int = 0, env: str = "production", context: Context = None) -> List[dict]:
|
||||
"""fetches events from metastream for an entire day. See README.md for full details"""
|
||||
_validate_day(day)
|
||||
|
||||
user_agent_extra = _create_user_agent_extra(name, account_code)
|
||||
num_events = 0
|
||||
with S3Client(_get_bucket(env), access_key, secret_key, user_agent_extra, context=context) as s3:
|
||||
for sensor_prefix in s3.fetch_common_prefixes(_get_customer_prefix(account_code, env)):
|
||||
if _basename(sensor_prefix) != 'signals':
|
||||
continue
|
||||
|
||||
for date_prefix in s3.fetch_common_prefixes(sensor_prefix):
|
||||
if day != _prefix_to_datetime(date_prefix).date():
|
||||
continue
|
||||
|
||||
for obj in s3.fetch_file_objects(date_prefix):
|
||||
if not _basename(obj.get('Key', '')).startswith('detection_none'):
|
||||
continue
|
||||
events = s3.fetch_gzipped_json_lines_file(obj.get('Key'))
|
||||
if limit:
|
||||
yield events[:limit - num_events]
|
||||
num_events += len(events)
|
||||
if num_events >= limit:
|
||||
return
|
||||
else:
|
||||
yield events
|
||||
|
||||
|
||||
def fetch_detections(name: str, account_code: str, start_date: datetime, access_key: str = None, secret_key: str = None,
|
||||
limit: int = 0, env: str = "production", context: Context = None):
|
||||
"""fetches events from metastream. See README.md for full details"""
|
||||
checkpoint = datetime.now(tz=timezone.utc).replace(microsecond=0)
|
||||
if context:
|
||||
context.checkpoint = checkpoint
|
||||
|
||||
_validate_start_date(start_date, checkpoint)
|
||||
|
||||
start_day = start_date.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=timezone.utc)
|
||||
|
||||
num_events = 0
|
||||
cut_off = checkpoint - timedelta(seconds=1)
|
||||
|
||||
user_agent_extra = _create_user_agent_extra(name, account_code)
|
||||
|
||||
with S3Client(_get_bucket(env), access_key, secret_key, user_agent_extra, context=context) as s3:
|
||||
for sensor_prefix in s3.fetch_common_prefixes(_get_customer_prefix(account_code, env)):
|
||||
if _basename(sensor_prefix) != 'signals':
|
||||
continue
|
||||
|
||||
for date_prefix in s3.fetch_common_prefixes(sensor_prefix):
|
||||
if start_day > _prefix_to_datetime(date_prefix):
|
||||
continue
|
||||
|
||||
for obj in s3.fetch_file_objects(date_prefix):
|
||||
if not _basename(obj.get('Key', '')).startswith('detection_none'):
|
||||
continue
|
||||
if start_date > obj.get('LastModified'):
|
||||
continue
|
||||
if obj.get('LastModified') > cut_off:
|
||||
continue
|
||||
|
||||
events = s3.fetch_gzipped_json_lines_file(obj.get('Key'))
|
||||
if limit:
|
||||
yield events[:limit - num_events]
|
||||
num_events += len(events)
|
||||
if num_events >= limit:
|
||||
return
|
||||
else:
|
||||
yield events
|
||||
|
||||
|
||||
def fetch_event_types():
|
||||
return SUPPORTED_EVENT_TYPES
|
|
@ -0,0 +1,137 @@
|
|||
import gzip
|
||||
import io
|
||||
import json
|
||||
from typing import List
|
||||
|
||||
import boto3
|
||||
import botocore.client
|
||||
import botocore.config
|
||||
|
||||
|
||||
class Context:
|
||||
def __init__(self):
|
||||
self.file_downloads = 0
|
||||
self.api_calls = 0
|
||||
self.checkpoint = None
|
||||
|
||||
def file_downloads_incr(self):
|
||||
self.file_downloads += 1
|
||||
|
||||
def api_calls_incr(self):
|
||||
self.api_calls += 1
|
||||
|
||||
|
||||
class S3Client:
|
||||
def __init__(self, bucket: str, access_key: str, secret_key: str, user_agent_extra: str, client: botocore.client.BaseClient = None,
|
||||
context: Context = None):
|
||||
"""
|
||||
S3Client provides a context manager for _S3Client. Provides higher level methods for S3.
|
||||
|
||||
:param bucket: S3 bucket
|
||||
:param access_key: aws access key
|
||||
:param secret_key: aws secret access key
|
||||
:param user_agent_extra: appends to user-agent
|
||||
:param client: optional boto3 client
|
||||
:param context: optional context for exporting metrics
|
||||
"""
|
||||
self.bucket = bucket
|
||||
self.access_key = access_key
|
||||
self.secret_key = secret_key
|
||||
self.user_agent_extra = user_agent_extra
|
||||
self.client = client
|
||||
self.context = context
|
||||
|
||||
def __enter__(self):
|
||||
self.client = _S3Client(self.bucket, self.access_key, self.secret_key, self.user_agent_extra, self.client, self.context)
|
||||
return self.client
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
pass
|
||||
# older version of boto3 in splunk cloud doesn't have close() method.
|
||||
# self.client.client.close()
|
||||
|
||||
|
||||
class _S3Client:
|
||||
S3_MAX_KEYS = 1000
|
||||
|
||||
def __init__(self, bucket: str, access_key: str, secret_key: str, user_agent_extra: str, client, context: Context):
|
||||
self.bucket = bucket
|
||||
self.context = context or Context()
|
||||
if client is not None:
|
||||
self.client = client
|
||||
else:
|
||||
config = botocore.config.Config(user_agent_extra=user_agent_extra)
|
||||
self.client = boto3.client('s3', aws_access_key_id=access_key, aws_secret_access_key=secret_key, config=config)
|
||||
|
||||
def fetch_common_prefixes(self, prefix: str) -> List[str]:
|
||||
"""
|
||||
A generator function that yields common prefix found after the given prefix.
|
||||
|
||||
:param prefix: s3 bucket key prefix
|
||||
"""
|
||||
if not prefix.endswith('/'):
|
||||
prefix += '/'
|
||||
self.context.api_calls_incr()
|
||||
obj = self.client.list_objects_v2(
|
||||
Bucket=self.bucket,
|
||||
Delimiter="/",
|
||||
Prefix=prefix,
|
||||
MaxKeys=self.S3_MAX_KEYS
|
||||
)
|
||||
common_prefixes = obj.get('CommonPrefixes') or []
|
||||
for prefix in common_prefixes:
|
||||
yield prefix.get('Prefix')
|
||||
|
||||
while obj.get('IsTruncated'):
|
||||
self.context.api_calls_incr()
|
||||
obj = self.client.list_objects_v2(
|
||||
Bucket=self.bucket,
|
||||
Delimiter="/",
|
||||
Prefix=prefix,
|
||||
ContinuationToken=obj.get('NextContinuationToken'),
|
||||
MaxKeys=self.S3_MAX_KEYS
|
||||
)
|
||||
common_prefixes = obj.get('CommonPrefixes') or []
|
||||
for prefix in common_prefixes:
|
||||
yield prefix.get('Prefix')
|
||||
|
||||
def fetch_file_objects(self, prefix: str) -> List:
|
||||
"""
|
||||
A generator method that yields file objects found after the given key prefix.
|
||||
|
||||
:param prefix: s3 bucket key prefix
|
||||
"""
|
||||
self.context.api_calls_incr()
|
||||
obj = self.client.list_objects_v2(
|
||||
Bucket=self.bucket,
|
||||
Prefix=prefix,
|
||||
MaxKeys=self.S3_MAX_KEYS
|
||||
)
|
||||
contents = obj.get('Contents') or []
|
||||
for item in contents:
|
||||
yield item
|
||||
|
||||
while obj.get('IsTruncated'):
|
||||
self.context.api_calls_incr()
|
||||
obj = self.client.list_objects_v2(
|
||||
Bucket=self.bucket,
|
||||
Prefix=prefix,
|
||||
ContinuationToken=obj.get('NextContinuationToken'),
|
||||
MaxKeys=self.S3_MAX_KEYS
|
||||
)
|
||||
contents = obj.get('Contents') or []
|
||||
for item in contents:
|
||||
yield item
|
||||
|
||||
def fetch_gzipped_json_lines_file(self, key: str) -> List[dict]:
|
||||
"""
|
||||
Downloads a gzipped file of `JSON Lines` format and converts it to Python.
|
||||
|
||||
:param key: s3 key to a gzipped JSON Lines file
|
||||
:returns Contents of the file converted to Python
|
||||
"""
|
||||
self.context.file_downloads_incr()
|
||||
datagz = io.BytesIO()
|
||||
self.client.download_fileobj(Bucket=self.bucket, Key=key, Fileobj=datagz)
|
||||
data = gzip.decompress(datagz.getvalue())
|
||||
return [json.loads(line) for line in data.splitlines(False)]
|
|
@ -0,0 +1 @@
|
|||
from .sentinel import post_data
|
|
@ -0,0 +1,50 @@
|
|||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
import requests
|
||||
|
||||
LOG_ANALYTICS_URI = (os.environ.get('LogAnalyticsUri') or "").strip()
|
||||
SENTINEL_CUSTOMER_ID = (os.environ.get('WorkspaceId') or '').strip()
|
||||
SENTINEL_RESOURCE = '/api/logs'
|
||||
if not LOG_ANALYTICS_URI:
|
||||
LOG_ANALYTICS_URI = f'https://{SENTINEL_CUSTOMER_ID}.ods.opinsights.azure.com{SENTINEL_RESOURCE}?api-version=2016-04-01'
|
||||
SENTINEL_SHARED_KEY = (os.environ.get('WorkspaceKey') or '').strip()
|
||||
|
||||
def post_data(events: list[dict], log_type_suffix: str):
|
||||
"""Build and send a request to the POST API"""
|
||||
body = json.dumps(events)
|
||||
method = 'POST'
|
||||
content_type = 'application/json'
|
||||
resource = '/api/logs'
|
||||
rfc1123date = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||
content_length = len(body)
|
||||
signature = _build_signature(rfc1123date, content_length, method, content_type, resource)
|
||||
log_type = f'FncEvents{log_type_suffix.title()}'
|
||||
|
||||
headers = {
|
||||
'content-type': content_type,
|
||||
'Authorization': signature,
|
||||
'Log-Type': log_type,
|
||||
'x-ms-date': rfc1123date
|
||||
}
|
||||
response = requests.post(LOG_ANALYTICS_URI, data=body, headers=headers)
|
||||
if (response.status_code >= 200 and response.status_code <= 299):
|
||||
logging.info(f'SentinelClient: posted {len(events)} events to {log_type}')
|
||||
else:
|
||||
logging.error(f"SentinelClient: failed to post events to Sentinel. Response code: {response.status_code}")
|
||||
raise requests.exceptions.HTTPError(f"SentinelClient: failed to post events to Sentinel. Response code: {response.status_code}")
|
||||
|
||||
def _build_signature(date, content_length, method, content_type, resource):
|
||||
'''Build the API signature'''
|
||||
x_headers = 'x-ms-date:' + date
|
||||
string_to_hash = f'{method}\n{str(content_length)}\n{content_type}\n{x_headers}\n{resource}'
|
||||
bytes_to_hash = bytes(string_to_hash, encoding="utf-8")
|
||||
decoded_key = base64.b64decode(SENTINEL_SHARED_KEY)
|
||||
encoded_hash = base64.b64encode(hmac.new(
|
||||
decoded_key, bytes_to_hash, digestmod=hashlib.sha256).digest()).decode()
|
||||
return f"SharedKey {SENTINEL_CUSTOMER_ID}:{encoded_hash}"
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"version": "2.0",
|
||||
"logging": {
|
||||
"applicationInsights": {
|
||||
"samplingSettings": {
|
||||
"isEnabled": true,
|
||||
"excludedTypes": "Request"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extensionBundle": {
|
||||
"id": "Microsoft.Azure.Functions.ExtensionBundle",
|
||||
"version": "[3.*, 4.0.0)"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
# DO NOT include azure-functions-worker in this file
|
||||
# The Python Worker is managed by Azure Functions platform
|
||||
# Manually managing azure-functions-worker may cause unexpected issues
|
||||
|
||||
aiohttp==3.8.6
|
||||
aiosignal==1.3.1
|
||||
astor==0.8.1
|
||||
astroid==2.9.3
|
||||
async-timeout==4.0.3
|
||||
attrs==23.1.0
|
||||
autopep8==1.7.0
|
||||
azure-functions==1.17.0
|
||||
azure-functions-durable==1.2.6
|
||||
bandit==1.7.5
|
||||
bcrypt==4.0.1
|
||||
beautifulsoup4==4.12.2
|
||||
boto3==1.28.67
|
||||
botocore==1.31.67
|
||||
bracex==2.4
|
||||
cachetools==5.3.1
|
||||
certifi==2023.7.22
|
||||
cffi==1.16.0
|
||||
chardet==5.2.0
|
||||
charset-normalizer==3.3.0
|
||||
click==8.1.7
|
||||
colorama==0.4.6
|
||||
coloredlogs==15.0.1
|
||||
commonmark==0.9.1
|
||||
ConfigArgParse==1.7
|
||||
configparser==5.3.0
|
||||
coverage==7.3.2
|
||||
cryptography==36.0.2
|
||||
dateparser==1.1.8
|
||||
decorator==5.1.1
|
||||
demisto-py==3.2.13
|
||||
demisto-sdk==1.20.7
|
||||
dictdiffer==0.9.0
|
||||
dictor==0.1.12
|
||||
docker==5.0.3
|
||||
docopt==0.6.2
|
||||
exceptiongroup==1.1.3
|
||||
flatten-dict==0.4.2
|
||||
freezegun==1.2.2
|
||||
frozenlist==1.4.0
|
||||
furl==2.1.3
|
||||
future==0.18.3
|
||||
gitdb==4.0.10
|
||||
GitPython==3.1.37
|
||||
giturlparse==0.10.0
|
||||
google-api-core==2.12.0
|
||||
google-auth==2.23.3
|
||||
google-cloud-core==2.3.3
|
||||
google-cloud-storage==2.11.0
|
||||
google-crc32c==1.5.0
|
||||
google-resumable-media==2.6.0
|
||||
googleapis-common-protos==1.60.0
|
||||
grpcio==1.59.0
|
||||
humanfriendly==10.0
|
||||
idna==3.4
|
||||
imagesize==1.4.1
|
||||
importlib-resources==5.13.0
|
||||
inflection==0.5.1
|
||||
iniconfig==2.0.0
|
||||
isort==5.12.0
|
||||
jmespath==1.0.1
|
||||
joblib==1.3.2
|
||||
jsonschema==4.19.1
|
||||
jsonschema-specifications==2023.7.1
|
||||
junitparser==3.1.0
|
||||
klara==0.6.3
|
||||
lazy-object-proxy==1.9.0
|
||||
mccabe==0.6.1
|
||||
mergedeep==1.3.4
|
||||
more-itertools==9.1.0
|
||||
multidict==6.0.4
|
||||
mypy==0.982
|
||||
mypy-extensions==1.0.0
|
||||
neo4j==5.13.0
|
||||
networkx==2.8.8
|
||||
nltk==3.8.1
|
||||
ordered-set==4.1.0
|
||||
orderedmultidict==1.0.1
|
||||
orjson==3.9.8
|
||||
packaging==23.2
|
||||
paramiko==2.12.0
|
||||
pbr==5.11.1
|
||||
Pebble==5.0.3
|
||||
platformdirs==3.11.0
|
||||
pluggy==1.3.0
|
||||
prettytable==3.9.0
|
||||
protobuf==4.24.4
|
||||
pyasn1==0.5.0
|
||||
pyasn1-modules==0.3.0
|
||||
pycodestyle==2.11.0
|
||||
pycparser==2.21
|
||||
pydantic==1.10.13
|
||||
Pygments==2.16.1
|
||||
pykwalify==1.8.0
|
||||
pylint==2.12.2
|
||||
PyNaCl==1.5.0
|
||||
PyPDF2==1.28.6
|
||||
pyspellchecker==0.6.3
|
||||
pytest==7.4.2
|
||||
pytest-freezegun==0.4.2
|
||||
python-dateutil==2.8.2
|
||||
python-dotenv==0.20.0
|
||||
pytz==2023.3.post1
|
||||
pytz-deprecation-shim==0.1.0.post0
|
||||
PyYAML==6.0.1
|
||||
referencing==0.30.2
|
||||
regex==2023.10.3
|
||||
requests==2.31.0
|
||||
rich==12.6.0
|
||||
rpds-py==0.10.6
|
||||
rsa==4.9
|
||||
ruamel.yaml==0.17.35
|
||||
ruamel.yaml.clib==0.2.8
|
||||
s3transfer==0.7.0
|
||||
shellingham==1.5.3
|
||||
six==1.16.0
|
||||
slack-sdk==3.23.0
|
||||
smmap==5.0.1
|
||||
soupsieve==2.5
|
||||
stevedore==5.1.0
|
||||
tabulate==0.9.0
|
||||
tenacity==8.2.3
|
||||
toml==0.10.2
|
||||
tomli==2.0.1
|
||||
tqdm==4.66.1
|
||||
typed-ast==1.5.5
|
||||
typer==0.7.0
|
||||
types-chardet==5.0.4.6
|
||||
types-cryptography==3.3.23.2
|
||||
types-dateparser==1.1.4.10
|
||||
types-decorator==5.1.8.4
|
||||
types-emoji==2.1.0.3
|
||||
types-filelock==3.2.7
|
||||
types-futures==3.3.8
|
||||
types-ipaddress==1.0.8
|
||||
types-Markdown==3.5.0.0
|
||||
types-mock==4.0.15.2
|
||||
types-paramiko==2.12.0.1
|
||||
types-pkg-resources==0.1.3
|
||||
types-protobuf==3.20.4.6
|
||||
types-PyMySQL==1.1.0.1
|
||||
types-python-dateutil==2.8.19.14
|
||||
types-pytz==2022.7.1.2
|
||||
types-pyvmomi==8.0.0.6
|
||||
types-PyYAML==6.0.12.12
|
||||
types-requests==2.28.11
|
||||
types-setuptools==67.8.0.0
|
||||
types-six==1.16.21.9
|
||||
types-tabulate==0.9.0.3
|
||||
types-ujson==5.8.0.1
|
||||
types-urllib3==1.26.25.14
|
||||
typing_extensions==4.8.0
|
||||
tzdata==2023.3
|
||||
tzlocal==4.3.1
|
||||
ujson==5.8.0
|
||||
urllib3==1.26.17
|
||||
vulture==2.10
|
||||
wcmatch==8.5
|
||||
wcwidth==0.2.8
|
||||
websocket-client==1.6.4
|
||||
wrapt==1.13.3
|
||||
yamlordereddictloader==0.4.2
|
||||
yarl==1.9.2
|
||||
z3-solver==4.12.2.0
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"Name": "Fortinet FortiNDR Cloud",
|
||||
"Author": "Microsoft - support@microsoft.com",
|
||||
"Logo": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/Azure_Sentinel.svg\" width=\"75px\" height=\"75px\">",
|
||||
"Description": "The [Fortinet FortiNDR Cloud](https://docs.fortinet.com/product/fortindr-cloud) solution for Microsoft Sentinel provides the capability to ingest Fortinet FortiNDR Cloud events stored in Amazon S3 into Microsoft Sentinel using the Amazon S3 REST API. For questions about Fortinet FortiNDR Cloud, please contact Fortinet at [azuresales@fortinet.com](mailto:azuresales@fortinet.com).",
|
||||
"Data Connectors": [
|
||||
"Data Connectors/FortinetFortiNdrCloud_API_AzureFunctionApp.json"
|
||||
],
|
||||
"Parsers": [
|
||||
"Parsers/Fortinet_FortiNDR_Cloud.yaml"
|
||||
],
|
||||
"Workbooks": [
|
||||
"Workbooks/FortinetFortiNdrCloudWorkbook.json"
|
||||
],
|
||||
"BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\Fortinet FortiNDR Cloud",
|
||||
"Version": "1.0.0",
|
||||
"Metadata": "SolutionMetadata.json",
|
||||
"TemplateSpec": true,
|
||||
"Is1PConnector": false
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
|
||||
"handler": "Microsoft.Azure.CreateUIDef",
|
||||
"version": "0.1.2-preview",
|
||||
"parameters": {
|
||||
"config": {
|
||||
"isWizard": false,
|
||||
"basics": {
|
||||
"description": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Logos/Azure_Sentinel.svg\" width=\"75px\" height=\"75px\">\n\n**Note:** Please refer to the following before installing the solution: \r \n • Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/tree/master/Solutions/Fortinet%20FortiNDR%20Cloud/ReleaseNotes.md)\r \n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe [Fortinet FortiNDR Cloud](https://docs.fortinet.com/product/fortindr-cloud) solution for Microsoft Sentinel provides the capability to ingest Fortinet FortiNDR Cloud events stored in Amazon S3 into Microsoft Sentinel using the Amazon S3 REST API. For questions about Fortinet FortiNDR Cloud, please contact Fortinet at [azuresales@fortinet.com](mailto:azuresales@fortinet.com).\n\n**Data Connectors:** 1, **Parsers:** 1, **Workbooks:** 1\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)",
|
||||
"subscription": {
|
||||
"resourceProviders": [
|
||||
"Microsoft.OperationsManagement/solutions",
|
||||
"Microsoft.OperationalInsights/workspaces/providers/alertRules",
|
||||
"Microsoft.Insights/workbooks",
|
||||
"Microsoft.Logic/workflows"
|
||||
]
|
||||
},
|
||||
"location": {
|
||||
"metadata": {
|
||||
"hidden": "Hiding location, we get it from the log analytics workspace"
|
||||
},
|
||||
"visible": false
|
||||
},
|
||||
"resourceGroup": {
|
||||
"allowExisting": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"basics": [
|
||||
{
|
||||
"name": "getLAWorkspace",
|
||||
"type": "Microsoft.Solutions.ArmApiControl",
|
||||
"toolTip": "This filters by workspaces that exist in the Resource Group selected",
|
||||
"condition": "[greater(length(resourceGroup().name),0)]",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"path": "[concat(subscription().id,'/providers/Microsoft.OperationalInsights/workspaces?api-version=2020-08-01')]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "workspace",
|
||||
"type": "Microsoft.Common.DropDown",
|
||||
"label": "Workspace",
|
||||
"placeholder": "Select a workspace",
|
||||
"toolTip": "This dropdown will list only workspace that exists in the Resource Group selected",
|
||||
"constraints": {
|
||||
"allowedValues": "[map(filter(basics('getLAWorkspace').value, (filter) => contains(toLower(filter.id), toLower(resourceGroup().name))), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]",
|
||||
"required": true
|
||||
},
|
||||
"visible": true
|
||||
}
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"name": "dataconnectors",
|
||||
"label": "Data Connectors",
|
||||
"bladeTitle": "Data Connectors",
|
||||
"elements": [
|
||||
{
|
||||
"name": "dataconnectors1-text",
|
||||
"type": "Microsoft.Common.TextBlock",
|
||||
"options": {
|
||||
"text": "This Solution installs the data connector for Fortinet FortiNDR Cloud. You can get Fortinet FortiNDR Cloud custom log data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dataconnectors-parser-text",
|
||||
"type": "Microsoft.Common.TextBlock",
|
||||
"options": {
|
||||
"text": "The Solution installs a parser that transforms the ingested data into Microsoft Sentinel normalized format. The normalized format enables better correlation of different types of data from different data sources to drive end-to-end outcomes seamlessly in security monitoring, hunting, incident investigation and response scenarios in Microsoft Sentinel."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dataconnectors-link2",
|
||||
"type": "Microsoft.Common.TextBlock",
|
||||
"options": {
|
||||
"link": {
|
||||
"label": "Learn more about connecting data sources",
|
||||
"uri": "https://docs.microsoft.com/azure/sentinel/connect-data-sources"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "workbooks",
|
||||
"label": "Workbooks",
|
||||
"subLabel": {
|
||||
"preValidation": "Configure the workbooks",
|
||||
"postValidation": "Done"
|
||||
},
|
||||
"bladeTitle": "Workbooks",
|
||||
"elements": [
|
||||
{
|
||||
"name": "workbooks-text",
|
||||
"type": "Microsoft.Common.TextBlock",
|
||||
"options": {
|
||||
"text": "This solution installs workbook(s) to help you gain insights into the telemetry collected in Microsoft Sentinel. After installing the solution, start using the workbook in Manage solution view."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "workbooks-link",
|
||||
"type": "Microsoft.Common.TextBlock",
|
||||
"options": {
|
||||
"link": {
|
||||
"label": "Learn more",
|
||||
"uri": "https://docs.microsoft.com/azure/sentinel/tutorial-monitor-your-data"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "workbook1",
|
||||
"type": "Microsoft.Common.Section",
|
||||
"label": "FortiNDR Cloud",
|
||||
"elements": [
|
||||
{
|
||||
"name": "workbook1-text",
|
||||
"type": "Microsoft.Common.TextBlock",
|
||||
"options": {
|
||||
"text": "Gain insights into Fortinet FortiNDR CLoud events, including the Suricata, Observatino and Detections data."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": {
|
||||
"workspace-location": "[first(map(filter(basics('getLAWorkspace').value, (filter) => and(contains(toLower(filter.id), toLower(resourceGroup().name)),equals(filter.name,basics('workspace')))), (item) => item.location))]",
|
||||
"location": "[location()]",
|
||||
"workspace": "[basics('workspace')]"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"location": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"defaultValue": "[resourceGroup().location]",
|
||||
"metadata": {
|
||||
"description": "Not used, but needed to pass arm-ttk test `Location-Should-Not-Be-Hardcoded`. We instead use the `workspace-location` which is derived from the LA workspace"
|
||||
}
|
||||
},
|
||||
"workspace-location": {
|
||||
"type": "string",
|
||||
"defaultValue": "",
|
||||
"metadata": {
|
||||
"description": "[concat('Region to deploy solution resources -- separate from location selection',parameters('location'))]"
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"defaultValue": "",
|
||||
"type": "string",
|
||||
"metadata": {
|
||||
"description": "Workspace name for Log Analytics where Microsoft Sentinel is setup"
|
||||
}
|
||||
},
|
||||
"workbook1-name": {
|
||||
"type": "string",
|
||||
"defaultValue": "FortiNDR Cloud",
|
||||
"minLength": 1,
|
||||
"metadata": {
|
||||
"description": "Name for the workbook"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,349 @@
|
|||
// Usage Instruction :
|
||||
// Paste below query in log analytics, click on Save button and select as Function from drop down by specifying function name and alias as Fortinet_FortiNDR_Cloud.
|
||||
// Function usually takes 10-15 minutes to activate. You can then use function alias from any other queries (e.g. Fortinet_FortiNDR_Cloud | take 10).
|
||||
// Reference : Using functions in Azure monitor log queries : https://docs.microsoft.com/azure/azure-monitor/log-query/functions
|
||||
|
||||
let FortiNDR_Cloud_suricata_view = view () {
|
||||
FncEventsSuricata_CL
|
||||
| extend
|
||||
su_timestamp=column_ifexists('timestamp_t',''),
|
||||
su_uuid=column_ifexists('uuid_g',''),
|
||||
su_event_type=column_ifexists('event_type_s',''),
|
||||
su_customer_id=column_ifexists('customer_id_s',''),
|
||||
su_sensor_id=column_ifexists('sensor_id_s',''),
|
||||
su_source=column_ifexists('source_s',''),
|
||||
su_src_ip=column_ifexists('src_ip_s',''),
|
||||
su_src_port=column_ifexists('src_port_d',''),
|
||||
su_dst_ip=column_ifexists('dest_ip_s',''),
|
||||
su_dst_port=column_ifexists('dest_port_d',''),
|
||||
su_proto=column_ifexists('proto_s',''),
|
||||
su_sig_id=column_ifexists('alert_signature_id_d',''),
|
||||
su_sig_rev=column_ifexists('alert_rev_d',''),
|
||||
su_sig_name=column_ifexists('alert_signature_s',''),
|
||||
su_sig_category=column_ifexists('alert_category_s',''),
|
||||
su_sig_severity=column_ifexists('alert_severity_d',''),
|
||||
su_src_internal=column_ifexists('src_ip_enrichments_internal_b',''),
|
||||
su_src_geo_lat=column_ifexists('src_ip_enrichments_geo_location_lat_d',''),
|
||||
su_src_geo_lon=column_ifexists('src_ip_enrichments_geo_location_lon_d',''),
|
||||
su_src_geo_country=column_ifexists('src_ip_enrichments_geo_country_s',''),
|
||||
su_src_geo_subdivision=column_ifexists('src_ip_enrichments_geo_subdivision_s',''),
|
||||
su_src_geo_city=column_ifexists('src_ip_enrichments_geo_city_s',''),
|
||||
su_src_asn_asn=column_ifexists('src_ip_enrichments_asn_asn_d',''),
|
||||
su_src_asn_org=column_ifexists('src_ip_enrichments_asn_org_s',''),
|
||||
su_src_asn_isp=column_ifexists('src_ip_enrichments_asn_isp_s',''),
|
||||
su_src_asn_asn_org=column_ifexists('src_ip_enrichments_asn_asn_org_s',''),
|
||||
su_src_annotations_applications=column_ifexists('src_ip_enrichments_annotations_applications_s',''),
|
||||
su_src_annotations_environments=column_ifexists('src_ip_enrichments_annotations_environments_s',''),
|
||||
su_src_annotations_locations=column_ifexists('src_ip_enrichments_annotations_locations_s',''),
|
||||
su_src_annotations_owners=column_ifexists('src_ip_enrichments_annotations_owners_s',''),
|
||||
su_src_annotations_roles=column_ifexists('src_ip_enrichments_annotations_roles_s',''),
|
||||
su_src_annotations_tags=column_ifexists('src_ip_enrichments_annotations_tags_s',''),
|
||||
su_dst_internal=column_ifexists('dst_ip_enrichments_internal_b',''),
|
||||
su_dst_geo_lat=column_ifexists('dst_ip_enrichments_geo_location_lat_d',''),
|
||||
su_dst_geo_lon=column_ifexists('dst_ip_enrichments_geo_location_lon_d',''),
|
||||
su_dst_geo_country=column_ifexists('dst_ip_enrichments_geo_country_s',''),
|
||||
su_dst_geo_subdivision=column_ifexists('dst_ip_enrichments_geo_subdivision_s',''),
|
||||
su_dst_geo_city=column_ifexists('dst_ip_enrichments_geo_city_s',''),
|
||||
su_dst_asn_asn=column_ifexists('dst_ip_enrichments_asn_asn_d',''),
|
||||
su_dst_asn_org=column_ifexists('dst_ip_enrichments_asn_org_s',''),
|
||||
su_dst_asn_isp=column_ifexists('dst_ip_enrichments_asn_isp_s',''),
|
||||
su_dst_asn_asn_org=column_ifexists('dst_ip_enrichments_asn_asn_org_s',''),
|
||||
su_dst_annotations_applications=column_ifexists('dst_ip_enrichments_annotations_applications_s',''),
|
||||
su_dst_annotations_environments=column_ifexists('dst_ip_enrichments_annotations_environments_s',''),
|
||||
su_dst_annotations_locations=column_ifexists('dst_ip_enrichments_annotations_locations_s',''),
|
||||
su_dst_annotations_owners=column_ifexists('dst_ip_enrichments_annotations_owners_s',''),
|
||||
su_dst_annotations_roles=column_ifexists('dst_ip_enrichments_annotations_roles_s',''),
|
||||
su_dst_annotations_tags=column_ifexists('dst_ip_enrichments_annotations_tags_s',''),
|
||||
su_geo_distance=column_ifexists('geo_distance_d',''),
|
||||
su_http_status=column_ifexists('http_status_d',''),
|
||||
su_http_protocol=column_ifexists('http_protocol_s',''),
|
||||
su_http_url=column_ifexists('http_url_s',''),
|
||||
su_http_hostname=column_ifexists('http_hostname_s',''),
|
||||
su_http_host_internal=column_ifexists('http_hostname_enrichments_ip_enrichments_internal_b',''),
|
||||
su_http_host_geo_lat=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_location_lat_d',''),
|
||||
su_http_host_geo_lon=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_location_lon_d',''),
|
||||
su_http_host_geo_subdivision=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_subdivision_s',''),
|
||||
su_http_host_geo_city=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_city_s',''),
|
||||
su_http_host_asn_asn=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_asn_d',''),
|
||||
su_http_host_asn_org=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_org_s',''),
|
||||
su_http_host_asn_isp=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_isp_s',''),
|
||||
su_http_host_asn_asn_org=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_asn_org_s',''),
|
||||
su_http_host_geo_country=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_country_s',''),
|
||||
su_http_host_annotations_applications=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_applications_s',''),
|
||||
su_http_host_annotations_environments=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_environments_s',''),
|
||||
su_http_host_annotations_locations=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_locations_s',''),
|
||||
su_http_host_annotations_owners=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_owners_s',''),
|
||||
su_http_host_annotations_roles=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_roles_s',''),
|
||||
su_http_host_annotations_tags=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_tags_s',''),
|
||||
su_http_host_domain_entropy=column_ifexists('http_hostname_enrichments_domain_enrichments_domain_entropy_d',''),
|
||||
su_http_length=column_ifexists('http_length_d',''),
|
||||
su_http_method=column_ifexists('http_http_method_s',''),
|
||||
su_http_content_type=column_ifexists('http_http_content_type_s',''),
|
||||
su_http_refer=column_ifexists('http_http_refer_s',''),
|
||||
su_http_user_agent=column_ifexists('http_http_user_agent_s',''),
|
||||
su_http_redirect=column_ifexists('http_redirect_s',''),
|
||||
su_http_xtf=column_ifexists('http_xtf_s',''),
|
||||
su_payload=column_ifexists('payload_s',''),
|
||||
su_intel=column_ifexists('intel_s','')
|
||||
| project
|
||||
su_timestamp,
|
||||
su_event_type,
|
||||
su_src_ip,
|
||||
su_src_port,
|
||||
su_dst_ip,
|
||||
su_dst_port,
|
||||
su_intel,
|
||||
su_sig_name,
|
||||
su_sig_id,
|
||||
su_sig_rev,
|
||||
su_sig_category,
|
||||
su_sig_severity,
|
||||
su_payload,
|
||||
su_source,
|
||||
su_proto,
|
||||
su_sensor_id,
|
||||
su_src_internal,
|
||||
su_src_geo_lat,
|
||||
su_src_geo_lon,
|
||||
su_src_geo_country,
|
||||
su_src_geo_subdivision,
|
||||
su_src_geo_city,
|
||||
su_src_asn_asn,
|
||||
su_src_asn_org,
|
||||
su_src_asn_isp,
|
||||
su_src_asn_asn_org,
|
||||
su_src_annotations_applications,
|
||||
su_src_annotations_environments,
|
||||
su_src_annotations_locations,
|
||||
su_src_annotations_owners,
|
||||
su_src_annotations_roles,
|
||||
su_src_annotations_tags,
|
||||
su_dst_internal,
|
||||
su_dst_geo_lat,
|
||||
su_dst_geo_lon,
|
||||
su_dst_geo_country,
|
||||
su_dst_geo_subdivision,
|
||||
su_dst_geo_city,
|
||||
su_dst_asn_asn,
|
||||
su_dst_asn_org,
|
||||
su_dst_asn_isp,
|
||||
su_dst_asn_asn_org,
|
||||
su_dst_annotations_applications,
|
||||
su_dst_annotations_environments,
|
||||
su_dst_annotations_locations,
|
||||
su_dst_annotations_owners,
|
||||
su_dst_annotations_roles,
|
||||
su_dst_annotations_tags,
|
||||
su_geo_distance,
|
||||
su_http_status,
|
||||
su_http_protocol,
|
||||
su_http_url,
|
||||
su_http_hostname,
|
||||
su_http_host_internal,
|
||||
su_http_host_geo_lat,
|
||||
su_http_host_geo_lon,
|
||||
su_http_host_geo_country,
|
||||
su_http_host_geo_subdivision,
|
||||
su_http_host_geo_city,
|
||||
su_http_host_asn_asn,
|
||||
su_http_host_asn_org,
|
||||
su_http_host_asn_isp,
|
||||
su_http_host_asn_asn_org,
|
||||
su_http_host_annotations_applications,
|
||||
su_http_host_annotations_environments,
|
||||
su_http_host_annotations_locations,
|
||||
su_http_host_annotations_owners,
|
||||
su_http_host_annotations_roles,
|
||||
su_http_host_annotations_tags,
|
||||
su_http_host_domain_entropy,
|
||||
su_http_length,
|
||||
su_http_method,
|
||||
su_http_content_type,
|
||||
su_http_refer,
|
||||
su_http_user_agent,
|
||||
su_http_redirect,
|
||||
su_http_xtf,
|
||||
su_uuid,
|
||||
su_customer_id,
|
||||
Type
|
||||
};
|
||||
|
||||
let FortiNDR_Cloud_observation_view = view () {
|
||||
FncEventsObservation_CL
|
||||
| extend
|
||||
ob_timestamp=column_ifexists('timestamp_t',''),
|
||||
ob_uuid=column_ifexists('uuid_g',''),
|
||||
ob_event_type=column_ifexists('event_type_s',''),
|
||||
ob_customer_id=column_ifexists('customer_id_s',''),
|
||||
ob_sensor_id=column_ifexists('sensor_id_s',''),
|
||||
ob_source=column_ifexists('source_s',''),
|
||||
ob_evidence_start_timestamp=column_ifexists('evidence_start_timestamp_t',''),
|
||||
ob_evidence_end_timestamp=column_ifexists('evidence_end_timestamp_t',''),
|
||||
ob_observation_uuid=column_ifexists('observation_uuid_g',''),
|
||||
ob_observation_title=column_ifexists('title_s',''),
|
||||
ob_confidence=column_ifexists('confidence_s',''),
|
||||
ob_src_ip=column_ifexists('src_ip_s',''),
|
||||
ob_dst_ip=column_ifexists('dst_ip_s',''),
|
||||
ob_src_internal=column_ifexists('src_ip_enrichments_internal_b',''),
|
||||
ob_src_geo_lat=column_ifexists('src_ip_enrichments_geo_location_lat_d',''),
|
||||
ob_src_geo_lon=column_ifexists('src_ip_enrichments_geo_location_lon_d',''),
|
||||
ob_src_geo_country=column_ifexists('src_ip_enrichments_geo_country_s',''),
|
||||
ob_src_geo_subdivision=column_ifexists('src_ip_enrichments_geo_subdivision_s',''),
|
||||
ob_src_geo_city=column_ifexists('src_ip_enrichments_geo_city_s',''),
|
||||
ob_src_asn_asn=column_ifexists('src_ip_enrichments_asn_asn_d',''),
|
||||
ob_src_asn_org=column_ifexists('src_ip_enrichments_asn_org_s',''),
|
||||
ob_src_asn_isp=column_ifexists('src_ip_enrichments_asn_isp_s',''),
|
||||
ob_src_asn_asn_org=column_ifexists('src_ip_enrichments_asn_asn_org_s',''),
|
||||
ob_src_annotations_applications=column_ifexists('src_ip_enrichments_annotations_applications_s',''),
|
||||
ob_src_annotations_environments=column_ifexists('src_ip_enrichments_annotations_environments_s',''),
|
||||
ob_src_annotations_locations=column_ifexists('src_ip_enrichments_annotations_locations_s',''),
|
||||
ob_src_annotations_owners=column_ifexists('src_ip_enrichments_annotations_owners_s',''),
|
||||
ob_src_annotations_roles=column_ifexists('src_ip_enrichments_annotations_roles_s',''),
|
||||
ob_src_annotations_tags=column_ifexists('src_ip_enrichments_annotations_tags_s',''),
|
||||
ob_dst_internal=column_ifexists('dst_ip_enrichments_internal_b',''),
|
||||
ob_dst_geo_lat=column_ifexists('dst_ip_enrichments_geo_location_lat_d',''),
|
||||
ob_dst_geo_lon=column_ifexists('dst_ip_enrichments_geo_location_lon_d',''),
|
||||
ob_dst_geo_country=column_ifexists('dst_ip_enrichments_geo_country_s',''),
|
||||
ob_dst_geo_subdivision=column_ifexists('dst_ip_enrichments_geo_subdivision_s',''),
|
||||
ob_dst_geo_city=column_ifexists('dst_ip_enrichments_geo_city_s',''),
|
||||
ob_dst_asn_asn=column_ifexists('dst_ip_enrichments_asn_asn_d',''),
|
||||
ob_dst_asn_org=column_ifexists('dst_ip_enrichments_asn_org_s',''),
|
||||
ob_dst_asn_isp=column_ifexists('dst_ip_enrichments_asn_isp_s',''),
|
||||
ob_dst_asn_asn_org=column_ifexists('dst_ip_enrichments_asn_asn_org_s',''),
|
||||
ob_dst_annotations_applications=column_ifexists('dst_ip_enrichments_annotations_applications_s',''),
|
||||
ob_dst_annotations_environments=column_ifexists('dst_ip_enrichments_annotations_environments_s',''),
|
||||
ob_dst_annotations_locations=column_ifexists('dst_ip_enrichments_annotations_locations_s',''),
|
||||
ob_dst_annotations_owners=column_ifexists('dst_ip_enrichments_annotations_owners_s',''),
|
||||
ob_dst_annotations_roles=column_ifexists('dst_ip_enrichments_annotations_roles_s',''),
|
||||
ob_dst_annotations_tags=column_ifexists('dst_ip_enrichments_annotations_tags_s',''),
|
||||
ob_geo_distance=column_ifexists('geo_distance_d',''),
|
||||
ob_sensor_ids=column_ifexists('sensor_ids_s',''),
|
||||
ob_evidence_iql=column_ifexists('evidence_iql_s',''),
|
||||
ob_description=column_ifexists('description_s',''),
|
||||
ob_context=column_ifexists('context_s',''),
|
||||
ob_class=column_ifexists('class_s',''),
|
||||
ob_intel=column_ifexists('intel_s', ''),
|
||||
ob_category=column_ifexists('Category', '')
|
||||
| project
|
||||
ob_timestamp,
|
||||
ob_observation_title,
|
||||
ob_confidence,
|
||||
ob_category,
|
||||
ob_class,
|
||||
ob_context,
|
||||
ob_evidence_iql,
|
||||
ob_evidence_end_timestamp,
|
||||
ob_evidence_start_timestamp,
|
||||
ob_description,
|
||||
ob_observation_uuid,
|
||||
ob_sensor_ids,
|
||||
ob_event_type,
|
||||
ob_src_ip,
|
||||
ob_dst_ip,
|
||||
ob_intel,
|
||||
ob_source,
|
||||
ob_sensor_id,
|
||||
ob_src_internal,
|
||||
ob_src_geo_lat,
|
||||
ob_src_geo_lon,
|
||||
ob_src_geo_country,
|
||||
ob_src_geo_subdivision,
|
||||
ob_src_geo_city,
|
||||
ob_src_asn_asn,
|
||||
ob_src_asn_org,
|
||||
ob_src_asn_isp,
|
||||
ob_src_asn_asn_org,
|
||||
ob_src_annotations_applications,
|
||||
ob_src_annotations_environments,
|
||||
ob_src_annotations_locations,
|
||||
ob_src_annotations_owners,
|
||||
ob_src_annotations_roles,
|
||||
ob_src_annotations_tags,
|
||||
ob_dst_internal,
|
||||
ob_dst_geo_lat,
|
||||
ob_dst_geo_lon,
|
||||
ob_dst_geo_country,
|
||||
ob_dst_geo_subdivision,
|
||||
ob_dst_geo_city,
|
||||
ob_dst_asn_asn,
|
||||
ob_dst_asn_org,
|
||||
ob_dst_asn_isp,
|
||||
ob_dst_asn_asn_org,
|
||||
ob_dst_annotations_applications,
|
||||
ob_dst_annotations_environments,
|
||||
ob_dst_annotations_locations,
|
||||
ob_dst_annotations_owners,
|
||||
ob_dst_annotations_roles,
|
||||
ob_dst_annotations_tags,
|
||||
ob_geo_distance,
|
||||
ob_uuid,
|
||||
ob_customer_id,
|
||||
Type
|
||||
};
|
||||
|
||||
let FortiNDR_Cloud_detections_view = view () {
|
||||
FncEventsDetections_CL
|
||||
| extend
|
||||
de_vendor=column_ifexists('vendor_s',''),
|
||||
de_product=column_ifexists('product_s',''),
|
||||
de_signal_version=column_ifexists('signal_version_s',''),
|
||||
de_event_type=column_ifexists('event_type_s',''),
|
||||
de_subject=column_ifexists('subject_s',''),
|
||||
de_timestamp=column_ifexists('timestamp_t',''),
|
||||
de_device_ip=column_ifexists('device_ip_s',''),
|
||||
de_rule_name=column_ifexists('name_s',''),
|
||||
de_severity=column_ifexists('severity_s',''),
|
||||
de_confidence=column_ifexists('confidence_s',''),
|
||||
de_sensor_ids=column_ifexists('sensor_id_s',''),
|
||||
de_muted=column_ifexists('muted_b',''),
|
||||
de_rule_muted=column_ifexists('muted_rule_b',''),
|
||||
de_rule_uuid=column_ifexists('rule_uuid_g',''),
|
||||
de_mute_comment=column_ifexists('muted_comment_s',''),
|
||||
de_first_seen=column_ifexists('first_seen_t',''),
|
||||
de_last_seen=column_ifexists('last_seen_t',''),
|
||||
de_created=column_ifexists('created_t',''),
|
||||
de_updated=column_ifexists('updated_t',''),
|
||||
de_uuid=column_ifexists('uuid_g',''),
|
||||
de_status=column_ifexists('status_s',''),
|
||||
de_indicators=column_ifexists('indicators_s',''),
|
||||
de_customer_id=column_ifexists('customer_id_s',''),
|
||||
de_primary_pdns_hostnames=column_ifexists('primary_pdns_hostnames_s',''),
|
||||
de_other_pdns_hostnames=column_ifexists('other_pdns_hostnames_s',''),
|
||||
de_primary_dhcp_machost_pairs=column_ifexists('primary_dhcp_machost_pairs_s',''),
|
||||
de_other_dhcp_machost_pairs=column_ifexists('other_dhcp_machost_pairs_s',''),
|
||||
de_category=column_ifexists('Category', '')
|
||||
| project
|
||||
de_timestamp,
|
||||
de_device_ip,
|
||||
de_status,
|
||||
de_indicators,
|
||||
de_last_seen,
|
||||
de_rule_name,
|
||||
de_rule_uuid,
|
||||
de_category,
|
||||
de_created,
|
||||
de_updated,
|
||||
de_severity,
|
||||
de_confidence,
|
||||
de_muted,
|
||||
de_rule_muted,
|
||||
de_mute_comment,
|
||||
de_sensor_ids,
|
||||
de_primary_pdns_hostnames,
|
||||
de_other_pdns_hostnames,
|
||||
de_primary_dhcp_machost_pairs,
|
||||
de_other_dhcp_machost_pairs,
|
||||
de_vendor,
|
||||
de_product,
|
||||
de_signal_version,
|
||||
de_event_type,
|
||||
de_subject,
|
||||
de_uuid,
|
||||
de_customer_id,
|
||||
Type
|
||||
};
|
||||
|
||||
union isfuzzy=true
|
||||
FortiNDR_Cloud_suricata_view,
|
||||
FortiNDR_Cloud_observation_view,
|
||||
FortiNDR_Cloud_detections_view
|
|
@ -0,0 +1,353 @@
|
|||
id: 4c846775-c295-421f-9275-ded657b190d6
|
||||
Function:
|
||||
Title: Parser for Fortinet_FortiNDR_Cloud
|
||||
Version: '1.0.0'
|
||||
LastUpdated: '2024-01-09'
|
||||
Category: Microsoft Sentinel Parser
|
||||
FunctionName: Fortinet_FortiNDR_Cloud
|
||||
FunctionAlias: Fortinet_FortiNDR_Cloud
|
||||
FunctionQuery: |
|
||||
let FortiNDR_Cloud_suricata_view = view () {
|
||||
FncEventsSuricata_CL
|
||||
| extend
|
||||
su_timestamp=column_ifexists('timestamp_t',''),
|
||||
su_uuid=column_ifexists('uuid_g',''),
|
||||
su_event_type=column_ifexists('event_type_s',''),
|
||||
su_customer_id=column_ifexists('customer_id_s',''),
|
||||
su_sensor_id=column_ifexists('sensor_id_s',''),
|
||||
su_source=column_ifexists('source_s',''),
|
||||
su_src_ip=column_ifexists('src_ip_s',''),
|
||||
su_src_port=column_ifexists('src_port_d',''),
|
||||
su_dst_ip=column_ifexists('dest_ip_s',''),
|
||||
su_dst_port=column_ifexists('dest_port_d',''),
|
||||
su_proto=column_ifexists('proto_s',''),
|
||||
su_sig_id=column_ifexists('alert_signature_id_d',''),
|
||||
su_sig_rev=column_ifexists('alert_rev_d',''),
|
||||
su_sig_name=column_ifexists('alert_signature_s',''),
|
||||
su_sig_category=column_ifexists('alert_category_s',''),
|
||||
su_sig_severity=column_ifexists('alert_severity_d',''),
|
||||
su_src_internal=column_ifexists('src_ip_enrichments_internal_b',''),
|
||||
su_src_geo_lat=column_ifexists('src_ip_enrichments_geo_location_lat_d',''),
|
||||
su_src_geo_lon=column_ifexists('src_ip_enrichments_geo_location_lon_d',''),
|
||||
su_src_geo_country=column_ifexists('src_ip_enrichments_geo_country_s',''),
|
||||
su_src_geo_subdivision=column_ifexists('src_ip_enrichments_geo_subdivision_s',''),
|
||||
su_src_geo_city=column_ifexists('src_ip_enrichments_geo_city_s',''),
|
||||
su_src_asn_asn=column_ifexists('src_ip_enrichments_asn_asn_d',''),
|
||||
su_src_asn_org=column_ifexists('src_ip_enrichments_asn_org_s',''),
|
||||
su_src_asn_isp=column_ifexists('src_ip_enrichments_asn_isp_s',''),
|
||||
su_src_asn_asn_org=column_ifexists('src_ip_enrichments_asn_asn_org_s',''),
|
||||
su_src_annotations_applications=column_ifexists('src_ip_enrichments_annotations_applications_s',''),
|
||||
su_src_annotations_environments=column_ifexists('src_ip_enrichments_annotations_environments_s',''),
|
||||
su_src_annotations_locations=column_ifexists('src_ip_enrichments_annotations_locations_s',''),
|
||||
su_src_annotations_owners=column_ifexists('src_ip_enrichments_annotations_owners_s',''),
|
||||
su_src_annotations_roles=column_ifexists('src_ip_enrichments_annotations_roles_s',''),
|
||||
su_src_annotations_tags=column_ifexists('src_ip_enrichments_annotations_tags_s',''),
|
||||
su_dst_internal=column_ifexists('dst_ip_enrichments_internal_b',''),
|
||||
su_dst_geo_lat=column_ifexists('dst_ip_enrichments_geo_location_lat_d',''),
|
||||
su_dst_geo_lon=column_ifexists('dst_ip_enrichments_geo_location_lon_d',''),
|
||||
su_dst_geo_country=column_ifexists('dst_ip_enrichments_geo_country_s',''),
|
||||
su_dst_geo_subdivision=column_ifexists('dst_ip_enrichments_geo_subdivision_s',''),
|
||||
su_dst_geo_city=column_ifexists('dst_ip_enrichments_geo_city_s',''),
|
||||
su_dst_asn_asn=column_ifexists('dst_ip_enrichments_asn_asn_d',''),
|
||||
su_dst_asn_org=column_ifexists('dst_ip_enrichments_asn_org_s',''),
|
||||
su_dst_asn_isp=column_ifexists('dst_ip_enrichments_asn_isp_s',''),
|
||||
su_dst_asn_asn_org=column_ifexists('dst_ip_enrichments_asn_asn_org_s',''),
|
||||
su_dst_annotations_applications=column_ifexists('dst_ip_enrichments_annotations_applications_s',''),
|
||||
su_dst_annotations_environments=column_ifexists('dst_ip_enrichments_annotations_environments_s',''),
|
||||
su_dst_annotations_locations=column_ifexists('dst_ip_enrichments_annotations_locations_s',''),
|
||||
su_dst_annotations_owners=column_ifexists('dst_ip_enrichments_annotations_owners_s',''),
|
||||
su_dst_annotations_roles=column_ifexists('dst_ip_enrichments_annotations_roles_s',''),
|
||||
su_dst_annotations_tags=column_ifexists('dst_ip_enrichments_annotations_tags_s',''),
|
||||
su_geo_distance=column_ifexists('geo_distance_d',''),
|
||||
su_http_status=column_ifexists('http_status_d',''),
|
||||
su_http_protocol=column_ifexists('http_protocol_s',''),
|
||||
su_http_url=column_ifexists('http_url_s',''),
|
||||
su_http_hostname=column_ifexists('http_hostname_s',''),
|
||||
su_http_host_internal=column_ifexists('http_hostname_enrichments_ip_enrichments_internal_b',''),
|
||||
su_http_host_geo_lat=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_location_lat_d',''),
|
||||
su_http_host_geo_lon=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_location_lon_d',''),
|
||||
su_http_host_geo_subdivision=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_subdivision_s',''),
|
||||
su_http_host_geo_city=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_city_s',''),
|
||||
su_http_host_asn_asn=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_asn_d',''),
|
||||
su_http_host_asn_org=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_org_s',''),
|
||||
su_http_host_asn_isp=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_isp_s',''),
|
||||
su_http_host_asn_asn_org=column_ifexists('http_hostname_enrichments_ip_enrichments_asn_asn_org_s',''),
|
||||
su_http_host_geo_country=column_ifexists('http_hostname_enrichments_ip_enrichments_geo_country_s',''),
|
||||
su_http_host_annotations_applications=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_applications_s',''),
|
||||
su_http_host_annotations_environments=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_environments_s',''),
|
||||
su_http_host_annotations_locations=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_locations_s',''),
|
||||
su_http_host_annotations_owners=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_owners_s',''),
|
||||
su_http_host_annotations_roles=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_roles_s',''),
|
||||
su_http_host_annotations_tags=column_ifexists('http_hostname_enrichments_ip_enrichments_annotations_tags_s',''),
|
||||
su_http_host_domain_entropy=column_ifexists('http_hostname_enrichments_domain_enrichments_domain_entropy_d',''),
|
||||
su_http_length=column_ifexists('http_length_d',''),
|
||||
su_http_method=column_ifexists('http_http_method_s',''),
|
||||
su_http_content_type=column_ifexists('http_http_content_type_s',''),
|
||||
su_http_refer=column_ifexists('http_http_refer_s',''),
|
||||
su_http_user_agent=column_ifexists('http_http_user_agent_s',''),
|
||||
su_http_redirect=column_ifexists('http_redirect_s',''),
|
||||
su_http_xtf=column_ifexists('http_xtf_s',''),
|
||||
su_payload=column_ifexists('payload_s',''),
|
||||
su_intel=column_ifexists('intel_s','')
|
||||
| project
|
||||
su_timestamp,
|
||||
su_event_type,
|
||||
su_src_ip,
|
||||
su_src_port,
|
||||
su_dst_ip,
|
||||
su_dst_port,
|
||||
su_intel,
|
||||
su_sig_name,
|
||||
su_sig_id,
|
||||
su_sig_rev,
|
||||
su_sig_category,
|
||||
su_sig_severity,
|
||||
su_payload,
|
||||
su_source,
|
||||
su_proto,
|
||||
su_sensor_id,
|
||||
su_src_internal,
|
||||
su_src_geo_lat,
|
||||
su_src_geo_lon,
|
||||
su_src_geo_country,
|
||||
su_src_geo_subdivision,
|
||||
su_src_geo_city,
|
||||
su_src_asn_asn,
|
||||
su_src_asn_org,
|
||||
su_src_asn_isp,
|
||||
su_src_asn_asn_org,
|
||||
su_src_annotations_applications,
|
||||
su_src_annotations_environments,
|
||||
su_src_annotations_locations,
|
||||
su_src_annotations_owners,
|
||||
su_src_annotations_roles,
|
||||
su_src_annotations_tags,
|
||||
su_dst_internal,
|
||||
su_dst_geo_lat,
|
||||
su_dst_geo_lon,
|
||||
su_dst_geo_country,
|
||||
su_dst_geo_subdivision,
|
||||
su_dst_geo_city,
|
||||
su_dst_asn_asn,
|
||||
su_dst_asn_org,
|
||||
su_dst_asn_isp,
|
||||
su_dst_asn_asn_org,
|
||||
su_dst_annotations_applications,
|
||||
su_dst_annotations_environments,
|
||||
su_dst_annotations_locations,
|
||||
su_dst_annotations_owners,
|
||||
su_dst_annotations_roles,
|
||||
su_dst_annotations_tags,
|
||||
su_geo_distance,
|
||||
su_http_status,
|
||||
su_http_protocol,
|
||||
su_http_url,
|
||||
su_http_hostname,
|
||||
su_http_host_internal,
|
||||
su_http_host_geo_lat,
|
||||
su_http_host_geo_lon,
|
||||
su_http_host_geo_country,
|
||||
su_http_host_geo_subdivision,
|
||||
su_http_host_geo_city,
|
||||
su_http_host_asn_asn,
|
||||
su_http_host_asn_org,
|
||||
su_http_host_asn_isp,
|
||||
su_http_host_asn_asn_org,
|
||||
su_http_host_annotations_applications,
|
||||
su_http_host_annotations_environments,
|
||||
su_http_host_annotations_locations,
|
||||
su_http_host_annotations_owners,
|
||||
su_http_host_annotations_roles,
|
||||
su_http_host_annotations_tags,
|
||||
su_http_host_domain_entropy,
|
||||
su_http_length,
|
||||
su_http_method,
|
||||
su_http_content_type,
|
||||
su_http_refer,
|
||||
su_http_user_agent,
|
||||
su_http_redirect,
|
||||
su_http_xtf,
|
||||
su_uuid,
|
||||
su_customer_id,
|
||||
Type
|
||||
};
|
||||
|
||||
let FortiNDR_Cloud_observation_view = view () {
|
||||
FncEventsObservation_CL
|
||||
| extend
|
||||
ob_timestamp=column_ifexists('timestamp_t',''),
|
||||
ob_uuid=column_ifexists('uuid_g',''),
|
||||
ob_event_type=column_ifexists('event_type_s',''),
|
||||
ob_customer_id=column_ifexists('customer_id_s',''),
|
||||
ob_sensor_id=column_ifexists('sensor_id_s',''),
|
||||
ob_source=column_ifexists('source_s',''),
|
||||
ob_evidence_start_timestamp=column_ifexists('evidence_start_timestamp_t',''),
|
||||
ob_evidence_end_timestamp=column_ifexists('evidence_end_timestamp_t',''),
|
||||
ob_observation_uuid=column_ifexists('observation_uuid_g',''),
|
||||
ob_observation_title=column_ifexists('title_s',''),
|
||||
ob_confidence=column_ifexists('confidence_s',''),
|
||||
ob_src_ip=column_ifexists('src_ip_s',''),
|
||||
ob_dst_ip=column_ifexists('dst_ip_s',''),
|
||||
ob_src_internal=column_ifexists('src_ip_enrichments_internal_b',''),
|
||||
ob_src_geo_lat=column_ifexists('src_ip_enrichments_geo_location_lat_d',''),
|
||||
ob_src_geo_lon=column_ifexists('src_ip_enrichments_geo_location_lon_d',''),
|
||||
ob_src_geo_country=column_ifexists('src_ip_enrichments_geo_country_s',''),
|
||||
ob_src_geo_subdivision=column_ifexists('src_ip_enrichments_geo_subdivision_s',''),
|
||||
ob_src_geo_city=column_ifexists('src_ip_enrichments_geo_city_s',''),
|
||||
ob_src_asn_asn=column_ifexists('src_ip_enrichments_asn_asn_d',''),
|
||||
ob_src_asn_org=column_ifexists('src_ip_enrichments_asn_org_s',''),
|
||||
ob_src_asn_isp=column_ifexists('src_ip_enrichments_asn_isp_s',''),
|
||||
ob_src_asn_asn_org=column_ifexists('src_ip_enrichments_asn_asn_org_s',''),
|
||||
ob_src_annotations_applications=column_ifexists('src_ip_enrichments_annotations_applications_s',''),
|
||||
ob_src_annotations_environments=column_ifexists('src_ip_enrichments_annotations_environments_s',''),
|
||||
ob_src_annotations_locations=column_ifexists('src_ip_enrichments_annotations_locations_s',''),
|
||||
ob_src_annotations_owners=column_ifexists('src_ip_enrichments_annotations_owners_s',''),
|
||||
ob_src_annotations_roles=column_ifexists('src_ip_enrichments_annotations_roles_s',''),
|
||||
ob_src_annotations_tags=column_ifexists('src_ip_enrichments_annotations_tags_s',''),
|
||||
ob_dst_internal=column_ifexists('dst_ip_enrichments_internal_b',''),
|
||||
ob_dst_geo_lat=column_ifexists('dst_ip_enrichments_geo_location_lat_d',''),
|
||||
ob_dst_geo_lon=column_ifexists('dst_ip_enrichments_geo_location_lon_d',''),
|
||||
ob_dst_geo_country=column_ifexists('dst_ip_enrichments_geo_country_s',''),
|
||||
ob_dst_geo_subdivision=column_ifexists('dst_ip_enrichments_geo_subdivision_s',''),
|
||||
ob_dst_geo_city=column_ifexists('dst_ip_enrichments_geo_city_s',''),
|
||||
ob_dst_asn_asn=column_ifexists('dst_ip_enrichments_asn_asn_d',''),
|
||||
ob_dst_asn_org=column_ifexists('dst_ip_enrichments_asn_org_s',''),
|
||||
ob_dst_asn_isp=column_ifexists('dst_ip_enrichments_asn_isp_s',''),
|
||||
ob_dst_asn_asn_org=column_ifexists('dst_ip_enrichments_asn_asn_org_s',''),
|
||||
ob_dst_annotations_applications=column_ifexists('dst_ip_enrichments_annotations_applications_s',''),
|
||||
ob_dst_annotations_environments=column_ifexists('dst_ip_enrichments_annotations_environments_s',''),
|
||||
ob_dst_annotations_locations=column_ifexists('dst_ip_enrichments_annotations_locations_s',''),
|
||||
ob_dst_annotations_owners=column_ifexists('dst_ip_enrichments_annotations_owners_s',''),
|
||||
ob_dst_annotations_roles=column_ifexists('dst_ip_enrichments_annotations_roles_s',''),
|
||||
ob_dst_annotations_tags=column_ifexists('dst_ip_enrichments_annotations_tags_s',''),
|
||||
ob_geo_distance=column_ifexists('geo_distance_d',''),
|
||||
ob_sensor_ids=column_ifexists('sensor_ids_s',''),
|
||||
ob_evidence_iql=column_ifexists('evidence_iql_s',''),
|
||||
ob_description=column_ifexists('description_s',''),
|
||||
ob_context=column_ifexists('context_s',''),
|
||||
ob_class=column_ifexists('class_s',''),
|
||||
ob_intel=column_ifexists('intel_s', ''),
|
||||
ob_category=column_ifexists('Category', '')
|
||||
| project
|
||||
ob_timestamp,
|
||||
ob_observation_title,
|
||||
ob_confidence,
|
||||
ob_category,
|
||||
ob_class,
|
||||
ob_context,
|
||||
ob_evidence_iql,
|
||||
ob_evidence_end_timestamp,
|
||||
ob_evidence_start_timestamp,
|
||||
ob_description,
|
||||
ob_observation_uuid,
|
||||
ob_sensor_ids,
|
||||
ob_event_type,
|
||||
ob_src_ip,
|
||||
ob_dst_ip,
|
||||
ob_intel,
|
||||
ob_source,
|
||||
ob_sensor_id,
|
||||
ob_src_internal,
|
||||
ob_src_geo_lat,
|
||||
ob_src_geo_lon,
|
||||
ob_src_geo_country,
|
||||
ob_src_geo_subdivision,
|
||||
ob_src_geo_city,
|
||||
ob_src_asn_asn,
|
||||
ob_src_asn_org,
|
||||
ob_src_asn_isp,
|
||||
ob_src_asn_asn_org,
|
||||
ob_src_annotations_applications,
|
||||
ob_src_annotations_environments,
|
||||
ob_src_annotations_locations,
|
||||
ob_src_annotations_owners,
|
||||
ob_src_annotations_roles,
|
||||
ob_src_annotations_tags,
|
||||
ob_dst_internal,
|
||||
ob_dst_geo_lat,
|
||||
ob_dst_geo_lon,
|
||||
ob_dst_geo_country,
|
||||
ob_dst_geo_subdivision,
|
||||
ob_dst_geo_city,
|
||||
ob_dst_asn_asn,
|
||||
ob_dst_asn_org,
|
||||
ob_dst_asn_isp,
|
||||
ob_dst_asn_asn_org,
|
||||
ob_dst_annotations_applications,
|
||||
ob_dst_annotations_environments,
|
||||
ob_dst_annotations_locations,
|
||||
ob_dst_annotations_owners,
|
||||
ob_dst_annotations_roles,
|
||||
ob_dst_annotations_tags,
|
||||
ob_geo_distance,
|
||||
ob_uuid,
|
||||
ob_customer_id,
|
||||
Type
|
||||
};
|
||||
|
||||
let FortiNDR_Cloud_detections_view = view () {
|
||||
FncEventsDetections_CL
|
||||
| extend
|
||||
de_vendor=column_ifexists('vendor_s',''),
|
||||
de_product=column_ifexists('product_s',''),
|
||||
de_signal_version=column_ifexists('signal_version_s',''),
|
||||
de_event_type=column_ifexists('event_type_s',''),
|
||||
de_subject=column_ifexists('subject_s',''),
|
||||
de_timestamp=column_ifexists('timestamp_t',''),
|
||||
de_device_ip=column_ifexists('device_ip_s',''),
|
||||
de_rule_name=column_ifexists('name_s',''),
|
||||
de_severity=column_ifexists('severity_s',''),
|
||||
de_confidence=column_ifexists('confidence_s',''),
|
||||
de_sensor_ids=column_ifexists('sensor_id_s',''),
|
||||
de_muted=column_ifexists('muted_b',''),
|
||||
de_rule_muted=column_ifexists('muted_rule_b',''),
|
||||
de_rule_uuid=column_ifexists('rule_uuid_g',''),
|
||||
de_mute_comment=column_ifexists('muted_comment_s',''),
|
||||
de_first_seen=column_ifexists('first_seen_t',''),
|
||||
de_last_seen=column_ifexists('last_seen_t',''),
|
||||
de_created=column_ifexists('created_t',''),
|
||||
de_updated=column_ifexists('updated_t',''),
|
||||
de_uuid=column_ifexists('uuid_g',''),
|
||||
de_status=column_ifexists('status_s',''),
|
||||
de_indicators=column_ifexists('indicators_s',''),
|
||||
de_customer_id=column_ifexists('customer_id_s',''),
|
||||
de_primary_pdns_hostnames=column_ifexists('primary_pdns_hostnames_s',''),
|
||||
de_other_pdns_hostnames=column_ifexists('other_pdns_hostnames_s',''),
|
||||
de_primary_dhcp_machost_pairs=column_ifexists('primary_dhcp_machost_pairs_s',''),
|
||||
de_other_dhcp_machost_pairs=column_ifexists('other_dhcp_machost_pairs_s',''),
|
||||
de_category=column_ifexists('Category', '')
|
||||
| project
|
||||
de_timestamp,
|
||||
de_device_ip,
|
||||
de_status,
|
||||
de_indicators,
|
||||
de_last_seen,
|
||||
de_rule_name,
|
||||
de_rule_uuid,
|
||||
de_category,
|
||||
de_created,
|
||||
de_updated,
|
||||
de_severity,
|
||||
de_confidence,
|
||||
de_muted,
|
||||
de_rule_muted,
|
||||
de_mute_comment,
|
||||
de_sensor_ids,
|
||||
de_primary_pdns_hostnames,
|
||||
de_other_pdns_hostnames,
|
||||
de_primary_dhcp_machost_pairs,
|
||||
de_other_dhcp_machost_pairs,
|
||||
de_vendor,
|
||||
de_product,
|
||||
de_signal_version,
|
||||
de_event_type,
|
||||
de_subject,
|
||||
de_uuid,
|
||||
de_customer_id,
|
||||
Type
|
||||
};
|
||||
|
||||
union isfuzzy=true
|
||||
FortiNDR_Cloud_suricata_view,
|
||||
FortiNDR_Cloud_observation_view,
|
||||
FortiNDR_Cloud_detections_view
|
|
@ -0,0 +1,3 @@
|
|||
| **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** |
|
||||
|-------------|--------------------------------|---------------------------------------------|
|
||||
| 3.0.0 | 30-01-2024 | Initial Solution Release |
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"publisherId": "azuresentinel",
|
||||
"offerId": "azure-sentinel-solution-fortindrcloud",
|
||||
"firstPublishDate": "2024-01-15",
|
||||
"providers": ["Fortinet"],
|
||||
"categories": {
|
||||
"domains" : ["Security - Automation (SOAR)"],
|
||||
"verticals": []
|
||||
},
|
||||
"support": {
|
||||
"name": "Microsoft Corporation",
|
||||
"email": "support@microsoft.com",
|
||||
"tier": "Microsoft",
|
||||
"link": "https://support.microsoft.com"
|
||||
}
|
||||
}
|
|
@ -1,23 +1,23 @@
|
|||
{
|
||||
"Name": "Armorblox",
|
||||
"Author": "Armorblox - support@armorblox.com",
|
||||
"Logo": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Armorblox/Data%20Connectors/Logo/armorblox.svg\" width=\"75px\" height=\"75px\">",
|
||||
"Description": "The [Armorblox](https://www.armorblox.com/) solution provides the capability to ingest incidents from your Armorblox instance into Microsoft Sentinel through the REST API.\r\n \r\n **Underlying Microsoft Technologies used:** \r\n\r\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs:\r\n\n a. [Azure Monitor HTTP Data Collector API](https://docs.microsoft.com/azure/azure-monitor/logs/data-collector-api)\r\n\n \r\n\n b. [Azure Functions](https://azure.microsoft.com/services/functions/#overview)\r\n\n",
|
||||
"Data Connectors": [
|
||||
"Data Connectors/Armorblox_API_FunctionApp.json"
|
||||
],
|
||||
"Workbooks": [
|
||||
"Workbooks/ArmorbloxOverview.json"
|
||||
],
|
||||
"Analytic Rules": [
|
||||
"Analytic Rules/ArmorbloxNeedsReviewAlert.yaml"
|
||||
],
|
||||
"Playbooks": [
|
||||
"Playbooks/Needs-Review-Incident-Email-Notification/azuredeploy.json"
|
||||
],
|
||||
"Metadata": "SolutionMetadata.json",
|
||||
"BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\Armorblox",
|
||||
"Version": "2.0.2",
|
||||
"TemplateSpec": true,
|
||||
"Is1PConnector": false
|
||||
}
|
||||
"Name": "Armorblox",
|
||||
"Author": "Armorblox - support@armorblox.com",
|
||||
"Logo": "<img src=\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Solutions/Armorblox/Data%20Connectors/Logo/armorblox.svg\" width=\"75px\" height=\"75px\">",
|
||||
"Description": "The [Armorblox](https://www.armorblox.com/) solution provides the capability to ingest incidents from your Armorblox instance into Microsoft Sentinel through the REST API.\r\n \r\n **Underlying Microsoft Technologies used:** \r\n\r\nThis solution takes a dependency on the following technologies, and some of these dependencies either may be in [Preview](https://azure.microsoft.com/support/legal/preview-supplemental-terms/) state or might result in additional ingestion or operational costs:\r\n\n a. [Azure Monitor HTTP Data Collector API](https://docs.microsoft.com/azure/azure-monitor/logs/data-collector-api)\r\n\n \r\n\n b. [Azure Functions](https://azure.microsoft.com/services/functions/#overview)\r\n\n",
|
||||
"Data Connectors": [
|
||||
"Data Connectors/Armorblox_API_FunctionApp.json"
|
||||
],
|
||||
"Workbooks": [
|
||||
"Workbooks/ArmorbloxOverview.json"
|
||||
],
|
||||
"Analytic Rules": [
|
||||
"Analytic Rules/ArmorbloxNeedsReviewAlert.yaml"
|
||||
],
|
||||
"Playbooks": [
|
||||
"Playbooks/Needs-Review-Incident-Email-Notification/azuredeploy.json"
|
||||
],
|
||||
"Metadata": "SolutionMetadata.json",
|
||||
"BasePath": "C:\\GitHub\\Azure-Sentinel\\Solutions\\Armorblox",
|
||||
"Version": "2.0.2",
|
||||
"TemplateSpec": true,
|
||||
"Is1PConnector": false
|
||||
}
|
После Ширина: | Высота: | Размер: 171 KiB |
После Ширина: | Высота: | Размер: 167 KiB |
После Ширина: | Высота: | Размер: 111 KiB |
После Ширина: | Высота: | Размер: 110 KiB |
После Ширина: | Высота: | Размер: 172 KiB |
После Ширина: | Высота: | Размер: 172 KiB |
После Ширина: | Высота: | Размер: 181 KiB |
После Ширина: | Высота: | Размер: 180 KiB |
|
@ -6910,5 +6910,33 @@
|
|||
"templateRelativePath": "MalwareProtectionEssentialsWorkbook.json",
|
||||
"subtitle": "",
|
||||
"provider": "Microsoft Sentinel community"
|
||||
},
|
||||
{
|
||||
"workbookKey": "FortinetFortiNdrCloudWorkbook",
|
||||
"logoFileName": "fortinet_logo.svg",
|
||||
"description": "Gain insights into Fortinet FortiNDR CLoud events, including the Suricata, Observatino and Detections data.",
|
||||
"dataTypesDependencies": [
|
||||
"FncEventsSuricata_CL",
|
||||
"FncEventsObservation_CL",
|
||||
"FncEventsDetections_CL"
|
||||
],
|
||||
"dataConnectorsDependencies": [
|
||||
"FortinetFortiNdrCloudDataConnector"
|
||||
],
|
||||
"previewImagesFileNames": [
|
||||
"FncDetectionDashboardBlack.png",
|
||||
"FncDetectionDashboardWhite.png",
|
||||
"FncObservationDashboardBlack.png",
|
||||
"FncObservationDashboardWhite.png",
|
||||
"FncSuricataDashboardBlack.png",
|
||||
"FncSuricataDashboardWhite.png",
|
||||
"FncMainDashboardBlack.png",
|
||||
"FncMainDashboardWhite.png"
|
||||
],
|
||||
"version": "1.0.0",
|
||||
"title": "FortiNDR Cloud",
|
||||
"templateRelativePath": "FortinetFortiNdrCloudWorkbook.json",
|
||||
"subtitle": "",
|
||||
"provider": "Fortinet"
|
||||
}
|
||||
]
|
||||
|
|