Skip to content

Commit

Permalink
Allow deletion of custom log type if custom rule index is missing (#767)
Browse files Browse the repository at this point in the history
* Allow deletion of custom log type if custom rule index is missing

Signed-off-by: Megha Goyal <goyamegh@amazon.com>

* Allow custom log type name to be updated when custom rule index is missing

Signed-off-by: Megha Goyal <goyamegh@amazon.com>

* Adding changes for detector index missing

Signed-off-by: Megha Goyal <goyamegh@amazon.com>

* Update log type when detector index is missing

Signed-off-by: Megha Goyal <goyamegh@amazon.com>

---------

Signed-off-by: Megha Goyal <goyamegh@amazon.com>
  • Loading branch information
goyamegh committed Dec 8, 2023
1 parent 7066923 commit c373343
Show file tree
Hide file tree
Showing 5 changed files with 384 additions and 204 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

package org.opensearch.securityanalytics.transport;

import org.apache.commons.logging.Log;
import org.apache.lucene.search.join.ScoreMode;
import org.opensearch.OpenSearchStatusException;
import org.opensearch.action.ActionRunnable;
Expand All @@ -27,6 +28,7 @@
import org.opensearch.commons.authuser.User;
import org.opensearch.core.action.ActionListener;
import org.opensearch.core.rest.RestStatus;
import org.opensearch.index.IndexNotFoundException;
import org.opensearch.index.query.QueryBuilder;
import org.opensearch.index.query.QueryBuilders;
import org.opensearch.search.builder.SearchSourceBuilder;
Expand All @@ -36,16 +38,16 @@
import org.opensearch.securityanalytics.logtype.LogTypeService;
import org.opensearch.securityanalytics.model.CustomLogType;
import org.opensearch.securityanalytics.model.Detector;
import org.opensearch.securityanalytics.model.Rule;
import org.opensearch.securityanalytics.model.LogType;
import org.opensearch.securityanalytics.settings.SecurityAnalyticsSettings;
import org.opensearch.securityanalytics.util.CustomLogTypeIndices;
import org.opensearch.securityanalytics.util.DetectorIndices;
import org.opensearch.securityanalytics.util.RuleIndices;
import org.opensearch.securityanalytics.util.SecurityAnalyticsException;
import org.opensearch.tasks.Task;
import org.opensearch.threadpool.ThreadPool;
import org.opensearch.transport.TransportService;

import java.io.IOException;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
Expand All @@ -65,6 +67,8 @@ public class TransportDeleteCustomLogTypeAction extends HandledTransportAction<D

private final DetectorIndices detectorIndices;

private final RuleIndices ruleIndices;

private final CustomLogTypeIndices customLogTypeIndices;

private volatile Boolean filterByEnabled;
Expand All @@ -77,6 +81,7 @@ public TransportDeleteCustomLogTypeAction(TransportService transportService,
ActionFilters actionFilters,
ClusterService clusterService,
DetectorIndices detectorIndices,
RuleIndices ruleIndices,
CustomLogTypeIndices customLogTypeIndices,
Settings settings,
ThreadPool threadPool) {
Expand All @@ -86,6 +91,7 @@ public TransportDeleteCustomLogTypeAction(TransportService transportService,
this.threadPool = threadPool;
this.settings = settings;
this.detectorIndices = detectorIndices;
this.ruleIndices = ruleIndices;
this.customLogTypeIndices = customLogTypeIndices;
this.filterByEnabled = SecurityAnalyticsSettings.FILTER_BY_BACKEND_ROLES.get(this.settings);
this.indexTimeout = SecurityAnalyticsSettings.INDEX_TIMEOUT.get(this.settings);
Expand Down Expand Up @@ -166,15 +172,17 @@ public void onFailure(Exception e) {

private void onGetResponse(CustomLogType logType) {
if (logType.getSource().equals("Sigma")) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Log Type with id %s cannot be deleted because source is sigma", logType.getId()), RestStatus.BAD_REQUEST));
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(),
"Log Type with id %s cannot be deleted because source is sigma", logType.getId()), RestStatus.BAD_REQUEST));
}

if (detectorIndices.detectorIndexExists()) {
searchDetectors(logType.getName(), new ActionListener<>() {
@Override
public void onResponse(SearchResponse response) {
if (response.isTimedOut()) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Search request timed out. Log Type with id %s cannot be deleted", logType.getId()), RestStatus.REQUEST_TIMEOUT));
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(),
"Search request timed out. Log Type with id %s cannot be deleted", logType.getId()), RestStatus.REQUEST_TIMEOUT));
return;
}

Expand All @@ -183,44 +191,7 @@ public void onResponse(SearchResponse response) {
return;
}

searchRules(logType.getName(), new ActionListener<>() {
@Override
public void onResponse(SearchResponse response) {
if (response.isTimedOut()) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Search request timed out. Log Type with id %s cannot be deleted", logType.getId()), RestStatus.REQUEST_TIMEOUT));
return;
}

if (response.getHits().getTotalHits().value > 0) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Log Type with id %s cannot be deleted because active rules exist", logType.getId()), RestStatus.BAD_REQUEST));
return;
}

DeleteRequest deleteRequest = new DeleteRequest(LogTypeService.LOG_TYPE_INDEX, logType.getId())
.setRefreshPolicy(request.getRefreshPolicy())
.timeout(indexTimeout);

client.delete(deleteRequest, new ActionListener<>() {
@Override
public void onResponse(DeleteResponse response) {
if (response.status() != RestStatus.OK) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Log Type with id %s cannot be deleted", logType.getId()), RestStatus.INTERNAL_SERVER_ERROR));
}
onOperation(response);
}

@Override
public void onFailure(Exception e) {
onFailures(e);
}
});
}

