Google SecOps SIEM
In order to integrate SailPoint Entro with Google SecOps SIEM you will need to forward SailPoint Entro's risks to the platform by creating a webhook in Google SecOps' SIEM Feed settings.
SailPoint Entro is an official Google SecOps technology partner.
Webhook Feed Configuration
-
In your Google SecOps tenant, go to Settings > SIEM Settings

-
From the Settings panel, at the bottom of the screen, select Feeds

-
Create a new webhook by clicking on the "+ ADD NEW FEED" button at the top of the screen

-
Fill in the form as below
Note
You will use the "Entrust DataControl Audit" Log type as SailPoint Entro is working on offering our Log Type within the Google SecOps platform

-
If needed, add an ingestion label as show below

-
Generate the secret key and copy it to a safe place

-
On the Feeds screen, select the created feed and click "View Feed"

-
In the View feed modal, copy the Endpoint Information address

-
Head over to your GCP Project affiliated with the Google SecOps instance, and create a new API key in the Credentials section. Copy it once created.

-
Restrict the API key's access to Chronicle

-
Create the following URL structure and copy it onto SailPoint Entro in the Webhooks section
Now, SailPoint Entro risks will be forwarded to your Google SecOps SIEM.
Parsing
Google SecOps requires the webhook payload data to be parsed as SecOps' entity.
-
Head over to Parsers

-
Create a parser

-
Fill in the modal as below

-
Once created, a coding section will open

