-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4e9807d
Showing
51 changed files
with
5,449 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
name: Deploy to PyPI | ||
|
||
on: | ||
release: | ||
types: [published] | ||
|
||
jobs: | ||
deploy: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/setup-python@v2 | ||
with: | ||
python-version: "3.10" | ||
- name: Build Package | ||
run: | | ||
pip install -U wheel build | ||
python -m build | ||
- name: Publish to PyPI | ||
uses: pypa/[email protected] | ||
with: | ||
skip_existing: true | ||
user: __token__ | ||
password: ${{ secrets.PYPI_API_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
name: Testing Pipeline | ||
|
||
on: | ||
push: | ||
branches: [master] | ||
pull_request: | ||
types: [opened, synchronize, reopened] | ||
|
||
jobs: | ||
unit_tests: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
python-version: ["3.10", "3.11", "3.12"] | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Set up Python ${{ matrix.python-version }} | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
- name: Install dependencies | ||
run: | | ||
python -m pip install -U pip | ||
pip install pytest \ | ||
pytest-cov \ | ||
responses | ||
pip install -r requirements.txt | ||
- name: Run the unit test suite. | ||
run: | | ||
pytest tests \ | ||
--cov-report term-missing \ | ||
--cov-report xml:cov/coverage.xml \ | ||
--cov=tenable tests | ||
- name: Test if the library is installable | ||
run: | | ||
pip install . | ||
cd aux_tests && pytest test_installable.py | ||
- name: Save Coverage Report | ||
uses: actions/upload-artifact@v2 | ||
with: | ||
name: coverage_report_${{ matrix.python-version }} | ||
path: cov | ||
retention-days: 1 | ||
|
||
style: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/setup-python@v2 | ||
with: | ||
python-version: 3.8 | ||
- name: Setup environment | ||
run: | | ||
python -m pip install -U pip | ||
pip install flake8 \ | ||
flake8-fixme \ | ||
flake8-author \ | ||
flake8-pylint \ | ||
flake8-plugin-utils | ||
- name: Run flake8 | ||
run: | | ||
flake8 tenable \ | ||
--count \ | ||
--select=E9,F63,F7,F82 \ | ||
--show-source \ | ||
--statistics | ||
flake8 tenable \ | ||
--count \ | ||
--exit-zero \ | ||
--max-complexity=12 \ | ||
--statistics |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
__pycache__ | ||
.DS_Store | ||
.python-version | ||
.nova | ||
.coverage | ||
*.egg-info | ||
/dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
FROM python:3.12-alpine | ||
|
||
COPY setup.py /src/ | ||
COPY tenable_jira /src/tenable_jira | ||
|
||
RUN pip install /src && rm -rf /src | ||
|
||
WORKDIR / | ||
|
||
ENTRYPOINT '/usr/local/bin/tenb2jira' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
# Tenable to Jira Cloud Sync Tool | ||
|
||
This integration is designed to pull Tenable.io vulnerability data, then | ||
generate Jira Tasks and sub-tasks based on the vulnerabilities' current state. | ||
Vulnerabilities are automatically closed once the state of the vulnerability | ||
is marked as "fixed" in Tenable.io or Tenable.sc. | ||
|
||
* The integration creates a _**Vulnerability Management**_ _Business_ project | ||
using the project key _**VULN**_ and the _Simplified Task Tracking_ template. | ||
The integration then creates the appropriate custom fields and links them to | ||
the associated screen that stores and displays all of the necessary | ||
information. | ||
* The integration creates a _**Task**_ for each Vulnerability and creates each | ||
_vulnerability instance_ as a _**Sub-task**_. Example: if you have 5 hosts | ||
with [plugin 151074][151074], the integration creates 1 Task with the details | ||
of [151074] and creates 5 Sub-tasks, each one pointing to a specific instance | ||
of the vulnerability on a specific host. | ||
* Vulnerability Instances (Sub-tasks) are closed automatically by the | ||
integration once the vulnerability is _**fixed**_ in Tenable.io. | ||
* Vulnerabilities (Tasks) are closed once all Sub-tasks enter a closed state. | ||
* If a vulnerability is re-opened, new issue tickets are generated | ||
(The integration will not reopen previously closed issues (otherwise known | ||
as necromancy)) | ||
* All data imports from Tenable.io use the last_found/last_seen fields. This | ||
ensures that all issues are updated whenever new information becomes | ||
available, unless overridden with the `--first-discovery` flag. | ||
* For those that don't mind a bit more management of the script in exchange for | ||
less permissions, there is a **setup-only** mode that will create the project, | ||
fields, and screens, then generate a full configuration file afterwards. This | ||
file must be then used for all future runs of the integration and may need to | ||
be modified with the new, non-elevated user's authentication settings. | ||
* Task summaries are generated using the following formula: | ||
|
||
``` | ||
[Plugin ID] Plugin Name | ||
``` | ||
|
||
* Sub-task summaries are generated using the following formula: | ||
|
||
``` | ||
[IP Address/Port Number/Protocol] [Plugin ID] Plugin Name | ||
``` | ||
|
||
The integration will create the following fields into the Jira instance | ||
|
||
| Field Name | Field Type | v1 Field Type | Screen Tab | | ||
|:------------------------------|:-------------:|:-------------:|:-------------:| | ||
| Tenable Asset UUID | labels | labels | Asset | | ||
| Tenable Asset Tags | labels | labels | Asset | | ||
| Tenable Platform | readonlyfield | readonlyfield | Asset | | ||
| Device Hostname | readonlyfield | readonlyfield | Asset | | ||
| Device NetBIOS Name | readonlyfield | readonlyfield | Asset | | ||
| Device DNS Name | readonlyfield | readonlyfield | Asset | | ||
| Device IPv4 Addresses | labels | labels | Asset | | ||
| Device IPv6 Addresses | labels | labels | Asset | | ||
| Device Network ID | readonlyfield | readonlyfield | Asset | | ||
| Vulnerability Repository ID | readonlyfield | readonlyfield | Asset | | ||
| Vulnerability Repository Name | readonlyfield | readonlyfield | Asset | | ||
| CVEs | labels | labels | Vulnerability | | ||
| Tenable VPR Score | float | readonlyfield | Vulnerability | | ||
| CVSSv2 Base Score | float | readonlyfield | Vulnerability | | ||
| CVSSv2 Temporal Score | float | readonlyfield | Vulnerability | | ||
| CVSSv3 Base Score | float | readonlyfield | Vulnerability | | ||
| CVSSv3 Temporal Score | float | readonlyfield | Vulnerability | | ||
| Tenable Plugin ID | readonlyfield | readonlyfield | Vulnerability | | ||
| Tenable Plugin Family | readonlyfield | readonlyfield | Vulnerability | | ||
| Tenable Plugin Name | readonlyfield | readonlyfield | Vulnerability | | ||
| Vulnerability Severity | readonlyfield | readonlyfield | Vulnerability | | ||
| Vulnerability First Seen | datetime | datetime | Vulnerability | | ||
| Vulnerability Last Seen | datetime | datetime | Vulnerability | | ||
| Vulnerability Last Seen | datetime | datetime | Vulnerability | | ||
| Vulnerability Last Fixed | datetime | datetime | Vulnerability | | ||
| Vulnerability State | readonlyfield | readonlyfield | Vulnerability | | ||
| Vulnerability Port | readonlyfield | readonlyfield | Vulnerability | | ||
| Vulnerability Protocol | readonlyfield | readonlyfield | Vulnerability | | ||
| Patch Publication Date | date | date | Vulnerability | | ||
| Finding Severity | readonlyfield | | Vulnerability | | ||
| Tenable Finding ID | readonlyfield | | Vulnerability | | ||
|
||
* Vulnerability Definition (Task Issue-Type) uniqueness is determined by the | ||
following attributes: | ||
* Tenable Plugin ID | ||
|
||
* Vulnerability Instance (Sub-Task Issue-Type) uniqueness is determines by the | ||
following attributes: | ||
* Tenable Platform | ||
* Tenable Plugin ID | ||
* Tenable Asset UUID | ||
* Device IPv4 Addresses | ||
* Device IPv6 Addresses | ||
* Vulnerability Port | ||
* Vulnerability Protocol | ||
|
||
[151074]: https://www.tenable.com/plugins/nessus/131074 | ||
|
||
## Requirements | ||
|
||
* Python 3.10+ Installed (Versions less than 3.10 are untested and YMMV). | ||
* Tenable.io API Keys associated to an account with "CanView" permissions | ||
for "AllAssets" (required for the Vuln Export APIs) | ||
* Tenable.sc API Keys associated to an account with full access to the | ||
vulnerability data. | ||
* For Tenable.sc, an Analysis Query ID that represents the query to run against | ||
the vulnerability data. | ||
* Jira Cloud Basic Auth API Token and Username. For automatic project creation | ||
and management, the account must have Admin privileges. | ||
* A host to run the script on. This can be located anywhere as the integration | ||
is cloud-to-cloud. | ||
|
||
## Permissions | ||
|
||
* The script requires **Site Admin** Access at least initially to create the | ||
project, the custom fields, and link everything to the right screens. | ||
* The script requires Admin access to the project that it has created. | ||
Depending on the permissions setup within your own Jira Cloud instance, this | ||
may not be enough however. If you are seeing errors, please refer to the | ||
list of required permissions (below). | ||
* If using setup-only (as Admin) to let the script create all of the | ||
requirements, afterwards, it's been [reported][i28_perms] that the following | ||
permissions should yield successful runs: | ||
* Assignable User | ||
* Assign Issues | ||
* Close Issues | ||
* Create Issues | ||
* Delete Issues | ||
* Edit Issues | ||
* Link Issues | ||
* Modify Reporter | ||
* Move Issues | ||
* Resolve Issues | ||
* Schedule Issues | ||
* Set Issue Security | ||
* Transition Issues | ||
|
||
[i28_perms]: https://github.com/tenable/integration-jira-cloud/issues/28#issuecomment-607386580 | ||
|
||
## Quickstart | ||
|
||
### Installation | ||
|
||
``` | ||
pip install tenb2jira | ||
``` | ||
|
||
### Configuration | ||
|
||
In order to configure the integration, pull either the | ||
[New Integration][nconfig] or the [Version 1 Migration][cconfig] configuration | ||
templates and add populate the configuration file with the relevant details. | ||
The configuration file has documentation within it that should walk you all of | ||
the available settings, however at a minimum, you will need to configure the | ||
following attributes within the following sections: | ||
|
||
```toml | ||
[tenable] | ||
platform = The platform we will be interfacing to. Either "tvm" or "tsc" | ||
access_key = The API Access key for the account | ||
secret_key = The API Secret key for the account | ||
url = The URL (if not a TVM instance) | ||
|
||
[jira] | ||
api_username = The username that we will be interfacing with | ||
api_token = The API token we will be using for auth | ||
url = The URL for the Jira instance. | ||
``` | ||
|
||
The rest of the settings in the configuration file are pre-configured for the | ||
most common use cases, however can be modified if need be. For information | ||
on what the various settings do, refer to the documentation within the config | ||
file itself for more information. | ||
|
||
Once the configuration file has been modified and saved, you can confirm that | ||
the changes are still valid using the "validate" command within the CLI. | ||
|
||
``` | ||
tenb2jira validate /path/to/config.toml | ||
``` | ||
|
||
[nconfig]: tmpl_v2_new_config.toml | ||
[cconfig]: tmpl_v1_conversion_config.toml | ||
|
||
### Initial Setup | ||
|
||
We a valid configuration file, we can tell the integration to create and/or | ||
link up the project, issue-types, and fields necessary to make this integration | ||
run. To perform this operation, simply run the following: | ||
|
||
``` | ||
tenb2jira build /path/to/config.toml | ||
``` | ||
|
||
Once the Jira project setup process is complete, a series ot tables will be | ||
returned to the screen detailing what was setup, which should look similar | ||
to this: | ||
|
||
![config-display](docs/mapping_screenshot.png) | ||
|
||
If everything looks good, then we can move on to the actual sync! | ||
|
||
### General operation | ||
|
||
This integration is designed to first query Jira and get the listing of open | ||
issues, store them in a sqlite database, and then query the Tenable platform to | ||
get the findings. From there we will match up against that mapping database | ||
any existing findings, search Jira for anything that could match if that fails, | ||
and lastly create a new issue if no matches exist in either the database or | ||
within Jira. For a more detailed workflow diagram, scroll to the bottom of | ||
this document. | ||
|
||
Once the job has completed, a `last_run` parameter will also be added/updated | ||
to the `[tenable]` section of the configuration file. This parameter will be | ||
used for subsequent runs to pull the updates from that timestamp. | ||
|
||
To launch the integration, just run the sync command: | ||
|
||
``` | ||
tenb2jira sync /path/to/config.toml | ||
``` | ||
|
||
|
||
![workflow](docs/workflow.png) |
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
[build-system] | ||
requires = ["setuptools"] | ||
build-backend = "setuptools.build_meta" | ||
|
||
[project] | ||
dynamic = ["version", "readme"] | ||
name = "tenb2jira" | ||
description = "Tenable Vulnerability Management to Jira Cloud issue manager" | ||
authors = [ | ||
{name = "Tenable, Inc.", email = "[email protected]" } | ||
] | ||
keywords = [ | ||
"tenable", | ||
"tenable vulnerability management", | ||
"tenable security center", | ||
"tenable.io", | ||
"tenable.sc", | ||
"jira", | ||
"jira cloud" | ||
] | ||
license = {text = "MIT License"} | ||
classifiers = [ | ||
"Development Status :: 5 - Production/Stable", | ||
"Intended Audience :: Information Technology", | ||
"Topic :: System :: Systems Administration", | ||
"License :: OSI Approved :: MIT License", | ||
"Programming Language :: Python :: 3.10", | ||
"Programming Language :: Python :: 3.11", | ||
"Programming Language :: Python :: 3.12" | ||
] | ||
dependencies = [ | ||
"arrow>=1.3.0", | ||
"restfly>=1.4.5", | ||
"typer>=0.9.0", | ||
"tomlkit>=0.12.4", | ||
"rich>=13.3.1", | ||
"pytenable>=1.4.20", | ||
"SQLAlchemy>=2.0.28", | ||
"pydantic>=2.7.1" | ||
] | ||
|
||
[project.urls] | ||
Homepage = "https://github.com/tenable/integration-jira-cloud" | ||
Repository = "https://github.com/tenable/integration-jira-cloud" | ||
Issues = "https://github.com/tenable/integration-jira-cloud/issues" | ||
Changelog = "https://github.com/tenable/integration-jira-cloud/blob/master/CHANGELOG.md" | ||
|
||
[project.scripts] | ||
tenb2jira = "tenb2jira.cli:app" | ||
|
||
[tool.setuptools.dynamic] | ||
version = {attr = "tenb2jira.version.version"} | ||
readme = {file = ["README.md"], content-type = "text/markdown"} | ||
|
||
[tool.setuptools.packages.find] | ||
include = ["tenb2jira*"] | ||
|
Oops, something went wrong.