Ansible-Cisco-CVE-Parser

Ansible role that parses CVE feeds from Cisco's PSIRT OpenVuln API. Can post content via Confluence, Mattermost, Slack or regular HTML.

This project is maintained by AdamMack2007

Network CVE Report with Ansible

Purpose

Creates a report of all CVEs that affect a specific platform (Cisco NXOS, IOS, IOS-XE) based on the version of the software the hosts are running. Simplifies collection and documentation of CVE tracking allowing teams to quickly identify threats to their devices.

Notes

  1. The required variables are found in cve_parser/defaults/main.yml. The required vars will be documented below.
  2. This role uses custom filters, these can be found in the filter_plugins directory and are also documented below in the Structure documentation.
  3. Confluence is assumed to be the Atlassian hosted solution, you may have to modify the URI call if its an on-premise device.

Structure

The playbook will perform the following steps:

  1. If a GIT repo is specified, it will attempt to pull any existing documented data in. If this is your first time running this it will skip this playbook.

  2. Gather facts on the devices to determine platform and version

  3. Filter the host_vars output to find all NXOS, IOS and IOS-XE devices and create the base data structure. This filter is found in filter_plugins/net_version_mapping.py and an example output file can be found in cve_parser/files/net_version_mapping_example.json

  4. Query the Cisco OpenVuln API by first getting an API auth token then looping through the platforms and versions. It will register the output to a variable that will be filtered next.

  5. With the variable from the API output, we’ll then filter it with the cve_mapping filter to create the data structure. This filter is found in filter_plugins/cve_mapping.py and an example output file can be found in cve_parser/files/cve_mapping_example.json

  6. With the data structures from step 3 and step 5, we’ll merge the dictionaries to create the cve_data dictionary that we will pass into the jinja2 templates to render the report.

  7. From this point we’ll either post to Confluence, Mattermost or generate a local HTML report based on the requested action.

  8. Backup the updated dictionary to GIT repo if specified, this allows us to track existing CVEs and not have duplicates.

  9. ???

  10. Profit

Required Variables

There are currently 2 ways to create a report, Mattermost and Confluence. Below are the required variables for each and where they should be placed.

I strongly recommend vaulting the API tokens! In Ansible Tower use a Custom Credential Type.

If you set them as vars it’s ideal to remove them from the role, though exta-vars injected at runtime will take precedence over role defaults.

Example Variables

Below is the list of variables that are predefined for you in defaults/main.yml:

enable_mattermost: no
enable_confluence: yes
enable_git_backup: yes

#Mattermost Settings
mattermost_channel: "cve-report"
mattermost_url: "https://mymattermost.com"
mattermost_token: "abc123456789"

#Confluence Settings
confluence_parent_title: "Network CVE Report"
confluence_space: "NETWORK"
confluence_url: myconfluence.atlassian.net
confluence_user: jdoe@gmail.com
confluence_token: "abc123456789"

#Cisco PSIRT Settings
cisco_psirt_clientid: "123456789"
cisco_psirt_clientsecret: "abc123456789"

#GIT backup settings
cve_data_dir: /var/tmp/cve/
cve_data_file: "cve_data.json"
cve_data_repository: "git@192.168.6.101:amack/network-cve-data.git"

Below is the Confluence JSON query that will find the parent page in the Confluence API output. This is required and is set in vars/main.yml to prevent from being left out.

confluence_parent_query: "json.page.results[?title==''].id"

OS Information

Cisco PSIRT

For information on the PSIRT OpenVuln API and how to obtain the below variables see PSIRT OpenVuln Docs

These two variables are required to get a valid oauth token from the API.

GIT

This is highly recommended so we can store and track revisions to the CVE data that is generated. This allows you to keep track of what is already documented and not have duplicate CVEs show up over and over.

If you are using Tower please see my notes at Storing Files on Ansible Tower!

These can be found in defaults/main.yml

Confluence

These can be found in defaults/main.yml

Mattermost

These can be found in defaults/main.yml

Example Output

Confluence Output

Confluence

Storing Files on Ansible Tower

If you are trying to store files to the Ansible Tower execution nodes, for example /var/tmp/cve, you will need to perform a few steps.

The Error

If you try to run this without setting the permissions you will likely see the following errors:

“Aborting, target uses selinux but python bindings (libselinux-python) aren’t installed!”

This is because we need to grant write permissions for the directory we’re copying the data into.

The Fix

Follow the guide in Ansible Bubblewrap to enable the directory to be accessed.

In my example I am storing the data in /var/tmp/cve so I need to put /var/tmp/cve in the “Paths to Expose to Isolated Jobs” field.

Once this is done, make sure to restart the Tower service:

ansible-tower-service restart

Getting API Tokens

See the below guides on how to get the tokens for each application

Confluence API

Manage API Tokens for your Atlassian account

Cisco PSIRT API

Getting Started with Cisco PSIRT openVuln API

Mattermost API

Mattermost Personal Access Tokens

Issues

Currently there is an issue with IOS-XE devices (and possibly others) that Cisco is improperly converting the version.

An example is the version from the device is 16.12.03 but Cisco’s API converts it to 16.12.3, thus 16.12.03 != 16.12.3 and an error is thrown.

I will need to come up with a way to use a Python version library to compare and map versions.

Testing

I have included the following scripts/ouputs that may assist with testing. The following can be found in cve_parser/files/tests: