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

Threat intel monitor implementation #1092

Merged
merged 15 commits into from
Jun 27, 2024

Conversation

eirsep
Copy link
Member

@eirsep eirsep commented Jun 21, 2024

Description

Threat intel monitor is a job that runs periodically to scan the configured customer data for malicious indicators. It's corpus of malicious indicators is a list of system indices containing threat intel data curated from the configured threat intelligence source configs.

We refer threat intel source configs that are in AVAILABLE or REFRESHING state.
we fetch the ioc system indices mentioned in these TIF source configs for corpus of indicators.
Threat intel monitor does the following steps when it runs:

  • fetch configs
  • get ioc indices for each ioc type
  • fetch documents since last seen seq_no for the assigned data sources
  • extract iocs from docs from configured fields for each ioc type
  • search for extracted ioc list with terms query in batches of MAX_TERMS_SETTING against the ioc indices
  • create Findings fi there are malicious iocs in data matched against threat intel sysytem indices

TODO: pending alert triggers and notifications

Issues Resolved

[List any issues this PR will resolve]

Check List

  • New functionality includes testing.
    • All tests pass
  • New functionality has been documented.
    • New functionality has javadoc added
  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

engechas and others added 5 commits June 10, 2024 14:58
Signed-off-by: Chase Engelbrecht <engechas@amazon.com>
* notification for alerting in correlation

* correlation alerts mapping change

* working code

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* alertsInCorrelation without notifciations

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* alertsInCorrelation without notifciations

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* alertsInCorrelation without notifciations

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* alerts in correlations notification service added

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* addressing the comments

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* addressing the comments

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* address the design changes discussed

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* address the design changes discussed

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* fixed tests

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

---------

Signed-off-by: Riya <69919272+riysaxen-amzn@users.noreply.github.com>
Signed-off-by: Riya Saxena <riysaxen@amazon.com>
* notification for alerting in correlation

* correlation alerts mapping change

* working code

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* alertsInCorrelation without notifciations

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* alertsInCorrelation without notifciations

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* alertsInCorrelation without notifciations

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* alerts in correlations notification service added

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* addressing the comments

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* addressing the comments

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* getCorrelationAlerts API changes

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* APIs added for Alerts in Correlations

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* update alerts with an errorMessage  when correlationRule is deleted

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* address the design changes discussed

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* address the design changes discussed

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* fixed tests

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* minor fixes due to merge

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* alerts API changes

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* klint fixes

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* license headers added

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

* fixed format violations

Signed-off-by: Riya Saxena <riysaxen@amazon.com>

---------

Signed-off-by: Riya <69919272+riysaxen-amzn@users.noreply.github.com>
Signed-off-by: Riya Saxena <riysaxen@amazon.com>
Signed-off-by: Riya Saxena <riysaxen@amazon.com>
Signed-off-by: Subhobrata Dey <sbcd90@gmail.com>

final String url = Objects.requireNonNull(BuiltinLogTypeLoader.class.getClassLoader().getResource(BASE_PATH)).toURI().toString();
logger.error("SASHANK Path url is {}", pathurl);
Copy link
Collaborator

Choose a reason for hiding this comment

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

@eirsep I believe you mentioned offline that there was some old code in this file?

Copy link
Member Author

Choose a reason for hiding this comment

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

removed thanks

public class GetIocFindingsAction extends ActionType<GetIocFindingsResponse> {

public static final GetIocFindingsAction INSTANCE = new GetIocFindingsAction();
public static final String NAME = "cluster:admin/opensearch/securityanalytics/ioc/findings/get";
Copy link
Collaborator

Choose a reason for hiding this comment

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

In the ListIOCs API, I have /ioc/ pluralized to /iocs/. Any preference for which to use?

Copy link
Member Author

Choose a reason for hiding this comment

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

for rest api naming plural

Comment on lines 135 to 136
* Index name: .opensearch-sap-iocmatch
* Mapping: /mappings/ioc_match_mapping.json
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

updated

Monitor monitor = iocScanContext.getMonitor();

long startTime = System.currentTimeMillis();
// log.debug("beginning to scan IoC's")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Dev code?

Copy link
Member Author

Choose a reason for hiding this comment

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

removed

Map<String, List<String>> iocTypeToIndices);

