Showing results for 
Search instead for 
Did you mean: 
Cisco Employee
Cisco Employee

In this morning’s email, you receive a request from your CSO for a report of the vulnerability risks per company site. The CEO wants to run a competition to see which IT site managers can reduce the vulnerability risk the most within the next month and then monitor the site risk over time.

As the DevOps person, are you going to manually create risk meters for twelve sites?  What happens when a new site comes online, are you going to search through your notes to suss-out how to create a risk meter?  The answer is automation.

I found automation useful for repeating tasks I don’t do very often. Automation saves time and reduces errors even for occasional tasks because it saves me time from remembering how to do the task.

Let’s start off with a couple of definitions:

  • An Asset is a "thing" (a server, a router, a laptop, etc) that the vulnerabilities are tied to.
  • Asset Tags or just "tags" are asset metadata.  Some tags are imported from scanners when Kenna Security (now Cisco Vulnerability Management) connectors bring in assets, while others are imported from asset management tools.
  • A Risk Meter is a group of assets based on search or filter criteria. Each Risk Meter has its own Vulnerability Risk Score, which is a measure of the security risk a group of assets poses to the organization. 

This blog will discuss risk meter creation from an asset tag and is a follow-up to the How To Start Using APIs in Your Vulnerability Management webinar.  In the webinar, the risk meter creation example based on business unit asset tag (bu: <business unit>). The asset tag in this example represents site name (site: <site>).  In the webinar, the current risk meters were in a file, but this example uses the Vulnerability Manager (VM) server.  It is assumed the tag with the site information is imported from the scanner.

Obtaining the Current Site Risk Meters

The first step is to collect the current site risk meters.  This is accomplished by the convention that the ‘site risk meter’ names in this example end with the string “Site”.  Unfortunately, there is no search risk meter API, so we have to invoke the list asset group API and perform client-side processing. Note: A risk meter is the vulnerability score of an asset group. The terms risk meter and asset group are used interchangeably.

Here is the code to obtain the first page of risk meters.

 12     sites = []
 13     list_url = base_url + "asset_groups"
 15     page_num = 1
 16     page_param = "?page=" + str(page_num) + "&per_page=100"
 17     url = list_url + page_param
 19     response = requests.get(url, headers=headers)
 20     if response.status_code != 200:
 21         print(f"Search Assets Error: {response.status_code} with {url}")
 22         sys.exit(1)
 24     resp_json = response.json()
 . . .
 33     asset_groups = resp_json['asset_groups']
 34     for asset_group in asset_groups:
 35         risk_meter_name = asset_group['name']
 36         if " Site" in risk_meter_name:
 37             site_name = risk_meter_name.rsplit(' ', 1)[0]
 38             sites.append(site_name)

The code above builds the list asset groups API from a base_url and page information and then invokes it.  If no errors occur, then the code goes through each asset group looking for the string “ Site” in the asset group name.  If “ Site” is found, it is assumed it is at the end of the name and truncated. The truncated name is stored in the sites list.

Obtaining Site Assets

Now that we have a list of site names, let’s go and obtain a list of assets that contain the site:” tag.  Instead of invoking the list asset API, the search asset API is invoked because not all assets could have the site tag.  Let the back-end do some work for us this time.

The query string is part of the URL and needs some special consideration.  Let’s take a look.

66     # Query for all tags with "site:", tag:site\:*
67     query_string = "?q=tag%3Asite%5C%3A%2A"
68     search_url = base_url + "assets/search" + query_string

The rest of the code is very similar to “Fetching Asset Pages” section in “Acquiring Vulnerabilities per Asset”. Since colon (%3A) is a special character, a backslash (%5C) is needed in the search string.

70 assets = []
71 page_num = 1
72 page_param = "&amp;page=" + str(page_num)
73 url = search_url + page_param
75 response = requests.get(url, headers=headers)
76 if response.status_code != 200:
77 print(f"Search Assets Error: {response.status_code} with {url}")
78 sys.exit(1)
80 resp_json = response.json()
81 meta = resp_json['meta']
82 num_pages = meta['pages']
83 if num_pages &gt; 20:
84 print(f"There are over 10,000 assets that have the 'site::' tag. Please use the export assets API.")
85 print("The first 10,000 assets will be processed.")
86 num_pages = 20
87 print(f"Number of assets pages: {num_pages}")
89 assets.extend(resp_json['assets'])

Note that search_url is saved so that the page number can be easily added to the end of the URL.

91 page_num += 1
92 while page_num &lt;= num_pages:
93 page_param = "&amp;page=" + str(page_num)
94 url = search_url + page_param
96 response = requests.get(url, headers=headers)
97 if response.status_code != 200:
98 print(f"Search Assets Error: {response.status_code} with {url}")
99 sys.exit(1)
101 resp_json = response.json()
102 assets.extend(resp_json['assets'])
103 page_num += 1
105 return assets

All the assets with the site tag are returned.

Creating a New Risk Meter

Now that we have all the assets and the site risk meter names, the code checks if each asset site tag has a risk meter associated with it.  If not, a new risk meter is created.

176 # For each asset, check the tags for 'site'.
177 # Verify if the Site exists in the `sites` cache.
178 # If not, create a new risk meter.
179 is_risk_meter_created = False
180 for asset in assets:
181 tags = asset['tags']
182 site_tag = get_site_tag(tags)
183 site_name = site_tag_to_site_name(site_tag)
185 if not site_name in sites:
186 risk_meter = create_risk_meter(site_name, base_url, headers)
187 print(f"Created risk meter: {risk_meter['name']} - {risk_meter['id']}")
188 sites.append(site_name)
189 is_risk_meter_created = True
191 if not is_risk_meter_created:
192 print(f"No risk meters created.")

To create a risk meter, the create asset group and risk meter API is used.

124     # Forge the risk meter asset query string.
125     site_tag_for_query = "site: " + site_name
126     print(f"{site_name} -> site tag for query: {site_tag_for_query}")
127     risk_meter_name = site_name + " Site"
129     asset_query = {
130         "status": ["active"],
131         "tags": [site_tag_for_query]
132     }
134     asset_group_data = {
135         "asset_group": {
136             "name": risk_meter_name,
137             "query": asset_query
138         }
139     }
141     url = base_url + "asset_groups"
143     response =, headers=headers, data=json.dumps(asset_group_data))
144     if response.status_code != 201:
145         print(f"Create Risk Meter Error: {response.status_code} with url: {url}")
146         sys.exit(1)

The risk meter query or filter is POST data.  The code has to create a site tag and a risk meter name to be included in the POST data.  Note that an HTTP response code not 200 is returned.

To verify the risk meter creation, go to your VM dashboard. In the search box, type in “Site” for this example, and you should see all the site risk meters.


This blog shows how to use three APIs: list asset groups, search assets, and create a risk meter.  Since there can be a plethora of metadata, I recommend using keys and values in the metadata.  Also, the code could be written to multi-threaded; for example, risk meter testing could be done at each asset page load, and if a risk meter needs to be created, it could be done in another thread while asset scanning proceeds.

Now that you’re ready to provide your CSO with the needed information, what else can you automate with Kenna Security APIs?

If you’re interested in playing with these samples, they’re located in the python Kenna Security blog_samples repo in the tag_create_risk_meter directory.

Rick Ehrhart

API Evangelist

This blog was originally written for Kenna Security, which has been acquired by Cisco Systems.
Learn more about Cisco Vulnerability Management.

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community:

Recognize Your Peers