Security data analysis and reporting
Latest Dynatrace
Dynatrace allows you to accomplish various analysis and reporting tasks on top of the security data on Grail, helping you to maintain consistent and efficient communication within DevSecOps teams and their stakeholders. Leveraging native apps, such as Dashboards and Notebooks, you can visualize data and find answers to security-related questions.
You can start exploring security data from scratch or use out-of-the-box templates, integrated into Dynatrace security apps such as Third-party vulnerabilities, so you can remain in the context of the analysis flow.
Permissions
You need to assign the following policies to the Security admin group:
-
Storage Security Events Read (allows querying of security data on Grail)
Alternatively, you can assign the Storage All Grail Data Read policy (includes the access to the security data).
-
Storage All System Data Read (allows you to fully benefit from the out-of-the-box security templates, by enriching data with additional information for the Dynatrace-monitored entities, such as
dt.entity.process_group
)
-
In the user menu , go to Account settings.
Shortcut: go to https://myaccount.dynatrace.com
-
Go to Identity & access management > Groups and filter for Security admin.
-
In Actions, select View group.
-
Scroll down to Policies and select Edit.
-
Select the necessary policies, then select Save.
Explore data from scratch
To start exploring security data
- On the third-party vulnerabilities list or details page, select Open with….
- Select Dashboards or Notebooks.
- In the Choose a dashboard/notebook… menu, select Open blank(…), and then select Go.
- In Select destination, select an existing document or create a new one.
- Select Add.
Now you can start analyzing the vulnerability data available on Grail using the Security queries provided as DQL query snippets.
- In Dashboards or Notebooks, select
.
- Select one of the snippets in Security.
Some examples of tasks that you can accomplish with the Security queries are listed below.
Visualize exposure to vulnerabilities
-
Summarize vulnerabilities by status:
1fetch events2| filter event.provider == "Dynatrace" // events generated by Dynatrace3| filter event.type == "VULNERABILITY_STATE_REPORT_EVENT" // historical vulnerability data4| filter event.level == "VULNERABILITY" // aggregation on the vulnerability level5// filter only the latest snapshot data6| sort timestamp, direction:"descending"7| summarize event.status = takeFirst(event.status), by:{vulnerability.display_id}8//end of filtering for the latest snapshot9| summarize count(), by:{event.status} // event.status represents the combined status of vulnerability resolution and muting -
Track vulnerability counts over time:
1fetch events2| filter event.provider == "Dynatrace" // events generated by Dynatrace3| filter event.type == "VULNERABILITY_STATE_REPORT_EVENT" // historical vulnerability data4| filter event.level == "VULNERABILITY" // aggregation on the vulnerability level5// first get the snapshots of each hour per vulnerability6| sort timestamp, direction:"descending"7| summarize {vulnerability.davis_assessment.level = takeFirst(vulnerability.davis_assessment.level),8 vulnerability.mute.status = takeFirst(vulnerability.mute.status),9 vulnerability.resolution.status=takeFirst(vulnerability.resolution.status)}, by:{vulnerability.display_id, timestamp = bin(timestamp,1h)}10| filter vulnerability.resolution.status == "OPEN" // filter for open vulnerabilities only11// aggregate per each timestamp12| summarize {Critical = countIf((vulnerability.davis_assessment.level) == "CRITICAL" AND (vulnerability.mute.status) == "NOT_MUTED"),13 High = countIf((vulnerability.davis_assessment.level) == "HIGH" AND (vulnerability.mute.status) == "NOT_MUTED"),14 Medium = countIf((vulnerability.davis_assessment.level) == "MEDIUM" AND (vulnerability.mute.status) == "NOT_MUTED"),15 Low = countIf((vulnerability.davis_assessment.level) == "LOW" AND (vulnerability.mute.status) == "NOT_MUTED"),16 Muted = countIf((vulnerability.mute.status) == "MUTED") }, by:{timestamp}17| sort timestamp, direction:"descending"
Prioritize remediation efforts
-
List top vulnerabilities by risk assessment:
1fetch events2| filter event.provider=="Dynatrace"3| filter event.type=="VULNERABILITY_STATE_REPORT_EVENT"4| filter event.level=="VULNERABILITY"5// filter only the latest snapshot data6| sort timestamp, direction:"descending"7| summarize8{vulnerability.resolution.status=takeFirst(vulnerability.resolution.status),9vulnerability.resolution.change_date=takeFirst(vulnerability.resolution.change_date),10vulnerability.mute.status=takeFirst(vulnerability.mute.status),11vulnerability.davis_assessment.score=takeFirst(vulnerability.davis_assessment.score),12vulnerability.davis_assessment.level=takeFirst(vulnerability.davis_assessment.level),13vulnerability.title=takeFirst(vulnerability.title),14vulnerability.external_id=takeFirst(vulnerability.external_id),15vulnerability.references.cve=takeFirst(vulnerability.references.cve),16timestamp=takeFirst(timestamp)},17by: {vulnerability.display_id}18//end of filtering for the latest snapshot19| filter vulnerability.resolution.status=="OPEN" AND vulnerability.mute.status!="MUTED" // filter for open non-muted vulnerabilities20| sort vulnerability.davis_assessment.score, direction:"descending"21| fields22vulnerability.display_id,23Title=vulnerability.title,24`Davis Security Score`=concat(vulnerability.davis_assessment.level," (",round(vulnerability.davis_assessment.score,decimals:1),")"),25Status=vulnerability.resolution.status,26`Status date`=formatTimestamp(toTimestamp(vulnerability.resolution.change_date), format:"MMM dd, HH:mm:ss"),27`CVE list`=substring(toString(vulnerability.references.cve), from:1, to:-1),28`External id`=vulnerability.external_id -
List top affected entities by vulnerability count:
1fetch events2| filter event.provider=="Dynatrace"3| filter event.type=="VULNERABILITY_STATE_REPORT_EVENT"4| filter event.level=="ENTITY"5// fetch the latest snapshot6| sort timestamp, direction:"descending"7| summarize8{9affected_entity.type=takeFirst(affected_entity.type),10affected_entity.name=takeFirst(affected_entity.name),11vulnerability.davis_assessment.exposure_status=takeFirst(vulnerability.davis_assessment.exposure_status),12dt.entity.process_group=takeFirst(dt.entity.process_group),13dt.entity.host=takeFirst(dt.entity.host),14dt.entity.kubernetes_node=takeFirst(dt.entity.kubernetes_node)15}, by: {affected_entity.id, vulnerability.display_id}16// end of latest snapshot fetch17// summarize per affected entity18| summarize {19`Affected entity name`=takeFirst(affected_entity.name),20Type=takeFirst(affected_entity.type),21`Vulnerabilities`=countDistinct(vulnerability.display_id),22`Exposure status`=takeFirst(vulnerability.davis_assessment.exposure_status),23dt.entity.process_group=takeFirst(dt.entity.process_group),24dt.entity.host=takeFirst(dt.entity.host),25dt.entity.kubernetes_node=takeFirst(dt.entity.kubernetes_node)},26by: {affected_entity.id}27| fieldsRemove affected_entity.id28| sort {`Vulnerabilities`,direction:"descending"}, `Exposure status`29| fields30dt.source_entity=if(isNotNull(dt.entity.process_group),dt.entity.process_group, else:if(isNotNull(dt.entity.host),dt.entity.host,else:dt.entity.kubernetes_node)),31`Affected entity name`,32Type,33`Vulnerabilities`,34`Exposure status`35| limit 5 // limit to the top 5 affected entities
Communicate findings to owning teams
-
Relate findings to responsible teams:
1fetch events2| filter event.provider=="Dynatrace"3| filter event.type=="VULNERABILITY_STATE_REPORT_EVENT"4| filter event.level=="ENTITY"5// fetch the latest snapshot6| sort timestamp, direction:"descending"7| summarize8{9affected_entity.name=takeFirst(affected_entity.name),10affected_entity.affected_processes.count=takeFirst(affected_entity.affected_processes.count),11vulnerability.davis_assessment.exposure_status=takeFirst(vulnerability.davis_assessment.exposure_status),12dt.entity.process_group=takeFirst(dt.entity.process_group),13dt.entity.host=takeFirst(dt.entity.host),14dt.entity.kubernetes_node=takeFirst(dt.entity.kubernetes_node)15}, by: {affected_entity.id, vulnerability.display_id}16// end of latest snapshot fetch17// summarize per affected entity18| summarize {19`Affected entity name`=takeFirst(affected_entity.name),20`Vulnerabilities`=countDistinct(vulnerability.display_id),21`Affected processes`=takeFirst(affected_entity.affected_processes.count),22`Internet exposure`=takeFirst(vulnerability.davis_assessment.exposure_status),23dt.entity.process_group=takeFirst(dt.entity.process_group),24dt.entity.host=takeFirst(dt.entity.host),25dt.entity.kubernetes_node=takeFirst(dt.entity.kubernetes_node)},26by: {affected_entity.id}27| fieldsRemove affected_entity.id28| sort {`Vulnerabilities`,direction:"descending"}, {`Affected processes`,direction:"descending"}, `Internet exposure`29| limit 5 // limit to the top 5 affected entities30//add ownership information31| lookup [32fetch dt.entity.process_group33| fieldsAdd tags34], sourceField:dt.entity.process_group, lookupField:id, fields:{tags}35| parse toString(tags), "LD ('owner:'|'owner\\\\:') (SPACE)? LD:Team ('\"')" // extract the ownership information36| fieldsAdd Team37| fields38dt.source_entity=if(isNotNull(dt.entity.process_group),dt.entity.process_group,39 else:if(isNotNull(dt.entity.host),dt.entity.host,else:dt.entity.kubernetes_node)),40Name=`Affected entity name`,41`Owner team`=if(isNotNull(Team),Team, else:"-"),42`Vulnerabilities`,43`Affected processes` -
List teams with the most vulnerabilities:
1fetch events2| filter event.provider=="Dynatrace"3| filter event.type=="VULNERABILITY_STATE_REPORT_EVENT"4| filter event.level=="ENTITY"5| filter isNotNull(dt.entity.process_group)6// fetch the latest snapshot7| sort timestamp, direction:"descending"8| summarize9{10dt.entity.process_group=takeFirst(dt.entity.process_group)11}, by: {affected_entity.id, vulnerability.display_id}12// end of latest snapshot fetch13//add ownership information14| lookup [15fetch dt.entity.process_group16| fieldsAdd tags17], sourceField:dt.entity.process_group, lookupField:id, fields:{tags}18| parse toString(tags), "LD ('owner:'|'owner\\\\:') (SPACE)? LD:Team ('\"')"19| fieldsAdd Team=if(isNotNull(Team),Team,else:"-")20// end of adding ownership info21| summarize {22`Vulnerabilities`=countDistinct(vulnerability.display_id),23`Affected entities`=countDistinct(affected_entity.id)24}, by: {Team}25| sort {`Vulnerabilities`, direction:"descending"}, {`Affected entities`, direction:"descending"}26| limit 5
For a list of limitations, see Data structure: Limitations.
Out-of-the-box templates
With integrated reporting, Dynatrace helps you to quickly start from fully customizable templates that already include the most interesting insights and allows you to fine-tune them for the specific needs of your organization and share the results with shareholders.
Our out-of-the-box dashboard and notebook templates make it easy to complete various security reporting use cases, some of which are listed below.
Visualize the risk and impact of vulnerabilities
With Threat exposure template for Dashboards, you're provided with immediate answers to the vulnerability exposure risk question and an overview of the exploitation risk and potential impact on your environment.
For details about the mechanism used to calculate the exploitation risk, see FAQ: What is Exploitation Risk Score?.
Sample template:
To start generating Dashboard reports
When generating the reports from templates, the filters and the context of the environment persist automatically in the generated dashboards.
Analyze the impact of vulnerabilities and prioritize remediation efforts
With Threat exposure template for Notebooks, you're provided with an additional level of detail, including the exact areas at risk due to the vulnerability threat, as well as the responsible teams, which allows you to prepare an efficient remediation plan.
Sample template:
To start generating Notebook reports
When generating the reports from templates, the filters and the context of the environment persist automatically in the generated notebooks.
For a list of limitations, see Data structure: Limitations.