Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tio_client — Tenable.io (Tenable Vulnerability Management) exporter

A dependency-free Python module that exports everything out of cloud.tenable.com. Companion to ec_client.py (ManageEngine). Stdlib only — no pip install, Python 3.8+.

📄 In a hurry? See QUICKSTART.md — a one-page command reference.

Tenable.io client family

Same exporter, in the language you reach for:

Language Repo
Python tenable-io-python (this repo)
PowerShell tenable-io-powershell

Auth (static API keys — never hardcode)

Create a key pair in Tenable: Settings → My Account → API Keys (or a service-account user under Access Control). The client resolves keys in this order: explicit arg → environment → OS secret store.

The secret store is picked automatically per platform — no extra module to install:

OS Store used
macOS login Keychain (via security)
Windows Credential Manager (via advapi32 / ctypes)
Linux / RHEL Secret Service if present (secret-tool), else a 0600 owner-only file under ~/.local/share/tio_client/

Easiest — the store-keys command (hidden prompts for both keys, saves to whichever store fits your OS, then validates). Works the same on macOS, Windows, and Linux:

python3 tio_client.py store-keys      # enter ACCESS key, then SECRET key at the hidden prompts
python3 tio_client.py whoami          # (store-keys already validates, but confirm anytime)
python3 tio_client.py export-all ./tio_data

Headless servers (RHEL, CI) — don't store locally, pull from your vault

On a server the strongest option is to keep the keys out of any local file entirely. Two ways, both higher-precedence than the OS store:

# a) inject env vars from your secrets manager (CI secret, systemd LoadCredential, etc.)
export TIO_ACCESS_KEY=...   export TIO_SECRET_KEY=...

# b) point the client at your vault — it runs the command and uses stdout as the key,
#    writing nothing to disk. Works with Vault, CyberArk, AWS/Azure Secrets Manager, `pass`, …
export TIO_ACCESS_KEY_CMD="vault kv get -field=access secret/tenable"
export TIO_SECRET_KEY_CMD="vault kv get -field=secret secret/tenable"

If you do fall back to the 0600 file, the client fails closed: it refuses to read keys.json unless it's owner-only and owned by you (a loose umask or a planted file can't leak your keys).

Resolution order: CLI flag → TIO_* env value → TIO_*_CMD vault command → OS secret store.

Or store them manually (same result, two commands):

security add-generic-password -s tenable-io -a access -w   # paste your ACCESS key at the prompt
security add-generic-password -s tenable-io -a secret -w   # paste your SECRET key at the prompt

First run, macOS may show a Keychain "allow access" dialog for security / python — click Always Allow. To update a key later, add -U to the add-generic-password command. To remove: security delete-generic-password -s tenable-io -a access.

Alternative — environment variables (good for Linux/servers, CI):

export TIO_ACCESS_KEY=...  export TIO_SECRET_KEY=...
python3 tio_client.py whoami

Alternative — command-line flags (quick one-offs / CI with masked secrets):

python3 tio_client.py --access-key AK --secret-key SK whoami
python3 tio_client.py --base https://fedcloud.tenable.com export-all ./tio_data   # e.g. FedRAMP

Flags may appear anywhere in the args and accept --flag value or --flag=value. Caveat: flag values are visible in ps and shell history, so prefer Keychain/env for anything long-lived.

Resolution order: flag → environment → Keychain.

The keys are sent only to cloud.tenable.com over TLS, in the X-ApiKeys header. Nothing is stored or transmitted elsewhere.

What it exports

Big datasets — via Tenable's async export APIs (start → poll → download chunks), streamed to .jsonl so they're memory-safe at any scale and drop straight into pandas / Power BI:

Output Contents
vulns.jsonl Every vulnerability finding — the full object (plugin detail, ports, output, state, first/last found, VPR + its key drivers, recast, severity mods). Default includes OPEN + REOPENED and FIXED (full history) — drop FIXED for current-only.
assets.jsonl Every asset/host — full object incl. ACR, AES/exposure score, tags, interfaces, sources, last-seen/scan.
compliance.jsonl Compliance/audit findings (if you run compliance scans).
plugins.jsonl The full plugin catalog — every plugin definition (~335k) with all attributes (CVSS, VPR, CVE, CPE, description, solution, see-also…), not just the ones in your findings.

The export API returns the complete object per record — it's not a column subset, so these are already "all properties."

Configuration / inventory — .json: scans, policies, scanners, scanner_groups, agents, agent_groups, networks, tag_values, tag_categories, exclusions, target_groups, access_groups, credentials, credential_types, scan_templates, policy_templates, folders, users, groups, plugin_families, vuln_fields + asset_fields (the catalog of every available column), audit_log, server_properties, server_status, session.

What your key can / can't reach (permissions & license)

The exact coverage depends on the role of the key's user:

  • A Scan Manager key (perms 40) reaches everything above except admin-scoped endpoints, which return 403 Insufficient scope: reports, audit log, roles, permissions, recast/accept-risk rules, access-groups v2, Lumin exposure, settings/tags. To pull those, use an Administrator key (perms 64).
  • WAS (Web App Scanning) data returns 404 unless that module is licensed on the tenant.
  • export_all treats every endpoint as best-effort — anything that 403s/404s is skipped and noted in _manifest.json, so a lower-privileged key still gets a complete dump of what it's allowed to see.

export-all also writes _manifest.json listing every file + record count (or the error, if a given endpoint was skipped — some depend on your license/permissions).

As a library

from tio_client import TenableIO
tio = TenableIO()                       # reads env keys
for v in tio.export_vulns():            # generator — memory-safe
    ...
tio.export_all("./tio_data")
# current-only vulns, criticals + highs, since a date:
tio.export_vulns(states=("OPEN","REOPENED"), severities=("critical","high"), since=1719792000)

Notes

  • Rate limits / transient errors are retried with backoff (honors Retry-After).
  • Agents are listed per-scanner and aggregated (Tenable has no single "all agents" endpoint); each record is tagged with _scanner_id.
  • Endpoints that need a specific license/permission (compliance, audit log, access groups) are best-effort — they're skipped and noted in _manifest.json rather than failing the whole run.
  • Fits the connector plan (see the app's docs/BACKEND-CONNECTOR.md): run this on the gateway server, land the .jsonl in Power BI via a dataflow, and the browser reads it directly.

About

Dependency-free Python client/exporter for Tenable Vulnerability Management (Tenable.io / cloud.tenable.com) — stdlib only, keys via macOS Keychain.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages