def _fetch_conjur_variable(conjur_variable, token, conjur_url, account): token = b64encode(token) headers = {'Authorization': 'Token token="{0}"'.format(token)} display.vvvv('Header: {0}'.format(headers)) url = '{0}/secrets/{1}/variable/{2}'.format(conjur_url, account, quote_plus(conjur_variable)) display.vvvv('Conjur Variable URL: {0}'.format(url)) response = open_url(url, headers=headers, method='GET') if response.getcode() == 200: display.vvvv('Conjur variable {0} was successfully retrieved'.format( conjur_variable)) return [response.read()] if response.getcode() == 401: raise AnsibleError( 'Conjur request has invalid authorization credentials') if response.getcode() == 403: raise AnsibleError( 'The controlling host\'s Conjur identity does not have authorization to retrieve {0}' .format(conjur_variable)) if response.getcode() == 404: raise AnsibleError( 'The variable {0} does not exist'.format(conjur_variable)) return {}
def waitForNoTask(client, name, timeout): currentTimeout = timeout while client.get('/ip/{0}/task'.format(quote_plus(name)), function='genericMoveFloatingIp', status='todo'): time.sleep(1) # Delay for 1 sec currentTimeout -= 1 if currentTimeout < 0: return False return True
def _fetch_conjur_token(conjur_url, account, username, api_key, validate_certs): conjur_url = '{0}/authn/{1}/{2}/authenticate'.format( conjur_url, account, quote_plus(username)) display.vvvv( 'Authentication request to Conjur at: {0}, with user: {1}'.format( conjur_url, quote_plus(username))) response = open_url(conjur_url, data=api_key, method='POST', validate_certs=validate_certs) code = response.getcode() if code != 200: raise AnsibleError( 'Failed to authenticate as \'{0}\' (got {1} response)'.format( username, code)) return response.read()
def waitForTaskDone(client, name, taskId, timeout): currentTimeout = timeout while True: task = client.get('/ip/{0}/task/{1}'.format(quote_plus(name), taskId)) if task['status'] == 'done': return True time.sleep(5) # Delay for 5 sec because it's long to wait completion, do not harass the API currentTimeout -= 5 if currentTimeout < 0: return False
def set_offense_values(module, qradar_request): if module.params["closing_reason"]: found_closing_reason = qradar_request.get_by_path( "api/siem/offense_closing_reasons?filter={0}".format( quote_plus('text="{0}"'.format( module.params["closing_reason"])))) if found_closing_reason: module.params["closing_reason_id"] = found_closing_reason[0]["id"] else: module.fail_json("Unable to find closing_reason text: {0}".format( module.params["closing_reason"])) if module.params["status"]: module.params["status"] = module.params["status"].upper()
def main(): argspec = dict(name=dict(required=False, type="str")) module = AnsibleModule(argument_spec=argspec, supports_check_mode=True) splunk_request = SplunkRequest( module, headers={"Content-Type": "application/json"}) if module.params["name"]: try: query_dict = splunk_request.get_by_path( "servicesNS/nobody/SplunkEnterpriseSecuritySuite/saved/searches/{0}" .format(quote_plus(module.params["name"]))) except HTTPError as e: # the data monitor doesn't exist query_dict = {} else: query_dict = splunk_request.get_by_path( "servicesNS/nobody/SplunkEnterpriseSecuritySuite/saved/searches") module.exit_json(changed=False, splunk_correlation_search_info=query_dict)
def _fetch_conjur_variable(conjur_variable, token, conjur_url, account): token = b64encode(token) headers = {'Authorization': 'Token token="{0}"'.format(token)} display.vvvv('Header: {0}'.format(headers)) url = '{0}/secrets/{1}/variable/{2}'.format(conjur_url, account, quote_plus(conjur_variable)) display.vvvv('Conjur Variable URL: {0}'.format(url)) response = open_url(url, headers=headers, method='GET') if response.getcode() == 200: display.vvvv('Conjur variable {0} was successfully retrieved'.format(conjur_variable)) return [response.read()] if response.getcode() == 401: raise AnsibleError('Conjur request has invalid authorization credentials') if response.getcode() == 403: raise AnsibleError('The controlling host\'s Conjur identity does not have authorization to retrieve {0}' .format(conjur_variable)) if response.getcode() == 404: raise AnsibleError('The variable {0} does not exist'.format(conjur_variable)) return {}
def main(): module = AnsibleModule( argument_spec=dict( name=dict(required=True), service=dict(required=True), endpoint=dict(required=True), wait_completion=dict(default=True, type='bool'), wait_task_completion=dict(default=0, type='int'), application_key=dict(required=True, no_log=True), application_secret=dict(required=True, no_log=True), consumer_key=dict(required=True, no_log=True), timeout=dict(default=120, type='int') ), supports_check_mode=True ) result = dict( changed=False ) if not HAS_OVH: module.fail_json(msg='ovh-api python module is required to run this module ') # Get parameters name = module.params.get('name') service = module.params.get('service') timeout = module.params.get('timeout') wait_completion = module.params.get('wait_completion') wait_task_completion = module.params.get('wait_task_completion') # Connect to OVH API client = getOvhClient(module) # Check that the load balancing exists try: ips = client.get('/ip', ip=name, type='failover') except APIError as apiError: module.fail_json( msg='Unable to call OVH api for getting the list of ips, ' 'check application key, secret, consumerkey and parameters. ' 'Error returned by OVH api was : {0}'.format(apiError)) if name not in ips and '{0}/32'.format(name) not in ips: module.fail_json(msg='IP {0} does not exist'.format(name)) # Check that no task is pending before going on try: if not waitForNoTask(client, name, timeout): module.fail_json( msg='Timeout of {0} seconds while waiting for no pending ' 'tasks before executing the module '.format(timeout)) except APIError as apiError: module.fail_json( msg='Unable to call OVH api for getting the list of pending tasks ' 'of the ip, check application key, secret, consumerkey ' 'and parameters. Error returned by OVH api was : {0}' .format(apiError)) try: ipproperties = client.get('/ip/{0}'.format(quote_plus(name))) except APIError as apiError: module.fail_json( msg='Unable to call OVH api for getting the properties ' 'of the ip, check application key, secret, consumerkey ' 'and parameters. Error returned by OVH api was : {0}' .format(apiError)) if ipproperties['routedTo']['serviceName'] != service: if not module.check_mode: if wait_task_completion == 0: # Move the IP and get the created taskId task = client.post('/ip/{0}/move'.format(quote_plus(name)), to=service) taskId = task['taskId'] result['moved'] = True else: # Just wait for the given taskId to be completed taskId = wait_task_completion result['moved'] = False result['taskId'] = taskId if wait_completion or wait_task_completion != 0: if not waitForTaskDone(client, name, taskId, timeout): module.fail_json( msg='Timeout of {0} seconds while waiting for completion ' 'of move ip to service'.format(timeout)) result['waited'] = True else: result['waited'] = False result['changed'] = True module.exit_json(**result)
def main(): argspec = dict( state=dict( required=False, choices=["present", "absent", "enabled", "disable"], default="present", type="str", ), connection_host=dict(required=False, choices=["ip", "dns", "none"], default="ip", type="str"), host=dict(required=False, type="str", default=None), index=dict(required=False, type="str", default=None), name=dict(required=True, type="str"), protocol=dict(required=True, type="str", choices=["tcp", "udp"]), queue=dict( required=False, type="str", choices=["parsingQueue", "indexQueue"], default="parsingQueue", ), rawTcpDoneTimeout=dict(required=False, type="int", default=10), restrictToHost=dict(required=False, type="str", default=None), ssl=dict(required=False, type="bool", default=None), source=dict(required=False, type="str", default=None), sourcetype=dict(required=False, type="str", default=None), datatype=dict(required=False, choices=["cooked", "raw"], default="raw"), ) module = AnsibleModule(argument_spec=argspec, supports_check_mode=True) splunk_request = SplunkRequest( module, headers={"Content-Type": "application/x-www-form-urlencoded"}, not_rest_data_keys=["state", "datatype", "protocol"], ) # This is where the splunk_* args are processed request_data = splunk_request.get_data() query_dict = splunk_request.get_by_path( "servicesNS/nobody/search/data/inputs/{0}/{1}/{2}".format( quote_plus(module.params["protocol"]), quote_plus(module.params["datatype"]), quote_plus(module.params["name"]), )) if module.params["state"] in ["present", "enabled", "disabled"]: _data = splunk_request.get_data() if module.params["state"] in ["present", "enabled"]: _data["disabled"] = False else: _data["disabled"] = True if query_dict: needs_change = False for arg in request_data: if arg in query_dict["entry"][0]["content"]: if to_text( query_dict["entry"][0]["content"][arg]) != to_text( request_data[arg]): needs_change = True if not needs_change: module.exit_json(changed=False, msg="Nothing to do.", splunk_data=query_dict) if module.check_mode and needs_change: module.exit_json( changed=True, msg="A change would have been made if not in check mode.", splunk_data=query_dict, ) if needs_change: splunk_data = splunk_request.create_update( "servicesNS/nobody/search/data/inputs/{0}/{1}/{2}".format( quote_plus(module.params["protocol"]), quote_plus(module.params["datatype"]), quote_plus(module.params["name"]), data=urlencode(_data), )) if module.params["state"] in ["present", "enabled"]: module.exit_json(changed=True, msg="{0} updated.", splunk_data=splunk_data) else: module.exit_json(changed=True, msg="{0} disabled.", splunk_data=splunk_data) else: # Create it splunk_data = splunk_request.create_update( "servicesNS/nobody/search/data/inputs/{0}/{1}".format( quote_plus(module.params["protocol"]), quote_plus(module.params["datatype"]), ), data=urlencode(_data), ) module.exit_json(changed=True, msg="{0} created.", splunk_data=splunk_data) elif module.params["state"] == "absent": if query_dict: splunk_data = splunk_request.delete_by_path( "servicesNS/nobody/search/data/inputs/{0}/{1}/{2}".format( quote_plus(module.params["protocol"]), quote_plus(module.params["datatype"]), quote_plus(module.params["name"]), )) module.exit_json( changed=True, msg="Deleted {0}.".format(module.params["name"]), splunk_data=splunk_data, ) module.exit_json(changed=False, msg="Nothing to do.", splunk_data={})
def main(): argspec = dict( name=dict(required=True, type='str'), description=dict(required=True, type='str'), state=dict(choices=['present', 'absent'], required=True), search=dict(required=True, type='str'), app=dict(type="str", required=False, default="SplunkEnterpriseSecuritySuite"), ui_dispatch_context=dict(type="str", required=False), time_earliest=dict(type="str", required=False, default="-24h"), time_latest=dict(type="str", required=False, default="now"), cron_schedule=dict(type="str", required=False, default="*/5 * * * *"), scheduling=dict(type="str", required=False, default="real-time", choices=["real-time", "continuous"]), schedule_window=dict(type="str", required=False, default="0"), schedule_priority=dict(type="str", required=False, default="Default", choices=["Default", "Higher", "Highest"]), trigger_alert_when=dict(type="str", required=False, default="number of events", choices=[ "number of events", "number of results", "number of hosts", "number of sources" ]), trigger_alert_when_condition=dict(type="str", required=False, default="greater than", choices=[ "greater than", "less than", "equal to", "not equal to", "drops by", "rises by" ]), trigger_alert_when_value=dict(type="str", required=False, default="10"), throttle_window_duration=dict(type="str", required=False), throttle_fields_to_group_by=dict(type="str", required=False), suppress_alert=dict(type=bool, required=False, default=False), ) module = AnsibleModule(argument_spec=argspec, supports_check_mode=True) splunk_request = SplunkRequest( module, headers={"Content-Type": "application/x-www-form-urlencoded"}, not_rest_data_keys=['state']) try: query_dict = splunk_request.get_by_path( 'servicesNS/nobody/SplunkEnterpriseSecuritySuite/saved/searches/{0}' .format(quote_plus(module.params['name']))) except HTTPError as e: # the data monitor doesn't exist query_dict = {} # Have to custom craft the data here because they overload the saved searches # endpoint in the rest api and we want to hide the nuance from the user request_post_data = {} request_post_data['name'] = module.params['name'] request_post_data['action.correlationsearch.enabled'] = "1" request_post_data['is_scheduled'] = True request_post_data['dispatch.rt_backfill'] = True request_post_data['action.correlationsearch.label'] = module.params['name'] request_post_data['description'] = module.params['description'] request_post_data['search'] = module.params['search'] request_post_data['request.ui_dispatch_app'] = module.params['app'] if module.params['ui_dispatch_context']: request_post_data['request.ui_dispatch_context'] = module.params[ 'ui_dispatch_context'] request_post_data['dispatch.earliest_time'] = module.params[ 'time_earliest'] request_post_data['dispatch.latest_time'] = module.params['time_latest'] request_post_data['cron_schedule'] = module.params['cron_schedule'] if module.params['scheduling'] == 'real-time': request_post_data['realtime_schedule'] = True else: request_post_data['realtime_schedule'] = False request_post_data['schedule_window'] = module.params['schedule_window'] request_post_data['schedule_priority'] = module.params[ 'schedule_priority'].lower() request_post_data['alert_type'] = module.params['trigger_alert_when'] request_post_data['alert_comparator'] = module.params[ 'trigger_alert_when_condition'] request_post_data['alert_threshold'] = module.params[ 'trigger_alert_when_value'] request_post_data['alert.suppress'] = module.params['suppress_alert'] if module.params['state'] == 'present': if query_dict: needs_change = False for arg in request_post_data: if arg in query_dict['entry'][0]['content']: if to_text( query_dict['entry'][0]['content'][arg]) != to_text( request_post_data[arg]): needs_change = True if not needs_change: module.exit_json(changed=False, msg="Nothing to do.", splunk_data=query_dict) if module.check_mode and needs_change: module.exit_json( changed=True, msg="A change would have been made if not in check mode.", splunk_data=query_dict) if needs_change: # FIXME - need to find a reasonable way to deal with action.correlationsearch.enabled del request_post_data[ 'name'] # If this is present, splunk assumes we're trying to create a new one wit the same name splunk_data = splunk_request.create_update( 'servicesNS/nobody/SplunkEnterpriseSecuritySuite/saved/searches/{0}' .format(quote_plus(module.params['name'])), data=urlencode(request_post_data)) module.exit_json(changed=True, msg="{0} updated.", splunk_data=splunk_data) else: # Create it splunk_data = splunk_request.create_update( 'servicesNS/nobody/SplunkEnterpriseSecuritySuite/saved/searches', data=urlencode(request_post_data)) module.exit_json(changed=True, msg="{0} created.", splunk_data=splunk_data) if module.params['state'] == 'absent': if query_dict: splunk_data = splunk_request.delete_by_path( 'services/saved/searches/{0}'.format( quote_plus(module.params['name']))) module.exit_json(changed=True, msg="Deleted {0}.".format(module.params['name']), splunk_data=splunk_data) module.exit_json(changed=False, msg="Nothing to do.", splunk_data=query_dict)
def main(): argspec = dict( name=dict(required=True, type="str"), correlation_search_name=dict(required=True, type="str"), description=dict(required=True, type="str"), state=dict(choices=["present", "absent"], required=True), security_domain=dict( choices=["access", "endpoint", "network", "threat", "identity", "audit"], required=False, default="threat", ), severity=dict( choices=["informational", "low", "medium", "high", "critical", "unknown"], required=False, default="high", ), default_owner=dict(required=False, type="str"), default_status=dict( choices=[ "unassigned", "new", "in progress", "pending", "resolved", "closed", ], required=False, default="", ), drill_down_name=dict(required=False, type="str"), drill_down_search=dict(required=False, type="str"), drill_down_earliest_offset=dict( required=False, type="str", default="$info_min_time$" ), drill_down_latest_offset=dict( required=False, type="str", default="$info_max_time$" ), investigation_profiles=dict(required=False, type="str"), next_steps=dict(required=False, type="list", default=[]), recommended_actions=dict(required=False, type="list", default=[]), asset_extraction=dict( required=False, type="list", default=["src", "dest", "dvc", "orig_host"], choices=["src", "dest", "dvc", "orig_host"], ), identity_extraction=dict( required=False, type="list", default=["user", "src_user"], choices=["user", "src_user"], ), ) module = AnsibleModule(argument_spec=argspec, supports_check_mode=True) splunk_request = SplunkRequest( module, headers={"Content-Type": "application/x-www-form-urlencoded"}, not_rest_data_keys=["state"], ) query_dict = splunk_request.get_by_path( "servicesNS/nobody/SplunkEnterpriseSecuritySuite/saved/searches/{0}".format( quote_plus(module.params["correlation_search_name"]) ) ) # Have to custom craft the data here because they overload the saved searches # endpoint in the rest api and we want to hide the nuance from the user request_post_data = {} # FIXME need to figure out how to properly support these, the possible values appear to # be dynamically created based on what the search is indexing # request_post_data['action.notable.param.extract_assets'] = '[\"src\",\"dest\",\"dvc\",\"orig_host\"]' # request_post_data['action.notable.param.extract_identities'] = [\"src_user\",\"user\"] if module.params["next_steps"]: if len(module.params["next_steps"]) == 1: next_steps = "[[action|{0}]]".format(module.params["next_steps"][0]) else: next_steps = "" for next_step in module.params["next_steps"]: if next_steps: next_steps += "\n[[action|{0}]]".format(next_step) else: next_steps = "[[action|{0}]]".format(next_step) # NOTE: version:1 appears to be hard coded when you create this via the splunk web UI # but I don't know what it is/means because there's no docs on it next_steps_dict = {"version": 1, "data": next_steps} request_post_data["action.notable.param.next_steps"] = json.dumps( next_steps_dict ) if module.params["recommended_actions"]: if len(module.params["recommended_actions"]) == 1: request_post_data[ "action.notable.param.recommended_actions" ] = module.params["recommended_actions"][0] else: request_post_data["action.notable.param.recommended_actions"] = ",".join( module.params["recommended_actions"] ) request_post_data["action.notable.param.rule_description"] = module.params[ "description" ] request_post_data["action.notable.param.rule_title"] = module.params["name"] request_post_data["action.notable.param.security_domain"] = module.params[ "security_domain" ] request_post_data["action.notable.param.severity"] = module.params["severity"] request_post_data["action.notable.param.asset_extraction"] = module.params[ "asset_extraction" ] request_post_data["action.notable.param.identity_extraction"] = module.params[ "identity_extraction" ] # NOTE: this field appears to be hard coded when you create this via the splunk web UI # but I don't know what it is/means because there's no docs on it request_post_data["action.notable.param.verbose"] = "0" if module.params["default_owner"]: request_post_data["action.notable.param.default_owner"] = module.params[ "default_owner" ] if module.params["default_status"]: request_post_data["action.notable.param.default_status"] = module.params[ "default_status" ] if query_dict: request_post_data["search"] = query_dict["entry"][0]["content"]["search"] if "actions" in query_dict["entry"][0]["content"]: if query_dict["entry"][0]["content"]["actions"] == "notable": pass elif ( len(query_dict["entry"][0]["content"]["actions"].split(",")) > 0 and "notable" not in query_dict["entry"][0]["content"]["actions"] ): request_post_data["actions"] = ( query_dict["entry"][0]["content"]["actions"] + ", notable" ) else: request_post_data["actions"] = "notable" else: module.fail_json( msg="Unable to find correlation search: {0}", splunk_data=splunk_data ) if module.params["state"] == "present": needs_change = False for arg in request_post_data: if arg in query_dict["entry"][0]["content"]: if to_text(query_dict["entry"][0]["content"][arg]) != to_text( request_post_data[arg] ): needs_change = True if not needs_change: module.exit_json( changed=False, msg="Nothing to do.", splunk_data=query_dict ) if module.check_mode and needs_change: module.exit_json( changed=True, msg="A change would have been made if not in check mode.", splunk_data=query_dict, ) if needs_change: splunk_data = splunk_request.create_update( "servicesNS/nobody/SplunkEnterpriseSecuritySuite/saved/searches/{0}".format( quote_plus(module.params["correlation_search_name"]) ), data=urlencode(request_post_data), ) module.exit_json( changed=True, msg="{0} updated.".format(module.params["correlation_search_name"]), splunk_data=splunk_data, ) if module.params["state"] == "absent": # FIXME - need to figure out how to clear the action.notable.param fields from the api endpoint module.exit_json( changed=True, msg="Deleted {0}.".format(module.params["name"]), splunk_data=splunk_data, ) for arg in request_post_data: if arg in query_dict["entry"][0]["content"]: needs_change = True del query_dict["entry"][0]["content"][arg] if not needs_change: module.exit_json( changed=False, msg="Nothing to do.", splunk_data=query_dict ) if module.check_mode and needs_change: module.exit_json( changed=True, msg="A change would have been made if not in check mode.", splunk_data=query_dict, ) if needs_change: splunk_data = splunk_request.create_update( "servicesNS/nobody/SplunkEnterpriseSecuritySuite/saved/searches/{0}".format( quote_plus(module.params["correlation_search_name"]) ), data=urlencode(request_post_data), ) module.exit_json( changed=True, msg="{0} updated.".format(module.params["correlation_search_name"]), splunk_data=splunk_data, ) module.exit_json(changed=False, msg="Nothing to do.", splunk_data=query_dict)
def main(): argspec = dict( name=dict(required=True, type='str'), state=dict(choices=['present', 'absent'], required=True), blacklist=dict(required=False, type='str', default=None), check_indexed=dict(required=False, type='bool', default=None), check_path=dict(required=False, type='bool', default=None), crc_salt=dict(required=False, type='str', default=None), disabled=dict(required=False, type='str', default=None), followTail=dict(required=False, type='str', default=None), host=dict(required=False, type='str', default=None), host_segment=dict(required=False, type='int', default=None), host_regex=dict(required=False, type='int', default=None), ignore_older_than=dict(required=False, type='str', default=None), index=dict(required=False, type='str', default=None), recursive=dict(required=False, type='str', default=None), rename_source=dict(required=False, type='str', default=None), sourcetype=dict(required=False, type='str', default=None), time_before_close=dict(required=False, type='int', default=None), whitelist=dict(required=False, type='str', default=None), ) module = AnsibleModule( argument_spec=argspec, supports_check_mode=True ) # map of keys for the splunk REST API that aren't pythonic so we have to # handle the substitutes keymap = { 'check_index': 'check-index', 'check_path': 'check-path', 'crc_salt': 'crc-salt', 'ignore_older_than': 'ignore-older-than', 'rename_source': 'rename-source', 'time_before_close': 'time-before-close' } splunk_request = SplunkRequest( module, headers={"Content-Type": "application/x-www-form-urlencoded"}, keymap=keymap, not_rest_data_keys=['state'] ) # This is where the splunk_* args are processed request_data = splunk_request.get_data() query_dict = splunk_request.get_by_path('servicesNS/nobody/search/data/inputs/monitor/{0}'.format(quote_plus(module.params['name']))) if module.params['state'] == 'present': if query_dict: needs_change = False for arg in request_data: if arg in query_dict['entry'][0]['content']: if to_text(query_dict['entry'][0]['content'][arg]) != to_text(request_data[arg]): needs_change = True if not needs_change: module.exit_json(changed=False, msg="Nothing to do.", splunk_data=query_dict) if module.check_mode and needs_change: module.exit_json(changed=True, msg="A change would have been made if not in check mode.", splunk_data=query_dict) if needs_change: splunk_data = splunk_request.create_update( 'servicesNS/nobody/search/data/inputs/monitor/{0}'.format( quote_plus(module.params['name']) ) ) module.exit_json(changed=True, msg="{0} updated.", splunk_data=splunk_data) else: # Create it _data = splunk_request.get_data() _data['name'] = module.params['name'] splunk_data = splunk_request.create_update('servicesNS/nobody/search/data/inputs/monitor', data=urlencode(_data)) module.exit_json(changed=True, msg="{0} created.", splunk_data=splunk_data) if module.params['state'] == 'absent': if query_dict: splunk_data = splunk_request.delete_by_path('servicesNS/nobody/search/data/inputs/monitor/{0}'.format(quote_plus(module.params['name']))) module.exit_json(changed=True, msg="Deleted {0}.".format(module.params['name']), splunk_data=splunk_data) module.exit_json(changed=False, msg="Nothing to do.", splunk_data=query_dict)
def main(): argspec = dict( name=dict(required=True, type='str'), correlation_search_name=dict(required=True, type='str'), description=dict(required=True, type='str'), state=dict(choices=['present', 'absent'], required=True), security_domain=dict(choices=[ 'access', 'endpoint', 'network', 'threat', 'identity', 'audit' ], required=False, default='threat'), severity=dict(choices=[ 'informational', 'low', 'medium', 'high', 'critical', 'unknown' ], required=False, default='high'), default_owner=dict(required=False, type='str'), default_status=dict(choices=[ 'unassigned', 'new', 'in progress', 'pending', 'resolved', 'closed', '' ], required=False, default=''), drill_down_name=dict(required=False, type='str'), drill_down_search=dict(required=False, type='str'), drill_down_earliest_offset=dict(required=False, type='str', default='$info_min_time$'), drill_down_latest_offset=dict(required=False, type='str', default='$info_max_time$'), investigation_profiles=dict(required=False, type='str'), next_steps=dict(required=False, type='list', default=[]), recommended_actions=dict(required=False, type='list', default=[]), asset_extraction=dict(required=False, type='list', default=['src', 'dest', 'dvc', 'orig_host'], choices=['src', 'dest', 'dvc', 'orig_host']), identity_extraction=dict(required=False, type='list', default=['user', 'src_user'], choices=['user', 'src_user']), ) module = AnsibleModule(argument_spec=argspec, supports_check_mode=True) splunk_request = SplunkRequest( module, headers={"Content-Type": "application/x-www-form-urlencoded"}, not_rest_data_keys=['state']) query_dict = splunk_request.get_by_path( 'servicesNS/nobody/SplunkEnterpriseSecuritySuite/saved/searches/{0}'. format(quote_plus(module.params['correlation_search_name']))) # Have to custom craft the data here because they overload the saved searches # endpoint in the rest api and we want to hide the nuance from the user request_post_data = {} #FIXME need to figure out how to properly support these, the possible values appear to # be dynamically created based on what the search is indexing #request_post_data['action.notable.param.extract_assets'] = '[\"src\",\"dest\",\"dvc\",\"orig_host\"]' #request_post_data['action.notable.param.extract_identities'] = [\"src_user\",\"user\"] if module.params['next_steps']: if len(module.params['next_steps']) == 1: next_steps = "[[action|{0}]]".format( module.params['next_steps'][0]) else: next_steps = "" for next_step in module.params['next_steps']: if next_steps: next_steps += "\n[[action|{0}]]".format(next_step) else: next_steps = "[[action|{0}]]".format(next_step) # NOTE: version:1 appears to be hard coded when you create this via the splunk web UI # but I don't know what it is/means because there's no docs on it next_steps_dict = {"version": 1, "data": next_steps} request_post_data['action.notable.param.next_steps'] = json.dumps( next_steps_dict) if module.params['recommended_actions']: if len(module.params['recommended_actions']) == 1: request_post_data[ 'action.notable.param.recommended_actions'] = module.params[ 'recommended_actions'][0] else: request_post_data[ 'action.notable.param.recommended_actions'] = ','.join( module.params['recommended_actions']) request_post_data['action.notable.param.rule_description'] = module.params[ 'description'] request_post_data['action.notable.param.rule_title'] = module.params[ 'name'] request_post_data['action.notable.param.security_domain'] = module.params[ 'security_domain'] request_post_data['action.notable.param.severity'] = module.params[ 'severity'] request_post_data['action.notable.param.asset_extraction'] = module.params[ 'asset_extraction'] request_post_data[ 'action.notable.param.identity_extraction'] = module.params[ 'identity_extraction'] # NOTE: this field appears to be hard coded when you create this via the splunk web UI # but I don't know what it is/means because there's no docs on it request_post_data['action.notable.param.verbose'] = '0' if module.params['default_owner']: request_post_data[ 'action.notable.param.default_owner'] = module.params[ 'default_owner'] if module.params['default_status']: request_post_data[ 'action.notable.param.default_status'] = module.params[ 'default_status'] if query_dict: request_post_data['search'] = query_dict['entry'][0]['content'][ 'search'] if 'actions' in query_dict['entry'][0]['content']: if query_dict['entry'][0]['content']['actions'] == "notable": pass elif len(query_dict['entry'][0]['content']['actions'].split( ',')) > 0 and "notable" not in query_dict['entry'][0][ 'content']['actions']: request_post_data['actions'] = query_dict['entry'][0][ 'content']['actions'] + ", notable" else: request_post_data['actions'] = "notable" else: module.fail_json(msg="Unable to find correlation search: {0}", splunk_data=splunk_data) if module.params['state'] == 'present': needs_change = False for arg in request_post_data: if arg in query_dict['entry'][0]['content']: if to_text(query_dict['entry'][0]['content'][arg]) != to_text( request_post_data[arg]): needs_change = True if not needs_change: module.exit_json(changed=False, msg="Nothing to do.", splunk_data=query_dict) if module.check_mode and needs_change: module.exit_json( changed=True, msg="A change would have been made if not in check mode.", splunk_data=query_dict) if needs_change: splunk_data = splunk_request.create_update( 'servicesNS/nobody/SplunkEnterpriseSecuritySuite/saved/searches/{0}' .format(quote_plus(module.params['correlation_search_name'])), data=urlencode(request_post_data)) module.exit_json(changed=True, msg="{0} updated.".format( module.params['correlation_search_name']), splunk_data=splunk_data) if module.params['state'] == 'absent': #FIXME - need to figure out how to clear the action.notable.param fields from the api endpoint module.exit_json(changed=True, msg="Deleted {0}.".format(module.params['name']), splunk_data=splunk_data) for arg in request_post_data: if arg in query_dict['entry'][0]['content']: needs_change = True del query_dict['entry'][0]['content'][arg] if not needs_change: module.exit_json(changed=False, msg="Nothing to do.", splunk_data=query_dict) if module.check_mode and needs_change: module.exit_json( changed=True, msg="A change would have been made if not in check mode.", splunk_data=query_dict) if needs_change: splunk_data = splunk_request.create_update( 'servicesNS/nobody/SplunkEnterpriseSecuritySuite/saved/searches/{0}' .format(quote_plus(module.params['correlation_search_name'])), data=urlencode(request_post_data)) module.exit_json(changed=True, msg="{0} updated.".format( module.params['correlation_search_name']), splunk_data=splunk_data) module.exit_json(changed=False, msg="Nothing to do.", splunk_data=query_dict)
def main(): argspec = dict(state=dict( required=False, choices=['present', 'absent', 'enabled', 'disable'], default='present', type='str'), connection_host=dict(required=False, choices=['ip', 'dns', 'none'], default='none', type='str'), host=dict(required=False, type='str', default=None), index=dict(required=False, type='str', default=None), name=dict(required=True, type='str'), protocol=dict(required=True, type='str', choices=['tcp', 'udp']), queue=dict(required=False, type='str', choices=['parsingQueue', 'indexQueue'], default='parsingQueue'), rawTcpDoneTimeout=dict(required=False, type='int', default=10), restrictToHost=dict(required=False, type='str', default=None), ssl=dict(required=False, type='bool', default=None), source=dict(required=False, type='str', default=None), sourcetype=dict(required=False, type='str', default=None), datatype=dict(required=False, choices=["cooked", "raw"], default="raw")) module = AnsibleModule(argument_spec=argspec, supports_check_mode=True) splunk_request = SplunkRequest( module, headers={"Content-Type": "application/x-www-form-urlencoded"}, not_rest_data_keys=['state', 'datatype', 'protocol']) # This is where the splunk_* args are processed request_data = splunk_request.get_data() query_dict = splunk_request.get_by_path( 'servicesNS/nobody/search/data/inputs/{0}/{1}/{2}'.format( quote_plus(module.params['protocol']), quote_plus(module.params['datatype']), quote_plus(module.params['name']), )) if module.params['state'] in ['present', 'enabled', 'disabled']: _data = splunk_request.get_data() if module.params['state'] in ['present', 'enabled']: _data['disabled'] = False else: _data['disabled'] = True if query_dict: needs_change = False for arg in request_data: if arg in query_dict['entry'][0]['content']: if to_text( query_dict['entry'][0]['content'][arg]) != to_text( request_data[arg]): needs_change = True if not needs_change: module.exit_json(changed=False, msg="Nothing to do.", splunk_data=query_dict) if module.check_mode and needs_change: module.exit_json( changed=True, msg="A change would have been made if not in check mode.", splunk_data=query_dict) if needs_change: splunk_data = splunk_request.create_update( 'servicesNS/nobody/search/data/inputs/{0}/{1}/{2}'.format( quote_plus(module.params['protocol']), quote_plus(module.params['datatype']), quote_plus(module.params['name']), data=urlencode(_data))) if module.params['state'] in ['present', 'enabled']: module.exit_json(changed=True, msg="{0} updated.", splunk_data=splunk_data) else: module.exit_json(changed=True, msg="{0} disabled.", splunk_data=splunk_data) else: # Create it splunk_data = splunk_request.create_update( 'servicesNS/nobody/search/data/inputs/{0}/{1}'.format( quote_plus(module.params['protocol']), quote_plus(module.params['datatype']), ), data=urlencode(_data)) module.exit_json(changed=True, msg="{0} created.", splunk_data=splunk_data) elif module.params['state'] == 'absent': if query_dict: splunk_data = splunk_request.delete_by_path( 'servicesNS/nobody/search/data/inputs/{0}/{1}/{2}'.format( quote_plus(module.params['protocol']), quote_plus(module.params['datatype']), quote_plus(module.params['name']), )) module.exit_json(changed=True, msg="Deleted {0}.".format(module.params['name']), splunk_data=splunk_data) module.exit_json(changed=False, msg="Nothing to do.", splunk_data={})