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

Introduce aws_sqs backend #129

Merged
merged 3 commits into from
Sep 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Currently available backends are:
| Backend | Description | Deployment Guide(s) | Developer Guide(s) |
|:--------|:------------|:--------------------|:-------------------|
| AWS | Pushes events to AWS Security Hub | *Coming Soon* | [AWS backend](fig/backends/aws) |
| AWS_SQS | Pushes events to AWS SQS | *Coming Soon* | [AWS SQS backend](fig/backends/aws_sqs) |
| Azure | Pushes events to Azure Log Analytics | <ul><li>[Deployment to AKS](docs/aks)</li></ul> | [Azure backend](fig/backends/azure) |
| Chronicle | Pushes events to Google Chronicle | <ul><li>[Deployment to GKE](docs/listings/gke-chronicle/UserGuide.md) (using [marketplace](https://console.cloud.google.com/marketplace/product/crowdstrike-saas/falcon-integration-gateway-chronicle))</li><li>[Deployment to GKE](docs/chronicle) (manual)</li></ul> | [Chronicle backend](fig/backends/chronicle) |
| GCP | Pushes events to GCP Security Command Center | <ul><li>[Deployment to GKE](docs/listings/gke/UserGuide.md) (using [marketplace](https://console.cloud.google.com/marketplace/product/crowdstrike-saas/falcon-integration-gateway-scc))</li><li>[Deployment to GKE](docs/gke) (manual)</li></ul> | [GCP backend](fig/backends/gcp) |
Expand Down
11 changes: 11 additions & 0 deletions config/config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,21 @@

[aws]
# AWS section is applicable only when AWS backend is enabled in the [main] section.
# AWS Backend publishes Falcon Detection events to AWS Security Hub

# Uncomment to provide aws region. Alternatively, use AWS_REGION env variable
#region = eu-west-1

[aws_sqs]
# AWS SQS section is applicable only when AWS backend is enabled in the [main] section.
# AWS SQS Backend publishes raw events to SQS queue

# Uncomment to provide AWS region. Alternatively, use AWS_REGION env variable
#region = eu-west-1

# Uncomment to provide name of AWS SQS. Alternatively, use AWS_SQS env variable
#sqs_queue_name = my-sqs-queue-for-falcon

[workspaceone]
# Workspace One section is applicable only when Workspace One backend is enabled in the [main] section.

Expand Down
3 changes: 3 additions & 0 deletions config/defaults.ini
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ primary_key =

[aws]
region =

[aws_sqs]
region =
sqs_queue_name =

[workspaceone]
Expand Down
6 changes: 5 additions & 1 deletion fig/backends/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from fig.backends import chronicle
from . import aws
from . import aws_sqs
from . import azure
from . import gcp
from . import workspaceone
Expand All @@ -8,6 +9,7 @@

ALL_BACKENDS = {
'AWS': aws,
'AWS_SQS': aws_sqs,
'AZURE': azure,
'GCP': gcp,
'WORKSPACEONE': workspaceone,
Expand All @@ -25,9 +27,11 @@ def __init__(self):

def process(self, falcon_event):
for runtime in self.runtimes:
if falcon_event.original_event.event_type in runtime.RELEVANT_EVENT_TYPES and runtime.is_relevant(falcon_event):
if (runtime.RELEVANT_EVENT_TYPES == "ALL" or falcon_event.original_event.event_type in runtime.RELEVANT_EVENT_TYPES) and runtime.is_relevant(falcon_event):
runtime.process(falcon_event)

@property
def relevant_event_types(self):
if any(r.RELEVANT_EVENT_TYPES == "ALL" for r in self.runtimes):
return None
return set(typ for r in self.runtimes for typ in r.RELEVANT_EVENT_TYPES)
39 changes: 39 additions & 0 deletions fig/backends/aws_sqs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# AWS SQS Backend

Integration with AWS SQS -- pushes raw events from CrowdStrike event stream to AWS SQS. Deduplication of the events is done on SQS side.

### Example Configuration file

[config/config.ini](https://github.com/CrowdStrike/falcon-integration-gateway/blob/main/config/config.ini) configures Falcon Integration Gateway. Below is a minimal configuration example for AWS SQS backend:
```
[main]
# Cloud backends that are enabled. The gateway will push events to the cloud providers specified below
backends=AWS_SQS

[aws_sqs]
# AWS section is applicable only when AWS backend is enabled in the [main] section.

# Uncomment to provide aws region. Alternatively, use AWS_REGION env variable
#region=eu-west-1

# Uncomment to provide name of AWS SQS. Alternatively, use AWS_SQS env variable
#sqs_queue_name = my-sqs-queue-for-falcon
```

### Developer Guide

- Build the image
```
docker build . -t falcon-integration-gateway
```
- Run the application
```
docker run -it --rm \
-e FALCON_CLIENT_ID="$FALCON_CLIENT_ID" \
-e FALCON_CLIENT_SECRET="$FALCON_CLIENT_SECRET" \
-e FALCON_CLOUD_REGION="us-1" \
-e AWS_SQS=my-queue \
-e AWS_REGION=mars-west-2 \
-v ~/.aws:/fig/.aws \
falcon-integration-gateway:latest
```
63 changes: 63 additions & 0 deletions fig/backends/aws_sqs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import json
from functools import lru_cache
import boto3
from botocore.exceptions import ClientError
from ...config import config
from ...log import log


class Submitter():
def __init__(self):
aws_region = config.get('aws_sqs', 'region')
log.debug("Attempting to connect to AWS (region %s) SQS: %s", aws_region, self.sqs_queue_name)
try:
aws_client = boto3.resource('sqs', region_name=aws_region)
self.queue = aws_client.get_queue_by_name(QueueName=self.sqs_queue_name)
except ClientError: # pylint: disable=W0703
log.exception("Cannot configure AWS SQS Queue: %s in %s", aws_region, self.sqs_queue_name)
self.queue = None
raise

def submit(self, event):
eoe = event.original_event
if self.is_fifo:
feed_id = getattr(eoe, 'feed_id') if hasattr(eoe, 'feed_id') else 0
self.queue.send_message(
MessageGroupId="fig/%s/%s" % (self.app_id, feed_id),
MessageDeduplicationId=str(eoe.offset),
MessageBody=json.dumps(eoe)
)
else:
self.queue.send_message(MessageBody=json.dumps(eoe))

@property
@lru_cache
def is_fifo(self):
return self.sqs_queue_name.endswith('.fifo')

@property
@lru_cache
def sqs_queue_name(self):
return config.get('aws_sqs', 'sqs_queue_name')

@property
@lru_cache
def app_id(self):
return config.get('falcon', 'application_id')


class Runtime():
RELEVANT_EVENT_TYPES = "ALL"

def __init__(self):
log.info("AWS SQS Backend is enabled.")
self.submitter = Submitter()

def is_relevant(self, falcon_event):
return True

def process(self, falcon_event):
self.submitter.submit(falcon_event)


__all__ = ['Runtime']
9 changes: 8 additions & 1 deletion fig/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


class FigConfig(configparser.SafeConfigParser):
ALL_BACKENDS = {'AWS', 'AZURE', 'GCP', 'WORKSPACEONE', 'CHRONICLE'}
ALL_BACKENDS = {'AWS', 'AWS_SQS', 'AZURE', 'GCP', 'WORKSPACEONE', 'CHRONICLE'}
FALCON_CLOUD_REGIONS = {'us-1', 'us-2', 'eu-1', 'us-gov-1'}
ENV_DEFAULTS = [
['falcon', 'cloud_region', 'FALCON_CLOUD_REGION'],
Expand All @@ -12,6 +12,8 @@ class FigConfig(configparser.SafeConfigParser):
['azure', 'workspace_id', 'WORKSPACE_ID'],
['azure', 'primary_key', 'PRIMARY_KEY'],
['aws', 'region', 'AWS_REGION'],
['aws_sqs', 'region', 'AWS_REGION'],
['aws_sqs', 'sqs_queue_name', 'AWS_SQS'],
['workspaceone', 'token', 'WORKSPACEONE_TOKEN'],
['workspaceone', 'syslog_host', 'SYSLOG_HOST'],
['workspaceone', 'syslog_port', 'SYSLOG_PORT'],
Expand Down Expand Up @@ -65,6 +67,11 @@ def validate_backends(self):
if 'AWS' in self.backends:
if len(self.get('aws', 'region')) == 0:
raise Exception('Malformed Configuration: expected aws.region to be non-empty')
if 'AWS_SQS' in self.backends:
if len(self.get('aws_sqs', 'region')) == 0:
raise Exception('Malformed Configuration: expected aws_sqs.region to be non-empty')
if len(self.get('aws_sqs', 'sqs_queue_name')) == 0:
raise Exception('Malformed Configuration: expected aws_sqs.sqs_queue_name to be non-empty')
if 'WORKSPACEONE' in self.backends:
if len(self.get('workspaceone', 'token')) == 0:
raise Exception('Malformed Configuration: expected workspaceone.token to be non-empty')
Expand Down
2 changes: 1 addition & 1 deletion fig/falcon/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def run(self):

def process_event(self, event):
event = Event(event)
if event.event_type in self.relevant_event_types and not event.irrelevant():
if (self.relevant_event_types is None or event.event_type in self.relevant_event_types) and not event.irrelevant():
self.queue.put(event)


Expand Down