-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: New ActivityAuditClientV1 to query Activity Audit events (#197)
* feat: New ActivityAuditClientV1 to query Activity Audit events * chore: Deprecate old command audit methods * refactor: Import datetime package directly * fix(lint): Solve linting problems * fix(ci): Change the image to scan to quay.io/sysdig/agent
- Loading branch information
1 parent
5a93a4c
commit ff1f2d6
Showing
6 changed files
with
219 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
from ._activity_audit_v1 import ActivityAuditClientV1, ActivityAuditDataSource | ||
from ._falco_rules_files_old import FalcoRulesFilesClientOld | ||
from ._policy_events_old import PolicyEventsClientOld | ||
from ._policy_events_v1 import PolicyEventsClientV1 | ||
from ._policy_v2 import PolicyClientV2, policy_action_pause, policy_action_stop, policy_action_kill, \ | ||
policy_action_capture | ||
from ._policy_v2 import policy_action_capture, policy_action_kill, policy_action_pause, policy_action_stop, \ | ||
PolicyClientV2 | ||
|
||
__all__ = ["PolicyEventsClientOld", "PolicyEventsClientV1", "FalcoRulesFilesClientOld", | ||
"PolicyClientV2", "policy_action_pause", "policy_action_stop", "policy_action_kill", "policy_action_capture"] | ||
"PolicyClientV2", "policy_action_pause", "policy_action_stop", "policy_action_kill", "policy_action_capture", | ||
"ActivityAuditClientV1", "ActivityAuditDataSource"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
import datetime | ||
|
||
from sdcclient._common import _SdcCommon | ||
|
||
|
||
class ActivityAuditDataSource: | ||
CMD = "command" | ||
NET = "connection" | ||
KUBE_EXEC = "kubernetes" | ||
FILE = "fileaccess" | ||
|
||
|
||
_seconds_to_nanoseconds = 10 ** 9 | ||
|
||
|
||
class ActivityAuditClientV1(_SdcCommon): | ||
def __init__(self, token="", sdc_url='https://secure.sysdig.com', ssl_verify=True, custom_headers=None): | ||
super(ActivityAuditClientV1, self).__init__(token, sdc_url, ssl_verify, custom_headers) | ||
self.product = "SDS" | ||
|
||
def list_events(self, from_date=None, to_date=None, scope_filter=None, limit=0, | ||
data_sources=None): | ||
""" | ||
List the events in the Activity Audit. | ||
Args: | ||
from_date (datetime.datetime): the start of the time range from which to get events. The default value is yesterday. | ||
to_date (datetime.datetime): the end of the time range from which to get events. The default value is now. | ||
scope_filter (List): a list of Sysdig Monitor-like filter (e.g `processName in ("ubuntu")`). | ||
limit (int): max number of events to retrieve. A limit of 0 or negative will retrieve all events. | ||
data_sources (List): a list of data sources to retrieve events from. None or an empty list retrieves all events. | ||
Examples: | ||
>>> client = ActivityAuditClientV1(token=SECURE_TOKEN) | ||
>>> | ||
>>> now = datetime.datetime.utcnow() | ||
>>> three_days_ago = now - datetime.timedelta(days=3) | ||
>>> max_event_number_retrieved = 50 | ||
>>> data_sources = [ActivityAuditDataSource.CMD, ActivityAuditDataSource.KUBE_EXEC] | ||
>>> | ||
>>> ok, events = client.list_events(from_date=three_days_ago, | ||
>>> to_date=now, | ||
>>> limit=max_event_number_retrieved, | ||
>>> data_sources=data_sources) | ||
Returns: | ||
A list of event objects from the Activity Audit. | ||
""" | ||
number_of_events_per_query = 50 | ||
|
||
if from_date is None: | ||
from_date = datetime.datetime.utcnow() - datetime.timedelta(days=1) | ||
if to_date is None: | ||
to_date = datetime.datetime.utcnow() | ||
|
||
filters = scope_filter if scope_filter else [] | ||
if data_sources: | ||
quoted_data_sources = [f'"{data_source}"' for data_source in data_sources] | ||
data_source_filter = f'type in ({",".join(quoted_data_sources)})' | ||
filters.append(data_source_filter) | ||
|
||
query_params = { | ||
"from": int(from_date.timestamp()) * _seconds_to_nanoseconds, | ||
"to": int(to_date.timestamp()) * _seconds_to_nanoseconds, | ||
"limit": number_of_events_per_query, | ||
"filter": " and ".join(filters), | ||
} | ||
|
||
res = self.http.get(self.url + '/api/v1/activityAudit/events', headers=self.hdrs, verify=self.ssl_verify, | ||
params=query_params) | ||
ok, res = self._request_result(res) | ||
if not ok: | ||
return False, res | ||
|
||
events = [] | ||
|
||
# Pagination required by Secure API | ||
while "page" in res and \ | ||
"total" in res["page"] and \ | ||
res["page"]["total"] > number_of_events_per_query: | ||
events = events + res["data"] | ||
|
||
if 0 < limit < len(events): | ||
events = events[0:limit - 1] | ||
break | ||
|
||
paginated_query_params = { | ||
"limit": number_of_events_per_query, | ||
"filter": " and ".join(filters), | ||
"cursor": res["page"]["prev"] | ||
} | ||
|
||
res = self.http.get(self.url + '/api/v1/activityAudit/events', headers=self.hdrs, verify=self.ssl_verify, | ||
params=paginated_query_params) | ||
ok, res = self._request_result(res) | ||
if not ok: | ||
return False, res | ||
else: | ||
events = events + res["data"] | ||
|
||
return True, events | ||
|
||
def list_trace(self, traceable_event): | ||
""" | ||
Lists the events from an original traceable event. | ||
Args: | ||
traceable_event(object): an event retrieved from the list_events method. The event must be traceable, | ||
this is, it must have the "traceable" key as true. | ||
Examples: | ||
>>> client = ActivityAuditClientV1(token=SECURE_TOKEN) | ||
>>> | ||
>>> ok, events = client.list_events() | ||
>>> if not ok: | ||
>>> return | ||
>>> traceable_events = [event for event in events if event["traceable"]] | ||
>>> | ||
>>> ok, trace = client.list_trace(traceable_events[0]) | ||
>>> if not ok: | ||
>>> return | ||
>>> | ||
>>> for event in trace: | ||
>>> print(event) | ||
Returns: | ||
All the related events that are the trace of the given event. | ||
""" | ||
if not traceable_event or not traceable_event["traceable"]: | ||
return False, "a traceable event must be provided" | ||
|
||
endpoint = f'/api/v1/activityAudit/events/{traceable_event["type"]}/{traceable_event["id"]}/trace' | ||
res = self.http.get(self.url + endpoint, headers=self.hdrs, verify=self.ssl_verify) | ||
ok, res = self._request_result(res) | ||
if not ok: | ||
return False, res | ||
return True, res["data"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import datetime | ||
import os | ||
|
||
from expects import be_above, be_empty, contain, expect, have_keys, have_len | ||
from mamba import _it, before, context, description, it | ||
|
||
from sdcclient.secure import ActivityAuditClientV1 as ActivityAuditClient, ActivityAuditDataSource | ||
from specs import be_successful_api_call | ||
|
||
with description("Activity Audit v1", "integration") as self: | ||
with before.all: | ||
self.client = ActivityAuditClient(sdc_url=os.getenv("SDC_SECURE_URL", "https://secure.sysdig.com"), | ||
token=os.getenv("SDC_SECURE_TOKEN")) | ||
|
||
with it("is able to list the most recent commands with the default parameters"): | ||
ok, res = self.client.list_events() | ||
|
||
expect((ok, res)).to(be_successful_api_call) | ||
expect(res).to_not(be_empty) | ||
|
||
with context("when listing the most recent commands with a limit of 5"): | ||
with it("retrieves the 5 events"): | ||
ok, res = self.client.list_events(limit=5) | ||
|
||
expect((ok, res)).to(be_successful_api_call) | ||
expect(res).to_not(have_len(5)) | ||
|
||
with context("when listing the events from the last 3 days"): | ||
with it("retrieves all the events"): | ||
three_days_ago = datetime.datetime.utcnow() - datetime.timedelta(days=3) | ||
ok, res = self.client.list_events(from_date=three_days_ago) | ||
|
||
expect((ok, res)).to(be_successful_api_call) | ||
expect(res).to_not(be_empty) | ||
|
||
with context("when listing events from a specific type"): | ||
with it("retrieves the events of this event type only"): | ||
ok, res = self.client.list_events(data_sources=[ActivityAuditDataSource.CMD]) | ||
|
||
expect((ok, res)).to(be_successful_api_call) | ||
expect(res).to(contain(have_keys(type=ActivityAuditDataSource.CMD))) | ||
expect(res).to_not(contain(have_keys(type=ActivityAuditDataSource.KUBE_EXEC))) | ||
expect(res).to_not(contain(have_keys(type=ActivityAuditDataSource.FILE))) | ||
expect(res).to_not(contain(have_keys(type=ActivityAuditDataSource.NET))) | ||
|
||
with context("when retrieving the inner events of a traceable event"): | ||
with _it("retrieves the trace of these events"): | ||
ok, res = self.client.list_events(data_sources=[ActivityAuditDataSource.KUBE_EXEC]) | ||
expect((ok, res)).to(be_successful_api_call) | ||
|
||
expect(res).to(contain(have_keys(traceable=True))) | ||
|
||
traceable_events = [event for event in res if event["traceable"]] | ||
ok, res = self.client.list_trace(traceable_events[0]) | ||
|
||
expect((ok, res)).to(be_successful_api_call) | ||
expect(res).to(contain(have_keys(type=ActivityAuditDataSource.CMD))) | ||
expect(res).to(have_len(be_above(0))) # Not using be_empty, because we want to ensure this is a list |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters