Skip to content

[Bug] Missing Related Integrations and Required Fields for ESQL Rules #4506

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Mikaayenson opened this issue Mar 3, 2025 · 2 comments
Open
Labels
bug Something isn't working Team: TRADE

Comments

@Mikaayenson
Copy link
Contributor

Mikaayenson commented Mar 3, 2025

Describe the Bug

Since we do not have an ESQL parser that can pull out event.datasource and we do not include index since it is duplicative with the query, we are not able to populated the related_integration build time field.

This means that in the security solution, ESQL rules are missing this information.

One idea not fully explored would be to add the related integration information to the toml file (as a stop gap until we have an esql parser), but this would have to be fully explored with the team for viability.

We could potentially add the metadata to the toml.

[[rule.related_integrations]]
package="azure"
integration="signinlogs"
version = "N/A"

Note: This would increase toil for our detection engineers and require us to maintain.

To Reproduce

  1. Select any ESQL rule
  2. run the view-rule command with the rule
  3. See the related_integrations field is missing in the output.

Expected Behavior

Related Integrations should be available in the security solution.

Screenshots

Image

Desktop - OS

None

Desktop - Version

No response

Additional Context

One approach may be to manually add the related_integrations field and skip the required version field so that it can be programmatically picked up.

diff --git a/detection_rules/rule.py b/detection_rules/rule.py
index 7dd295feb..ee4ab00d3 100644
--- a/detection_rules/rule.py
+++ b/detection_rules/rule.py
@@ -1231,7 +1231,9 @@ class TOMLRuleContents(BaseRuleContents, MarshmallowDataclassMixin):
         field_name = "related_integrations"
         package_integrations = obj.get(field_name, [])
 
-        if not package_integrations and self.metadata.integration:
+        # missing if any versions are N/A
+        missing_package_versions = any(pk['version'] == "N/A" for pk in package_integrations)
+        if (not package_integrations or (package_integrations and missing_package_versions)) and self.metadata.integration:
             packages_manifest = load_integrations_manifests()
             current_stack_version = load_current_package_version()
 
@@ -1239,8 +1241,10 @@ class TOMLRuleContents(BaseRuleContents, MarshmallowDataclassMixin):
                 if (isinstance(self.data, QueryRuleData) or isinstance(self.data, MachineLearningRuleData)):
                     if (self.data.get('language') is not None and self.data.get('language') != 'lucene') or \
                             self.data.get('type') == 'machine_learning':
-                        package_integrations = self.get_packaged_integrations(self.data, self.metadata,
-                                                                              packages_manifest)
+
+                        if not package_integrations:
+                            package_integrations = self.get_packaged_integrations(self.data, self.metadata,
+                                                                                  packages_manifest)
 
                         if not package_integrations:
                             return
@@ -1259,6 +1263,7 @@ class TOMLRuleContents(BaseRuleContents, MarshmallowDataclassMixin):
                                 policy_templates = version_data.get("policy_templates", [])
 
                                 if package["integration"] not in policy_templates:
+                                    # TODO: Error when integration is not a policy template because we just didnt update the manifest
                                     del package["integration"]
 
                     # remove duplicate entries
@@ -1266,6 +1271,7 @@ class TOMLRuleContents(BaseRuleContents, MarshmallowDataclassMixin):
                                                 d for d in package_integrations}.values())
                     obj.setdefault("related_integrations", package_integrations)
 
+
     def _convert_add_required_fields(self, obj: dict) -> None:
         """Add restricted field required_fields to the obj, derived from the query AST."""
         if isinstance(self.data, QueryRuleData) and self.data.language != 'lucene':
diff --git a/detection_rules/rule_validators.py b/detection_rules/rule_validators.py
index 5fe957ec1..d94e529ea 100644
--- a/detection_rules/rule_validators.py
+++ b/detection_rules/rule_validators.py
@@ -597,11 +597,18 @@ class ESQLValidator(QueryValidator):
     def validate(self, data: 'QueryRuleData', meta: RuleMeta) -> None:
         """Validate an ESQL query while checking TOMLRule."""
         # temporarily override to NOP until ES|QL query parsing is supported
