Source code for tenable.io.assets

"""
Assets
======

The following methods allow for interaction into the Tenable Vulnerability Management
:devportal:`assets <assets>` API endpoints.

Methods available on ``tio.assets``:

.. rst-class:: hide-signature
.. autoclass:: AssetsAPI
    :members:
"""

from tenable.io.base import TIOEndpoint


[docs] class AssetsAPI(TIOEndpoint): """ This will contain all methods related to Assets """
[docs] def list(self): """ Returns a list of assets. :devportal:`assets: list-assets <assets-list-assets>` Returns: :obj:`list`: List of asset records. Examples: >>> for asset in tio.assets.list(): ... pprint(asset) """ return self._api.get("assets").json()["assets"]
[docs] def delete(self, *uuid): """ Deletes the asset. NOTE: This method is simply a link to the bulk delete API with the appropriate filter pre-populated. This is here for backwards-compatability reasons as the older workbench API has been removed. It's highly recommended to move to the bulk delete endpoint instead. Args: asset_uuid (str): The unique identifier for the asset. Returns: :obj:`None`: Examples: >>> asset_id = '00000000-0000-0000-0000-000000000000' >>> tio.asset.delete(asset_id) """ self.bulk_delete(*[("host.id", "eq", str(i)) for i in uuid], filter_type="or")
[docs] def details(self, uuid): """ Retrieves the details about a specific asset. :devportal:`assets: asset-info <assets-asset-info>` Args: uuid (str): The UUID (unique identifier) for the asset. Returns: :obj:`dict`: Asset resource definition. Examples: >>> asset = tio.assets.details( ... '00000000-0000-0000-0000-000000000000') """ return self._api.get("assets/{}".format(self._check("uuid", uuid, str))).json()
[docs] def assign_tags(self, action, assets, tags): """ Add/remove tags for asset(s). :devportal:`tags: assign-asset-tags <tags-assign-asset-tags>` Args: action (str): Specifies whether to add or remove tags. Valid values: add, remove. assets (List[str]): An array of asset UUIDs. tags (List[str]): An array of tag value UUIDs. Returns: :obj:`dict`: The job Resource record. Examples: >>> asset = tio.assets.assign_tags( ... 'add', ['00000000-0000-0000-0000-000000000000'], ... ['00000000-0000-0000-0000-000000000000']) """ return self._api.post( "tags/assets/assignments", json={ "action": self._check("action", action, str, choices=["add", "remove"]), "assets": [self._check("asset", i, "uuid") for i in assets], "tags": [self._check("source", i, "uuid") for i in tags], }, ).json()
[docs] def tags(self, uuid): """ Retrieves the details about a specific asset. :devportal:`tags: asset-tags <tags-list-asset-tags>` Args: uuid (str): The UUID (unique identifier) for the asset. Returns: :obj:`dict`: Asset resource definition. Examples: >>> asset = tio.assets.tags( ... '00000000-0000-0000-0000-000000000000') """ return self._api.get( "tags/assets/{}/assignments".format(self._check("uuid", uuid, "uuid")) ).json()
[docs] def asset_import(self, source, *assets): """ Imports asset information into Tenable Vulnerability Management from an external source. :devportal:`assets: import <assets-import>` Imports a list of asset definition dictionaries. Each asset record must contain at least one of the following attributes: ``fqdn``, ``ipv4``, ``netbios_name``, ``mac_address``. Each record may also contain additional properties. Args: *assets (dict): One or more asset definition dictionaries source (str): An identifier to be used to upload the assets. Returns: :obj:`str`: The job UUID. Examples: import single asset: >>> tio.assets.asset_import('example_source', { ... 'fqdn': ['example.py.test'], ... 'ipv4': ['192.168.254.1'], ... 'netbios_name': 'example', ... 'mac_address': ['00:00:00:00:00:00'] ... }) import multiple asset: >>> tio.assets.asset_import('multiple_asset_example_source', ... { ... 'fqdn': ['example_one.py.test'], ... 'ipv4': ['192.168.1.1'], ... 'netbios_name': 'example_one', ... 'mac_address': ['00:00:00:00:00:00'] ... },{ ... 'fqdn': ['example_two.py.test'], ... 'ipv4': ['192.168.255.1'], ... 'netbios_name': 'example_two', ... 'mac_address': ['00:00:00:00:00:00'] ... }) """ # We will likely want to perform some more stringent checking of the # asset resources that are being defined, however a simple type check # should suffice for now. return self._api.post( "import/assets", json={ "assets": [self._check("asset", i, dict) for i in assets], "source": self._check("source", source, str), }, ).json()["asset_import_job_uuid"]
[docs] def list_import_jobs(self): """ Returns a list of asset import jobs. :devportal:`assets: list-import-jobs <assets-list-import-jobs>` Returns: :obj:`list`: List of job records. Examples: >>> for job in tio.assets.list_import_jobs(): ... pprint(job) """ return self._api.get("import/asset-jobs").json()["asset_import_jobs"]
[docs] def import_job_details(self, uuid): """ Returns the details about a specific asset import job. :devportal:`assets: import-job-info <assets-import-job-info>` uuid (str): The UUID (unique identifier) for the job. Returns: :obj:`dict`: The job Resource record. Examples: >>> job = tio.assets.import_job_details( ... '00000000-0000-0000-0000-000000000000') >>> pprint(job) """ return self._api.get( "import/asset-jobs/{}".format(self._check("uuid", uuid, str)) ).json()
[docs] def move_assets(self, source, destination, targets): """ Moves assets from the specified network to another network. :devportal:`assets: move-assets <assets-bulk-move>` source (str): The UUID of the network currently associated with the assets. destination (str): The UUID of the network to associate with the specified assets. targets (list): The IPv4 addresses of the assets to move. Returns: :obj:`int`: Returns the number of moved assets. Examples: >>> asset = tio.assets.move_assets('00000000-0000-0000-0000-000000000000', ... '10000000-0000-0000-0000-000000000001', ["127.0.0.1"]) >>> pprint(asset) """ payload = { "source": self._check("source", source, "uuid"), "destination": self._check("destination", destination, "uuid"), "targets": ",".join(self._check("targets", targets, list)), } return self._api.post( "api/v2/assets/bulk-jobs/move-to-network", json=payload ).json()
[docs] def bulk_delete(self, *filters, hard_delete=None, filter_type=None): """ Deletes the specified assets. :devportal:`assets: bulk_delete <assets-bulk-delete>` Args: *filters (tuple): A defined filter tuple consisting of the name, operator, and value. Example: ``('host.hostname', 'match', 'asset.com')``. filter_type (str, optional): If multiple filters are defined, the filter_type toggles the behavior as to how these filters are used. Either all the filters have to match (``AND``) or any of the filters have to match (``OR``). If not specified, the default behavior is to assume filter_type is ``AND``. hard_delete (bool, optional): Should the assets be completely removed with all related data? Returns: :obj:`dict`: Returns the number of deleted assets. Examples: >>> asset = tio.assets.bulk_delete( ... ('host.hostname', 'match', 'asset.com'), filter_type='or') >>> pprint(asset) """ payload = dict() # run the rules through the filter parser... filter_type = self._check( "filter_type", filter_type, str, choices=["and", "or"], default="and", case="lower", ) parsed = self._parse_filters( filters, self._api.filters.workbench_asset_filters(), rtype="assets" )["asset"] if hard_delete: payload["hard_delete"] = self._check("hard_delete", hard_delete, bool) payload["query"] = {filter_type: parsed} return self._api.post("api/v2/assets/bulk-jobs/delete", json=payload).json()
[docs] def update_acr(self, assets_uuid_list, reason, value, note=""): """ Updates ACR for the provided asset UUID's with reason(s). Args: assets_uuid_list (list): Asset UUID's which are being updated. reason (list): List of reason(s). value (str): New ACR value for assets, ranging from 1 - 10. note (str): Additional note if any. Returns: :obj:`int`: Status code for the request. Examples: >>> tio.assets.update_acr( ... ['00000000-0000-0000-0000-000000000000', '00000000-0000-0000-0000-000000000001'], ... ['Other'], 1, 'some notes') """ asset_uuids = [] for asset_uuid in assets_uuid_list: asset_uuids.append({"id": asset_uuid}) note = note + " - pyTenable" payload = [ { "acr_score": int(value), "reason": reason, "asset": asset_uuids, "note": note, } ] return self._api.post("api/v2/assets/bulk-jobs/acr", json=payload).status_code