ml-configuring-detector-custom-rules.asciidoc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. [role="xpack"]
  2. [[ml-configuring-detector-custom-rules]]
  3. = Customizing detectors with custom rules
  4. <<ml-rules,Custom rules>> – or _job rules_ as {kib} refers to them – enable you
  5. to change the behavior of anomaly detectors based on domain-specific knowledge.
  6. Custom rules describe _when_ a detector should take a certain _action_ instead
  7. of following its default behavior. To specify the _when_ a rule uses
  8. a `scope` and `conditions`. You can think of `scope` as the categorical
  9. specification of a rule, while `conditions` are the numerical part.
  10. A rule can have a scope, one or more conditions, or a combination of
  11. scope and conditions. For the full list of specification details, see the
  12. {ref}/ml-put-job.html#put-customrules[`custom_rules` object] in the create
  13. {anomaly-jobs} API.
  14. [[ml-custom-rules-scope]]
  15. == Specifying custom rule scope
  16. Let us assume we are configuring an {anomaly-job} in order to detect DNS data
  17. exfiltration. Our data contain fields "subdomain" and "highest_registered_domain".
  18. We can use a detector that looks like
  19. `high_info_content(subdomain) over highest_registered_domain`. If we run such a
  20. job, it is possible that we discover a lot of anomalies on frequently used
  21. domains that we have reasons to trust. As security analysts, we are not
  22. interested in such anomalies. Ideally, we could instruct the detector to skip
  23. results for domains that we consider safe. Using a rule with a scope allows us
  24. to achieve this.
  25. First, we need to create a list of our safe domains. Those lists are called
  26. _filters_ in {ml}. Filters can be shared across {anomaly-jobs}.
  27. You can create a filter in **Anomaly Detection > Settings > Filter Lists** in
  28. {kib} or by using the {ref}/ml-put-filter.html[put filter API]:
  29. [source,console]
  30. ----------------------------------
  31. PUT _ml/filters/safe_domains
  32. {
  33. "description": "Our list of safe domains",
  34. "items": ["safe.com", "trusted.com"]
  35. }
  36. ----------------------------------
  37. // TEST[skip:needs-licence]
  38. Now, we can create our {anomaly-job} specifying a scope that uses the
  39. `safe_domains` filter for the `highest_registered_domain` field:
  40. [source,console]
  41. ----------------------------------
  42. PUT _ml/anomaly_detectors/dns_exfiltration_with_rule
  43. {
  44. "analysis_config" : {
  45. "bucket_span":"5m",
  46. "detectors" :[{
  47. "function":"high_info_content",
  48. "field_name": "subdomain",
  49. "over_field_name": "highest_registered_domain",
  50. "custom_rules": [{
  51. "actions": ["skip_result"],
  52. "scope": {
  53. "highest_registered_domain": {
  54. "filter_id": "safe_domains",
  55. "filter_type": "include"
  56. }
  57. }
  58. }]
  59. }]
  60. },
  61. "data_description" : {
  62. "time_field":"timestamp"
  63. }
  64. }
  65. ----------------------------------
  66. // TEST[skip:needs-licence]
  67. As time advances and we see more data and more results, we might encounter new
  68. domains that we want to add in the filter. We can do that in the
  69. **Anomaly Detection > Settings > Filter Lists** in {kib} or by using the
  70. {ref}/ml-update-filter.html[update filter API]:
  71. [source,console]
  72. ----------------------------------
  73. POST _ml/filters/safe_domains/_update
  74. {
  75. "add_items": ["another-safe.com"]
  76. }
  77. ----------------------------------
  78. // TEST[skip:setup:ml_filter_safe_domains]
  79. Note that we can use any of the `partition_field_name`, `over_field_name`, or
  80. `by_field_name` fields in the `scope`.
  81. In the following example we scope multiple fields:
  82. [source,console]
  83. ----------------------------------
  84. PUT _ml/anomaly_detectors/scoping_multiple_fields
  85. {
  86. "analysis_config" : {
  87. "bucket_span":"5m",
  88. "detectors" :[{
  89. "function":"count",
  90. "partition_field_name": "my_partition",
  91. "over_field_name": "my_over",
  92. "by_field_name": "my_by",
  93. "custom_rules": [{
  94. "actions": ["skip_result"],
  95. "scope": {
  96. "my_partition": {
  97. "filter_id": "filter_1"
  98. },
  99. "my_over": {
  100. "filter_id": "filter_2"
  101. },
  102. "my_by": {
  103. "filter_id": "filter_3"
  104. }
  105. }
  106. }]
  107. }]
  108. },
  109. "data_description" : {
  110. "time_field":"timestamp"
  111. }
  112. }
  113. ----------------------------------
  114. // TEST[skip:needs-licence]
  115. Such a detector skips results when the values of all three scoped fields are
  116. included in the referenced filters.
  117. [[ml-custom-rules-conditions]]
  118. == Specifying custom rule conditions
  119. Imagine a detector that looks for anomalies in CPU utilization. Given a machine
  120. that is idle for long enough, small movement in CPU could result in anomalous
  121. results where the `actual` value is quite small, for example, 0.02. Given our
  122. knowledge about how CPU utilization behaves we might determine that anomalies
  123. with such small actual values are not interesting for investigation.
  124. Let us now configure an {anomaly-job} with a rule that skips results where CPU
  125. utilization is less than 0.20.
  126. [source,console]
  127. ----------------------------------
  128. PUT _ml/anomaly_detectors/cpu_with_rule
  129. {
  130. "analysis_config" : {
  131. "bucket_span":"5m",
  132. "detectors" :[{
  133. "function":"high_mean",
  134. "field_name": "cpu_utilization",
  135. "custom_rules": [{
  136. "actions": ["skip_result"],
  137. "conditions": [
  138. {
  139. "applies_to": "actual",
  140. "operator": "lt",
  141. "value": 0.20
  142. }
  143. ]
  144. }]
  145. }]
  146. },
  147. "data_description" : {
  148. "time_field":"timestamp"
  149. }
  150. }
  151. ----------------------------------
  152. // TEST[skip:needs-licence]
  153. When there are multiple conditions they are combined with a logical `AND`. This
  154. is useful when we want the rule to apply to a range. We create a rule with two
  155. conditions, one for each end of the desired range.
  156. Here is an example where a count detector skips results when the count is
  157. greater than 30 and less than 50:
  158. [source,console]
  159. ----------------------------------
  160. PUT _ml/anomaly_detectors/rule_with_range
  161. {
  162. "analysis_config" : {
  163. "bucket_span":"5m",
  164. "detectors" :[{
  165. "function":"count",
  166. "custom_rules": [{
  167. "actions": ["skip_result"],
  168. "conditions": [
  169. {
  170. "applies_to": "actual",
  171. "operator": "gt",
  172. "value": 30
  173. },
  174. {
  175. "applies_to": "actual",
  176. "operator": "lt",
  177. "value": 50
  178. }
  179. ]
  180. }]
  181. }]
  182. },
  183. "data_description" : {
  184. "time_field":"timestamp"
  185. }
  186. }
  187. ----------------------------------
  188. // TEST[skip:needs-licence]
  189. [[ml-custom-rules-lifecycle]]
  190. == Custom rules in the lifecycle of a job
  191. Custom rules only affect results created after the rules were applied. Let us
  192. imagine that we have configured an {anomaly-job} and it has been running for
  193. some time. After observing its results, we decide that we can employ rules to
  194. get rid of some uninteresting results. We can use the
  195. {ref}/ml-update-job.html[update {anomaly-job} API] to do so. However, the rule
  196. we added will only be in effect for any results created from the moment we
  197. added the rule onwards. Past results remain unaffected.
  198. [[ml-custom-rules-filtering]]
  199. == Using custom rules vs. filtering data
  200. It might appear like using rules is just another way of filtering the data that
  201. feeds into an {anomaly-job}. For example, a rule that skips results when the
  202. partition field value is in a filter sounds equivalent to having a query that
  203. filters out such documents. However, there is a fundamental difference. When the
  204. data is filtered before reaching a job, it is as if they never existed for the
  205. job. With rules, the data still reaches the job and affects its behavior
  206. (depending on the rule actions).
  207. For example, a rule with the `skip_result` action means all data is still
  208. modeled. On the other hand, a rule with the `skip_model_update` action means
  209. results are still created even though the model is not updated by data matched
  210. by a rule.