Source code for tenable.sc

'''
Tenable Security Center
==========

.. note::
    Please refer to the common themes section for TenableSC for details on how
    these methods are written from an overall concept.  Not all attributes are
    explicitly documented, only the ones that pyTenable is augmenting,
    validating, or modifying.  For a complete listing of the attributes that can
    be passed to most APIs, refer to the official API documentation that each
    method calls, which is conveniently linked in each method's docs.

.. autoclass:: TenableSC
   :members:


.. toctree::
    :hidden:
    :glob:

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

'''
import warnings
from typing import Optional
from semver import VersionInfo
from tenable.errors import APIError, ConnectionError
from tenable.base.platform import APIPlatform
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


[docs]class TenableSC(APIPlatform): # noqa PLR0904 '''TenableSC API Wrapper The Tenable Security Center object is the primary interaction point for users to interface with Tenable Security Center 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 Security Center instance to connect to. (NOTE: The `hos`t parameter will be deprecated in favor of the `url` parameter in future releases). 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 Security Center 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``. (NOTE: The `port` parameter will be deprecated in favor of the unified `url` parameter in future releases). 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``. (NOTE: The `scheme` parameter will be deprecated in favor of the unified `url` parameter in future releases). 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 Security Center 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 Security Center: >>> from tenable.sc import TenableSC >>> sc = TenableSC('sc.company.tld') A connection to Tenable Security Center 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 Security Center: >>> sc = TenableSC('sc.company.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/security-center/api/index.htm .. _SC API Best Practices Guide: https://docs.tenable.com/security-center/api_best_practices/Content/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 ''' _env_base = 'TSC' _base_path: str = 'rest' _error_map = {403: APIError} _restricted_paths = ['token', 'credential'] _timeout = 300 _ssl_verify = False _version = None def __init__(self, # noqa: PLR0913 host: Optional[str] = None, access_key: Optional[str] = None, secret_key: Optional[str] = None, **kwargs ): # 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. if host: warnings.warn('The "host", "port", and "scheme" parameters are ' 'deprecated and will be removed from the TenableSC ' 'class in version 2.0.', DeprecationWarning ) kwargs['url'] = (f'{kwargs.get("scheme", "https")}://' f'{host}:{kwargs.get("port", 443)}' ) if access_key: kwargs['access_key'] = access_key if secret_key: kwargs['secret_key'] = secret_key # Now lets pass the relevant parts off to the APISession's constructor # to make sure we have everything lined up as we expect. super().__init__(**kwargs) def __enter__(self): return self def __exit__(self, exc_type, exc_value, exc_traceback): self.logout() def _resp_error_check(self, response, **kwargs): if not kwargs.get('stream', False): try: data = response.json() if data['error_code']: raise APIError(response) except ValueError: pass return response def _key_auth(self, access_key, secret_key): # if we can pull a version, check to see that the version is at least # 5.13, which is the minimum version of SC that supports API Keys. If # we cant pull a version, then we will assume it's ok. if (not self.version or VersionInfo.parse(self.version).match('>=5.13.0') ): self._session.headers.update({ 'X-APIKey': f'accessKey={access_key}; secretKey={secret_key}' }) self._auth_mech = 'keys' else: raise ConnectionError( f'API Keys not supported on Tenable Security Center {self.version}' ) def _session_auth(self, username, password): resp = self.post('token', json={ 'username': username, 'password': password }) self._auth_mech = 'user' self._session.headers.update({ 'X-SecurityCenter': str(resp.json()['response']['token']), 'TNS_SESSIONID': str(resp.headers['Set-Cookie'])[14:46] }) def _deauthenticate(self): # noqa PLW0221 super()._deauthenticate(path='token')
[docs] def login(self, username=None, password=None, access_key=None, secret_key=None): ''' Logs the user into Tenable Security Center 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') ''' self._authenticate(**{ 'username': username, 'password': password, 'access_key': access_key, 'secret_key': secret_key })
[docs] def logout(self): ''' Logs out of Tenable Security Center and resets the session. Examples: >>> sc.logout() ''' self._deauthenticate()
@property def version(self): if not self._version: # We will attempt to pull the version number from the system # details method. If we get an APRError response, then we will # simply pass through. try: version = self.system.details().get('version') except APIError: pass else: self._version = version return self._version @property def accept_risks(self): ''' The interface object for the :doc:`Tenable Security Center Accept Risks APIs <accept_risks>`. ''' return AcceptRiskAPI(self) @property def alerts(self): ''' The interface object for the :doc:`Tenable Security Center Alerts APIs <alerts>`. ''' return AlertAPI(self) @property def analysis(self): ''' The interface object for the :doc:`Tenable Security Center Analysis APIs <analysis>`. ''' return AnalysisAPI(self) @property def asset_lists(self): ''' The interface object for the :doc:`Tenable Security Center Asset Lists APIs <asset_lists>`. ''' return AssetListAPI(self) @property def audit_files(self): ''' The interface object for the :doc:`Tenable Security Center Audit Files APIs <audit_files>`. ''' return AuditFileAPI(self) @property def credentials(self): ''' The interface object for the :doc:`Tenable Security Center Credentials APIs <credentials>`. ''' return CredentialAPI(self) @property def current(self): ''' The interface object for the :doc:`Tenable Security Center Current Session APIs <current>`. ''' return CurrentSessionAPI(self) @property def feeds(self): ''' The interface object for the :doc:`Tenable Security Center Feeds APIs <feeds>`. ''' return FeedAPI(self) @property def files(self): ''' The interface object for the :doc:`Tenable Security Center Files APIs <files>`. ''' return FileAPI(self) @property def groups(self): ''' The interface object for the :doc:`Tenable Security Center Groups APIs <groups>`. ''' return GroupAPI(self) @property def organizations(self): ''' The interface object for the :doc:`Tenable Security Center Organization APIs <organizations>`. ''' return OrganizationAPI(self) @property def plugins(self): ''' The interface object for the :doc:`Tenable Security Center Plugins APIs <plugins>`. ''' return PluginAPI(self) @property def policies(self): ''' The interface object for the :doc:`Tenable Security Center Policies APIs <policies>`. ''' return ScanPolicyAPI(self) @property def queries(self): ''' The interface object for the :doc:`Tenable Security Center Queries APIs <queries>`. ''' return QueryAPI(self) @property def recast_risks(self): ''' The interface object for the :doc:`Tenable Security Center Recast Risks APIs <recast_risks>`. ''' return RecastRiskAPI(self) @property def repositories(self): ''' The interface object for the :doc:`Tenable Security Center Repositories APIs <repositories>`. ''' return RepositoryAPI(self) @property def roles(self): ''' The interface object for the :doc:`Tenable Security Center Roles APIs <roles>`. ''' return RoleAPI(self) @property def scanners(self): ''' The interface object for the :doc:`Tenable Security Center Scanners APIs <scanners>`. ''' return ScannerAPI(self) @property def scans(self): ''' The interface object for the :doc:`Tenable Security Center Scans APIs <scans>`. ''' return ScanAPI(self) @property def scan_instances(self): ''' The interface object for the :doc:`Tenable Security Center Scan Instances APIs <scan_instances>`. ''' return ScanResultAPI(self) @property def scan_zones(self): ''' The interface object for the :doc:`Tenable Security Center Scan Zones APIs <scan_zones>`. ''' return ScanZoneAPI(self) @property def status(self): ''' The interface object for the :doc:`Tenable Security Center Status APIs <status>`. ''' return StatusAPI(self) @property def system(self): ''' The interface object for the :doc:`Tenable Security Center System APIs <system>`. ''' return SystemAPI(self) @property def users(self): ''' The interface object for the :doc:`Tenable Security Center Users APIs <users>`. ''' return UserAPI(self)