Introduction to Falco Runtime Security
Falco is a cloud-native runtime security tool that detects anomalous activity in applications and infrastructure. This implementation provides Java integration for Falco, enabling real-time security monitoring, alerting, and response.
Maven Dependencies
<properties>
<falco.version>0.35.1</falco.version>
<grpc.version>1.56.1</grpc.version>
<kubernetes-client.version>18.0.0</kubernetes-client.version>
<jackson.version>2.15.2</jackson.version>
</properties>
<dependencies>
<!-- Falco Client -->
<dependency>
<groupId>org.falcosecurity</groupId>
<artifactId>falco-client</artifactId>
<version>${falco.version}</version>
</dependency>
<!-- gRPC -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>${grpc.version}</version>
</dependency>
<!-- Kubernetes Client -->
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>${kubernetes-client.version}</version>
</dependency>
<!-- JSON Processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
</dependencies>
Core Falco Integration
Falco gRPC Client
@Component
public class FalcoGrpcClient {
private static final Logger logger = LoggerFactory.getLogger(FalcoGrpcClient.class);
private ManagedChannel channel;
private outputServiceGrpc.outputServiceBlockingStub blockingStub;
private outputServiceGrpc.outputServiceStub asyncStub;
private final FalcoProperties properties;
private final FalcoEventProcessor eventProcessor;
public FalcoGrpcClient(FalcoProperties properties, FalcoEventProcessor eventProcessor) {
this.properties = properties;
this.eventProcessor = eventProcessor;
initializeChannel();
}
private void initializeChannel() {
try {
this.channel = ManagedChannelBuilder
.forAddress(properties.getHost(), properties.getPort())
.usePlaintext() // Use TLS in production
.build();
this.blockingStub = outputServiceGrpc.newBlockingStub(channel);
this.asyncStub = outputServiceGrpc.newStub(channel);
logger.info("Falco gRPC client initialized for {}:{}",
properties.getHost(), properties.getPort());
} catch (Exception e) {
logger.error("Failed to initialize Falco gRPC client", e);
throw new RuntimeException("Falco client initialization failed", e);
}
}
public void subscribeToEvents() {
if (!properties.isEnabled()) {
logger.info("Falco integration is disabled");
return;
}
request request = request.newBuilder()
.setPriority(properties.getPriority())
.build();
try {
Iterator<response> responses = blockingStub.subscribe(request);
while (responses.hasNext()) {
try {
response falcoResponse = responses.next();
processFalcoResponse(falcoResponse);
} catch (Exception e) {
logger.error("Error processing Falco response", e);
}
}
} catch (Exception e) {
logger.error("Falco subscription failed", e);
}
}
public void subscribeAsync() {
if (!properties.isEnabled()) {
return;
}
request request = request.newBuilder()
.setPriority(properties.getPriority())
.build();
StreamObserver<response> responseObserver = new StreamObserver<response>() {
@Override
public void onNext(response falcoResponse) {
processFalcoResponse(falcoResponse);
}
@Override
public void onError(Throwable t) {
logger.error("Falco async subscription error", t);
// Implement reconnection logic
scheduleReconnection();
}
@Override
public void onCompleted() {
logger.info("Falco async subscription completed");
}
};
asyncStub.subscribe(request, responseObserver);
}
private void processFalcoResponse(response falcoResponse) {
try {
FalcoEvent event = parseFalcoEvent(falcoResponse);
// Process based on event priority
switch (event.getPriority()) {
case EMERGENCY:
case ALERT:
case CRITICAL:
eventProcessor.processCriticalEvent(event);
break;
case ERROR:
eventProcessor.processErrorEvent(event);
break;
case WARNING:
eventProcessor.processWarningEvent(event);
break;
case NOTICE:
case INFORMATIONAL:
case DEBUG:
eventProcessor.processInfoEvent(event);
break;
}
// Always log for audit purposes
logger.info("Falco Event: {} - {}", event.getPriority(), event.getRule());
} catch (Exception e) {
logger.error("Failed to process Falco event", e);
}
}
private FalcoEvent parseFalcoEvent(response falcoResponse) {
FalcoEvent event = new FalcoEvent();
// Parse the JSON output from Falco
String jsonOutput = falcoResponse.getJson();
ObjectMapper mapper = new ObjectMapper();
try {
JsonNode root = mapper.readTree(jsonOutput);
event.setOutput(root.path("output").asText());
event.setPriority(FalcoEvent.Priority.valueOf(root.path("priority").asText().toUpperCase()));
event.setRule(root.path("rule").asText());
event.setTime(root.path("time").asText());
event.setSource(FalcoEvent.Source.valueOf(root.path("source").asText().toUpperCase()));
// Parse output fields
JsonNode outputFields = root.path("output_fields");
event.setContainerId(outputFields.path("container.id").asText());
event.setContainerName(outputFields.path("container.name").asText());
event.setImage(outputFields.path("container.image.repository").asText());
event.setK8sNamespace(outputFields.path("k8s.ns.name").asText());
event.setK8sPodName(outputFields.path("k8s.pod.name").asText());
event.setProcessName(outputFields.path("proc.name").asText());
event.setCommand(outputFields.path("proc.cmdline").asText());
event.setUserId(outputFields.path("user.uid").asInt());
event.setFileName(outputFields.path("fd.name").asText());
} catch (Exception e) {
logger.error("Failed to parse Falco JSON response", e);
// Fallback to raw output
event.setOutput(falcoResponse.getOutput());
}
return event;
}
private void scheduleReconnection() {
// Implement reconnection logic with exponential backoff
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.schedule(this::initializeChannel, 30, TimeUnit.SECONDS);
}
public void shutdown() {
if (channel != null && !channel.isShutdown()) {
channel.shutdown();
try {
if (!channel.awaitTermination(5, TimeUnit.SECONDS)) {
channel.shutdownNow();
}
} catch (InterruptedException e) {
channel.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
}
Falco Event Models
public class FalcoEvent {
public enum Priority {
EMERGENCY,
ALERT,
CRITICAL,
ERROR,
WARNING,
NOTICE,
INFORMATIONAL,
DEBUG
}
public enum Source {
SYSCALL,
K8S_AUDIT
}
private String output;
private Priority priority;
private String rule;
private String time;
private Source source;
// Output fields
private String containerId;
private String containerName;
private String image;
private String k8sNamespace;
private String k8sPodName;
private String processName;
private String command;
private int userId;
private String fileName;
private Map<String, String> additionalFields;
public FalcoEvent() {
this.additionalFields = new HashMap<>();
}
// Getters and setters
public String getOutput() { return output; }
public void setOutput(String output) { this.output = output; }
public Priority getPriority() { return priority; }
public void setPriority(Priority priority) { this.priority = priority; }
public String getRule() { return rule; }
public void setRule(String rule) { this.rule = rule; }
public String getTime() { return time; }
public void setTime(String time) { this.time = time; }
public Source getSource() { return source; }
public void setSource(Source source) { this.source = source; }
public String getContainerId() { return containerId; }
public void setContainerId(String containerId) { this.containerId = containerId; }
public String getContainerName() { return containerName; }
public void setContainerName(String containerName) { this.containerName = containerName; }
public String getImage() { return image; }
public void setImage(String image) { this.image = image; }
public String getK8sNamespace() { return k8sNamespace; }
public void setK8sNamespace(String k8sNamespace) { this.k8sNamespace = k8sNamespace; }
public String getK8sPodName() { return k8sPodName; }
public void setK8sPodName(String k8sPodName) { this.k8sPodName = k8sPodName; }
public String getProcessName() { return processName; }
public void setProcessName(String processName) { this.processName = processName; }
public String getCommand() { return command; }
public void setCommand(String command) { this.command = command; }
public int getUserId() { return userId; }
public void setUserId(int userId) { this.userId = userId; }
public String getFileName() { return fileName; }
public void setFileName(String fileName) { this.fileName = fileName; }
public Map<String, String> getAdditionalFields() { return additionalFields; }
public void setAdditionalFields(Map<String, String> additionalFields) {
this.additionalFields = additionalFields;
}
public void addAdditionalField(String key, String value) {
this.additionalFields.put(key, value);
}
public boolean isContainerEvent() {
return containerId != null && !containerId.isEmpty();
}
public boolean isKubernetesEvent() {
return k8sNamespace != null && !k8sNamespace.isEmpty();
}
public boolean isHighSeverity() {
return priority == Priority.EMERGENCY ||
priority == Priority.ALERT ||
priority == Priority.CRITICAL;
}
}
Event Processing and Response
Falco Event Processor
@Component
public class FalcoEventProcessor {
private static final Logger logger = LoggerFactory.getLogger(FalcoEventProcessor.class);
private final KubernetesClient k8sClient;
private final AlertService alertService;
private final SecurityIncidentService incidentService;
private final FalcoRulesEngine rulesEngine;
// Known benign patterns (would be configurable)
private final Set<String> benignProcesses = Set.of(
"java", "bash", "sh", "cat", "ls", "ps", "top", "sleep"
);
private final Set<String> criticalRules = Set.of(
"Terminal shell in container",
"Contact K8S API Server From Container",
"Unexpected K8s NodePort Connection",
"Launch Suspicious Network Tool in Container"
);
public FalcoEventProcessor(KubernetesClient k8sClient, AlertService alertService,
SecurityIncidentService incidentService, FalcoRulesEngine rulesEngine) {
this.k8sClient = k8sClient;
this.alertService = alertService;
this.incidentService = incidentService;
this.rulesEngine = rulesEngine;
}
public void processCriticalEvent(FalcoEvent event) {
logger.warn("CRITICAL Falco event detected: {}", event.getRule());
// Immediate response actions
triggerImmediateResponse(event);
// Create security incident
SecurityIncident incident = createSecurityIncident(event);
incidentService.createIncident(incident);
// Send high-priority alerts
alertService.sendCriticalAlert(event);
// Log for SIEM integration
logSecurityEvent(event);
}
public void processErrorEvent(FalcoEvent event) {
logger.info("ERROR Falco event: {}", event.getRule());
// Evaluate for automated response
if (requiresAutomatedResponse(event)) {
triggerAutomatedResponse(event);
}
// Create alert
alertService.sendAlert(event);
// Log for analysis
logSecurityEvent(event);
}
public void processWarningEvent(FalcoEvent event) {
logger.debug("WARNING Falco event: {}", event.getRule());
// Analyze pattern for correlation
rulesEngine.analyzeEventPattern(event);
// Store for trend analysis
storeEventForAnalysis(event);
}
public void processInfoEvent(FalcoEvent event) {
// Log for audit purposes
logger.trace("INFO Falco event: {}", event.getRule());
storeEventForAnalysis(event);
}
private void triggerImmediateResponse(FalcoEvent event) {
// Determine appropriate response based on event type
switch (event.getRule()) {
case "Terminal shell in container":
handleTerminalShell(event);
break;
case "Contact K8S API Server From Container":
handleK8sApiAccess(event);
break;
case "Unexpected K8s NodePort Connection":
handleSuspiciousNetwork(event);
break;
case "Launch Suspicious Network Tool in Container":
handleSuspiciousTool(event);
break;
default:
logger.warn("No immediate response defined for rule: {}", event.getRule());
}
}
private void handleTerminalShell(FalcoEvent event) {
if (event.isContainerEvent()) {
// Check if this is an expected container
if (!isExpectedContainer(event.getContainerName())) {
logger.warn("Unexpected shell in container: {}", event.getContainerName());
// Optionally isolate the container
if (shouldIsolateContainer(event)) {
isolateContainer(event.getContainerId());
}
}
}
}
private void handleK8sApiAccess(FalcoEvent event) {
if (event.isContainerEvent()) {
// Check if container should have API access
if (!isAuthorizedApiAccess(event)) {
logger.warn("Unauthorized K8s API access from container: {}", event.getContainerName());
// Block further API access
blockContainerApiAccess(event.getContainerId());
}
}
}
private void handleSuspiciousNetwork(FalcoEvent event) {
// Analyze network pattern
NetworkThreat threat = analyzeNetworkThreat(event);
if (threat.isCritical()) {
// Implement network isolation
isolateNetworkTraffic(event);
}
}
private void handleSuspiciousTool(FalcoEvent event) {
String tool = event.getProcessName();
if (isMaliciousTool(tool)) {
// Kill the process and alert
killProcess(event);
alertService.sendToolAlert(event, tool);
}
}
private boolean requiresAutomatedResponse(FalcoEvent event) {
return criticalRules.contains(event.getRule()) ||
event.isHighSeverity() ||
isSuspiciousPattern(event);
}
private void triggerAutomatedResponse(FalcoEvent event) {
// Implement automated response based on policy
SecurityPolicy policy = rulesEngine.evaluatePolicy(event);
switch (policy.getAction()) {
case ALERT:
alertService.sendAlert(event);
break;
case ISOLATE:
isolateResource(event);
break;
case TERMINATE:
terminateProcess(event);
break;
case QUARANTINE:
quarantineContainer(event);
break;
case NO_ACTION:
// Just log
break;
}
}
private SecurityIncident createSecurityIncident(FalcoEvent event) {
SecurityIncident incident = new SecurityIncident();
incident.setId(UUID.randomUUID().toString());
incident.setTitle("Security Incident: " + event.getRule());
incident.setDescription(event.getOutput());
incident.setSeverity(mapToIncidentSeverity(event.getPriority()));
incident.setTimestamp(Instant.now());
incident.setSource("Falco");
incident.setStatus(SecurityIncident.Status.OPEN);
incident.setAffectedResource(event.getContainerName() != null ?
event.getContainerName() : event.getK8sPodName());
// Add evidence
incident.addEvidence("falco_event", event);
return incident;
}
private SecurityIncident.Severity mapToIncidentSeverity(FalcoEvent.Priority priority) {
switch (priority) {
case EMERGENCY:
case ALERT:
case CRITICAL:
return SecurityIncident.Severity.CRITICAL;
case ERROR:
return SecurityIncident.Severity.HIGH;
case WARNING:
return SecurityIncident.Severity.MEDIUM;
default:
return SecurityIncident.Severity.LOW;
}
}
// Response implementation methods (simplified)
private boolean isExpectedContainer(String containerName) {
// Check against allowed container patterns
return containerName != null &&
(containerName.contains("app") ||
containerName.contains("db") ||
containerName.contains("cache"));
}
private boolean isAuthorizedApiAccess(FalcoEvent event) {
// Check if container has legitimate reason to access K8s API
return event.getK8sNamespace() != null &&
event.getK8sNamespace().equals("kube-system");
}
private boolean isMaliciousTool(String tool) {
Set<String> maliciousTools = Set.of("nmap", "masscan", "metasploit", "john", "hashcat");
return maliciousTools.contains(tool);
}
private boolean isSuspiciousPattern(FalcoEvent event) {
// Implement pattern matching logic
return event.getProcessName() != null &&
event.getProcessName().contains("miner") ||
event.getCommand() != null &&
event.getCommand().contains("curl") &&
event.getCommand().contains("pastebin");
}
private void isolateContainer(String containerId) {
// Implement container isolation using container runtime API
logger.info("Isolating container: {}", containerId);
}
private void blockContainerApiAccess(String containerId) {
// Implement network policy to block API server access
logger.info("Blocking API access for container: {}", containerId);
}
private void killProcess(FalcoEvent event) {
// Send signal to terminate suspicious process
logger.info("Terminating process: {} in container: {}",
event.getProcessName(), event.getContainerName());
}
private void logSecurityEvent(FalcoEvent event) {
// Log to security information and event management (SIEM) system
SecurityLogEntry logEntry = new SecurityLogEntry(event);
// Send to SIEM (implementation depends on SIEM system)
}
private void storeEventForAnalysis(FalcoEvent event) {
// Store in database for trend analysis and machine learning
EventRepository.store(event);
}
}
Kubernetes Integration
Kubernetes Security Operations
@Component
public class KubernetesSecurityOperator {
private static final Logger logger = LoggerFactory.getLogger(KubernetesSecurityOperator.class);
private final KubernetesClient k8sClient;
private final FalcoEventProcessor eventProcessor;
public KubernetesSecurityOperator(KubernetesClient k8sClient, FalcoEventProcessor eventProcessor) {
this.k8sClient = k8sClient;
this.eventProcessor = eventProcessor;
}
public void createSecurityNetworkPolicy(String namespace, String policyName) {
try {
NetworkPolicy networkPolicy = new NetworkPolicyBuilder()
.withNewMetadata()
.withName(policyName)
.withNamespace(namespace)
.endMetadata()
.withNewSpec()
.withNewPodSelector()
.endPodSelector()
.withPolicyTypes("Ingress", "Egress")
.addNewIngress()
.addNewFrom()
.withNewNamespaceSelector()
.addNewMatchLabel()
.withKey("security-level")
.withValue("trusted")
.endMatchLabel()
.endNamespaceSelector()
.endFrom()
.endIngress()
.addNewEgress()
.addNewTo()
.withNewNamespaceSelector()
.addNewMatchLabel()
.withKey("security-level")
.withValue("trusted")
.endMatchLabel()
.endNamespaceSelector()
.endTo()
.endEgress()
.endSpec()
.build();
k8sClient.network().networkPolicies()
.inNamespace(namespace)
.createOrReplace(networkPolicy);
logger.info("Created security network policy: {}/{}", namespace, policyName);
} catch (Exception e) {
logger.error("Failed to create network policy", e);
}
}
public void isolatePod(String namespace, String podName) {
try {
// Add isolation label
k8sClient.pods()
.inNamespace(namespace)
.withName(podName)
.edit(pod -> new PodBuilder(pod)
.editMetadata()
.addToLabels("security-status", "isolated")
.endMetadata()
.build());
// Create network policy to block all traffic
NetworkPolicy isolationPolicy = createIsolationNetworkPolicy(namespace, podName);
k8sClient.network().networkPolicies()
.inNamespace(namespace)
.createOrReplace(isolationPolicy);
logger.info("Isolated pod: {}/{}", namespace, podName);
} catch (Exception e) {
logger.error("Failed to isolate pod: {}/{}", namespace, podName, e);
}
}
public void quarantineNamespace(String namespace) {
try {
// Add quarantine label to namespace
k8sClient.namespaces()
.withName(namespace)
.edit(ns -> new NamespaceBuilder(ns)
.editMetadata()
.addToLabels("security-status", "quarantined")
.endMetadata()
.build());
// Create restrictive network policies
createQuarantineNetworkPolicies(namespace);
// Scale down deployments (optional - based on policy)
scaleDownNamespaceDeployments(namespace);
logger.info("Quarantined namespace: {}", namespace);
} catch (Exception e) {
logger.error("Failed to quarantine namespace: {}", namespace, e);
}
}
public void createPodSecurityPolicy(String name, SecurityPolicy policy) {
try {
// Create PodSecurityPolicy or PodSecurityStandard
if (isOpenshift()) {
createSecurityContextConstraints(name, policy);
} else {
createPodSecurityStandard(name, policy);
}
logger.info("Created pod security policy: {}", name);
} catch (Exception e) {
logger.error("Failed to create pod security policy: {}", name, e);
}
}
public List<Pod> findPodsWithSuspiciousActivity() {
return k8sClient.pods()
.inAnyNamespace()
.withLabel("security-status", "suspicious")
.list()
.getItems();
}
public void annotatePodWithSecurityEvent(String namespace, String podName, FalcoEvent event) {
try {
k8sClient.pods()
.inNamespace(namespace)
.withName(podName)
.edit(pod -> new PodBuilder(pod)
.editMetadata()
.addToAnnotations("falco-events",
String.format("%s: %s", event.getRule(), event.getTime()))
.endMetadata()
.build());
} catch (Exception e) {
logger.error("Failed to annotate pod with security event", e);
}
}
private NetworkPolicy createIsolationNetworkPolicy(String namespace, String podName) {
return new NetworkPolicyBuilder()
.withNewMetadata()
.withName("isolate-" + podName)
.withNamespace(namespace)
.endMetadata()
.withNewSpec()
.withNewPodSelector()
.addToMatchLabels("security-status", "isolated")
.endPodSelector()
.withPolicyTypes("Ingress", "Egress")
.withIngress(Collections.emptyList()) // No incoming traffic
.withEgress(Collections.emptyList()) // No outgoing traffic
.endSpec()
.build();
}
private void createQuarantineNetworkPolicies(String namespace) {
// Block all ingress traffic
NetworkPolicy blockIngress = new NetworkPolicyBuilder()
.withNewMetadata()
.withName("quarantine-block-ingress")
.withNamespace(namespace)
.endMetadata()
.withNewSpec()
.withNewPodSelector()
.endPodSelector()
.withPolicyTypes("Ingress")
.withIngress(Collections.emptyList())
.endSpec()
.build();
// Allow only essential egress (DNS, logging)
NetworkPolicy restrictEgress = new NetworkPolicyBuilder()
.withNewMetadata()
.withName("quarantine-restrict-egress")
.withNamespace(namespace)
.endMetadata()
.withNewSpec()
.withNewPodSelector()
.endPodSelector()
.withPolicyTypes("Egress")
.addNewEgress()
.addNewTo()
.withNewNamespaceSelector()
.addToMatchLabels("name", "kube-system")
.endNamespaceSelector()
.endTo()
.withPorts(
new NetworkPolicyPortBuilder().withPort(new IntOrString(53)).withProtocol("UDP").build(),
new NetworkPolicyPortBuilder().withPort(new IntOrString(53)).withProtocol("TCP").build()
)
.endEgress()
.endSpec()
.build();
k8sClient.network().networkPolicies()
.inNamespace(namespace)
.createOrReplace(blockIngress);
k8sClient.network().networkPolicies()
.inNamespace(namespace)
.createOrReplace(restrictEgress);
}
private void scaleDownNamespaceDeployments(String namespace) {
k8sClient.apps().deployments()
.inNamespace(namespace)
.list()
.getItems()
.forEach(deployment -> {
k8sClient.apps().deployments()
.inNamespace(namespace)
.withName(deployment.getMetadata().getName())
.edit()
.editSpec()
.withReplicas(0)
.endSpec()
.done();
});
}
private boolean isOpenshift() {
try {
k8sClient.apis().getApiGroups().getGroups().stream()
.anyMatch(group -> group.getName().contains("openshift.io"));
return true;
} catch (Exception e) {
return false;
}
}
private void createSecurityContextConstraints(String name, SecurityPolicy policy) {
// OpenShift specific security constraints
// Implementation depends on OpenShift client
}
private void createPodSecurityStandard(String name, SecurityPolicy policy) {
// Kubernetes Pod Security Standards
// Implementation for PSS or PSA
}
}
Security Incident Management
@Component
public class SecurityIncidentService {
private static final Logger logger = LoggerFactory.getLogger(SecurityIncidentService.class);
private final IncidentRepository incidentRepository;
private final AlertService alertService;
private final KubernetesSecurityOperator k8sOperator;
public SecurityIncidentService(IncidentRepository incidentRepository,
AlertService alertService,
KubernetesSecurityOperator k8sOperator) {
this.incidentRepository = incidentRepository;
this.alertService = alertService;
this.k8sOperator = k8sOperator;
}
public SecurityIncident createIncident(SecurityIncident incident) {
try {
// Validate incident
validateIncident(incident);
// Store incident
SecurityIncident savedIncident = incidentRepository.save(incident);
// Trigger incident response workflow
triggerIncidentResponse(savedIncident);
// Notify stakeholders
notifyStakeholders(savedIncident);
logger.info("Created security incident: {}", savedIncident.getId());
return savedIncident;
} catch (Exception e) {
logger.error("Failed to create security incident", e);
throw new RuntimeException("Incident creation failed", e);
}
}
public void updateIncidentStatus(String incidentId, SecurityIncident.Status status, String notes) {
try {
SecurityIncident incident = incidentRepository.findById(incidentId)
.orElseThrow(() -> new IllegalArgumentException("Incident not found: " + incidentId));
incident.setStatus(status);
incident.setLastUpdated(Instant.now());
// Add status change note
incident.addNote(new IncidentNote(
"Status changed to: " + status,
"System",
Instant.now()
));
if (notes != null) {
incident.addNote(new IncidentNote(notes, "System", Instant.now()));
}
incidentRepository.save(incident);
// If resolved, trigger post-incident actions
if (status == SecurityIncident.Status.RESOLVED) {
triggerPostIncidentActions(incident);
}
} catch (Exception e) {
logger.error("Failed to update incident status: {}", incidentId, e);
}
}
public List<SecurityIncident> getActiveIncidents() {
return incidentRepository.findByStatusIn(
SecurityIncident.Status.OPEN,
SecurityIncident.Status.INVESTIGATING
);
}
public List<SecurityIncident> getIncidentsBySeverity(SecurityIncident.Severity severity) {
return incidentRepository.findBySeverity(severity);
}
public void correlateIncidents() {
List<SecurityIncident> activeIncidents = getActiveIncidents();
// Group incidents by similar patterns
Map<String, List<SecurityIncident>> incidentsByPattern = activeIncidents.stream()
.collect(Collectors.groupingBy(this::extractIncidentPattern));
// Create correlated incidents for patterns with multiple occurrences
incidentsByPattern.entrySet().stream()
.filter(entry -> entry.getValue().size() > 1)
.forEach(entry -> createCorrelatedIncident(entry.getKey(), entry.getValue()));
}
private void validateIncident(SecurityIncident incident) {
if (incident.getTitle() == null || incident.getTitle().trim().isEmpty()) {
throw new IllegalArgumentException("Incident title is required");
}
if (incident.getSeverity() == null) {
throw new IllegalArgumentException("Incident severity is required");
}
if (incident.getTimestamp() == null) {
incident.setTimestamp(Instant.now());
}
}
private void triggerIncidentResponse(SecurityIncident incident) {
// Implement incident response based on severity
switch (incident.getSeverity()) {
case CRITICAL:
triggerCriticalIncidentResponse(incident);
break;
case HIGH:
triggerHighIncidentResponse(incident);
break;
case MEDIUM:
triggerMediumIncidentResponse(incident);
break;
case LOW:
triggerLowIncidentResponse(incident);
break;
}
}
private void triggerCriticalIncidentResponse(SecurityIncident incident) {
// Immediate actions for critical incidents
logger.warn("Triggering critical incident response for: {}", incident.getId());
// Isolate affected resources
if (incident.getAffectedResource() != null) {
k8sOperator.isolatePod(extractNamespace(incident.getAffectedResource()),
extractPodName(incident.getAffectedResource()));
}
// Escalate to security team
alertService.escalateToSecurityTeam(incident);
// Trigger on-call notification
alertService.triggerOnCallNotification(incident);
}
private void triggerHighIncidentResponse(SecurityIncident incident) {
logger.info("Triggering high incident response for: {}", incident.getId());
// Enhanced monitoring
enhanceMonitoring(incident);
// Security team notification
alertService.notifySecurityTeam(incident);
}
private void triggerMediumIncidentResponse(SecurityIncident incident) {
logger.info("Triggering medium incident response for: {}", incident.getId());
// Standard investigation workflow
initiateInvestigation(incident);
}
private void triggerLowIncidentResponse(SecurityIncident incident) {
logger.debug("Triggering low incident response for: {}", incident.getId());
// Log and monitor
monitorIncident(incident);
}
private void notifyStakeholders(SecurityIncident incident) {
// Notify based on incident severity and type
List<String> stakeholders = determineStakeholders(incident);
stakeholders.forEach(stakeholder ->
alertService.notifyStakeholder(incident, stakeholder));
}
private void triggerPostIncidentActions(SecurityIncident incident) {
// Restore isolated resources
restoreIsolatedResources(incident);
// Generate incident report
generateIncidentReport(incident);
// Update security policies
updateSecurityPolicies(incident);
}
private String extractIncidentPattern(SecurityIncident incident) {
// Extract pattern for correlation (simplified)
return incident.getTitle() + "|" + incident.getAffectedResource();
}
private void createCorrelatedIncident(String pattern, List<SecurityIncident> incidents) {
SecurityIncident correlated = new SecurityIncident();
correlated.setId(UUID.randomUUID().toString());
correlated.setTitle("Correlated Security Incident: " + pattern);
correlated.setDescription("Multiple related security incidents detected");
correlated.setSeverity(determineCorrelatedSeverity(incidents));
correlated.setTimestamp(Instant.now());
correlated.setSource("Falco-Correlation");
correlated.setStatus(SecurityIncident.Status.OPEN);
// Link original incidents
incidents.forEach(incident ->
correlated.addRelatedIncident(incident.getId()));
createIncident(correlated);
}
private SecurityIncident.Severity determineCorrelatedSeverity(List<SecurityIncident> incidents) {
// Use highest severity from correlated incidents
return incidents.stream()
.map(SecurityIncident::getSeverity)
.max(Comparator.naturalOrder())
.orElse(SecurityIncident.Severity.LOW);
}
private List<String> determineStakeholders(SecurityIncident incident) {
List<String> stakeholders = new ArrayList<>();
// Always include security team
stakeholders.add("security-team");
// Include application team for app-related incidents
if (incident.getAffectedResource() != null &&
incident.getAffectedResource().contains("app")) {
stakeholders.add("application-team");
}
// Include infrastructure team for infrastructure incidents
if (incident.getSource().equals("K8S_AUDIT")) {
stakeholders.add("infrastructure-team");
}
return stakeholders;
}
// Helper methods for resource extraction
private String extractNamespace(String resource) {
if (resource != null && resource.contains("/")) {
return resource.split("/")[0];
}
return "default";
}
private String extractPodName(String resource) {
if (resource != null && resource.contains("/")) {
return resource.split("/")[1];
}
return resource;
}
// Implementation details for other methods
private void enhanceMonitoring(SecurityIncident incident) {
// Implement enhanced monitoring logic
}
private void initiateInvestigation(SecurityIncident incident) {
// Implement investigation workflow
}
private void monitorIncident(SecurityIncident incident) {
// Implement monitoring logic
}
private void restoreIsolatedResources(SecurityIncident incident) {
// Implement resource restoration logic
}
private void generateIncidentReport(SecurityIncident incident) {
// Implement report generation
}
private void updateSecurityPolicies(SecurityIncident incident) {
// Implement policy updates based on incident learnings
}
}
Configuration and Properties
@ConfigurationProperties(prefix = "falco")
public class FalcoProperties {
private boolean enabled = true;
private String host = "localhost";
private int port = 5060;
private String priority = "warning";
private long reconnectDelay = 30000;
private int maxRetries = 5;
private boolean asyncMode = true;
// Alerting configuration
private Alerting alerting = new Alerting();
private Kubernetes kubernetes = new Kubernetes();
private Response response = new Response();
public static class Alerting {
private boolean enabled = true;
private String webhookUrl;
private String slackChannel;
private String pagerDutyKey;
private String email;
private List<String> criticalRules = new ArrayList<>();
// Getters and setters
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
public String getWebhookUrl() { return webhookUrl; }
public void setWebhookUrl(String webhookUrl) { this.webhookUrl = webhookUrl; }
public String getSlackChannel() { return slackChannel; }
public void setSlackChannel(String slackChannel) { this.slackChannel = slackChannel; }
public String getPagerDutyKey() { return pagerDutyKey; }
public void setPagerDutyKey(String pagerDutyKey) { this.pagerDutyKey = pagerDutyKey; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public List<String> getCriticalRules() { return criticalRules; }
public void setCriticalRules(List<String> criticalRules) { this.criticalRules = criticalRules; }
}
public static class Kubernetes {
private boolean enabled = true;
private String namespace;
private boolean autoIsolate = false;
private boolean createNetworkPolicies = true;
private List<String> trustedNamespaces = Arrays.asList("kube-system");
// Getters and setters
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
public String getNamespace() { return namespace; }
public void setNamespace(String namespace) { this.namespace = namespace; }
public boolean isAutoIsolate() { return autoIsolate; }
public void setAutoIsolate(boolean autoIsolate) { this.autoIsolate = autoIsolate; }
public boolean isCreateNetworkPolicies() { return createNetworkPolicies; }
public void setCreateNetworkPolicies(boolean createNetworkPolicies) {
this.createNetworkPolicies = createNetworkPolicies;
}
public List<String> getTrustedNamespaces() { return trustedNamespaces; }
public void setTrustedNamespaces(List<String> trustedNamespaces) {
this.trustedNamespaces = trustedNamespaces;
}
}
public static class Response {
private boolean enabled = true;
private boolean autoIsolate = false;
private boolean blockNetwork = true;
private boolean terminateProcesses = false;
private int responseDelay = 5000;
// Getters and setters
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
public boolean isAutoIsolate() { return autoIsolate; }
public void setAutoIsolate(boolean autoIsolate) { this.autoIsolate = autoIsolate; }
public boolean isBlockNetwork() { return blockNetwork; }
public void setBlockNetwork(boolean blockNetwork) { this.blockNetwork = blockNetwork; }
public boolean isTerminateProcesses() { return terminateProcesses; }
public void setTerminateProcesses(boolean terminateProcesses) {
this.terminateProcesses = terminateProcesses;
}
public int getResponseDelay() { return responseDelay; }
public void setResponseDelay(int responseDelay) { this.responseDelay = responseDelay; }
}
// Getters and setters for main properties
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
public String getHost() { return host; }
public void setHost(String host) { this.host = host; }
public int getPort() { return port; }
public void setPort(int port) { this.port = port; }
public String getPriority() { return priority; }
public void setPriority(String priority) { this.priority = priority; }
public long getReconnectDelay() { return reconnectDelay; }
public void setReconnectDelay(long reconnectDelay) { this.reconnectDelay = reconnectDelay; }
public int getMaxRetries() { return maxRetries; }
public void setMaxRetries(int maxRetries) { this.maxRetries = maxRetries; }
public boolean isAsyncMode() { return asyncMode; }
public void setAsyncMode(boolean asyncMode) { this.asyncMode = asyncMode; }
public Alerting getAlerting() { return alerting; }
public void setAlerting(Alerting alerting) { this.alerting = alerting; }
public Kubernetes getKubernetes() { return kubernetes; }
public void setKubernetes(Kubernetes kubernetes) { this.kubernetes = kubernetes; }
public Response getResponse() { return response; }
public void setResponse(Response response) { this.response = response; }
}
Spring Boot Integration
@Configuration
@EnableConfigurationProperties(FalcoProperties.class)
public class FalcoAutoConfiguration {
@Bean
@ConditionalOnProperty(name = "falco.enabled", havingValue = "true")
public FalcoGrpcClient falcoGrpcClient(FalcoProperties properties,
FalcoEventProcessor eventProcessor) {
return new FalcoGrpcClient(properties, eventProcessor);
}
@Bean
public FalcoEventProcessor falcoEventProcessor(KubernetesClient k8sClient,
AlertService alertService,
SecurityIncidentService incidentService,
FalcoRulesEngine rulesEngine) {
return new FalcoEventProcessor(k8sClient, alertService, incidentService, rulesEngine);
}
@Bean
public KubernetesSecurityOperator kubernetesSecurityOperator(KubernetesClient k8sClient,
FalcoEventProcessor eventProcessor) {
return new KubernetesSecurityOperator(k8sClient, eventProcessor);
}
@Bean
public SecurityIncidentService securityIncidentService(IncidentRepository incidentRepository,
AlertService alertService,
KubernetesSecurityOperator k8sOperator) {
return new SecurityIncidentService(incidentRepository, alertService, k8sOperator);
}
@Bean
@ConditionalOnMissingBean
public KubernetesClient kubernetesClient() {
return new DefaultKubernetesClient();
}
@EventListener(ContextRefreshedEvent.class)
public void startFalcoSubscription() {
// Start Falco subscription when application context is ready
FalcoGrpcClient falcoClient = applicationContext.getBean(FalcoGrpcClient.class);
if (falcoClient != null) {
new Thread(() -> falcoClient.subscribeToEvents()).start();
}
}
}
Conclusion
This comprehensive Falco runtime security implementation provides:
- Real-time Security Monitoring - Continuous monitoring of system calls and Kubernetes audit events
- Automated Response - Immediate and automated responses to security threats
- Kubernetes Integration - Deep integration with Kubernetes for container security
- Incident Management - Complete security incident lifecycle management
- Alerting and Notification - Multi-channel alerting for security teams
- Policy Engine - Configurable security policies and response rules
- Spring Boot Integration - Seamless integration with Spring Boot applications
The implementation enables organizations to detect and respond to security threats in real-time, providing comprehensive runtime security for cloud-native applications.