pyTenableでスキャン結果を自動エクスポートする

「Tenable.io SDK for Python」でスキャン結果を自動エクスポートしておりましたが、
気が付くとpyTenableに変わっていたのでpythonスクリプトを改修しました。

## 1.環境
OS：Windows10
Python3.8.xx(Pythonのパスは通しておく)

## 2.前準備
Tenalbe.ioでアカウントの作成
Tenalbe.ioでスキャン作成、検査対象のスキャンが完了している

## 3.手順
### 3.1.APIキーの取得
Tenalbe.ioでAPIを叩くにはAPIキーで認証を通過する必要があります。
アカウントの設定画面のAPIの項目でGenerateボタンを押して
Access KeyとSecret Keyを表示させて
内容をメモして下さい。

### 3.2.pyTenableのインストール
コマンドプロンプトにて以下を実行

```
pip install pytenable
```
### 3.3.作業用ディレクトリの作成
```
mkdir tio
cd tio
```

### 3.4.自動エクスポート用スクリプト作成

{スキャン名1}
{スキャン名2}
{スキャン名3}
{スキャン名4}
{アクセスキー}
{シークレットキー}
{プロキシサーバURL}
は環境に合わせて文字列を置き換えて下さい。


```scan_list.txt
{スキャン名1}
{スキャン名2}
{スキャン名3}
{スキャン名4}
```

プロキシを通さない場合のスクリプト
```python:scan_result_export_non_proxy.py
from tenable.io import TenableIO
import re

# Tenable.ioのAPIキーを指定
access_key = '{アクセスキー}'
secret_key = '[シークレットキー}'

# Tenable.ioに接続
tio = TenableIO(access_key, secret_key)

# スキャン名リストをファイルから読み込む
with open('scan_list.txt', 'r') as f:
    kw_list = f.read().splitlines()

# スキャンのリストを取得
scans = {scan['name']: scan['id'] for scan in tio.scans.list()}

# 各スキャン名に対して処理を実行
for kw_name in kw_list:
    try:
        # スキャンIDを取得
        scan_id = scans[kw_name]

        # ファイル名を生成
        filename = re.sub(r'\\|\.|\s', '_', kw_name) + '.html'
        print(f"Downloading scan results for {kw_name} to {filename}...")

        # スキャン結果をダウンロード
        report = tio.scans.export(scan_id, format='html', chapter='vuln_by_plugin')

        # 結果をファイルに保存
        with open(filename, 'wb') as f:
            f.write(report.read())  # BytesIOオブジェクトからバイナリデータを読み込む

        print(f"{filename} のダウンロードが完了しました。")
    except KeyError:
        print(f"スキャン名 '{kw_name}' が見つかりません。")
    except Exception as e:
        print(f"Error processing {kw_name}: {e}")
```

プロキシを通す場合のスクリプト
```python:scan_result_export_proxy.py
from tenable.io import TenableIO
import re
import os.path

os.environ['https_proxy'] = 'http://{プロキシサーバURL}/'

# Tenable.ioのAPIキーを指定
access_key = '{アクセスキー}'
secret_key = '[シークレットキー}'

# Tenable.ioに接続
tio = TenableIO(access_key, secret_key)

# スキャン名リストをファイルから読み込む
with open('scan_list.txt', 'r') as f:
    kw_list = f.read().splitlines()

# スキャンのリストを取得
scans = {scan['name']: scan['id'] for scan in tio.scans.list()}

# 各スキャン名に対して処理を実行
for kw_name in kw_list:
    try:
        # スキャンIDを取得
        scan_id = scans[kw_name]

        # ファイル名を生成
        filename = re.sub(r'\\|\.|\s', '_', kw_name) + '.html'
        print(f"Downloading scan results for {kw_name} to {filename}...")

        # スキャン結果をダウンロード
        report = tio.scans.export(scan_id, format='html', chapter='vuln_by_plugin')

        # 結果をファイルに保存
        with open(filename, 'wb') as f:
            f.write(report.read())  # BytesIOオブジェクトからバイナリデータを読み込む

        print(f"{filename} のダウンロードが完了しました。")
    except KeyError:
        print(f"スキャン名 '{kw_name}' が見つかりません。")
    except Exception as e:
        print(f"Error processing {kw_name}: {e}")
```

### 3.5.スクリプトの実行
プロキシが無い環境では、
```
scan_result_export_non_proxy.py
```
プロキシがある環境では、
```
scan_result_export_proxy.py
```
を実行して下さい。

scan_result_export_proxy.pyでSSL証明書のエラーが出た場合は、
環境で使用するCA証明書をPythonプログラムのディレクトリにある
certificate.pem
に追記して下さい。

## 4.まとめ
「Tenable.io SDK for Python」と書き方がガラッと変わってしまったので
改修に時間が掛かってしまいましたが、pyTenableの方がレポートのダウンロード処理時間が1/3になり、かなり早くなりました。