Source code for tenable.sc

'''
.. autoclass:: TenableSC

    .. automethod:: login
    .. automethod:: logout

.. automodule:: tenable.sc.alerts
.. automodule:: tenable.sc.accept_risks
.. automodule:: tenable.sc.analysis
.. automodule:: tenable.sc.asset_lists
.. automodule:: tenable.sc.audit_files
.. automodule:: tenable.sc.credentials
.. automodule:: tenable.sc.current
.. automodule:: tenable.sc.feeds
.. automodule:: tenable.sc.files
.. automodule:: tenable.sc.groups
.. automodule:: tenable.sc.organizations
.. automodule:: tenable.sc.plugins
.. automodule:: tenable.sc.policies
.. automodule:: tenable.sc.queries
.. automodule:: tenable.sc.repositories
.. automodule:: tenable.sc.roles
.. automodule:: tenable.sc.scan_zones
.. automodule:: tenable.sc.scans
.. automodule:: tenable.sc.scan_instances
.. automodule:: tenable.sc.scanners
.. automodule:: tenable.sc.status
.. automodule:: tenable.sc.system
.. automodule:: tenable.sc.users
.. automodule:: tenable.sc.base


Raw HTTP Calls
==============

Even though the ``TenableSC`` object pythonizes the Tenable.sc API for
you, there may still bee the occasional need to make raw HTTP calls to the
Tenable.sc API.  The methods listed below aren't run through any
naturalization by the library aside from the response code checking.  These
methods effectively route directly into the requests session.  The responses
will be Response objects from the ``requests`` library.  In all cases, the path
is appended to the base ``url`` parameter that the ``TenableSC`` object was
instantiated with.

Example:

.. code-block:: python

   resp = sc.get('feed')

.. py:module:: tenable.sc
.. rst-class:: hide-signature
.. py:class:: TenableSC

    .. automethod:: get
    .. automethod:: post
    .. automethod:: put
    .. automethod:: delete
'''
from tenable.base import APISession
from tenable.errors import *
from .accept_risks import AcceptRiskAPI
from .alerts import AlertAPI
from .analysis import AnalysisAPI
from .asset_lists import AssetListAPI
from .audit_files import AuditFileAPI
from .credentials import CredentialAPI
from .current import CurrentSessionAPI
from .files import FileAPI
from .feeds import FeedAPI
from .groups import GroupAPI
from .organizations import OrganizationAPI
from .plugins import PluginAPI
from .policies import ScanPolicyAPI
from .queries import QueryAPI
from .recast_risks import RecastRiskAPI
from .repositories import RepositoryAPI
from .roles import RoleAPI
from .scanners import ScannerAPI
from .scans import ScanAPI
from .scan_instances import ScanResultAPI
from .scan_zones import ScanZoneAPI
from .status import StatusAPI
from .system import SystemAPI
from .users import UserAPI
import warnings, logging, semver