/**
* For each doc, we extract the list of
Copy link
Collaborator

Choose a reason for hiding this comment

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

Comment unfinished?

Copy link
Member Author

Choose a reason for hiding this comment

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

done

public class SaIoCScanService extends IoCScanService<SearchHit> {

private static final Logger log = LogManager.getLogger(SaIoCScanService.class);
public static final int MAX_TERMS = 65536; //make ioc index setting based. use same setting value to create index
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: Not marked as a TODO. Just mentioning this so it's easier to spot.

Copy link
Member Author

Choose a reason for hiding this comment

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

ack

@@ -268,6 +268,9 @@ public static SATIFSourceConfig parse(XContentParser xcp, String id, Long versio
case NAME_FIELD:
name = xcp.text();
break;
case VERSION_FIELD:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we be parsing this from the SearchHit/some other source? It looks like we don't do that for detectors, and we instead take in the version as a parameter in the parse function.
https://github.com/opensearch-project/security-analytics/blob/feature/threat_intel/src/main/java/org/opensearch/securityanalytics/model/Detector.java#L315

Copy link
Member Author

Choose a reason for hiding this comment

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

i am blocked on the actual fix so i made an adhoc.. will rebased from feature branch


@Override
public String getName() {
return "get_ioc_findings_action_sa";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

i am blocked on the PR so i integrated.. will rebased that PR's commits.


private void indexIocs(List<String> iocVals, String iocIndexName, int i1, String configId) throws IOException {
String iocId = iocIndexName + i1;
STIX2IOC stix2IOC = new STIX2IOC(
Copy link
Collaborator

Choose a reason for hiding this comment

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

listener.onResponse(null);
return;
}
log.error("Failed to create security analytics threat intel job index", e);
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: log line specified job index

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

}

public void createIndexIfNotExists(final ActionListener<Void> listener) {
// check if job index exists
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: job index comment

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

import java.util.List;
import java.util.Map;

public class IocScanContext<Data> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does IocScanContext need serialization/deserialization?

Copy link
Member Author

Choose a reason for hiding this comment

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

no
just dto between classes - single node operation too

}
}

abstract void saveIocs(List<IocFinding> iocs, BiConsumer<List<IocFinding>, Exception> callback, Monitor monitor);
Copy link
Collaborator

Choose a reason for hiding this comment

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

saveIocFindings might be a better name to differentiate saving the actual iocs

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

eirsep and others added 5 commits June 25, 2024 00:37
Signed-off-by: Subhobrata Dey <sbcd90@gmail.com>
…generic entity to re-use for threat intel alert

Signed-off-by: Surya Sashank Nistala <snistala@amazon.com>
Signed-off-by: Surya Sashank Nistala <snistala@amazon.com>
public class GetCorrelationAlertsAction extends ActionType<GetCorrelationAlertsResponse> {

public static final GetCorrelationAlertsAction INSTANCE = new GetCorrelationAlertsAction();
public static final String NAME = "cluster:admin/opensearch/securityanalytics/correlationAlerts/get";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: Should correlationAlerts be all lowercase like securityanalytics?

Copy link
Member Author

Choose a reason for hiding this comment

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

not from my PR
merged main branch

// Convert CorrelationAlert to a map
try {
XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
builder.field("correlated_finding_ids", correlationAlert.getCorrelatedFindingIds());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: I think you have constants for the field names that could be used instead to help maintain consistency.

Copy link
Member Author

Choose a reason for hiding this comment

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

not from my PR
merged main branch

// Iterate through the search hits
for (SearchHit hit : searchResponse.getHits().getHits()) {
// Construct a script to update the document with the new state and acknowledgedTime
// Construct a script to update the document with the new state and acknowledgedTime
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: Duplicated comment.

Copy link
Member Author

Choose a reason for hiding this comment

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

not from my PR
merged main branch

// Construct a script to update the document with the new state and error_message
Script script = new Script(ScriptType.INLINE, "painless",
"ctx._source.state = params.state; ctx._source.error_message = params.error_message",
Map.of("state", Alert.State.ERROR, "error_message", "The rule associated to this Alert is deleted"));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just to clarify, is this the only error case we expect, or is there a more dynamic way to construct the error_message?

Copy link
Member Author

Choose a reason for hiding this comment

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

not from my PR
merged main branch

if (getNotificationConfigResponse.getStatus() == RestStatus.OK) {
getNotificationConfigResponse = configResp;
} else {
logger.error("Successfully sent a notification, Notification Event: " + getNotificationConfigResponse);
Copy link
Collaborator

Choose a reason for hiding this comment

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

To clarify, is the error message here correct? Looks like this is a fail case.

Copy link
Member Author

Choose a reason for hiding this comment

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

not from my PR
merged main branch

import java.util.Objects;
import java.util.stream.Collectors;

public class CorrelationRuleTrigger implements Writeable, ToXContentObject {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

not from my PR
merged main branch

ActionListener<SearchHits> listener) {

if (prevSeqNo != null && prevSeqNo.equals(maxSeqNo) && maxSeqNo != 0L) {
log.debug("Seqquence number unchanged.");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: Typo in "Sequence".

}
), indices.toArray(new String[0])
);
// log.debug("Delete old IOC indices by age");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: Are these still needed now that PR #1094 is merged?

Copy link
Member Author

Choose a reason for hiding this comment

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

reverted

@@ -330,72 +334,6 @@ public void deleteTIFSourceConfig(
));
}

public void deleteAllOldIocIndices(List<String> indicesToDelete) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this deleted?

Copy link
Member Author

Choose a reason for hiding this comment

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

reverted

) {

this.id = id != null ? id : NO_ID;
this.version = version != 0 ? version : NO_VERSION;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it possible for version to be null?

Copy link
Member Author

Choose a reason for hiding this comment

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

its primitive long

@@ -108,4 +108,34 @@ public static IocWithFeeds parse(XContentParser xcp) throws IOException {
public static IocWithFeeds readFrom(StreamInput sin) throws IOException {
return new IocWithFeeds(sin);
}

@Override
public int hashCode() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

how is this hashcode calculated? Can we use Objects.hash?

Copy link
Member Author

Choose a reason for hiding this comment

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

changed

}
}

public void bulkIndexEntities(List<Entity> entityList,
Copy link
Collaborator

Choose a reason for hiding this comment

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

why does bulkIndexEntities need to be overloaded?

Copy link
Member Author

Choose a reason for hiding this comment

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

one is for only new entities and
one for create new and update old entities

Signed-off-by: Surya Sashank Nistala <snistala@amazon.com>
));
}

private void getAlerts(List<String> monitorIds,
Copy link
Collaborator

Choose a reason for hiding this comment

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

not blocking but should logic be moved to a service class outside of transport?

Signed-off-by: Surya Sashank Nistala <snistala@amazon.com>
@eirsep eirsep merged commit ef54c62 into opensearch-project:feature/threat_intel Jun 27, 2024
1 of 2 checks passed
AWSHurneyt pushed a commit to AWSHurneyt/security-analytics that referenced this pull request Jun 28, 2024
* ioc scan business logic

* add search ioc findings api

Signed-off-by: Subhobrata Dey <sbcd90@gmail.com>

* refactor iocFinding model and service to pull out CRUD operations to generic entity to re-use for threat intel alert

Signed-off-by: Surya Sashank Nistala <snistala@amazon.com>

* threat intel alert model and crud operations

Signed-off-by: Surya Sashank Nistala <snistala@amazon.com>

* threat intel trigger execution logic

* wire in ioc findings

* get threat intel monitor alerts API

Signed-off-by: Surya Sashank Nistala <snistala@amazon.com>

* revert commented out code

Signed-off-by: Surya Sashank Nistala <snistala@amazon.com>

---------

Signed-off-by: Chase Engelbrecht <engechas@amazon.com>
Signed-off-by: Riya <69919272+riysaxen-amzn@users.noreply.github.com>
Signed-off-by: Riya Saxena <riysaxen@amazon.com>
Signed-off-by: Subhobrata Dey <sbcd90@gmail.com>
Signed-off-by: Surya Sashank Nistala <snistala@amazon.com>
Co-authored-by: Chase <62891993+engechas@users.noreply.github.com>
Co-authored-by: Riya <69919272+riysaxen-amzn@users.noreply.github.com>
Co-authored-by: Subhobrata Dey <sbcd90@gmail.com>
Signed-off-by: AWSHurneyt <hurneyt@amazon.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants