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.

To explore security data, you have the following options:

  • Built-in security query snippets

    A snippet is an individual query based on a simple use case (for example, Chart open vulnerabilities by risk level over time).

  • Out-of-the-box templates

    A template is a set of multiple queries based on a broad use-case scenario (for example, Threat exposure), and is integrated into Dynatrace Application Security apps such as Third-Party Vulnerabilities, so you can remain in the context of the analysis flow.

For details on each of these options, see below.

Prerequisites

To run security data analysis and reporting, 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 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)

  1. Go to Account Management > Identity & access management > Groups.
  2. Filter for Security admin.
  3. In Actions, select View group.
  4. Scroll down to Policies and select Edit.
  5. Select the necessary policies, then select Save.

Built-in security query snippets

The built-in security snippet queries on Dashboards and Notebooks help you to

  • Visualize exposure to vulnerabilities
  • Prioritize remediation efforts
  • Communicate findings to owning teams

To use the snippets

  1. Go to Dashboards or Notebooks and select Add.
  2. Under Snippets, go to Security and select a snippet.

How to access security snippets

Some examples of tasks that you can accomplish are listed below.

Using Open with… with snippets doesn't include the aggregation to return the same amount of data as on the source Third-party vulnerabilities list page. To aggregate data, manually run the summarize DQL command.

Chart vulnerability counts by status

Shows number of vulnerabilities by status (OPEN, RESOLVED, MUTED).

Query:

fetch events
| filter event.provider == "Dynatrace" // events generated by Dynatrace
| filter event.type == "VULNERABILITY_STATE_REPORT_EVENT" // historical vulnerability data
| filter event.level == "VULNERABILITY" // aggregation on the vulnerability level
// filter only the latest snapshot data
| sort timestamp, direction:"descending"
| summarize event.status = takeFirst(event.status), by:{vulnerability.display_id}
//end of filtering for the latest snapshot
| summarize count(), by:{event.status} // event.status represents the combined status of vulnerability resolution and muting

Query result:

Summarize vulnerabilities by status

Chart open vulnerabilities by risk level over time

Shows an over-time chart with the number of open vulnerabilities split by severity. Muted vulnerabilities are counted separately.

Query:

fetch events
| filter event.provider == "Dynatrace" // events generated by Dynatrace
| filter event.type == "VULNERABILITY_STATE_REPORT_EVENT" // historical vulnerability data
| filter event.level == "VULNERABILITY" // aggregation on the vulnerability level
// first get the snapshots of each hour per vulnerability
| sort timestamp, direction:"descending"
| summarize {vulnerability.davis_assessment.level = takeFirst(vulnerability.davis_assessment.level),
vulnerability.mute.status = takeFirst(vulnerability.mute.status),
vulnerability.resolution.status=takeFirst(vulnerability.resolution.status)}, by:{vulnerability.display_id, timestamp = bin(timestamp,1h)}
| filter vulnerability.resolution.status == "OPEN" // filter for open vulnerabilities only
// aggregate per each timestamp
| summarize {Critical = countIf((vulnerability.davis_assessment.level) == "CRITICAL" AND (vulnerability.mute.status) == "NOT_MUTED"),
High = countIf((vulnerability.davis_assessment.level) == "HIGH" AND (vulnerability.mute.status) == "NOT_MUTED"),
Medium = countIf((vulnerability.davis_assessment.level) == "MEDIUM" AND (vulnerability.mute.status) == "NOT_MUTED"),
Low = countIf((vulnerability.davis_assessment.level) == "LOW" AND (vulnerability.mute.status) == "NOT_MUTED"),
Muted = countIf((vulnerability.mute.status) == "MUTED") }, by:{timestamp}
| sort timestamp, direction:"descending"

Query result:

Track vulnerability counts over time

Fetch open non-muted vulnerabilities

Lists currently open non-muted vulnerabilities with basic information such as risk assessment.

Query:

fetch events
| filter event.provider=="Dynatrace"
| filter event.type=="VULNERABILITY_STATE_REPORT_EVENT"
| filter event.level=="VULNERABILITY"
// filter only the latest snapshot data
| sort timestamp, direction:"descending"
| summarize
{vulnerability.resolution.status=takeFirst(vulnerability.resolution.status),
vulnerability.resolution.change_date=takeFirst(vulnerability.resolution.change_date),
vulnerability.mute.status=takeFirst(vulnerability.mute.status),
vulnerability.davis_assessment.score=takeFirst(vulnerability.davis_assessment.score),
vulnerability.davis_assessment.level=takeFirst(vulnerability.davis_assessment.level),
vulnerability.title=takeFirst(vulnerability.title),
vulnerability.external_id=takeFirst(vulnerability.external_id),
vulnerability.references.cve=takeFirst(vulnerability.references.cve),
timestamp=takeFirst(timestamp)},
by: {vulnerability.display_id}
//end of filtering for the latest snapshot
| filter vulnerability.resolution.status=="OPEN" AND vulnerability.mute.status!="MUTED" // filter for open non-muted vulnerabilities
| sort vulnerability.davis_assessment.score, direction:"descending"
| fields
vulnerability.display_id,
Title=vulnerability.title,
`Davis Security Score`=concat(vulnerability.davis_assessment.level," (",round(vulnerability.davis_assessment.score,decimals:1),")"),
Status=vulnerability.resolution.status,
`Status date`=formatTimestamp(toTimestamp(vulnerability.resolution.change_date), format:"MMM dd, HH:mm:ss"),
`CVE list`=substring(toString(vulnerability.references.cve), from:1, to:-1),
`External id`=vulnerability.external_id

Query result:

List top vulnerabilities by risk assessment

Fetch top five affected entities by vulnerability count

Lists top five affected entities sorted by the count of open vulnerabilities, with essential information such as internet exposure.

Query:

fetch events
| filter event.provider=="Dynatrace"
| filter event.type=="VULNERABILITY_STATE_REPORT_EVENT"
| filter event.level=="ENTITY"
// fetch the latest snapshot
| sort timestamp, direction:"descending"
| summarize
{
affected_entity.type=takeFirst(affected_entity.type),
affected_entity.name=takeFirst(affected_entity.name),
vulnerability.davis_assessment.exposure_status=takeFirst(vulnerability.davis_assessment.exposure_status),
dt.entity.process_group=takeFirst(dt.entity.process_group),
dt.entity.host=takeFirst(dt.entity.host),
dt.entity.kubernetes_node=takeFirst(dt.entity.kubernetes_node)
}, by: {affected_entity.id, vulnerability.display_id}
// end of latest snapshot fetch
// summarize per affected entity
| summarize {
`Affected entity name`=takeFirst(affected_entity.name),
Type=takeFirst(affected_entity.type),
`Vulnerabilities`=countDistinct(vulnerability.display_id),
`Exposure status`=takeFirst(vulnerability.davis_assessment.exposure_status),
dt.entity.process_group=takeFirst(dt.entity.process_group),
dt.entity.host=takeFirst(dt.entity.host),
dt.entity.kubernetes_node=takeFirst(dt.entity.kubernetes_node)},
by: {affected_entity.id}
| fieldsRemove affected_entity.id
| sort {`Vulnerabilities`,direction:"descending"}, `Exposure status`
| fields
dt.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)),
`Affected entity name`,
Type,
`Vulnerabilities`,
`Exposure status`
| limit 5 // limit to the top 5 affected entities

Query result:

List top affected entities by vulnerability count

Chart vulnerability status change events over time

Shows the count of status change events of vulnerabilities over time, grouped in one-hour buckets.

Query:

fetch events
| filter event.provider == "Dynatrace" // events generated by Dynatrace
| filter event.type == "VULNERABILITY_STATUS_CHANGE_EVENT" // vulnerability status change events
| filter event.level == "VULNERABILITY" // vulnerability level aggregation
| summarize {Open = countIf(event.status == "OPEN"),
Resolved = countIf(event.status == "RESOLVED"),
Muted = countIf(event.status == "MUTED")}, by:{timestamp = bin(timestamp, 1h)}
| sort timestamp, direction:"descending"

Query result:

Chart vulnerability status change events over time

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.

Dashboards: 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.

When generating the reports from templates, the filters and the context of the environment persist automatically in the generated dashboards.

Sample template:

template-dashboard-example

For details about the mechanism used to calculate the exploitation risk, see FAQ: What is Exploitation Risk Score?.

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.

Notebooks: 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.

When generating the reports from templates, the filters and the context of the environment persist automatically in the generated notebooks.

Sample template:

template-notebook-example

To start generating Notebook reports

Limitations

DQL queries for a specific entity

When you run DQL queries for a specific entity, the vulnerable functions in use by all entities are reported, instead of those in use only by the specific entity.

Entity change events

For Entity change events, filtering by closed events (event.status_transition == "CLOSE") doesn't return information about the vulnerable component of an affected entity if the resolved entity is the last affected entity of a vulnerability.