@@ -66,6 +66,13 @@ def main(mytimer: func.TimerRequest) -> None:
6666 logging .info ('Script is running too long. Saving progress and exit.' )
6767 return
6868
69+ if 'activity' in log_types :
70+ state_manager = StateManager (FILE_SHARE_CONN_STRING , file_path = 'cisco_duo_activity_logs_last_ts.txt' )
71+ process_activity_logs (admin_api , start_ts , state_manager = state_manager , sentinel = sentinel )
72+ if check_if_script_runs_too_long (start_ts ):
73+ logging .info ('Script is running too long. Saving progress and exit.' )
74+ return
75+
6976 if 'administrator' in log_types :
7077 state_manager = StateManager (FILE_SHARE_CONN_STRING , file_path = 'cisco_duo_admin_logs_last_ts.txt' )
7178 process_admin_logs (admin_api , start_ts , state_manager = state_manager , sentinel = sentinel )
@@ -90,7 +97,7 @@ def main(mytimer: func.TimerRequest) -> None:
9097def get_log_types ():
9198 res = str (os .environ .get ('CISCO_DUO_LOG_TYPES' , '' ))
9299 if not res :
93- res = 'trust_monitor,authentication,administrator,telephony,offline_enrollment'
100+ res = 'trust_monitor,authentication,administrator,telephony,offline_enrollment,activity '
94101 return [x .lower ().strip () for x in res .split (',' )]
95102
96103
@@ -290,86 +297,6 @@ def get_admin_logs(admin_api: duo_client.Admin, mintime: int) -> Iterable[dict]:
290297 events = None
291298 return events
292299
293- def process_tele_logs (admin_api : duo_client .Admin , start_ts , state_manager : StateManager , sentinel : AzureSentinelConnector ) -> None :
294- limit = 1000
295- logging .info ('Start processing telephony logs' )
296-
297- logging .info ('Getting last timestamp' )
298- mintime = state_manager .get ()
299- if mintime :
300- logging .info ('Last timestamp is {}' .format (mintime ))
301- mintime = int (mintime ) + 1
302- else :
303- logging .info ('Last timestamp is not known. Getting data for last 24h' )
304- mintime = int (time .time () - 86400 )
305-
306- last_ts = None
307-
308- events = get_tele_logs (admin_api , mintime )
309-
310- for event in events :
311- last_ts = event ['timestamp' ]
312- sentinel .send (event )
313-
314- sentinel .flush ()
315-
316- if last_ts :
317- logging .info ('Saving telephony logs last timestamp {}' .format (last_ts ))
318- state_manager .post (str (last_ts ))
319-
320- while len (events ) == limit :
321- mintime = last_ts
322- mintime += 1
323- logging .info ('Making telephony logs request: mintime={}' .format (mintime ))
324- try :
325- events = admin_api .get_telephony_log (mintime )
326- except Exception as ex :
327- logging .info ('Error while getting telephony logs - {}' .format (ex ))
328- if ex .status == 429 :
329- logging .info ('429 exception occurred, trying retry after 60 seconds' )
330- time .sleep (60 )
331- events = admin_api .get_telephony_log (mintime )
332-
333- if (events is not None ):
334- logging .info ('Obtained {} tele events' .format (len (events )))
335-
336- else :
337- logging .info ('Events returned as null in telephony logs' )
338-
339- for event in events :
340- last_ts = event ['timestamp' ]
341- sentinel .send (event )
342-
343- sentinel .flush ()
344-
345- if last_ts :
346- logging .info ('Saving telephony logs last timestamp {}' .format (last_ts ))
347- state_manager .post (str (last_ts ))
348-
349- if check_if_script_runs_too_long (start_ts ):
350- logging .info ('Script is running too long. Saving progress and exit.' )
351- return
352-
353-
354- def get_tele_logs (admin_api : duo_client .Admin , mintime : int ) -> Iterable [dict ]:
355- limit = 1000
356- logging .info ('Making telephony logs request: mintime={}' .format (mintime ))
357- try :
358- events = admin_api .get_telephony_log (mintime )
359- except Exception as err :
360- logging .info ('Error while getting telephony logs - {}' .format (err ))
361- if err .status == 429 :
362- logging .info ('429 exception occurred, trying retry after 60 seconds' )
363- time .sleep (60 )
364- events = admin_api .get_telephony_log (mintime )
365-
366- if (events is not None ):
367- logging .info ('Obtained {} tele events' .format (len (events )))
368- else :
369- logging .info ('Error while getting telephony logs' )
370- events = None
371- return events
372-
373300
374301def process_offline_enrollment_logs (admin_api : duo_client .Admin , start_ts , state_manager : StateManager , sentinel : AzureSentinelConnector ) -> None :
375302 limit = 1000
@@ -470,3 +397,137 @@ def check_if_script_runs_too_long(start_ts):
470397 max_duration = int (MAX_SCRIPT_EXEC_TIME_MINUTES * 60 * 0.85 )
471398 return duration > max_duration
472399
400+
401+ def process_activity_logs (admin_api : duo_client .Admin , start_ts , state_manager : StateManager , sentinel : AzureSentinelConnector ) -> None :
402+ limit = 1000
403+ logging .info ('Start processing activity logs' )
404+
405+ logging .info ('Getting last timestamp' )
406+ mintime = state_manager .get ()
407+ if mintime :
408+ logging .info ('Last timestamp is {}' .format (mintime ))
409+ mintime = int (mintime ) + 1
410+ else :
411+ logging .info ('Last timestamp is not known. Getting data for last 24h' )
412+ mintime = int (time .time () - 86400 ) * 1000
413+
414+ maxtime = int (time .time () - 120 ) * 1000
415+ diff = maxtime - mintime
416+ maxwindow = int (MAX_SYNC_WINDOW_PER_RUN_MINUTES ) * 60000
417+ if diff > maxwindow :
418+ maxtime = mintime + maxwindow
419+ logging .warn ('Ingestion is lagging for activity logs, limiting synchronization window to {}' .format (maxwindow ))
420+
421+ next_offset = None
422+ while True :
423+ events , next_offset = get_activity_logs (admin_api , mintime , maxtime , limit , next_offset )
424+ for event in events :
425+ sentinel .send (event )
426+ sentinel .flush ()
427+ logging .info ('Saving activity logs last timestamp {}' .format (maxtime ))
428+ state_manager .post (str (maxtime ))
429+ if not events :
430+ break
431+ if len (events ) < limit or check_if_script_runs_too_long (start_ts ):
432+ if check_if_script_runs_too_long (start_ts ):
433+ logging .info ('Script is running too long. Saving progress and exit.' )
434+ break
435+
436+ def get_activity_logs (admin_api : duo_client .Admin , mintime : int , maxtime : int , limit = 1000 , next_offset = None ):
437+ logging .info ('Making activity logs request: mintime={}, maxtime={}, next_offset={}' .format (mintime , maxtime , next_offset ))
438+ try :
439+ params = {
440+ 'api_version' : 2 ,
441+ 'mintime' : mintime ,
442+ 'maxtime' : maxtime ,
443+ 'limit' : str (limit ),
444+ 'sort' : 'ts:asc'
445+ }
446+ if next_offset :
447+ params ['next_offset' ] = next_offset
448+ res = admin_api .get_activity_logs (** params )
449+ except Exception as err :
450+ logging .info ('Error while getting activity logs- {}' .format (err ))
451+ if hasattr (err , 'status' ) and err .status == 429 :
452+ logging .info ('429 exception occurred, trying retry after 60 seconds' )
453+ time .sleep (60 )
454+ res = admin_api .get_activity_logs (** params )
455+ else :
456+ return [], None
457+
458+ if res is not None :
459+ events = res .get ('items' , [])
460+ next_offset = res .get ('metadata' , {}).get ('next_offset' )
461+ logging .info ('Obtained {} activity events' .format (len (events )))
462+ else :
463+ logging .info ('Error while getting activity logs' )
464+ events = []
465+ next_offset = None
466+ return events , next_offset
467+
468+
469+ def process_tele_logs (admin_api : duo_client .Admin , start_ts , state_manager : StateManager , sentinel : AzureSentinelConnector ) -> None :
470+ limit = 1000
471+ logging .info ('Start processing telephony v2 logs' )
472+ logging .info ('Getting last timestamp' )
473+ mintime = state_manager .get ()
474+ if mintime :
475+ logging .info ('Last timestamp is {}' .format (mintime ))
476+ mintime = int (mintime ) + 1
477+ else :
478+ logging .info ('Last timestamp is not known. Getting data for last 24h' )
479+ mintime = int (time .time () - 86400 ) * 1000
480+
481+ maxtime = int (time .time () - 120 ) * 1000
482+ diff = maxtime - mintime
483+ maxwindow = int (MAX_SYNC_WINDOW_PER_RUN_MINUTES ) * 60000
484+ if diff > maxwindow :
485+ maxtime = mintime + maxwindow
486+ logging .warn ('Ingestion is lagging for telephony logs v2, limiting synchronization window to {}' .format (maxwindow ))
487+
488+ next_offset = None
489+ while True :
490+ events , next_offset = get_tele_logs (admin_api , mintime , maxtime , limit , next_offset )
491+ for event in events :
492+ sentinel .send (event )
493+ sentinel .flush ()
494+ logging .info ('Saving telephony logs v2 last timestamp {}' .format (maxtime ))
495+ state_manager .post (str (maxtime ))
496+ if not events :
497+ break
498+ if len (events ) < limit or check_if_script_runs_too_long (start_ts ):
499+ if check_if_script_runs_too_long (start_ts ):
500+ logging .info ('Script is running too long. Saving progress and exit.' )
501+ break
502+
503+ def get_tele_logs (admin_api : duo_client .Admin , mintime : int , maxtime : int , limit = 1000 , next_offset = None ):
504+ logging .info ('Making telephony logs v2 request: mintime={}, maxtime={}, next_offset={}' .format (mintime , maxtime , next_offset ))
505+ try :
506+ params = {
507+ 'api_version' : 2 ,
508+ 'mintime' : mintime ,
509+ 'maxtime' : maxtime ,
510+ 'limit' : str (limit ),
511+ 'sort' : 'ts:asc'
512+ }
513+ if next_offset :
514+ params ['next_offset' ] = next_offset
515+ res = admin_api .get_telephony_log (** params )
516+ except Exception as err :
517+ logging .info ('Error while getting telephony logs v2 {}' .format (err ))
518+ if hasattr (err , 'status' ) and err .status == 429 :
519+ logging .info ('429 exception occurred, trying retry after 60 seconds' )
520+ time .sleep (60 )
521+ res = admin_api .get_telephony_log (** params )
522+ else :
523+ return [], None
524+
525+ if res is not None :
526+ events = res .get ('items' , [])
527+ next_offset = res .get ('metadata' , {}).get ('next_offset' )
528+ logging .info ('Obtained {} tele events v2' .format (len (events )))
529+ else :
530+ logging .info ('Error while getting telephony logs v2' )
531+ events = []
532+ next_offset = None
533+ return events , next_offset
0 commit comments