[docs]class TenableSC(APISession): '''TenableSC API Wrapper The Tenable.sc object is the primary interaction point for users to interface with Tenable.sc via the pyTenable library. All of the API endpoint classes that have been written will be grafted onto this class. Args: host (str): The address of the Tenable.sc instance to connect to. access_key (str, optional): The API access key to use for sessionless authentication. adapter (requests.Adaptor, optional): If a requests session adaptor is needed to ensure connectivity to the Tenable.sc host, one can be provided here. backoff (float, optional): If a 429 response is returned, how much do we want to backoff if the response didn't send a Retry-After header. The default backoff is ``1`` second. cert (tuple, optional): The client-side SSL certificate to use for authentication. This format could be either a tuple or a string pointing to the certificate. For more details, please refer to the `Requests Client-Side Certificates`_ documentation. password (str, optional): The password to use for session authentication. port (int, optional): The port number to connect to on the specified host. The default is port ``443``. retries (int, optional): The number of retries to make before failing a request. The default is ``5``. scheme (str, optional): What HTTP scheme should be used for URI path construction. The default is ``https``. secret_key (str, optional): The API secret key to use for sessionless authentication. session (requests.Session, optional): If a requests Session is provided, the provided session will be used instead of constructing one during initialization. ssl_verify (bool, optional): Should the SSL certificate on the Tenable.sc instance be verified? Default is False. username (str, optional): The username to use for session authentication. timeout (int, optional): The connection timeout parameter informing the library how long to wait in seconds for a stalled response before terminating the connection. If unspecified, the default is 300 seconds. Examples: A direct connection to Tenable.sc: >>> from tenable.sc import TenableSC >>> sc = TenableSC('sc.company.tld') A connection to Tenable.sc using SSL certificates: >>> sc = TenableSC('sc.company.tld', ... cert=('/path/client.cert', '/path/client.key')) Using an adaptor to use a passworded certificate (via the immensely useful `requests_pkcs12`_ adaptor): >>> from requests_pkcs12 import Pkcs12Adapter >>> adapter = Pkcs12Adapter( ... pkcs12_filename='certificate.p12', ... pkcs12_password='omgwtfbbq!') >>> sc = TenableSC('sc.company.tld', adapter=adapter) Using API Keys to communicate to Tenable.sc: >>> sc = TenableSC('sc.compant.tld', access_key='key', secret_key='key') Using context management to handle For more information, please See Tenable's `SC API documentation`_ and the `SC API Best Practices Guide`_. .. _SC API documentation: https://docs.tenable.com/sccv/api/index.html .. _SC API Best Practices Guide: https://docs.tenable.com/sccv/api_best_practices/Content/ScApiBestPractices/AboutScApiBestPrac.htm .. _Requests Client-Side Certificates: http://docs.python-requests.org/en/master/user/advanced/#client-side-certificates .. _requests_pkcs12: https://github.com/m-click/requests_pkcs12 ''' _apikeys = False _restricted_paths = ['token'] _timeout = 300 _error_codes = { 400: InvalidInputError, 403: APIError, 404: NotFoundError, 500: ServerError, } def __init__(self, host, access_key=None, secret_key=None, username=None, password=None, port=443, ssl_verify=False, cert=None, adapter=None, scheme='https', retries=None, backoff=None, ua_identity=None, session=None, proxies=None, timeout=None, vendor=None, product=None, build=None, base_path='rest',): # As we will always be passing a URL to the APISession class, we will # want to construct a URL that APISession (and further requests) # understands. base = '{}://{}:{}'.format(scheme, host, port) url = '{}/{}'.format(base, base_path) # Setting the SSL Verification flag on the object itself so that it's # reusable if the user logs out and logs back in. self._ssl_verify = ssl_verify # Now lets pass the relevent parts off to the APISession's constructor # to make sure we have everything lined up as we expect. super(TenableSC, self).__init__(url, retries=retries, backoff=backoff, ua_identity=ua_identity, session=session, proxies=proxies, vendor=vendor, product=product, build=build, timeout=timeout ) # If a client-side certificate is specified, then we will want to add # it into the session object as well. The cert parameter is expecting # a path pointing to the client certificate file. if cert: self._session.cert = cert # If an adapter for requests was provided, we should pull that in as # well. if adapter: self._session.mount(base, adapter) # We will attempt to make the first call to the Tenable.sc instance # and get the system information. If this call fails, then we likely # aren't pointing to a SecurityCenter at all and should throw an error # stating this. try: self.info = self.system.details() except: raise ConnectionError('No Tenable.sc Instance at {}:{}'.format(host, port)) # Now we will try to interpret the Tenable.sc information into # something usable. try: self.version = self.info['version'] self.build_id = self.info['buildID'] self.license = self.info['licenseStatus'] self.uuid = self.info['uuid'] if 'token' in self.info: # if a token was passed in the system info page, then we should # update the X-SecurityCenter header with the token info. self._session.headers.update({ 'X-SecurityCenter': str(self.info['token']) }) except: raise ConnectionError('Invalid Tenable.sc Instance') # Now we will attempt to authenticate to the API using any auth settings # passed into the constructor. self.login( username=username, password=password, access_key=access_key, secret_key=secret_key) def __enter__(self): return self def __exit__(self, exc_type, exc_value, exc_traceback): self.logout() def _build_session(self, session=None): super(TenableSC, self)._build_session(session) # As Tenable.sc is generally installed without a certificate chain that # we can validate, we will want to turn off verification and the # associated warnings unless told to otherwise: self._session.verify = self._ssl_verify if not self._ssl_verify: warnings.filterwarnings('ignore', 'Unverified HTTPS request') def _resp_error_check(self, response, **kwargs): if not kwargs.get('stream', False): try: d = response.json() if d['error_code']: raise APIError(d['error_code'], d['error_msg']) except ValueError: pass return response
[docs] def login(self, username=None, password=None, access_key=None, secret_key=None): ''' Logs the user into Tenable.sc Args: username (str, optional): Username password (str, optional): Password access_key (str, optional): API Access Key secret_key (str, optional): API Secret Key Returns: None Examples: Using a username && password: >>> sc = TenableSC('127.0.0.1', port=8443) >>> sc.login('username', 'password') Using API Keys: >>> sc = TenableSC('127.0.0.1', port=8443) >>> sc.login(access_key='ACCESSKEY', secret_key='SECRETKEY') ''' if username != None and password != None: resp = self.post('token', json={ 'username': username, 'password': password }) self._session.headers.update({ 'X-SecurityCenter': str(resp.json()['response']['token']) }) elif access_key != None and secret_key != None: if semver.match(self.version, '<5.13.0'): raise ConnectionError( 'API Keys not supported on this version of Tenable.sc') self._session.headers.update({ 'X-APIKey': 'accessKey={}; secretKey={}'.format( access_key, secret_key) }) self._apikeys = True
[docs] def logout(self): ''' Logs out of Tenable.sc and resets the session. Returns: None Examples: >>> sc.logout() ''' if not self._apikeys: resp = self.delete('token') self._build_session() self._apikeys = False
@property def accept_risks(self): return AcceptRiskAPI(self) @property def alerts(self): return AlertAPI(self) @property def analysis(self): return AnalysisAPI(self) @property def asset_lists(self): return AssetListAPI(self) @property def audit_files(self): return AuditFileAPI(self) @property def credentials(self): return CredentialAPI(self) @property def current(self): return CurrentSessionAPI(self) @property def feeds(self): return FeedAPI(self) @property def files(self): return FileAPI(self) @property def groups(self): return GroupAPI(self) @property def organizations(self): return OrganizationAPI(self) @property def plugins(self): return PluginAPI(self) @property def policies(self): return ScanPolicyAPI(self) @property def queries(self): return QueryAPI(self) @property def recast_risks(self): return RecastRiskAPI(self) @property def repositories(self): return RepositoryAPI(self) @property def roles(self): return RoleAPI(self) @property def scanners(self): return ScannerAPI(self) @property def scans(self): return ScanAPI(self) @property def scan_instances(self): return ScanResultAPI(self) @property def scan_zones(self): return ScanZoneAPI(self) @property def status(self): return StatusAPI(self) @property def system(self): return SystemAPI(self) @property def users(self): return UserAPI(self)