+        self.validate_integration(data, meta, data.related_integrations)
 
     def validate_integration(self, data: QueryRuleData, meta: RuleMeta, package_integrations: List[dict]) -> Union[
             ValidationError, None, ValueError]:
-        # return self.validate(data, meta)
-        pass
+        # Force all esql rules to manually specify the related_integrations
+        if not package_integrations:
+            raise ValueError("ES|QL rules must specify related_integrations")
+
+        for package in package_integrations:
+            version = package.version.strip("^")
+            if version != "N/A" and not Version.is_valid(version):
+                raise ValueError("ES|QL rules must specify a version for related_integrations or N/A to get the latest")
 
 
 def extract_error_field(source: str, exc: Union[eql.EqlParseError, kql.KqlParseError]) -> Optional[str]:
diff --git a/rules/integrations/azure/credential_access_entra_signin_brute_force_microsoft_365.toml b/rules/integrations/azure/credential_access_entra_signin_brute_force_microsoft_365.toml
index 7e451f3a7..b41e05538 100644
--- a/rules/integrations/azure/credential_access_entra_signin_brute_force_microsoft_365.toml
+++ b/rules/integrations/azure/credential_access_entra_signin_brute_force_microsoft_365.toml
@@ -6,6 +6,7 @@ min_stack_comments = "ES|QL not available until 8.13.0 in technical preview."
 min_stack_version = "8.13.0"
 updated_date = "2025/01/15"
 
+
 [rule]
 author = ["Elastic"]
 description = """
@@ -108,6 +109,10 @@ from logs-azure.signinlogs*
 | where (login_source_count >= 20 or failed_login_count >= 20)
 '''
 
+[[rule.related_integrations]]
+package="azure"
+integration="signinlogs"
+version = "N/A"
 
 [[rule.threat]]
 framework = "MITRE ATT&CK"
diff --git a/rules/windows/collection_email_powershell_exchange_mailbox.toml b/rules/windows/collection_email_powershell_exchange_mailbox.toml
index 1d39e1988..af74334fe 100644
--- a/rules/windows/collection_email_powershell_exchange_mailbox.toml
+++ b/rules/windows/collection_email_powershell_exchange_mailbox.toml
@@ -95,6 +95,7 @@ tags = [
     "Data Source: SentinelOne",
     "Data Source: Microsoft Defender for Endpoint",
     "Data Source: System",
+
 ]
 timestamp_override = "event.ingested"
 type = "eql"

Caution

With the new docs system, they will be picking up the toml and auto converting to markdown. Since this approach uses a buildtime automation, this will not work for docs.

@Mikaayenson Mikaayenson added bug Something isn't working Team: TRADE labels Mar 3, 2025
@eric-forte-elastic
Copy link
Contributor

We might be able to leverage Kibana's Lexer/parser (ref: https://github.com/elastic/kibana/pull/213006/files) 🤔

@Mikaayenson
Copy link
Contributor Author

Here is the short outcome after discussing with the team:

  • This workaround will only address related integrations. We will still have issues pulling required_fields since we do not have a parser.
  • It creates toil for our authors to maintain the actual fields which are otherwise built automatically for all other rule types
  • This may inadvertently set precedence to continue adding workarounds instead of prioritizing a parser.

At the moment we do not have plans to implement this, and will instead hold until https://github.com/elastic/security-team/issues/11554 is provided.

@Mikaayenson Mikaayenson changed the title [Bug] Missing Related Integrations for ESQL Rules [Bug] Missing Related Integrations and Required Fields for ESQL Rules Mar 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Team: TRADE
Projects
None yet
Development

No branches or pull requests

2 participants