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] [Cases] Introduce case observables (phase 0 & 1) #190237

Open
wants to merge 90 commits into
base: main
Choose a base branch
from

Conversation

lgestc
Copy link
Contributor

@lgestc lgestc commented Aug 9, 2024

Summary

Introducting Case Observables - phases 0 and 1

This pull request introduces case observables to Kibana, enhancing the platform's case management capabilities. It adds support for capturing and displaying observables (e.g., IP addresses, URLs, file hashes) linked to cases. The feature integrates with the Cases UI, allowing users to easily associate observables with cases for better tracking and analysis in incident response workflows. This improves investigative efficiency by correlating observables across multiple cases.

Requirements:

https://docs.google.com/document/d/12hZTpyn0eXy3Xnq8qLBd6_sJxBhNZoI7vXztxWHhUds/edit#heading=h.srf6mb8ifiad

Design document: https://docs.google.com/document/d/1MeDLl6OEWast1RC1M3_hQXnRCd8frrXdGkFnypIYKJQ/edit#heading=h.kb5lrp2j62id

Notable Cases sections are added in this pr:

1. Observables section in the case view, allowing for adding and listing up to 10 observables for the case

image

2. Similar cases view for every case, allowing for similar case discovery

image

3. Observable types management view in Cases settings

image

Original issue:

#180360

Things skipped for now from MVP:

  • Allow users to manually create observables from the cases alerts table using the table actions (Phase 1)
  • Allow users to manually create observables of type “hash” from the files table using the table actions (Phase 1)

@lgestc lgestc changed the title --wip-- [skip ci] WIP case observables Aug 12, 2024
@lgestc lgestc force-pushed the cases_observables branch 2 times, most recently from b7c8f0e to b70f7cc Compare August 20, 2024 08:37
@lgestc lgestc force-pushed the cases_observables branch 2 times, most recently from 3ea6323 to 1dfdc9b Compare September 16, 2024 10:13
@lgestc lgestc force-pushed the cases_observables branch 2 times, most recently from ad86b09 to fa8ed50 Compare October 1, 2024 10:10
@lgestc lgestc changed the title WIP case observables [Security Solution] [Cases] Introduce case observables (phase 0 & 1) Oct 2, 2024
@lgestc lgestc added Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. 8.16 candidate release_note:feature Makes this part of the condensed release notes labels Oct 2, 2024
@lgestc lgestc marked this pull request as ready for review October 2, 2024 15:07
@lgestc lgestc requested a review from a team as a code owner October 2, 2024 15:07
@lgestc lgestc added backport:skip This commit does not require backporting Team:Threat Hunting:Investigations Security Solution Investigations Team labels Oct 2, 2024
Copy link
Contributor

@jloleysens jloleysens left a comment

Choose a reason for hiding this comment

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

Left a non-blocker question about mapped fields.

@lgestc lgestc requested review from a team as code owners October 3, 2024 12:40
@elastic elastic deleted a comment from kibana-ci Oct 3, 2024
@cnasikas cnasikas removed backport:skip This commit does not require backporting 8.16 candidate labels Oct 3, 2024
@lgestc
Copy link
Contributor Author

lgestc commented Nov 12, 2024

Hey @lgestc ,

Did some desk testing and it overall looks good. Below are some of my observations:

When you click on a case ( say Target Case ) under Similar Cases, the name of the case does not change, it is not clear whether user is under the context of original case or they have navigated to the Target Case.
What is IOC? There are no details/info on the toggle. Is it a known term in security domain?
Product Requirement say that Reason for similarity should also be visible but I cannot see it in the Similar Cases table.
Also, ++ on validations issue raised by @js-jankisalvi

ioc and the other field is remove now, will improve the validation + the weird state issue is in progress

@PhilippeOberti
Copy link
Contributor

PhilippeOberti commented Nov 12, 2024

I started testing and here are some first notes I quickly noticed:

After adding an observable to a case, I do not see an entry in the All tab, something that would say elastic added an observable 1 second ago. We do this for alerts, for files... is there a reason we're not doing this for observables?

Screen.Recording.2024-11-12.at.4.45.19.PM.mov

In the Requirements section of this document it is written that observables should be searchable, but the UI does not contain a search bar. I see a search bar on the Files tab.

Screenshot 2024-11-12 at 4 50 29 PM


I feel like we should improve slightly the values rendered in the Similar cases table. On a normal screen size, it's very easy to get into a place where things are barely readable

Screenshot 2024-11-12 at 5 00 52 PM


