Skip to content

Commit b5b18e8

Browse files
authored
Adding default agent for incident rules (#397)
* Adding default_agent field to utm_alert_response_rule, to use its value as default if the alert log is not coming from an agent. Adding new logic to UtmAlertResponseRuleService to manage the default agent to execute the incident response when the alert log is not coming from an agent. * Reformat code to implement better solution.
1 parent 8218d3a commit b5b18e8

File tree

5 files changed

+94
-16
lines changed

5 files changed

+94
-16
lines changed

backend/src/main/java/com/park/utmstack/domain/alert_response_rule/UtmAlertResponseRule.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
import org.springframework.data.annotation.LastModifiedDate;
1010
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
1111
import org.springframework.util.CollectionUtils;
12+
import org.springframework.util.StringUtils;
1213

1314
import javax.persistence.*;
15+
import javax.validation.constraints.Size;
1416
import java.io.Serializable;
1517
import java.time.Instant;
1618

@@ -38,6 +40,9 @@ public class UtmAlertResponseRule implements Serializable {
3840
private String agentPlatform;
3941
@Column(name = "excluded_agents")
4042
private String excludedAgents;
43+
@Size(max = 500)
44+
@Column(name = "default_agent" , length = 500)
45+
private String defaultAgent;
4146
@CreatedBy
4247
@Column(name = "created_by", nullable = false, length = 50, updatable = false)
4348
private String createdBy;
@@ -62,6 +67,7 @@ public UtmAlertResponseRule(UtmAlertResponseRuleDTO dto) {
6267
this.ruleCmd = dto.getCommand();
6368
this.ruleActive = dto.getActive();
6469
this.agentPlatform = dto.getAgentPlatform();
70+
this.defaultAgent = dto.getDefaultAgent();
6571
if (!CollectionUtils.isEmpty(dto.getExcludedAgents()))
6672
this.excludedAgents = String.join(",", dto.getExcludedAgents());
6773
else
@@ -132,6 +138,14 @@ public void setExcludedAgents(String excludedAgents) {
132138
this.excludedAgents = excludedAgents;
133139
}
134140

141+
public String getDefaultAgent() {
142+
return defaultAgent;
143+
}
144+
145+
public void setDefaultAgent(String defaultAgent) {
146+
this.defaultAgent = defaultAgent;
147+
}
148+
135149
public String getCreatedBy() {
136150
return createdBy;
137151
}

backend/src/main/java/com/park/utmstack/service/alert_response_rule/UtmAlertResponseRuleService.java

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -129,48 +129,85 @@ public void evaluateRules(List<AlertType> alerts) {
129129
return;
130130

131131
List<UtmAlertResponseRule> rules = alertResponseRuleRepository.findAllByRuleActiveIsTrue();
132-
if (CollectionUtils.isEmpty(rules))
133-
return;
134132

135133
// Excluding alerts tagged as false positive
136134
alerts = alerts.stream().filter(a -> (CollectionUtils.isEmpty(a.getTags()) || !a.getTags().contains("False positive")))
137135
.collect(Collectors.toList());
138136

137+
// Do nothing if there is no valid alerts to check
138+
if (CollectionUtils.isEmpty(alerts))
139+
return;
140+
139141
String alertJsonArray = new Gson().toJson(alerts);
140142
for (UtmAlertResponseRule rule : rules) {
141-
List<FilterType> conditions = new ArrayList<>();
142143
List<String> agentNames = networkScanRepository.findAgentNamesByPlatform(rule.getAgentPlatform());
143-
if (!CollectionUtils.isEmpty(agentNames))
144-
conditions.add(new FilterType(Constants.alertDataSourceKeyword, OperatorType.IS_ONE_OF, agentNames));
145144

146-
if (StringUtils.hasText(rule.getRuleConditions()))
147-
conditions.addAll(new Gson().fromJson(rule.getRuleConditions(), TypeToken.getParameterized(List.class, FilterType.class).getType()));
145+
if (CollectionUtils.isEmpty(agentNames))
146+
continue;
147+
148+
// Matching agents (these are the alerts made from logs coming from an agent)
149+
//------------------------------------------------------------------------------------------
150+
createResponseRuleExecution(rule,alertJsonArray,agentNames,true);
151+
152+
// Then the alerts that match the filters but aren't from an agent, gets executed using the default agent if there is one
153+
//-----------------------------------------------------------------------------------------------------------------------
154+
if (StringUtils.hasText(rule.getDefaultAgent())) {
155+
createResponseRuleExecution(rule,alertJsonArray,agentNames,false);
156+
}
157+
}
158+
} catch (Exception e) {
159+
String msg = ctx + ": " + e.getLocalizedMessage();
160+
log.error(msg);
161+
eventService.createEvent(msg, ApplicationEventType.ERROR);
162+
}
163+
}
164+
165+
private void createResponseRuleExecution (UtmAlertResponseRule rule, String alertJsonArray, List<String> agentNames, boolean isAgent) throws Exception {
166+
final String ctx = CLASSNAME + ".createResponseRuleExecution";
167+
List<FilterType> conditions = new ArrayList<>();
168+
try {
169+
// Common conditions
170+
if (StringUtils.hasText(rule.getRuleConditions()))
171+
conditions.addAll(new Gson().fromJson(rule.getRuleConditions(), TypeToken.getParameterized(List.class, FilterType.class).getType()));
148172

149-
if (StringUtils.hasText(rule.getExcludedAgents()))
150-
conditions.add(new FilterType(Constants.alertDataSourceKeyword, OperatorType.IS_NOT_ONE_OF, List.of(rule.getExcludedAgents().split(","))));
173+
if (StringUtils.hasText(rule.getExcludedAgents()))
174+
conditions.add(new FilterType(Constants.alertDataSourceKeyword, OperatorType.IS_NOT_ONE_OF, List.of(rule.getExcludedAgents().split(","))));
151175

152-
Filter filter = buildFilters(conditions);
153-
List<?> matches = UtilJson.read("$[?]", alertJsonArray, filter);
176+
// Specific condition for agent and non agents
177+
if (isAgent) {
178+
conditions.add(new FilterType(Constants.alertDataSourceKeyword, OperatorType.IS_ONE_OF, agentNames));
179+
} else {
180+
conditions.add(new FilterType(Constants.alertDataSourceKeyword, OperatorType.IS_NOT_ONE_OF, agentNames));
181+
}
154182

155-
if (CollectionUtils.isEmpty(matches))
156-
continue;
183+
// Processing the alerts and generating the rule executions
184+
Filter filter = buildFilters(conditions);
185+
List<?> matches = UtilJson.read("$[?]", alertJsonArray, filter);
186+
187+
if (!CollectionUtils.isEmpty(matches)) {
157188

158189
for (Object match : matches) {
159190
String matchAsJson = new Gson().toJson(match);
160191

161192
UtmAlertResponseRuleExecution exe = new UtmAlertResponseRuleExecution();
162-
exe.setAgent(UtilJson.read("$.dataSource", matchAsJson));
193+
// Execution agent takes the rule's default agent if the alert was generated by logs from non agent datasource
194+
if (isAgent) {
195+
exe.setAgent(UtilJson.read("$.dataSource", matchAsJson));
196+
} else {
197+
exe.setAgent(rule.getDefaultAgent());
198+
}
199+
163200
exe.setAlertId(UtilJson.read("$.id", matchAsJson));
164201
exe.setRuleId(rule.getId());
165202
exe.setCommand(buildCommand(rule.getRuleCmd(), matchAsJson));
166203
exe.setExecutionStatus(RuleExecutionStatus.PENDING);
167204
alertResponseRuleExecutionRepository.save(exe);
168205
}
169206
}
207+
170208
} catch (Exception e) {
171209
String msg = ctx + ": " + e.getLocalizedMessage();
172-
log.error(msg);
173-
eventService.createEvent(msg, ApplicationEventType.ERROR);
210+
throw new Exception(msg);
174211
}
175212
}
176213

backend/src/main/java/com/park/utmstack/service/dto/UtmAlertResponseRuleDTO.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public class UtmAlertResponseRuleDTO {
3131
private Boolean active;
3232
@NotBlank
3333
private String agentPlatform;
34+
@Size(max = 500)
35+
private String defaultAgent;
3436
private List<String> excludedAgents = new ArrayList<>();
3537
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
3638
private String createdBy;
@@ -52,6 +54,7 @@ public UtmAlertResponseRuleDTO(UtmAlertResponseRule rule) {
5254
this.command = rule.getRuleCmd();
5355
this.active = rule.getRuleActive();
5456
this.agentPlatform = rule.getAgentPlatform();
57+
this.defaultAgent = rule.getDefaultAgent();
5558
if (StringUtils.hasText(rule.getExcludedAgents()))
5659
this.excludedAgents.addAll(Arrays.asList(rule.getExcludedAgents().split(",")));
5760
this.createdBy = rule.getCreatedBy();
@@ -112,6 +115,14 @@ public String getAgentPlatform() {
112115
return agentPlatform;
113116
}
114117

118+
public String getDefaultAgent() {
119+
return defaultAgent;
120+
}
121+
122+
public void setDefaultAgent(String defaultAgent) {
123+
this.defaultAgent = defaultAgent;
124+
}
125+
115126
public void setAgentPlatform(String agentPlatform) {
116127
this.agentPlatform = agentPlatform;
117128
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<databaseChangeLog
3+
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
6+
7+
<changeSet id="20240131001" author="Freddy">
8+
<addColumn tableName="utm_alert_response_rule">
9+
<column name="default_agent" type="varchar(500)">
10+
<constraints nullable="true"/>
11+
</column>
12+
</addColumn>
13+
</changeSet>
14+
</databaseChangeLog>

backend/src/main/resources/config/liquibase/master.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,6 @@
3232

3333
<include file="config/liquibase/changelog/20240109001_modifying_requirement_for_configuration_parameters.xml" relativeToChangelogFile="false"/>
3434

35+
<include file="config/liquibase/changelog/20240131001_add_default_agent_utm_alert_response_rule.xml" relativeToChangelogFile="false"/>
36+
3537
</databaseChangeLog>

0 commit comments

Comments
 (0)