@Override
public void onFailure(Exception e) {
onFailures(e);
}
});
checkRuleIndexAndDeleteLogType(logType);
}

@Override
Expand All @@ -229,25 +200,62 @@ public void onFailure(Exception e) {
}
});
} else {
DeleteRequest deleteRequest = new DeleteRequest(LogTypeService.LOG_TYPE_INDEX, logType.getId())
.setRefreshPolicy(request.getRefreshPolicy())
.timeout(indexTimeout);
checkRuleIndexAndDeleteLogType(logType);
}
}

client.delete(deleteRequest, new ActionListener<>() {
void checkRuleIndexAndDeleteLogType(CustomLogType logType) {
if(ruleIndices.ruleIndexExists(false)) {
ruleIndices.searchRules(logType.getName(), new ActionListener<>() {
@Override
public void onResponse(DeleteResponse response) {
if (response.status() != RestStatus.OK) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Log Type with id %s cannot be deleted", logType.getId()), RestStatus.INTERNAL_SERVER_ERROR));
public void onResponse(SearchResponse response) {
if (response.isTimedOut()) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Search request timed out. Log Type with id %s cannot be deleted", logType.getId()), RestStatus.REQUEST_TIMEOUT));
return;
}

if (response.getHits().getTotalHits().value > 0) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Log Type with id %s cannot be deleted because active rules exist", logType.getId()), RestStatus.BAD_REQUEST));
return;
}
onOperation(response);
deleteLogType(logType);
}

@Override
public void onFailure(Exception e) {
onFailures(e);
if (e instanceof IndexNotFoundException) {
// let log type deletion to go through if the rule index is missing
deleteLogType(logType);
} else {
onFailures(e);
}
}
});
} else {
log.warn("Custom rule index missing, allowing deletion of custom log type {} to go through", logType.getId());
deleteLogType(logType);
}
}

private void deleteLogType(CustomLogType logType) {
DeleteRequest deleteRequest = new DeleteRequest(LogTypeService.LOG_TYPE_INDEX, logType.getId())
.setRefreshPolicy(request.getRefreshPolicy())
.timeout(indexTimeout);

client.delete(deleteRequest, new ActionListener<>() {
@Override
public void onResponse(DeleteResponse response) {
if (response.status() != RestStatus.OK) {
onFailures(new OpenSearchStatusException(String.format(Locale.getDefault(), "Log Type with id %s cannot be deleted", logType.getId()), RestStatus.INTERNAL_SERVER_ERROR));
}
onOperation(response);
}

@Override
public void onFailure(Exception e) {
onFailures(e);
}
});
}

private void searchDetectors(String logTypeName, ActionListener<SearchResponse> listener) {
Expand All @@ -267,23 +275,6 @@ private void searchDetectors(String logTypeName, ActionListener<SearchResponse>
client.search(searchRequest, listener);
}

private void searchRules(String logTypeName, ActionListener<SearchResponse> listener) {
QueryBuilder queryBuilder =
QueryBuilders.nestedQuery("rule",
QueryBuilders.boolQuery().must(
QueryBuilders.matchQuery("rule.category", logTypeName)
), ScoreMode.Avg);

SearchRequest searchRequest = new SearchRequest(Rule.CUSTOM_RULES_INDEX)
.source(new SearchSourceBuilder()
.seqNoAndPrimaryTerm(true)
.version(true)
.query(queryBuilder)
.size(0));

client.search(searchRequest, listener);
}

private void onOperation(DeleteResponse response) {
this.response.set(response);
if (counter.compareAndSet(false, true)) {
Expand All @@ -292,7 +283,7 @@ private void onOperation(DeleteResponse response) {
}

private void onFailures(Exception t) {
log.error(String.format(Locale.ROOT, "Failed to delete detector"));
log.error(String.format(Locale.ROOT, "Failed to delete log type"), t);
if (counter.compareAndSet(false, true)) {
finishHim(null, t);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ private void deleteRule(String ruleId) {
new DeleteByQueryRequestBuilder(client, DeleteByQueryAction.INSTANCE)
.source(Rule.CUSTOM_RULES_INDEX)
.filter(QueryBuilders.matchQuery("_id", ruleId))
.refresh(true)
.execute(new ActionListener<>() {
@Override
public void onResponse(BulkByScrollResponse response) {
Expand Down
Loading

0 comments on commit c373343

Please sign in to comment.