def handler(event, context): """Main lambda handler use as the entry point Args: event (dict): Event object that can potentially contain details on what to during this invocation. An example of this is the 'invocation_type' key that is used as an override to allow for successive invocations (and in the future, support for historical invocations) context (LambdaContxt): AWS LambdaContext object """ StreamAlertApp.get_app(event['app_type'])(event, context).gather()
def test_get_all_apps(self): """StreamAlertApp - Get All Apps""" expected_apps = { 'box_admin_events', 'duo_admin', 'duo_auth', 'gsuite_admin', 'gsuite_calendar', 'gsuite_drive', 'gsuite_gplus', 'gsuite_groups', 'gsuite_login', 'gsuite_mobile', 'gsuite_rules', 'gsuite_saml', 'gsuite_token', 'onelogin_events', 'salesforce_console', 'salesforce_login', 'salesforce_loginas', 'salesforce_report', 'salesforce_reportexport', 'slack_access', 'slack_integration', 'aliyun_actiontrail' } assert_items_equal(expected_apps, StreamAlertApp.get_all_apps())
def _setup_app_new_subparser(subparsers): """Add the app new subparser: manage.py app new [options]""" app_new_parser = _generate_subparser( subparsers, 'new', description= 'Create a new StreamAlert app to poll logs from various services', subcommand=True) _set_parser_epilog(app_new_parser, epilog=('''\ Example: manage.py app new \\ duo_auth \\ --cluster prod \\ --name duo_prod_collector \\ --schedule-expression 'rate(2 hours)' \\ --timeout 60 \\ --memory 256 ''')) _add_default_app_args(app_new_parser) app_types = sorted(StreamAlertApp.get_all_apps()) # App type options app_new_parser.add_argument('type', choices=app_types, metavar='APP_TYPE', help='Type of app being configured: {}'.format( ', '.join(app_types))) # Function schedule expression (rate) arg add_schedule_expression_arg(app_new_parser) # Function timeout arg add_timeout_arg(app_new_parser) # Function memory arg add_memory_arg(app_new_parser)
def add_app(self, func_name, app_info): """Add a configuration for a new streamalert app integration function Args: app_info (dict): The necessary values needed to begin configuring a new app integration Returns: bool: False if errors occurred, True otherwise """ exists, prompt_for_auth, overwrite = False, True, False app = StreamAlertApp.get_app(app_info['type']) cluster_name = app_info['cluster'] app_name = app_info['app_name'] # Check to see if there is an existing configuration for this app integration cluster_config = self.config['clusters'][cluster_name] if func_name in cluster_config['modules'].get('stream_alert_apps', {}): prompt = ( 'An app with the name \'{}\' is already configured for cluster ' '\'{}\'. Would you like to update the existing app\'s configuration' '?'.format(app_name, cluster_name)) exists = True # Return if the user is not deliberately updating an existing config if not continue_prompt(message=prompt): return prompt = ( 'Would you also like to update the authentication information for ' 'app integration with name \'{}\'?'.format(app_name)) # If this is true, we shouldn't prompt again to warn about overwriting prompt_for_auth = overwrite = continue_prompt(message=prompt) if prompt_for_auth and not save_app_auth_info(app, app_info, func_name, overwrite): return False apps_config = cluster_config['modules'].get('stream_alert_apps', {}) if not exists: # Save a default app settings to the config for new apps new_app_config = { 'app_name': app_info['app_name'], 'concurrency_limit': 2, 'log_level': 'info', 'log_retention_days': 14, 'memory': app_info['memory'], 'metric_alarms': { 'errors': { 'enabled': True, 'evaluation_periods': 1, 'period_secs': 120 } }, 'schedule_expression': app_info['schedule_expression'], 'timeout': app_info['timeout'], 'type': app_info['type'] } apps_config[func_name] = new_app_config else: # Allow for updating certain attributes for the app without overwriting # current parts of the configuration updated_app_config = { 'memory': app_info['memory'], 'schedule_expression': app_info['schedule_expression'], 'timeout': app_info['timeout'] } apps_config[func_name].update(updated_app_config) cluster_config['modules']['stream_alert_apps'] = apps_config # Add this service to the sources for this app integration # The `stream_alert_app` is purposely singular here app_sources = self.config['sources'].get('stream_alert_app', {}) app_sources[func_name] = {'logs': [app.service()]} self.config['sources']['stream_alert_app'] = app_sources LOGGER.info( 'Successfully added \'%s\' app integration to \'conf/clusters/%s.json\' ' 'for service \'%s\'.', app_info['app_name'], app_info['cluster'], app_info['type']) self.write() return True
def _app_handler(options): """Perform app related functions Args: options (argparser): Contains all of the necessary info for configuring a new app integration or updating an existing one """ if not options: return # Convert the options to a dict app_info = vars(options) # Add the region and prefix for this StreamAlert instance to the app info app_info['region'] = str(CONFIG['global']['account']['region']) app_info['prefix'] = str(CONFIG['global']['account']['prefix']) # Function name follows the format: '<prefix>_<cluster>_<service>_<app_name>_app func_parts = ['prefix', 'cluster', 'type', 'app_name'] # Create a new app integration function if options.subcommand == 'new': app_info['function_name'] = '_'.join([app_info.get(value) for value in func_parts] + ['app']) CONFIG.add_app(app_info) return # Update the auth information for an existing app integration function if options.subcommand == 'update-auth': cluster_config = CONFIG['clusters'][app_info['cluster']] if not app_info['app_name'] in cluster_config['modules'].get('stream_alert_apps', {}): LOGGER_CLI.error('App integration with name \'%s\' does not exist for cluster \'%s\'', app_info['app_name'], app_info['cluster']) return # Get the type for this app integration from the current # config so we can update it properly app_info['type'] = cluster_config['modules']['stream_alert_apps'] \ [app_info['app_name']]['type'] app_info['function_name'] = '_'.join([app_info.get(value) for value in func_parts] + ['app']) app = StreamAlertApp.get_app(app_info['type']) if not save_app_auth_info(app, app_info, True): return return # List all of the available app integrations, broken down by cluster if options.subcommand == 'list': all_info = { cluster: cluster_config['modules'].get('stream_alert_apps') for cluster, cluster_config in CONFIG['clusters'].iteritems() } for cluster, info in all_info.iteritems(): print '\nCluster: {}\n'.format(cluster) if not info: print '\tNo Apps configured\n' continue for name, details in info.iteritems(): print '\tName: {}'.format(name) print '\n'.join([ '\t\t{key}:{padding_char:<{padding_count}}{value}'.format( key=key_name, padding_char=' ', padding_count=30 - (len(key_name)), value=value) for key_name, value in details.iteritems() ] + ['\n'])
def test_get_app_invalid_type(self): """StreamAlertApp - Get App, Invalid Type""" StreamAlertApp.get_app('bad_app')
def test_get_app(self): """StreamAlertApp - Get App""" assert_equal(StreamAlertApp.get_app('duo_auth'), DuoAuthApp)
def app_handler(options, config): """Perform app related functions Args: options (argparse.Namespace): Parsed arguments with info to configure a new app or update an existing one config (CLIConfig): Loaded StreamAlert config Returns: bool: False if errors occurred, True otherwise """ if not options: return False # List all of the available app integrations, broken down by cluster if options.subcommand == 'list': all_info = { cluster: cluster_config['modules'].get('stream_alert_apps') for cluster, cluster_config in config['clusters'].iteritems() } for cluster, info in all_info.iteritems(): print '\nCluster: {}\n'.format(cluster) if not info: print '\tNo Apps configured\n' continue for name, details in info.iteritems(): print '\tName: {}'.format(name) print '\n'.join([ '\t\t{key}:{padding_char:<{padding_count}}{value}'.format( key=key_name, padding_char=' ', padding_count=30 - (len(key_name)), value=value) for key_name, value in details.iteritems() ] + ['\n']) return True # Convert the options to a dict app_info = vars(options) # Add the region and prefix for this StreamAlert instance to the app info app_info['region'] = str(config['global']['account']['region']) app_info['prefix'] = str(config['global']['account']['prefix']) # Create a new app integration function if options.subcommand == 'new': function_name = '_'.join([ app_info['prefix'], app_info['cluster'], app_info['type'], app_info['app_name'], 'app' ]) return config.add_app(function_name, app_info) # Update the auth information for an existing app integration function if options.subcommand == 'update-auth': cluster_config = config['clusters'][app_info['cluster']] apps = cluster_config['modules'].get('stream_alert_apps', {}) if not apps: LOGGER.error('No apps configured for cluster \'%s\'', app_info['cluster']) return False # Find the appropriate function config for this app func_name = None for function_name, app_config in apps.iteritems(): if app_config.get('app_name') == app_info['app_name']: func_name = function_name break if not func_name: LOGGER.error( 'App with name \'%s\' does not exist for cluster \'%s\'', app_info['app_name'], app_info['cluster']) return False # Get the type for this app integration from the current # config so we can update it properly app_info['type'] = cluster_config['modules']['stream_alert_apps'][ func_name]['type'] app = StreamAlertApp.get_app(app_info['type']) if not save_app_auth_info(app, app_info, func_name, True): return False return True