def fetch_sensitive_data(session_key, key, app_name=None): """ :param session_key: A raw system auth token :param key: the string key to fetch the sensitive data for :param app_name: Optional name of splunk app :return: string representation of the secret """ base_uri = rest.makeSplunkdUri() if app_name: uri = '{}servicesNS/nobody/{}/storage/passwords/{}'.format(base_uri, app_name, key) else: uri = '%s/services/storage/passwords/%s' % (base_uri, key) params = { 'output_mode': 'json' } r, content = rest.simpleRequest( uri, sessionKey=session_key, getargs=params, method='GET', raiseAllErrors=True ) parsed = json.loads(content) clear_password = parsed['entry'][0]['content']['clear_password'] return clear_password
def handleList(self, confInfo): helper = KVStoreHelper(self.getSessionKey()) uri = rest.makeSplunkdUri() content = helper.get_cluster_info(uri + 'servicesNS/nobody/splunk-checker/storage/collections/data/clusterinfo') # TODO: transform to confInfo for cluster_info in content: confInfo[cluster_info['cluster_id']]['cluster_info'] = json.dumps(cluster_info)
def do_run(self, inputs): """ The entry point for the modular input. :param inputs: The command line arguments used when running this modular input. See the parent method definition for more details. """ # noinspection PyBroadException try: if not modular_input_should_run(self.session_key, LOGGER): LOGGER.debug('The AR modular input will not run on this host.') return uri = rest.makeSplunkdUri() _wait_for_kvstore_to_start(uri=uri, session_key=self.session_key, timeout_seconds=30) task.react(self._run_initialization, [AsyncClientFactory(uri)]) except SystemExit as e: if e.code != 0: LOGGER.exception( 'Exited AR modular input with non-zero exit_code=%d message=%s', e.code, e.message) else: LOGGER.debug( 'Successfully ran the AR initialization modular input.') except Exception: LOGGER.exception( 'Unhandled exception while running AR modular input.')
def get_all_secure_gateway_tokens(authtoken, user): """ Returns all Splunk tokens :return: String """ LOGGER.debug("Getting Splunk tokens") query_args = { 'output_mode': 'json', 'sort_key': 'claims.exp', 'sort_dir': 'desc', 'username': user } request_url = "{}services/authorization/tokens".format( rest.makeSplunkdUri()) _, content = rest.simpleRequest(request_url, sessionKey=authtoken, method='GET', getargs=query_args, raiseAllErrors=True) all_tokens = json.loads(content)['entry'] cloudgateway_tokens = [ token for token in all_tokens if token['content']['claims']['aud'] == constants.CLOUDGATEWAY and token['content']['claims']['exp'] != 0 ] return cloudgateway_tokens
def authenticate_splunk_credentials(username, password): """ Checks whether a supplied username/password pair are valid Splunk credentials. Throws an error otherwise. :param username: User-supplied username :param password: User-supplied password :return: None """ request_url = '{}/services/auth/login'.format(rest.makeSplunkdUri()) body = {'username': username, 'password': password} response, c = rest.simpleRequest(request_url, postargs=body, rawResult=True) exception = requests.RequestException() exception.statusCode = response.status if response.status == 200: return elif response.status == 401: exception.msg = 'Error: Supplied username or password is incorrect' else: exception.msg = 'Error: unable to authenticate client' raise exception
def handleCreate(self, confInfo): post_data = self.callerArgs.data cluster_id = post_data['cluster_id'][0] branch = post_data['branch'][0] build = post_data['build'][0] package_type = post_data['package_type'][0] # Use another subprocess to make the upgrade happen. _NEW_PYTHON_PATH = read_conf_item('cluster_upgrade', 'general', 'pythonPath') _SPLUNK_PYTHON_PATH = os.environ['PYTHONPATH'] os.environ['PYTHONPATH'] = _NEW_PYTHON_PATH my_process = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'upgrade_cluster.py') # Read cache build server info. _CACHE_BUILD_SERVER = read_conf_item('cluster_upgrade', 'general', 'cacheBuildServer') # Pass the splunk python path as a argument of the subprocess. p = subprocess.Popen([ os.environ['PYTHONPATH'], my_process, _SPLUNK_PYTHON_PATH, _CACHE_BUILD_SERVER, rest.makeSplunkdUri(), self.getSessionKey(), cluster_id, branch, build, package_type ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = p.communicate()[0] logging.info(str(output)) confInfo['upgrade']['progress'] = str(output)
def get_telemetry_uri(): rest_uri = rest.makeSplunkdUri() return '%sservicesNS/%s/%s/telemetry-metric' % ( rest_uri, NOBODY, SPACEBRIDGE_APP_NAME )
def get_api_key_uri(self): """ Helper method to get uri for snl's api key api :return: [string] """ rest_uri = rest.makeSplunkdUri() return '%sservicesNS/nobody/snl/snl/api_key/backend_api_key?output_mode=json' % rest_uri
def get_hostname_uri(self): """ Helper method to get uri for snl's hostname api :return: [string] """ rest_uri = rest.makeSplunkdUri() return '%sservicesNS/nobody/snl/snl/settings/backend_settings?output_mode=json' % rest_uri
def __init__(self, uri=None, proxy=None, verify_ssl=True): if not uri: uri = rest.makeSplunkdUri() self.uri = uri super(AioServerInfoClient, self).__init__(proxy=proxy, verify_ssl=verify_ssl)
def async_get_shc_captain_info(self, auth_header): """ Async api call to get /shcluster/captain/info """ uri = '%s/services/shcluster/captain/info' % rest.makeSplunkdUri() return self.async_get_request(uri=uri, auth_header=auth_header, params={'output_mode': 'json'})
def async_get_server_info(self, auth_header): """ Async api call to get /server/info :param auth_header: :return: """ uri = '%s/services/server/info' % rest.makeSplunkdUri() return self.async_get_request(uri=uri, auth_header=auth_header, params={'output_mode': 'json'})
async def get_telemetry_instance_id(async_client, auth_header): rest_uri = rest.makeSplunkdUri() instance_id_uri = "{}services/properties/telemetry/general/deploymentID".format(rest_uri) r = await async_client.async_get_request(instance_id_uri, auth_header=auth_header) if r.code != HTTPStatus.OK: error_text = await r.text() LOGGER.info("Could not get telemetry instance id with error={} and status={}".format(error_text, r.code)) instance_id = await r.text() return instance_id
def makeRequestURL(self): user, app = self.user_app() eid = (None if self.callerArgs.id is None else quote( self.callerArgs.id.encode("utf-8"), safe="")) actions = (admin.ACTION_EDIT, admin.ACTION_LIST, admin.ACTION_REMOVE) name = ((self.requestedAction in actions and self.callerArgs.id is not None) and ("/" + eid) or "") return (rest.makeSplunkdUri() + "servicesNS/" + user + "/" + app + "/data/inputs/" + self.dataInputName + name + "?output_mode=json&count=-1")
def get_all_collections(session_key, app_name=constants.SPACEBRIDGE_APP_NAME): uri = encode_whitespace( '{}/servicesNS/nobody/{}/storage/collections/config'.format( rest.makeSplunkdUri(), app_name)) params = {'output_mode': 'json'} return rest.simpleRequest(uri, sessionKey=session_key, method='GET', getargs=params, raiseAllErrors=True)
def makeRequestURL(self): user, app = self.user_app() eid = None if self.callerArgs.id is None \ else quote(self.callerArgs.id.encode('utf-8'), safe='') actions = (admin.ACTION_EDIT, admin.ACTION_LIST, admin.ACTION_REMOVE) name = (self.requestedAction in actions and self.callerArgs.id is not None) and ('/' + eid) or '' return (rest.makeSplunkdUri() + 'servicesNS/' + user + '/' + app + '/data/inputs/' + self.dataInputName + name + '?output_mode=json&count=0')
async def do_trigger(alert_payload): auth_header = SplunkAuthHeader(alert_payload[SESSION_KEY]) # Use default URI for alerts try: uri = rest.makeSplunkdUri() except Exception as e: LOGGER.exception("Failed to generate default URI") if not uri: return mtls_spacebridge_client = None mtls_enabled = config.get_mtls_enabled() if mtls_enabled: mtls_spacebridge_client = build_mtls_spacebridge_client(alert_payload[SESSION_KEY]) async_client_factory = AsyncClientFactory(uri, spacebridge_client=mtls_spacebridge_client) async_kvstore_client = async_client_factory.kvstore_client() async_splunk_client = async_client_factory.splunk_client() async_spacebridge_client = async_client_factory.spacebridge_client() alert_sid = alert_payload[SEARCH_ID] preprocess_payload(alert_payload) # Default to empty string so urllib.quote doesn't fail if user doesn't exist user = alert_payload[RESULT].get(USER, '') request_context = RequestContext(auth_header=auth_header, is_alert=True, current_user=user) LOGGER.info("get_registered_devices alert_sid=%s", alert_sid) registered_devices = await get_registered_devices(request_context, async_kvstore_client, alert_payload) LOGGER.info("get_registered_devices ok alert_sid=%s", alert_sid) alert = await build_alert(request_context, alert_payload, async_splunk_client, async_kvstore_client) LOGGER.info("persist_alert alert_id=%s", alert_sid) response = persist_alert(alert, auth_header.session_token) LOGGER.info("persist_alert ok succeeded alert_id=%s", alert_sid) # If we get a proper response from KV Store, then we get the key of the stored alert # and create a (device_id, alert_id, timestamp) triplet for each device that should # receive the alert if response is not None and "_key" in response.keys(): alert_id = response["_key"] alert.notification.alert_id = alert_id # Persisting (recipient device, alert id) pairs and sending push notifications happens simultaneously via async LOGGER.info("persist_recipient_devices alert_id=%s", alert_id) await persist_recipient_devices(request_context, alert_id, registered_devices, alert_payload, async_kvstore_client) LOGGER.info("persist_recipient_devices ok alert_id=%s", alert_id) LOGGER.info("send_push_notifications starting registered_devices=%s", len(registered_devices)) await send_push_notifications( request_context, alert.notification, registered_devices, async_kvstore_client, async_spacebridge_client, async_splunk_client)
def __init__(self): self.logger = log() self.session = requestsbak.Session() self.session.trust_env = False self.kvstoreUri = entity.buildEndpoint( entityClass=["storage", "collections", "data"], entityName="credentials", owner="nobody", namespace="SplunkAppForWazuh", hostPath=rest.makeSplunkdUri().strip("/")) self.sessionKey = splunk.getSessionKey()
def do_trigger(reactor, alert_payload): auth_header = SplunkAuthHeader(alert_payload[SESSION_KEY]) # Use default URI for alerts try: uri = rest.makeSplunkdUri() except Exception as e: LOGGER.exception("Failed to generate default URI. {}".format(e)) if not uri: return async_client_factory = AsyncClientFactory(uri) async_kvstore_client = async_client_factory.kvstore_client() async_splunk_client = async_client_factory.splunk_client() async_spacebridge_client = async_client_factory.spacebridge_client() alert_sid = alert_payload[SEARCH_ID] preprocess_payload(alert_payload) request_context = RequestContext(auth_header=auth_header, is_alert=True) LOGGER.info("get_registered_devices alert_sid=%s" % alert_sid) registered_devices = yield get_registered_devices(request_context, async_kvstore_client, alert_payload) LOGGER.info("get_registered_devices ok alert_sid=%s" % alert_sid) alert = yield build_alert(request_context, alert_payload, async_splunk_client, async_kvstore_client) LOGGER.info("persist_alert alert_id=%s" % alert_sid) response = persist_alert(alert, auth_header.session_token) LOGGER.info("persist_alert ok succeeded alert_id=%s" % alert_sid) # If we get a proper response from KV Store, then we get the key of the stored alert # and create a (device_id, alert_id, timestamp) triplet for each device that should # receive the alert if response is not None and "_key" in response.keys(): alert_id = response["_key"] alert.notification.alert_id = alert_id # Persisting (recipient device, alert id) pairs and sending push notifications happens simultaneously via async LOGGER.info("persist_recipient_devices alert_id=%s" % alert_id) persist_recipient_devices(request_context, alert_id, registered_devices, alert_payload, async_kvstore_client) LOGGER.info("persist_recipient_devices ok alert_id=%s" % alert_id) LOGGER.info("send_push_notifications starting registered_devices=%s" % len(registered_devices)) yield send_push_notifications(request_context, alert.notification, registered_devices, async_kvstore_client, async_spacebridge_client, async_splunk_client)
def __init__(self, collection=None, session_key=None, app=constants.SPACEBRIDGE_APP_NAME, owner=NOBODY, timestamp_attribute_name='timestamp'): rest_uri = rest.makeSplunkdUri() path = f'servicesNS/{owner}/{app}/storage/collections/data/{collection}' self.uri = append_path_to_uri(rest_uri, path) self.session_key = session_key self.timestamp_attribute_name = timestamp_attribute_name
async def get_installation_environment(async_client, auth_header): rest_uri = rest.makeSplunkdUri() on_cloud_instance_uri = "{}services/properties/telemetry/general/onCloudInstance".format(rest_uri) r = await async_client.async_get_request(on_cloud_instance_uri, auth_header=auth_header) if r.code != HTTPStatus.OK: error_text = await r.text() LOGGER.info("Could not get telemetry instance id with error={} and status={}".format(error_text, r.code)) installation_environment_response = await r.text() installation_environment = InstallationEnvironment.CLOUD \ if installation_environment_response.lower().strip() == "true" \ else InstallationEnvironment.ENTERPRISE return installation_environment
def make_uri(self, endpoint, entry=None): user, app = self.user_app() endpoint = endpoint.strip("/ ") entry = "" if entry is None else "/" + quote(entry.strip("/"), safe="") uri = "{splunkd_uri}servicesNS/{user}/{app}/{endpoint}{entry}" "".format( splunkd_uri=rest.makeSplunkdUri(), user=user, app=app, endpoint=endpoint, entry=entry, ) return uri
def get_uri(session_key): """ Construct URI for REST API calls using the load balancer address or the Splunkd URI if not provided :param session_key: :return: URI string """ uri = config.get_config(stanza=config.SETUP, key=config.LOAD_BALANCER_ADDRESS, default=rest.makeSplunkdUri()) if not uri: raise GetConfigError( "Failed to get load balancer address from cloudgateway.conf") # If load balancer address is given, verify that it is correct if uri != rest.makeSplunkdUri(): if not uri.endswith('/'): uri += '/' if not verify_load_balancer_address(uri, session_key): raise AddressVerificationError( "Failed to verify load balancer address={}".format(uri)) return uri
def __init__(self, collection=None, session_key=None, owner=NOBODY, timestamp_attribute_name='timestamp'): rest_uri = rest.makeSplunkdUri() self.uri = unicode( encode_whitespace( '{}servicesNS/{}/{}/storage/collections/data/{}'.format( rest_uri, owner, constants.SPACEBRIDGE_APP_NAME, collection))) self.session_key = session_key self.timestamp_attribute_name = timestamp_attribute_name
def make_uri(self, endpoint, entry=None): user, app = self.user_app() endpoint = endpoint.strip('/ ') entry = '' if entry is None \ else '/' + quote(entry.strip('/'), safe='') uri = '{splunkd_uri}servicesNS/{user}/{app}/{endpoint}{entry}' \ ''.format(splunkd_uri=rest.makeSplunkdUri(), user=user, app=app, endpoint=endpoint, entry=entry ) return uri
def handleList(self, confInfo): """ List the progress of upgrading from kvstore. """ helper = KVStoreHelper(self.getSessionKey()) uri = rest.makeSplunkdUri() content = helper.get_upgrade_progress( uri + 'servicesNS/nobody/splunk-checker/storage/collections/data/upgrade_progress' ) for cluster_progress in content: confInfo[cluster_progress['cluster_id']][ 'upgrade_progress'] = json.dumps(cluster_progress)
def handleEdit(self, confInfo): user, app = self.user_app() proxy_info = self.getProxyInfo( splunkdMgmtUri=rest.makeSplunkdUri(), sessionKey=self.getSessionKey(), user=user, app=app, ) proxy_enabled = proxy_info.get("proxy_enabled", False) proxy_uri = util.get_proxy_uri(proxy_info if proxy_enabled else {}) proxies = {"http": proxy_uri, "https": proxy_uri} try: url = self.callerArgs.data["splunk_poster_url"][0] for regex in self.allowedURLs: if re.match(regex, url): break else: RH_Err.ctl(1104, msgx="Unsupported url to be posted") method = self.callerArgs.data["splunk_poster_method"][0] if method not in self.allowedMethods: RH_Err.ctl(1104, msgx="Unsupported method to be posted") payload = { key: val[0] for key, val in self.callerArgs.data.items() if key in self.retransmittedArgs } headers = { "Content-Type": "application/x-www-form-urlencoded", } resp = requests.request( # nosemgrep: python.requests.best-practice.use-raise-for-status.use-raise-for-status # noqa: E501 method=method, url=url, headers=headers, data=urllib.parse.urlencode(payload), timeout=120, proxies=proxies, verify=True, ) content = resp.json() if resp.status_code not in (200, 201): RH_Err.ctl(resp.status_code, msgx=content) for key, val in content.items(): confInfo[self.callerArgs.id][key] = val except Exception as exc: RH_Err.ctl(1104, msgx=exc)
def getDeploymentID(self, cookie): if not self.deploymentID: self.getToken(cookie) self.server_uri = rest.makeSplunkdUri() splunkd = Splunkd(token=self.token, server_uri=self.server_uri) telemetry_conf_service = TelemetryConfService(splunkd, is_read_only=True) telemetry_conf_service.fetch() deployment_id_manager = DeploymentIdManager( splunkd, telemetry_conf_service=telemetry_conf_service) self.deploymentID = deployment_id_manager.get_deployment_id() return self.deploymentID
def update_sensitive_data(session_key, key, data): """ :param session_key: A raw system auth token :param key: the string key to fetch the sensitive data for :param data: String data representing the secret :return: """ LOGGER.debug("Updating sensitive data, key={}".format(key)) base_uri = rest.makeSplunkdUri() uri = '{}servicesNS/nobody/{}/storage/passwords/{}'.format( base_uri, constants.SPACEBRIDGE_APP_NAME, key) form_data = {constants.PASSWORD: data} return _mutate_sensitive_data(session_key, uri, form_data)
def __init__(self): """Constructor.""" try: self.logger = log() self.session = requestsbak.Session() self.session.trust_env = False self.kvstoreUri = entity.buildEndpoint( entityClass=["storage", "collections", "data"], entityName="jobs", owner="nobody", namespace="SplunkAppForWazuh", hostPath=rest.makeSplunkdUri().strip("/") ) self.sessionKey = splunk.getSessionKey() except Exception as e: self.logger.error("bin.jobs_queu: Error in queue module constructor: %s" % (e))