Skip to content
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

[Security Solution] Add coverage overview dashboard API contract #159993

Merged
merged 24 commits into from
Jun 22, 2023

Conversation

maximpn
Copy link
Contributor

@maximpn maximpn commented Jun 20, 2023

Addresses: #158202

Summary

This PR defines Coverage Overview Dashboard API's request and response type definitions and adds UI domain models.

@maximpn maximpn added release_note:skip Skip the PR/issue when compiling release notes backport:skip This commit does not require backporting Team:Detections and Resp Security Detection Response Team Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. Feature:Rule Management Security Solution Detection Rule Management area Team:Detection Rule Management Security Detection Rule Management Team v8.10.0 labels Jun 20, 2023
@maximpn maximpn self-assigned this Jun 20, 2023
@maximpn maximpn marked this pull request as ready for review June 20, 2023 11:12
@maximpn maximpn requested a review from a team as a code owner June 20, 2023 11:12
@maximpn maximpn requested a review from dplumlee June 20, 2023 11:12
@elasticmachine
Copy link
Contributor

Pinging @elastic/security-detections-response (Team:Detections and Resp)

@elasticmachine
Copy link
Contributor

Pinging @elastic/security-solution (Team: SecuritySolution)

@maximpn maximpn requested a review from xcrzx June 20, 2023 11:12
Copy link
Contributor

@xcrzx xcrzx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving a couple of minor comments, but overall LGTM 👍

Comment on lines 8 to 11
export interface CoverageOverviewRuleData {
id: string; // rule SO's ids (not ruleId)
name: string;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two structures in the PR named CoverageOverviewRuleData what's the difference between them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One defined in response_schema.ts is a DTO and another one here in rule_data.ts is a domain model.

*/

export interface CoverageOverviewRuleData {
id: string; // rule SO's ids (not ruleId)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the RuleObjectId alias here?


export interface CoverageOverviewMitreTactic {
name: string;
reference: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments along the structure would be greatly appreciated. For example, it is not completely clear what reference means in this context.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, reference looks too generic. I used the same naming as in mitre_tactics_techniques.ts.

As it causes confusion I've added comments to some fields.

@banderror banderror self-requested a review June 21, 2023 11:43
@banderror
Copy link
Contributor

@maximpn I'd like to shortly check this PR too if you don't mind waiting for a little bit.

Copy link
Contributor

@banderror banderror left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the comments from my side are relatively minor, but it would be nice to address them before merging this PR.


export interface CoverageOverviewMitreTactic {
name: string;
reference: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++

* 2.0.
*/

export interface CoverageOverviewRuleData {
Copy link
Contributor

@banderror banderror Jun 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we reuse the CoverageOverviewRuleData from the common folder? Probably not if we want to have an id in the FE's model.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One defined in common/.../response_schema.ts is a DTO and another one here in rule_data.ts is a domain model.

Generally speaking we can reuse it but it will lead to excess id added in the API response which I'd like to avoid.

Copy link
Contributor

@banderror banderror Jun 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, maybe then we could rename the FE model to disambiguate from the DTO? E.g.

DTO: CoverageOverviewRuleAttributes
Model: CoverageOverviewRule

@maximpn maximpn force-pushed the mitre-dashboard-api-contract branch from 80b2bac to 585b307 Compare June 21, 2023 15:22
Comment on lines 11 to 56
export enum CoverageOverviewRuleActivity {
Enabled = 'enabled',
Disabled = 'disabled',
Available = 'available',
}
export const CoverageOverviewRuleActivitySchema = enumeration(
'CoverageOverviewRuleActivity',
CoverageOverviewRuleActivity
);

export enum CoverageOverviewRuleSource {
Prebuilt = 'prebuilt',
Custom = 'custom',
Customized = 'customized',
}
export const CoverageOverviewRuleSourceSchema = enumeration(
'CoverageOverviewRuleSource',
CoverageOverviewRuleSource
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: commenting on each individual enum option + enums themselves could be helpful too for someone who's out of context. It could be not obvious what, for example, available means, because this word is ambiguous.

Comment on lines 33 to 65
/**
* A search term to filter the response by rule name, index pattern, MITRE ATT&CK tactic or technique
*/
search_term: NonEmptyString,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: adding one or a few @example blah-blah could be helpful.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: for consistency with the other existing subdomains having this folder, let's call it model - in a singular form. It was assumed to mean "domain model" as a whole :)

*/
reference: string;
/**
* A number of covered subtechniques (having as minimum one rule enabled)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: as minimum -> at least

Comment on lines 16 to 19
/**
* A number of covered subtechniques (having as minimum one rule enabled)
*/
numOfCoveredSubtechniques: number;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to treat "covered" as "having at least one installed rule associated with it AND enabled" or just "having at least one installed rule associated with it" regardless of the enabled/disabled state?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logically speaking having at least one installed rule associated with it AND enabled is the right answer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but we should double-check it with @approksiu

Copy link
Contributor

@banderror banderror left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Posted two minor comments:

and a bunch of nits.

Looking good @maximpn, thank you for the fixes 👍 I'm gonna approve it so you don't have to wait for another cycle of review -- please address the rest of the comments at will and merge the PR! 🚀

@maximpn maximpn force-pushed the mitre-dashboard-api-contract branch from 94a7f1c to 73374a6 Compare June 22, 2023 09:15
@kibana-ci
Copy link
Collaborator

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] Security Solution Tests #6 / Detections : Page Filters Alert list is updated when the alerts are updated
  • [job] [logs] Security Solution Tests #6 / Detections : Page Filters Impact of inputs should recover from invalide kql Query result

Metrics [docs]

Unknown metric groups

ESLint disabled line counts

id before after diff
enterpriseSearch 13 15 +2
securitySolution 416 420 +4
total +6

Total ESLint disabled count

id before after diff
enterpriseSearch 14 16 +2
securitySolution 497 501 +4
total +6

History

