mirror of
https://github.com/falcosecurity/falco.git
synced 2025-08-01 22:47:46 +00:00
Add an integration with Phantom (#411)
* Add a Phantom Client which creates containers in Phantom server * Add a playbook for creating events in Phantom using a Falco alert * Add a flag for configuring SSL checking * Add a deployable playbook with Kubeless for integrating with Phantom * Add a README for Phantom integration * Use named argument as real parameters. Just cosmetic for clarification * Call to lower() before checking for case insensitive comparison * Add the playbook which creates a container in Phantom I lose it when rebase the branch :P
This commit is contained in:
parent
6ca316a7cc
commit
8d60d374f7
@ -199,3 +199,18 @@ $ ./deploy_playbook -p capture -e CAPTURE_DURATION=300 -e AWS_S3_BUCKET=s3://xxx
|
||||
In this example, when we detect a shell in a container, we start to collect data
|
||||
for 300 seconds. This playbook requires permissions for creating a new pod from
|
||||
a Kubeless function.
|
||||
|
||||
### Create a container in Phantom
|
||||
This playbook creates a container in Phantom
|
||||
|
||||
```
|
||||
./deploy_playbook -p phantom -t "falco.*.*" -e PHANTOM_USER=user -e PHANTOM_PASSWORD=xxxXxxxX -e PHANTOM_BASE_URL=https://..."
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
* PHANTOM_USER: This is the user used to connect to Phantom
|
||||
* PHANTOM_PASSWORD: This is the password used to connect to Phantom
|
||||
* PHANTOM_BASE_URL: This is the base URL where your Phantom server lives on. Ensure there's no trailing slash.
|
||||
* VERIFY_SSL: Verify SSL certificates for HTTPS requests. By default is enabled.
|
||||
|
||||
In this example, when Falco raises any kind of alert, the alert will be created in Phantom.
|
||||
|
25
integrations/kubernetes-response-engine/playbooks/phantom.py
Normal file
25
integrations/kubernetes-response-engine/playbooks/phantom.py
Normal file
@ -0,0 +1,25 @@
|
||||
import sys
|
||||
import os.path
|
||||
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__))))
|
||||
|
||||
import os
|
||||
import playbooks
|
||||
from playbooks import infrastructure
|
||||
|
||||
|
||||
def _to_bool(value):
|
||||
return value.lower() in ('yes', 'true', '1')
|
||||
|
||||
|
||||
playbook = playbooks.CreateContainerInPhantom(
|
||||
infrastructure.PhantomClient(
|
||||
os.environ['PHANTOM_USER'],
|
||||
os.environ['PHANTOM_PASSWORD'],
|
||||
os.environ['PHANTOM_BASE_URL'],
|
||||
verify_ssl=_to_bool(os.environ.get('VERIFY_SSL', 'True'))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def handler(event, context):
|
||||
playbook.run(event['data'])
|
@ -158,3 +158,42 @@ class StartSysdigCaptureForContainer:
|
||||
self._s3_bucket,
|
||||
self._aws_access_key_id,
|
||||
self._aws_secret_access_key)
|
||||
|
||||
|
||||
class CreateContainerInPhantom:
|
||||
def __init__(self, phantom_client):
|
||||
self._phantom_client = phantom_client
|
||||
|
||||
def run(self, alert):
|
||||
container = self._build_container_from(alert)
|
||||
self._phantom_client.create_container(container)
|
||||
|
||||
return container
|
||||
|
||||
def _build_container_from(self, alert):
|
||||
return {
|
||||
'description': _output_from_alert(alert),
|
||||
'name': alert['rule'],
|
||||
'start_time': maya.parse(alert['time']).iso8601(),
|
||||
'severity': self._severity_from(alert['priority']),
|
||||
'label': 'events',
|
||||
'status': 'new',
|
||||
'data': {
|
||||
'container.id': alert['output_fields']['container.id'],
|
||||
'k8s.pod.name': alert['output_fields']['k8s.pod.name'],
|
||||
}
|
||||
}
|
||||
|
||||
def _severity_from(self, priority):
|
||||
return self._SEVERITIES.get(priority, 0)
|
||||
|
||||
_SEVERITIES = {
|
||||
'Emergency': 'high',
|
||||
'Alert': 'high',
|
||||
'Critical': 'high',
|
||||
'Error': 'medium',
|
||||
'Warning': 'medium',
|
||||
'Notice': 'low',
|
||||
'Informational': 'low',
|
||||
'Debug': 'low',
|
||||
}
|
||||
|
@ -243,3 +243,25 @@ class DemistoClient:
|
||||
'Accept': 'application/json',
|
||||
'Authorization': self._api_key,
|
||||
}
|
||||
|
||||
|
||||
class PhantomClient:
|
||||
def __init__(self, user, password, base_url, verify_ssl=True):
|
||||
self._user = user
|
||||
self._password = password
|
||||
self._base_url = base_url
|
||||
self._verify_ssl = verify_ssl
|
||||
|
||||
def create_container(self, container):
|
||||
response = requests.post(self._base_url + '/rest/container',
|
||||
data=json.dumps(container),
|
||||
auth=(self._user, self._password),
|
||||
verify=self._verify_ssl)
|
||||
|
||||
response_as_json = response.json()
|
||||
if 'success' in response_as_json:
|
||||
result = container.copy()
|
||||
result['id'] = response_as_json['id']
|
||||
return result
|
||||
|
||||
raise RuntimeError(response_as_json['message'])
|
||||
|
@ -0,0 +1,45 @@
|
||||
from mamba import description, it, before, context
|
||||
from expects import expect, be_none, raise_error
|
||||
|
||||
import os
|
||||
|
||||
from playbooks import infrastructure
|
||||
|
||||
|
||||
with description(infrastructure.PhantomClient) as self:
|
||||
with before.each:
|
||||
self.phantom_client = infrastructure.PhantomClient(
|
||||
os.environ['PHANTOM_USER'],
|
||||
os.environ['PHANTOM_PASSWORD'],
|
||||
os.environ['PHANTOM_BASE_URL'],
|
||||
verify_ssl=False
|
||||
)
|
||||
|
||||
with it('creates a container in Phantom Server'):
|
||||
container = {
|
||||
'name': 'My Container',
|
||||
'description': 'Useful description of this container.',
|
||||
'label': 'events',
|
||||
'run_automation': False,
|
||||
'severity': 'high',
|
||||
'status': 'new',
|
||||
'start_time': '2015-03-21T19:28:13.759Z',
|
||||
}
|
||||
|
||||
container = self.phantom_client.create_container(container)
|
||||
|
||||
expect(container['id']).not_to(be_none)
|
||||
|
||||
with context('when an error happens'):
|
||||
with it('raises an error'):
|
||||
container = {
|
||||
'description': 'Useful description of this container.',
|
||||
'label': 'events',
|
||||
'run_automation': False,
|
||||
'severity': 'high',
|
||||
'status': 'new',
|
||||
'start_time': '2015-03-21T19:28:13.759Z',
|
||||
}
|
||||
|
||||
expect(lambda: self.phantom_client.create_container(container))\
|
||||
.to(raise_error(RuntimeError))
|
@ -0,0 +1,63 @@
|
||||
from mamba import description, it, before, context
|
||||
from expects import expect, have_key
|
||||
|
||||
from doublex import Spy
|
||||
from doublex_expects import have_been_called_with
|
||||
|
||||
from playbooks import infrastructure
|
||||
import playbooks
|
||||
|
||||
|
||||
with description(playbooks.CreateContainerInPhantom) as self:
|
||||
with before.each:
|
||||
self.phantom_client = Spy(infrastructure.PhantomClient)
|
||||
self.playbook = playbooks.CreateContainerInPhantom(self.phantom_client)
|
||||
|
||||
self.alert = {
|
||||
"output": "10:22:15.576767292: Notice Unexpected setuid call by non-sudo, non-root program (user=bin cur_uid=2 parent=event_generator command=event_generator uid=root) k8s.pod=falco-event-generator-6fd89678f9-cdkvz container=1c76f49f40b4",
|
||||
"output_fields": {
|
||||
"container.id": "1c76f49f40b4",
|
||||
"evt.arg.uid": "root",
|
||||
"evt.time": 1527157335576767292,
|
||||
"k8s.pod.name": "falco-event-generator-6fd89678f9-cdkvz",
|
||||
"proc.cmdline": "event_generator ",
|
||||
"proc.pname": "event_generator",
|
||||
"user.name": "bin",
|
||||
"user.uid": 2
|
||||
},
|
||||
"priority": "Notice",
|
||||
"rule": "Non sudo setuid",
|
||||
"time": "2018-05-24T10:22:15.576767292Z"
|
||||
}
|
||||
|
||||
self.container = self.playbook.run(self.alert)
|
||||
|
||||
with it('creates the container in phantom'):
|
||||
expect(self.phantom_client.create_container).to(have_been_called_with(self.container))
|
||||
|
||||
with it('includes falco output'):
|
||||
falco_output = 'Unexpected setuid call by non-sudo, non-root program (user=bin cur_uid=2 parent=event_generator command=event_generator uid=root) k8s.pod=falco-event-generator-6fd89678f9-cdkvz container=1c76f49f40b4'
|
||||
|
||||
expect(self.container).to(have_key('description', falco_output))
|
||||
|
||||
with it('includes severity'):
|
||||
expect(self.container).to(have_key('severity', 'low'))
|
||||
|
||||
with it('includes rule name'):
|
||||
expect(self.container).to(have_key('name', 'Non sudo setuid'))
|
||||
|
||||
with it('includes time when alert happened'):
|
||||
expect(self.container).to(have_key('start_time', '2018-05-24T10:22:15.576767Z'))
|
||||
|
||||
with it('includes label'):
|
||||
expect(self.container).to(have_key('label', 'events'))
|
||||
|
||||
with it('includes status'):
|
||||
expect(self.container).to(have_key('status', 'new'))
|
||||
|
||||
with context('when building additional data'):
|
||||
with it('includes kubernetes pod name'):
|
||||
expect(self.container['data']).to(have_key('k8s.pod.name', 'falco-event-generator-6fd89678f9-cdkvz'))
|
||||
|
||||
with it('includes container id'):
|
||||
expect(self.container['data']).to(have_key('container.id', '1c76f49f40b4'))
|
Loading…
Reference in New Issue
Block a user