When adding an observable to a case, right now (unless I'm mistaken) we only allow users to create new observables. It could be nice to have a list of already created observables to pick from... But we might not be able to do that due to how observables are being saved. If they are only saved within a case, then we would have to fetch observables for all cases which could be inefficient...
Isn't that what we do though to populate the Similar cases tab? Aren't we just fetching all cases and finding observables with similar value?

@lgestc
Copy link
Contributor Author

lgestc commented Nov 13, 2024

I started testing and here are some first notes I quickly noticed:

After adding an observable to a case, I do not see an entry in the All tab, something that would say elastic added an observable 1 second ago. We do this for alerts, for files... is there a reason we're not doing this for observables?

Screen.Recording.2024-11-12.at.4.45.19.PM.mov
In the Requirements section of this document it is written that observables should be searchable, but the UI does not contain a search bar. I see a search bar on the Files tab.

Screenshot 2024-11-12 at 4 50 29 PM

I feel like we should improve slightly the values rendered in the Similar cases table. On a normal screen size, it's very easy to get into a place where things are barely readable

Screenshot 2024-11-12 at 5 00 52 PM

When adding an observable to a case, right now (unless I'm mistaken) we only allow users to create new observables. It could be nice to have a list of already created observables to pick from... But we might not be able to do that due to how observables are being saved. If they are only saved within a case, then we would have to fetch observables for all cases which could be inefficient... Isn't that what we do though to populate the Similar cases tab? Aren't we just fetching all cases and finding observables with similar value?

Yeah searchability has been skipped for now, as for the list - I am open to remove columns for instance, as what should be displayed in there has not really been described.

@elastic elastic deleted a comment from elasticmachine Nov 13, 2024
@lgestc
Copy link
Contributor Author

lgestc commented Nov 13, 2024

added some simple client side validation

Copy link
Contributor

@adcoelho adcoelho left a comment

Choose a reason for hiding this comment

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

I started reviewing the frontend code from a cases perspective.

I tested the UI a bit too and have a couple of comments:

  • We should introduce some validation when creating observables in a case. Having a URL be 1234 does not make sense.
  • I think it would make sense to limit the columns seen in the Similar page. Name, observables, tags. Something like this but not the same as the cases list page.
  • We should limit the number of observable types that the user can create.
  • In the settings page if I edit an existing observable and close the flyout. If I click Add new observable the old observable will still be in the flyout. (See video below)
Screen.Recording.2024-11-13.at.14.46.07.mov

@@ -60,6 +71,16 @@ export const convertCaseToCamelCase = (theCase: Case): CaseUI => {

export const convertCasesToCamelCase = (cases: Cases): CasesUI => cases.map(convertCaseToCamelCase);

export const convertSimilarCaseToCamelCase = (theCase: SimilarCase): SimilarCaseUI => {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: doesn't need to be exported if it's only used in this file

x-pack/plugins/cases/public/api/utils.ts Show resolved Hide resolved
x-pack/plugins/cases/public/api/utils.ts Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add a section on x-pack/plugins/cases/public/components/configure_cases/index.test.tsx to test these changes? There's one for connectors, custom fields, templates, etc.

@@ -61,6 +68,35 @@ const FilesBadge = ({

FilesBadge.displayName = 'FilesBadge';

const ObservablesBadge = ({
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you update x-pack/plugins/cases/public/components/case_view/case_view_tabs.test.tsx to reflect the changes in this file?

@@ -526,6 +613,26 @@ export const ConfigureCases: React.FC = React.memo(() => {
</CommonFlyout>
) : null;

const AddOrEditObservableTypeFlyout =
Copy link
Contributor

Choose a reason for hiding this comment

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

We should include some limit to the number of Observables Types that can be created. Right now there seems to be no limit.

const [error, setError] = useState<boolean>(false);

const onAddCustomField = useCallback(() => {
if (observableTypes.length === MAX_CUSTOM_FIELDS_PER_CASE && !error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

MAX_CUSTOM_FIELDS_PER_CASE seems to be wrong here.

@lgestc
Copy link
Contributor Author

lgestc commented Nov 14, 2024

  • In the settings page if I edit an existing observable and close the flyout. If I click Add new observable the old observable will still be in the flyout. (See video below)

this should be fixed now:)

Copy link
Member

@cnasikas cnasikas left a comment

Choose a reason for hiding this comment

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

I did another pass only on the common and backend code. I left some comments. Also:

  • As we discussed we should validate observable values in the UI.
  • We should validate observable types (key and label) both in the UI and the API (they are public).
  • We should validate the number of max observables per case in the UI.
  • Missing unit tests:
    • x-pack/plugins/cases/public/api/utils.ts
    • x-pack/plugins/cases/server/client/cases/observables.ts
    • x-pack/plugins/cases/server/routes/api/cases/similar.ts
    • x-pack/plugins/cases/server/routes/api/observables/delete_observable.ts
    • x-pack/plugins/cases/server/routes/api/observables/patch_observable.ts
    • x-pack/plugins/cases/server/routes/api/observables/post_observable.ts

@@ -83,7 +83,12 @@ export const INTERNAL_DELETE_FILE_ATTACHMENTS_URL =
export const INTERNAL_GET_CASE_CATEGORIES_URL = `${CASES_INTERNAL_URL}/categories` as const;
export const INTERNAL_CASE_METRICS_URL = `${CASES_INTERNAL_URL}/metrics` as const;
export const INTERNAL_CASE_METRICS_DETAILS_URL = `${CASES_INTERNAL_URL}/metrics/{case_id}` as const;
export const INTERNAL_CASE_SIMILAR_CASES_URL = `${CASES_INTERNAL_URL}/_similar/{case_id}` as const;
Copy link
Member

Choose a reason for hiding this comment

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

I think it is better to follow the REST principles and conventions we have in the codebase for the URL.

Suggested change
export const INTERNAL_CASE_SIMILAR_CASES_URL = `${CASES_INTERNAL_URL}/_similar/{case_id}` as const;
export const INTERNAL_CASE_SIMILAR_CASES_URL = `${CASES_INTERNAL_URL}/{case_id}/_similar` as const;

/**
* Exporting an array of built-in observable types for use in the application
*/
export const OBSERVABLE_TYPES_BUILTIN = [
Copy link
Member

Choose a reason for hiding this comment

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

I thought about it more and it is ok to have the same keys across solutions and the same options to all solutions.

*/

import * as rt from 'io-ts';
import { CaseObservableRt, ObservablePatch } from '../../domain';
Copy link
Member

Choose a reason for hiding this comment

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

It seems that the ObservablePatch is only related to APIs. Better to move the type in this file or just import CaseObservableBaseRt and use it as the payload of the requests. You can import from the domain as you like but you have to import from v1 like ../../domain/observables/v1.

observable: ObservablePatch,
});

export const BulkGetObservablesResponseRt = rt.strict({
Copy link
Member

Choose a reason for hiding this comment

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

This type is not used anywhere.

export type AddObservableRequest = rt.TypeOf<typeof AddObservableRequestRt>;
export type UpdateObservableRequest = rt.TypeOf<typeof UpdateObservableRequestRt>;

export type ObservableRequest = AddObservableRequest;
Copy link
Member

Choose a reason for hiding this comment

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

This type is not used anywhere.


const newObservableData = {
value: 'test',
typeKey: '0ad4bf8e-575f-49ad-87ea-8bcafd5173e4',
Copy link
Member

Choose a reason for hiding this comment

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

The typeKey is not part of the configuration. Shouldn't the addObservable throw an error? Let's have the following tests:

  • Valid configuration exists and you can add an observable of a custom observable type
  • Valid configuration does not exist and you cannot add an observable
  • You can add a build in observable type

});
});

describe('shows similar cases', () => {
Copy link
Member

Choose a reason for hiding this comment

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

Tests for similar cases should be on each own file as it is not an API related to observables (in the sense of REST resource)

const { cases: casesAfterObservablesAreAdded } = await similarCases({
supertest,
body: { perPage: 10, page: 1 },
caseId: caseA.id,
Copy link
Member

Choose a reason for hiding this comment

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

Let's do another call for caseB.

});
});

describe('shows similar cases', () => {
Copy link
Member

Choose a reason for hiding this comment

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

Could you please add a test where cases from different solutions (different owner) are not returned even if they have the same observables?

]);

const newObservableData = {
value: '{"foo": "bar"}',
Copy link
Member

Choose a reason for hiding this comment

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

I do not think we should support this kind of values in the MVP. Also OBSERVABLE_TYPES_BUILTIN[0].key is an IPv4.

@elasticmachine
Copy link
Contributor

elasticmachine commented Nov 14, 2024

⏳ Build in-progress

History

cc @adcoelho @cnasikas

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:prev-minor Backport to (8.x) the previous minor version (i.e. one version back from main) ci:build-serverless-image ci:cloud-deploy Create or update a Cloud deployment release_note:feature Makes this part of the condensed release notes Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. Team:Threat Hunting:Investigations Security Solution Investigations Team v8.17.0 v9.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.