Skip to content

Commit

Permalink
[backend/frontend] Adapt code base to manage the installation of mult…
Browse files Browse the repository at this point in the history
…iples agents - chunk 2 (#1860)(#2151)(#2233)

Co-authored-by: Damien Goujard <damien.goujard@filigran.io>
  • Loading branch information
savacano28 and damgouj authored Feb 18, 2025
1 parent 9d9a1b4 commit 3374937
Show file tree
Hide file tree
Showing 55 changed files with 1,342 additions and 1,452 deletions.
Original file line number Diff line number Diff line change
@@ -1,73 +1,54 @@
package io.openbas.execution;

import io.openbas.database.model.*;
import io.openbas.database.model.Executor;
import io.openbas.database.model.InjectStatus;
import io.openbas.database.repository.InjectStatusRepository;
import io.openbas.executors.caldera.config.CalderaExecutorConfig;
import io.openbas.executors.caldera.service.CalderaExecutorContextService;
import io.openbas.executors.crowdstrike.config.CrowdStrikeExecutorConfig;
import io.openbas.executors.crowdstrike.service.CrowdStrikeExecutorContextService;
import io.openbas.executors.openbas.service.OpenBASExecutorContextService;
import io.openbas.executors.tanium.config.TaniumExecutorConfig;
import io.openbas.executors.tanium.service.TaniumExecutorContextService;
import io.openbas.executors.ExecutorContextService;
import io.openbas.rest.exception.AgentException;
import io.openbas.service.AssetGroupService;
import io.openbas.rest.inject.service.InjectService;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import lombok.extern.java.Log;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
@Log
public class ExecutionExecutorService {
private final AssetGroupService assetGroupService;
private final CalderaExecutorConfig calderaExecutorConfig;
private final CalderaExecutorContextService calderaExecutorContextService;
private final TaniumExecutorConfig taniumExecutorConfig;
private final TaniumExecutorContextService taniumExecutorContextService;
private final CrowdStrikeExecutorConfig crowdStrikeExecutorConfig;
private final CrowdStrikeExecutorContextService crowdStrikeExecutorContextService;
private final OpenBASExecutorContextService openBASExecutorContextService;

private final ApplicationContext context;

private final InjectStatusRepository injectStatusRepository;
private final InjectService injectService;

public void launchExecutorContext(Inject inject) {
// First, get the assets of this injects
List<Asset> assets =
Stream.concat(
inject.getAssets().stream(),
inject.getAssetGroups().stream()
.flatMap(
assetGroup ->
this.assetGroupService
.assetsFromAssetGroup(assetGroup.getId())
.stream()))
.toList();
// First, get the agents of this injects
List<Agent> agents = this.injectService.getAgentsByInject(inject);

InjectStatus injectStatus =
inject.getStatus().orElseThrow(() -> new IllegalArgumentException("Status should exists"));
inject.getStatus().orElseThrow(() -> new IllegalArgumentException("Status should exist"));
AtomicBoolean atLeastOneExecution = new AtomicBoolean(false);
AtomicBoolean atOneTraceAdded = new AtomicBoolean(false);
assets.forEach(
asset -> {

agents.forEach(
agent -> {
try {
launchExecutorContextForAsset(inject, asset);
launchExecutorContextForAgent(inject, agent);
atLeastOneExecution.set(true);
} catch (AgentException e) {
ExecutionTraceStatus traceStatus =
e.getMessage().startsWith("Asset error")
? ExecutionTraceStatus.ASSET_INACTIVE
e.getMessage().startsWith("Agent error")
? ExecutionTraceStatus.AGENT_INACTIVE
: ExecutionTraceStatus.ERROR;
injectStatus.addTrace(
traceStatus, e.getMessage(), ExecutionTraceAction.COMPLETE, e.getAgent());
atOneTraceAdded.set(true);
}
});
// if launchExecutorContextForAsset fail for every assets we throw to manually set injectStatus
// if launchExecutorContextForAgent fail for every agent we throw to manually set injectStatus
// to error
if (atOneTraceAdded.get()) {
this.injectStatusRepository.save(injectStatus);
Expand All @@ -77,47 +58,30 @@ public void launchExecutorContext(Inject inject) {
}
}

private void launchExecutorContextForAsset(Inject inject, Asset asset) {
Endpoint assetEndpoint = (Endpoint) Hibernate.unproxy(asset);
Executor executor = assetEndpoint.getExecutor();
private void launchExecutorContextForAgent(Inject inject, Agent agent) throws AgentException {
Endpoint assetEndpoint = (Endpoint) Hibernate.unproxy(agent.getAsset());
Executor executor = agent.getExecutor();
if (executor == null) {
log.log(Level.SEVERE, "Cannot find the executor for the asset " + assetEndpoint.getName());
} else if (!assetEndpoint.getActive()) {
throw new AgentException(
"Asset error: " + assetEndpoint.getName() + " is inactive",
assetEndpoint.getAgents().getFirst());
"Cannot find the executor for the agent "
+ agent.getExecutedByUser()
+ " from the asset "
+ assetEndpoint.getName(),
agent);
} else if (!agent.isActive()) {
throw new AgentException(
"Agent error: agent "
+ agent.getExecutedByUser()
+ " is inactive for the asset "
+ assetEndpoint.getName(),
agent);
} else {
switch (executor.getType()) {
case "openbas_caldera" -> {
if (!this.calderaExecutorConfig.isEnable()) {
throw new AgentException(
"Fatal error: Caldera executor is not enabled",
assetEndpoint.getAgents().getFirst());
}
this.calderaExecutorContextService.launchExecutorSubprocess(inject, assetEndpoint);
}
case "openbas_tanium" -> {
if (!this.taniumExecutorConfig.isEnable()) {
throw new AgentException(
"Fatal error: Tanium executor is not enabled",
assetEndpoint.getAgents().getFirst());
}
this.taniumExecutorContextService.launchExecutorSubprocess(inject, assetEndpoint);
}
case "openbas_crowdstrike" -> {
if (!this.crowdStrikeExecutorConfig.isEnable()) {
throw new AgentException(
"Fatal error: CrowdStrike executor is not enabled",
assetEndpoint.getAgents().getFirst());
}
this.crowdStrikeExecutorContextService.launchExecutorSubprocess(inject, assetEndpoint);
}
case "openbas_agent" ->
this.openBASExecutorContextService.launchExecutorSubprocess(inject, assetEndpoint);
default ->
throw new AgentException(
"Fatal error: Unsupported executor " + executor.getType(),
assetEndpoint.getAgents().getFirst());
try {
ExecutorContextService executorContextService =
context.getBean(agent.getExecutor().getName(), ExecutorContextService.class);
executorContextService.launchExecutorSubprocess(inject, assetEndpoint, agent);
} catch (NoSuchBeanDefinitionException e) {
throw new AgentException("Fatal error: Unsupported executor " + executor.getType(), agent);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.openbas.executors;

import io.openbas.database.model.Agent;
import io.openbas.database.model.Endpoint;
import io.openbas.database.model.Inject;
import io.openbas.rest.exception.AgentException;

public abstract class ExecutorContextService {

public abstract void launchExecutorSubprocess(Inject inject, Endpoint assetEndpoint, Agent agent)
throws AgentException;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.openbas.integrations;
package io.openbas.executors;

import static io.openbas.service.FileService.EXECUTORS_IMAGES_BASE_PATH;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package io.openbas.executors.caldera;

import io.openbas.executors.ExecutorService;
import io.openbas.executors.caldera.client.CalderaExecutorClient;
import io.openbas.executors.caldera.config.CalderaExecutorConfig;
import io.openbas.executors.caldera.service.CalderaExecutorContextService;
import io.openbas.executors.caldera.service.CalderaExecutorService;
import io.openbas.integrations.ExecutorService;
import io.openbas.integrations.InjectorService;
import io.openbas.service.AgentService;
import io.openbas.service.EndpointService;
import io.openbas.service.PlatformSettingsService;
import jakarta.annotation.PostConstruct;
Expand All @@ -26,6 +27,7 @@ public class CalderaExecutor {
private final ExecutorService executorService;
private final InjectorService injectorService;
private final PlatformSettingsService platformSettingsService;
private final AgentService agentService;

@PostConstruct
public void init() {
Expand All @@ -37,7 +39,8 @@ public void init() {
this.calderaExecutorContextService,
this.endpointService,
this.injectorService,
this.platformSettingsService);
this.platformSettingsService,
this.agentService);
if (this.config.isEnable()) {
this.taskScheduler.scheduleAtFixedRate(service, Duration.ofSeconds(60));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,9 @@ public List<Agent> agents() {
}
}

public void deleteAgent(Endpoint endpoint) {
public void deleteAgent(final String externalReference) {
try {
this.delete(
this.config.getRestApiV2Url()
+ AGENT_URI
+ "/"
+ endpoint.getAgents().getFirst().getExternalReference());
this.delete(this.config.getRestApiV2Url() + AGENT_URI + "/" + externalReference);
} catch (IOException e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,30 @@
package io.openbas.executors.caldera.service;

import static io.openbas.executors.caldera.service.CalderaExecutorService.CALDERA_EXECUTOR_NAME;

import io.openbas.database.model.*;
import io.openbas.executors.ExecutorContextService;
import io.openbas.executors.caldera.client.CalderaExecutorClient;
import io.openbas.executors.caldera.client.model.Ability;
import io.openbas.executors.caldera.config.CalderaExecutorConfig;
import io.openbas.integrations.InjectorService;
import io.openbas.rest.exception.AgentException;
import jakarta.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Log
@Service
public class CalderaExecutorContextService {

private InjectorService injectorService;
@Service(CALDERA_EXECUTOR_NAME)
@RequiredArgsConstructor
public class CalderaExecutorContextService extends ExecutorContextService {

private CalderaExecutorClient calderaExecutorClient;

@Autowired
public void setInjectorService(InjectorService injectorService) {
this.injectorService = injectorService;
}

@Autowired
public void setCalderaExecutorClient(CalderaExecutorClient calderaExecutorClient) {
this.calderaExecutorClient = calderaExecutorClient;
}
private final CalderaExecutorConfig calderaExecutorConfig;
private final InjectorService injectorService;
private final CalderaExecutorClient calderaExecutorClient;

public final Map<String, Ability> injectorExecutorAbilities = new HashMap<>();
public final Map<String, Ability> injectorExecutorClearAbilities = new HashMap<>();
Expand Down Expand Up @@ -71,7 +67,15 @@ public void registerAbilities() {
}

public void launchExecutorSubprocess(
@NotNull final Inject inject, @NotNull final Endpoint assetEndpoint) {
@NotNull final Inject inject,
@NotNull final Endpoint assetEndpoint,
@NotNull final Agent agent)
throws AgentException {

if (!this.calderaExecutorConfig.isEnable()) {
throw new AgentException("Fatal error: Caldera executor is not enabled", agent);
}

inject
.getInjectorContract()
.map(InjectorContract::getInjector)
Expand All @@ -81,26 +85,21 @@ public void launchExecutorSubprocess(
List<Map<String, String>> additionalFields =
List.of(
Map.of("trait", "inject", "value", inject.getId()),
Map.of(
"trait",
"agent",
"value",
assetEndpoint.getAgents().getFirst().getId()));
Map.of("trait", "agent", "value", agent.getId()));
calderaExecutorClient.exploit(
"base64",
assetEndpoint.getAgents().getFirst().getExternalReference(),
agent.getExternalReference(),
this.injectorExecutorAbilities.get(injector.getId()).getAbility_id(),
additionalFields);
}
});
}

public void launchExecutorClear(
@NotNull final Injector injector, @NotNull final Endpoint assetEndpoint) {
public void launchExecutorClear(@NotNull final Injector injector, @NotNull final Agent agent) {
if (this.injectorExecutorAbilities.containsKey(injector.getId())) {
calderaExecutorClient.exploit(
"base64",
assetEndpoint.getAgents().getFirst().getExternalReference(),
agent.getExternalReference(),
this.injectorExecutorClearAbilities.get(injector.getId()).getAbility_id(),
List.of());
}
Expand Down
Loading

0 comments on commit 3374937

Please sign in to comment.