-
Paste the code in the section below into the middle pane
SailPoint Entro Google SecOps SIEM custom parser
filter { # Parse the JSON message first json { source => "message" on_error => "not_json" } # Only process if JSON parsing was successful if ![not_json] { # Set basic vendor info first mutate { replace => { "event.idm.read_only_udm.metadata.event_type" => "SCAN_UNCATEGORIZED" "event.idm.read_only_udm.metadata.vendor_name" => "Entro" "event.idm.read_only_udm.metadata.product_name" => "Entro Security" "event.idm.read_only_udm.metadata.log_type" => "ENTRO_WEBHOOK" } } if [notificationType] == "Risk Status Changed" { mutate { rename => { "updatedRisk" => "riskData" } } } if [notificationType] == "Risk Created" { mutate { rename => { "createdRisk" => "riskData" } } } if [riskData][ruleCode] == "OVEREXPOSED" { drop {} } if [riskData][ruleCode] == "GOLD_MINE" { drop {} } # Extract basic fields directly mutate { replace => { "event.idm.read_only_udm.metadata.product_log_id" => "%{riskData.guid}" "event.idm.read_only_udm.metadata.description" => "%{riskData.name}" "event.idm.read_only_udm.metadata.product_event_type" => "%{riskData.type}" } on_error => "_basic_fields_failed" } # Convert detection time to timestamp date { match => ["riskData.detectionTime", "UNIX"] target => "event.idm.read_only_udm.metadata.event_timestamp" on_error => "_date_parsing_failed" } # Map principal with proper device/asset information mutate { replace => { "event.idm.read_only_udm.principal.hostname" => "entro-scanner" "event.idm.read_only_udm.principal.asset.hostname" => "entro-scanner" "event.idm.read_only_udm.principal.asset.asset_id" => "entro:security-scanner" } } mutate { replace => { "event.idm.read_only_udm.principal.user.userid" => "%{riskData.owner}" "event.idm.read_only_udm.principal.user.user_display_name" => "%{riskData.employee.name}" } on_error => "_principal_user_failed" } # Set fallbacks if fields were empty if "%{event.idm.read_only_udm.principal.user.userid}" == "" { mutate { replace => { "event.idm.read_only_udm.principal.user.userid" => "unknown-user" } } } if "%{event.idm.read_only_udm.principal.user.user_display_name}" == "" { mutate { replace => { "event.idm.read_only_udm.principal.user.user_display_name" => "unknown-user" } } } # Generic target information with proper resource details mutate { replace => { "event.idm.read_only_udm.target.resource.name" => "%{riskData.path}" "event.idm.read_only_udm.target.resource.resource_type" => "STORAGE_OBJECT" "event.idm.read_only_udm.target.hostname" => "%{riskData.source}" } on_error => "_target_failed" } # Check if path is empty and set fallback if "%{riskData.path}" == "" { mutate { replace => { "event.idm.read_only_udm.target.resource.name" => "unknown-resource" } } } # Check if source is empty and set fallback for target hostname if "%{riskData.source}" == "" { mutate { replace => { "event.idm.read_only_udm.target.hostname" => "unknown-source" } } } # Create security result object mutate { replace => { "_security_result.rule_id" => "%{riskData.guid}" "_security_result.rule_name" => "%{riskData.ruleCode}" "_security_result.summary" => "%{riskData.name}" "_security_result.description" => "%{riskData.name}" } on_error => "_security_basic_failed" } # Map severity dynamically if "%{riskData.severity}" == "LOW" { mutate { replace => { "_security_result.severity" => "LOW" } } } if "%{riskData.severity}" == "MEDIUM" { mutate { replace => { "_security_result.severity" => "MEDIUM" } } } if "%{riskData.severity}" == "HIGH" { mutate { replace => { "_security_result.severity" => "HIGH" } } } if "%{riskData.severity}" == "CRITICAL" { mutate { replace => { "_security_result.severity" => "CRITICAL" } } } # Default severity if none matched if "%{_security_result.severity}" == "" { mutate { replace => { "_security_result.severity" => "MEDIUM" } } } # Map category dynamically - generic approach if "%{riskData.category}" == "EXPOSED_SECRET" { mutate { replace => { "_category_item" => "DATA_EXFILTRATION" } } } else { mutate { replace => { "_category_item" => "POLICY_VIOLATION" } } } mutate { merge => { "_security_result.category" => "_category_item" } on_error => "_category_merge_failed" } # Map action dynamically based on status if "%{riskData.status}" == "RESOLVED" { mutate { replace => { "_action_item" => "BLOCK" } } } else { mutate { replace => { "_action_item" => "ALLOW" } } } mutate { merge => { "_security_result.action" => "_action_item" } on_error => "_action_merge_failed" } # Add ALL root fields as detection fields for searchability mutate { replace => { "_detection_field_status.key" => "status" "_detection_field_status.value" => "%{riskData.status}" } on_error => "_detection_status_failed" } mutate { merge => { "_security_result.detection_fields" => "_detection_field_status" } on_error => "_detection_status_merge_failed" } mutate { replace => { "_detection_field_name.key" => "risk_name" "_detection_field_name.value" => "%{riskData.name}" } on_error => "_detection_name_failed" } mutate { merge => { "_security_result.detection_fields" => "_detection_field_name" } on_error => "_detection_name_merge_failed" } mutate { replace => { "_detection_field_source.key" => "source" "_detection_field_source.value" => "%{riskData.source}" } on_error => "_detection_source_failed" } mutate { merge => { "_security_result.detection_fields" => "_detection_field_source" } on_error => "_detection_source_merge_failed" } mutate { replace => { "_detection_field_owner.key" => "owner" "_detection_field_owner.value" => "%{riskData.owner}" } on_error => "_detection_owner_failed" } mutate { merge => { "_security_result.detection_fields" => "_detection_field_owner" } on_error => "_detection_owner_merge_failed" } mutate { replace => { "_detection_field_severity.key" => "severity" "_detection_field_severity.value" => "%{riskData.severity}" } on_error => "_detection_severity_failed" } mutate { merge => { "_security_result.detection_fields" => "_detection_field_severity" } on_error => "_detection_severity_merge_failed" } mutate { replace => { "_detection_field_type.key" => "risk_type" "_detection_field_type.value" => "%{riskData.type}" } on_error => "_detection_type_failed" } mutate { merge => { "_security_result.detection_fields" => "_detection_field_type" } on_error => "_detection_type_merge_failed" } mutate { replace => { "_detection_field_category.key" => "category" "_detection_field_category.value" => "%{riskData.category}" } on_error => "_detection_category_failed" } mutate { merge => { "_security_result.detection_fields" => "_detection_field_category" } on_error => "_detection_category_merge_failed" } mutate { replace => { "_detection_field_rule_code.key" => "rule_code" "_detection_field_rule_code.value" => "%{riskData.ruleCode}" } on_error => "_detection_rule_code_failed" } mutate { merge => { "_security_result.detection_fields" => "_detection_field_rule_code" } on_error => "_detection_rule_code_merge_failed" } mutate { replace => { "_detection_field_path.key" => "path" "_detection_field_path.value" => "%{riskData.path}" } on_error => "_detection_path_failed" } mutate { merge => { "_security_result.detection_fields" => "_detection_field_path" } on_error => "_detection_path_merge_failed" } # Add notification type detection field mutate { replace => { "_detection_field_notification.key" => "notification_type" "_detection_field_notification.value" => "%{notificationType}" } on_error => "_detection_notification_failed" } mutate { merge => { "_security_result.detection_fields" => "_detection_field_notification" } on_error => "_detection_notification_merge_failed" } # Merge security result into the event mutate { merge => { "event.idm.read_only_udm.security_result" => "_security_result" } on_error => "_security_result_merge_failed" } # Add core additional fields mutate { replace => { "_additional_notification_type.key" => "notification_type" "_additional_notification_type.value.string_value" => "%{notificationType}" } on_error => "_notification_type_failed" } mutate { merge => { "event.idm.read_only_udm.additional.fields" => "_additional_notification_type" } on_error => "_notification_type_merge_failed" } mutate { replace => { "_additional_owner_uid.key" => "owner_uid" "_additional_owner_uid.value.string_value" => "%{riskData.ownerUid}" } on_error => "_owner_uid_failed" } mutate { merge => { "event.idm.read_only_udm.additional.fields" => "_additional_owner_uid" } on_error => "_owner_uid_merge_failed" } mutate { replace => { "_additional_archived.key" => "is_archived" "_additional_archived.value.string_value" => "%{riskData.isArchived}" } on_error => "_archived_failed" } mutate { merge => { "event.idm.read_only_udm.additional.fields" => "_additional_archived" } on_error => "_archived_merge_failed" } mutate { replace => { "_additional_creation_date.key" => "creation_date" "_additional_creation_date.value.string_value" => "%{riskData.creationDate}" } on_error => "_creation_date_failed" } mutate { merge => { "event.idm.read_only_udm.additional.fields" => "_additional_creation_date" } on_error => "_creation_date_merge_failed" } mutate { replace => { "_additional_modify_date.key" => "modify_date" "_additional_modify_date.value.string_value" => "%{riskData.modifyDate}" } on_error => "_modify_date_failed" } mutate { merge => { "event.idm.read_only_udm.additional.fields" => "_additional_modify_date" } on_error => "_modify_date_merge_failed" } mutate { replace => { "_additional_employee_status.key" => "employee_status" "_additional_employee_status.value.string_value" => "%{riskData.employee.status}" } on_error => "_employee_status_failed" } mutate { merge => { "event.idm.read_only_udm.additional.fields" => "_additional_employee_status" } on_error => "_employee_status_merge_failed" } # Final merge to output mutate { merge => { "@output" => "event" } on_error => "_final_merge_failed" } } } -
Click on Validate

-
When validation passes, click on Next and Submit


-
The following message should appear

Now you will be able to process events in the SIEM Search investigation panel