  • 💔 Build #137023 failed 94a7f1cc24c7f948d04bcaf4f4a4bcf5baf0de7b
  • 💛 Build #136459 was flaky b17f5bc1d837fb5d4863651a37d4f4c7447a9b48

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @maximpn

@maximpn
Copy link
Contributor Author

maximpn commented Jun 22, 2023

@banderror thank you for the through review and useful comments. I've addressed all of them so merging back the PR.

@maximpn maximpn merged commit 7186684 into elastic:main Jun 22, 2023
@maximpn maximpn deleted the mitre-dashboard-api-contract branch June 22, 2023 12:31
maximpn added a commit that referenced this pull request Jun 29, 2023
**Addresses:** #158238

## Summary

This PR adds Coverage Overview API endpoint necessary to implement Coverage Overview Dashboard.

## Details

The Coverage Overview API implementation is represented by one HTTP POST internal route `/internal/detection_engine/rules/_coverage_overview` hidden by a feature flag `detectionsCoverageOverview`. It returns response in the format defined in #159993.

Implementation is done in a quite simple way. It basically just fetches all the rules in chunks and adds them to appropriate MITRE ATT&CK category buckets depending on the assigned categories. The chunk size has been chosen to be `10000` as it's the default limit.

At the current stage the API doesn't handle available rules which means it doesn't return available rules in the response.

Sample response containing two rules looks like

```json
{
  "coverage": {
    "TA001": ["e2c9ee90-12d6-11ee-a0ab-c95a1fc4921d"],
    "T001": ["e2c9ee90-12d6-11ee-a0ab-c95a1fc4921d"],
    "T001.001": ["e2c9ee90-12d6-11ee-a0ab-c95a1fc4921d"],
    "TA002": ["e2f459f0-12d6-11ee-a0ab-c95a1fc4921d"],
    "T002": ["e2f459f0-12d6-11ee-a0ab-c95a1fc4921d"],
    "T002.002": ["e2f459f0-12d6-11ee-a0ab-c95a1fc4921d"],
  },
  "unmapped_rule_ids": [],
  "rules_data": {
    "e2c9ee90-12d6-11ee-a0ab-c95a1fc4921d": { "name": "Some rule", "activity": "disabled" },
    "e2f459f0-12d6-11ee-a0ab-c95a1fc4921d": { "name": "Another rule", "activity": "enabled" },
  },
}
```

### How to access the endpoint?

Make sure a feature `detectionsCoverageOverview` flag is set in `config/kibana.dev.yml` like

```yaml
xpack.securitySolution.enableExperimental:
  - detectionsCoverageOverview
```

Then access the API via an HTTP client for example `curl`

- an empty filter  
```sh
curl -X POST --user elastic:changeme -H 'Content-Type: application/json' -H 'kbn-xsrf: 123' -d '{}' http://localhost:5601/kbn/internal/detection_engine/rules/_coverage_overview
```

- filter by rule name
```sh
curl -X POST --user elastic:changeme -H 'Content-Type: application/json' -H 'kbn-xsrf: 123' -d '{"filter":{"search_term": "rule name"}}' http://localhost:5601/kbn/internal/detection_engine/rules/_coverage_overview
```

- filter by enabled rules
```sh
curl -X POST --user elastic:changeme -H 'Content-Type: application/json' -H 'kbn-xsrf: 123' -d '{"filter":{"activity": ["enabled"]}}' http://localhost:5601/kbn/internal/detection_engine/rules/_coverage_overview
```

- filter by prebuilt rules
```sh
curl -X POST --user elastic:changeme -H 'Content-Type: application/json' -H 'kbn-xsrf: 123' -d '{"filter":{"source": ["prebuilt"]}}' http://localhost:5601/kbn/internal/detection_engine/rules/_coverage_overview
```

## Known problems

- <del>Filtering by a tactic name doesn't guarantee the other tactics, techniques and sub-techniques will be filtered out. As one rule may be assigned to more than one tactic, technique and sub-technique filtering such rules by one tactic will lead to only rules assigned to the desired tactic be processed. But the result will include all the tactics, techniques and sub-techniques assigned to that rules.</del>

UPD: leave as is for now

- <del>Some of the implementation details are similar to `find_rules` endpoint. The difference is that `find_rules` accepts `query` parameter which is a KQL query while `coverage_overview` accepts filter fields and builds up a KQL query under the hood. Passing a prepared KQL query to `coverage_overview` looks too permissive and can lead to undesired filtering results. Some of KQL query building code is common and can be reused between FE and BE.</del>

UPD: Solved

- <del>One may ask why using an HTTP POST request instead of HTTP GET. In fact HTTP POST is needed only for convenience to send a JSON request query in the request body similar to GraphQL approach but it looks rather an overkill. One of the main reasons why HTTP POST is used is the limitation of `io-ts` schemas used to request query validation. It's handled by `buildRouteValidation()` which doesn't parse input parameters.  For example there is a request with a query string `/internal/detection_engine/rules/_coverage_overview?filter={"search_term": "rule 1"}`, it's handled and the following object gets passed to `buildRouteValidation()`</del>

```ts
{
  "filter": '{"search_term": "rule 1"}'
}
```

<del>as you may notice `'{"search_term": "rule 1"}'` is a string so the `io-ts` schema validation fails while the request looks correct. In contrast a similar `@kbn/config-schema` schema used instead for the request query validation handles it correctly. As the reference it works [here](https://github.com/elastic/kibana/blob/main/x-pack/plugins/alerting/server/routes/find_rules.ts#L100C16-L100C27) for `internal/alerting/rules/_find` endpoint, `fields` query parameter can be a JSON array and validation handles it correctly.</del>

UPD: discussed with the team and decided that HTTP POST is more convenient for complex filters.

- During FTR tests implementation I've noticed the server fails if the second page (10000 - 20000 rules) is requested with an error
```
illegal_argument_exception: Result window is too large, from + size must be less than or equal to: [10000] but was [20000]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting.
```

There is a chance it can fail with the same error in prod.

UPD: The problem in reproducible in prod. To avoid a server crash the endpoint doesn't handle more than 10k rules. The problem will be addressed in #160698.

## Posible improvements

- [x] Move KQL utility functions into common folder to be shared between FE and BE (done)
- Implement stricter filtering to return only searched tactic, technique and sub-technique (leave as is for now)
- Use HTTP GET instead of HTTP POST (discussed with the team and decided that HTTP POST is more convenient for complex filters)
- Make sure pages above 10000 rules are handled properly (will be addresses in #160698)

### Checklist

- [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials
- [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenario
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting Feature:Rule Management Security Solution Detection Rule Management area release_note:skip Skip the PR/issue when compiling release notes Team:Detection Rule Management Security Detection Rule Management Team Team:Detections and Resp Security Detection Response Team Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. v8.9.0 v8.10.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants