|  | 
|  | 1 | +import datetime | 
|  | 2 | + | 
|  | 3 | +from sdcclient._common import _SdcCommon | 
|  | 4 | + | 
|  | 5 | + | 
|  | 6 | +class ActivityAuditDataSource: | 
|  | 7 | +    CMD = "command" | 
|  | 8 | +    NET = "connection" | 
|  | 9 | +    KUBE_EXEC = "kubernetes" | 
|  | 10 | +    FILE = "fileaccess" | 
|  | 11 | + | 
|  | 12 | + | 
|  | 13 | +_seconds_to_nanoseconds = 10 ** 9 | 
|  | 14 | + | 
|  | 15 | + | 
|  | 16 | +class ActivityAuditClientV1(_SdcCommon): | 
|  | 17 | +    def __init__(self, token="", sdc_url='https://secure.sysdig.com', ssl_verify=True, custom_headers=None): | 
|  | 18 | +        super(ActivityAuditClientV1, self).__init__(token, sdc_url, ssl_verify, custom_headers) | 
|  | 19 | +        self.product = "SDS" | 
|  | 20 | + | 
|  | 21 | +    def list_events(self, from_date=None, to_date=None, scope_filter=None, limit=0, | 
|  | 22 | +                    data_sources=None): | 
|  | 23 | +        """ | 
|  | 24 | +        List the events in the Activity Audit. | 
|  | 25 | +
 | 
|  | 26 | +        Args: | 
|  | 27 | +            from_date (datetime.datetime): the start of the time range from which to get events. The default value is yesterday. | 
|  | 28 | +            to_date (datetime.datetime): the end of the time range from which to get events. The default value is now. | 
|  | 29 | +            scope_filter (List): a list of Sysdig Monitor-like filter (e.g `processName in ("ubuntu")`). | 
|  | 30 | +            limit (int): max number of events to retrieve. A limit of 0 or negative will retrieve all events. | 
|  | 31 | +            data_sources (List): a list of data sources to retrieve events from. None or an empty list retrieves all events. | 
|  | 32 | +
 | 
|  | 33 | +        Examples: | 
|  | 34 | +            >>> client = ActivityAuditClientV1(token=SECURE_TOKEN) | 
|  | 35 | +            >>> | 
|  | 36 | +            >>> now = datetime.datetime.utcnow() | 
|  | 37 | +            >>> three_days_ago = now - datetime.timedelta(days=3) | 
|  | 38 | +            >>> max_event_number_retrieved = 50 | 
|  | 39 | +            >>> data_sources = [ActivityAuditDataSource.CMD, ActivityAuditDataSource.KUBE_EXEC] | 
|  | 40 | +            >>> | 
|  | 41 | +            >>> ok, events = client.list_events(from_date=three_days_ago, | 
|  | 42 | +            >>>                                 to_date=now, | 
|  | 43 | +            >>>                                 limit=max_event_number_retrieved, | 
|  | 44 | +            >>>                                 data_sources=data_sources) | 
|  | 45 | +
 | 
|  | 46 | +        Returns: | 
|  | 47 | +            A list of event objects from the Activity Audit. | 
|  | 48 | +        """ | 
|  | 49 | +        number_of_events_per_query = 50 | 
|  | 50 | + | 
|  | 51 | +        if from_date is None: | 
|  | 52 | +            from_date = datetime.datetime.utcnow() - datetime.timedelta(days=1) | 
|  | 53 | +        if to_date is None: | 
|  | 54 | +            to_date = datetime.datetime.utcnow() | 
|  | 55 | + | 
|  | 56 | +        filters = scope_filter if scope_filter else [] | 
|  | 57 | +        if data_sources: | 
|  | 58 | +            quoted_data_sources = [f'"{data_source}"' for data_source in data_sources] | 
|  | 59 | +            data_source_filter = f'type in ({",".join(quoted_data_sources)})' | 
|  | 60 | +            filters.append(data_source_filter) | 
|  | 61 | + | 
|  | 62 | +        query_params = { | 
|  | 63 | +            "from": int(from_date.timestamp()) * _seconds_to_nanoseconds, | 
|  | 64 | +            "to": int(to_date.timestamp()) * _seconds_to_nanoseconds, | 
|  | 65 | +            "limit": number_of_events_per_query, | 
|  | 66 | +            "filter": " and ".join(filters), | 
|  | 67 | +        } | 
|  | 68 | + | 
|  | 69 | +        res = self.http.get(self.url + '/api/v1/activityAudit/events', headers=self.hdrs, verify=self.ssl_verify, | 
|  | 70 | +                            params=query_params) | 
|  | 71 | +        ok, res = self._request_result(res) | 
|  | 72 | +        if not ok: | 
|  | 73 | +            return False, res | 
|  | 74 | + | 
|  | 75 | +        events = [] | 
|  | 76 | + | 
|  | 77 | +        # Pagination required by Secure API | 
|  | 78 | +        while "page" in res and \ | 
|  | 79 | +                "total" in res["page"] and \ | 
|  | 80 | +                res["page"]["total"] > number_of_events_per_query: | 
|  | 81 | +            events = events + res["data"] | 
|  | 82 | + | 
|  | 83 | +            if 0 < limit < len(events): | 
|  | 84 | +                events = events[0:limit - 1] | 
|  | 85 | +                break | 
|  | 86 | + | 
|  | 87 | +            paginated_query_params = { | 
|  | 88 | +                "limit": number_of_events_per_query, | 
|  | 89 | +                "filter": " and ".join(filters), | 
|  | 90 | +                "cursor": res["page"]["prev"] | 
|  | 91 | +            } | 
|  | 92 | + | 
|  | 93 | +            res = self.http.get(self.url + '/api/v1/activityAudit/events', headers=self.hdrs, verify=self.ssl_verify, | 
|  | 94 | +                                params=paginated_query_params) | 
|  | 95 | +            ok, res = self._request_result(res) | 
|  | 96 | +            if not ok: | 
|  | 97 | +                return False, res | 
|  | 98 | +        else: | 
|  | 99 | +            events = events + res["data"] | 
|  | 100 | + | 
|  | 101 | +        return True, events | 
|  | 102 | + | 
|  | 103 | +    def list_trace(self, traceable_event): | 
|  | 104 | +        """ | 
|  | 105 | +        Lists the events from an original traceable event. | 
|  | 106 | +
 | 
|  | 107 | +        Args: | 
|  | 108 | +            traceable_event(object): an event retrieved from the list_events method. The event must be traceable, | 
|  | 109 | +                                     this is, it must have the "traceable" key as true. | 
|  | 110 | +
 | 
|  | 111 | +        Examples: | 
|  | 112 | +            >>> client = ActivityAuditClientV1(token=SECURE_TOKEN) | 
|  | 113 | +            >>> | 
|  | 114 | +            >>> ok, events = client.list_events() | 
|  | 115 | +            >>> if not ok: | 
|  | 116 | +            >>>     return | 
|  | 117 | +            >>> traceable_events = [event for event in events if event["traceable"]] | 
|  | 118 | +            >>> | 
|  | 119 | +            >>> ok, trace = client.list_trace(traceable_events[0]) | 
|  | 120 | +            >>> if not ok: | 
|  | 121 | +            >>>     return | 
|  | 122 | +            >>> | 
|  | 123 | +            >>> for event in trace: | 
|  | 124 | +            >>>     print(event) | 
|  | 125 | +
 | 
|  | 126 | +        Returns: | 
|  | 127 | +            All the related events that are the trace of the given event. | 
|  | 128 | +        """ | 
|  | 129 | +        if not traceable_event or not traceable_event["traceable"]: | 
|  | 130 | +            return False, "a traceable event must be provided" | 
|  | 131 | + | 
|  | 132 | +        endpoint = f'/api/v1/activityAudit/events/{traceable_event["type"]}/{traceable_event["id"]}/trace' | 
|  | 133 | +        res = self.http.get(self.url + endpoint, headers=self.hdrs, verify=self.ssl_verify) | 
|  | 134 | +        ok, res = self._request_result(res) | 
|  | 135 | +        if not ok: | 
|  | 136 | +            return False, res | 
|  | 137 | +        return True, res["data"] | 
0 commit comments