The examples below illustrate how to build powerful and flexible security reports by using DQL queries to slice and dice historical security events.
Get the total number of open, non-muted vulnerabilities in your environment.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status=="OPEN"AND vulnerability.parent.mute.status!="MUTED"AND vulnerability.mute.status!="MUTED"// count unique vulnerabilities| summarize {`Open vulnerabilities`=countDistinctExact(vulnerability.display_id)}
Query result:
Get the total number of critical open, non-muted vulnerabilities in your environment.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for critical open non-muted vulnerabilities| filter vulnerability.resolution.status=="OPEN"AND vulnerability.parent.mute.status!="MUTED"AND vulnerability.mute.status!="MUTED"AND vulnerability.risk.level=="CRITICAL"// count unique vulnerabilities| summarize {`Critical open vulnerabilities`=countDistinctExact(vulnerability.display_id)}
Query result:
Get the total number of open, non-muted vulnerabilities in a specific management zone (in this example, AppSec: UNGUARD
).
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities in a specific management zone| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"AND in("AppSec: Unguard", affected_entity.management_zones.names)// count unique vulnerabilities| summarize {`Open vulnerabilities (unguard)`=countDistinctExact(vulnerability.display_id)}
Query result:
Get the total number of open, non-muted vulnerabilities with public internet exposure in your environment.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities with public internet exposure| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"AND vulnerability.davis_assessment.exposure_status=="PUBLIC_NETWORK"// count unique vulnerabilities| summarize {`With internet exposure`=countDistinctExact(vulnerability.display_id)}
Query result:
Get the total number of affected entities in your environment.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"// count unique entities| summarize {`Affected entities`=countDistinctExact(affected_entity.id)}
Query result:
Get the total number of affected process groups in your environment.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities detected in running processes| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"AND affected_entity.type=="PROCESS_GROUP"// count unique entities| summarize {`Affected process groups`=countDistinctExact(affected_entity.id)}
Query result:
Get the total number of affected, non-muted entities over time (in three-hour buckets).
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for open non-muted vulnerabilitiesAND vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"// count unique entities for each timestamp bucket of 3h| sort timestamp desc| summarize {entities=countDistinctExact(affected_entity.id)}, by: {timestamp=bin(timestamp, 3h)}
Query result:
Get the total number of hosts that are indirectly affected by open vulnerabilities in your environment.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities|filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"// count hosts| summarize {`Related hosts`=arraySize(collectDistinct(related_entities.hosts.ids, expand:true))}
Query result:
Get a count of open vulnerabilities split by risk levels.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"// summarize score per vulnerability| summarize {vulnerability.risk.score=takeMax(vulnerability.risk.score)}, by: {vulnerability.display_id}// map the risk level| fieldsAdd vulnerability.risk.level=if(vulnerability.risk.score>=9,"CRITICAL",else:if(vulnerability.risk.score>=7,"HIGH",else:if(vulnerability.risk.score>=4,"MEDIUM",else:if(vulnerability.risk.score>=0.1,"LOW",else:"NONE"))))// count vulnerabilities per risk level| summarize { Vulnerabilities=count(), maxScore=takeMax(vulnerability.risk.score) }, by:{vulnerability.risk.level}| sort maxScore, direction:"descending"
Query result:
Get a count of open vulnerabilities split by type.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"// count vulnerabilities per type| summarize { Vulnerabilities=countDistinctExact(vulnerability.display_id) }, by:{vulnerability.type}| sort Vulnerabilities, direction:"descending"| limit 10
Query result:
Get the open vulnerability count over time, in three-hour buckets.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for open non-muted vulnerabilitiesAND vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"| sort timestamp desc| summarize {Open=countDistinctExact(vulnerability.display_id)}, by: {timestamp=bin(timestamp,3h)}
Query result:
Get the open vulnerabilities on a specific library (in this example, log4j
).
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"// filter by the vulnerable library/component nameAND contains(affected_entity.vulnerable_component.name,"log4j",caseSensitive:false)// now summarize on the vulnerability level| summarize{vulnerability.risk.score=round(takeMax(vulnerability.risk.score),decimals:1),vulnerability.title=takeFirst(vulnerability.title),vulnerability.references.cve=takeFirst(vulnerability.references.cve),last_detected=coalesce(takeMax(vulnerability.resolution.change_date),takeMax(vulnerability.parent.first_seen)),affected_entities=countDistinctExact(affected_entity.id),vulnerable_function_in_use=if(in("IN_USE",collectArray(vulnerability.davis_assessment.vulnerable_function_status)),true, else:false),public_internet_exposure=if(in("PUBLIC_NETWORK",collectArray(vulnerability.davis_assessment.exposure_status)),true,else:false),public_exploit_available=if(in("AVAILABLE",collectArray(vulnerability.davis_assessment.exploit_status)),true,else:false),data_assets_within_reach=if(in("REACHABLE",collectArray(vulnerability.davis_assessment.data_assets_status)),true,else:false)}, by: {vulnerability.display_id}// map the risk level| fieldsAdd vulnerability.risk.level=if(vulnerability.risk.score>=9,"CRITICAL",else:if(vulnerability.risk.score>=7,"HIGH",else:if(vulnerability.risk.score>=4,"MEDIUM",else:if(vulnerability.risk.score>=0.1,"LOW",else:"NONE"))))| sort {vulnerability.risk.score, direction:"descending"}, {affected_entities, direction:"descending"}
Query result:
Get the open vulnerabilities directly or indirectly affecting a specific host (in this example, i-05f1305a50721e04d
).
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"// filter by the host name of the related/affected hostAND in("easytravel-demo2",related_entities.hosts.names) OR affected_entity.name=="easytravel-demo2"// now summarize on the vulnerability level| summarize{vulnerability.risk.score=round(takeMax(vulnerability.risk.score),decimals:1),vulnerability.title=takeFirst(vulnerability.title),vulnerability.references.cve=takeFirst(vulnerability.references.cve),last_detected=coalesce(takeMax(vulnerability.resolution.change_date),takeMax(vulnerability.parent.first_seen)),affected_entities=countDistinctExact(affected_entity.id),vulnerable_function_in_use=if(in("IN_USE",collectArray(vulnerability.davis_assessment.vulnerable_function_status)),true, else:false),public_internet_exposure=if(in("PUBLIC_NETWORK",collectArray(vulnerability.davis_assessment.exposure_status)),true,else:false),public_exploit_available=if(in("AVAILABLE",collectArray(vulnerability.davis_assessment.exploit_status)),true,else:false),data_assets_within_reach=if(in("REACHABLE",collectArray(vulnerability.davis_assessment.data_assets_status)),true,else:false)}, by: {vulnerability.display_id}// map the risk level| fieldsAdd vulnerability.risk.level=if(vulnerability.risk.score>=9,"CRITICAL",else:if(vulnerability.risk.score>=7,"HIGH",else:if(vulnerability.risk.score>=4,"MEDIUM",else:if(vulnerability.risk.score>=0.1,"LOW",else:"NONE"))))| sort {vulnerability.risk.score, direction:"descending"}, {affected_entities, direction:"descending"}
Query result:
Get the open vulnerabilities affecting a specific application (in this example, www.easytravel.com
).
Query example:
| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"// filter by name of the related applicationsAND in("www.easytravel.com",related_entities.applications.names)// now summarize on the vulnerability level| summarize{vulnerability.risk.score=round(takeMax(vulnerability.risk.score),decimals:1),vulnerability.title=takeFirst(vulnerability.title),vulnerability.references.cve=takeFirst(vulnerability.references.cve),last_detected=coalesce(takeMax(vulnerability.resolution.change_date),takeMax(vulnerability.parent.first_seen)),affected_entities=countDistinctExact(affected_entity.id),vulnerable_function_in_use=if(in("IN_USE",collectArray(vulnerability.davis_assessment.vulnerable_function_status)),true, else:false),public_internet_exposure=if(in("PUBLIC_NETWORK",collectArray(vulnerability.davis_assessment.exposure_status)),true,else:false),public_exploit_available=if(in("AVAILABLE",collectArray(vulnerability.davis_assessment.exploit_status)),true,else:false),data_assets_within_reach=if(in("REACHABLE",collectArray(vulnerability.davis_assessment.data_assets_status)),true,else:false)}, by: {vulnerability.display_id}// map the risk level| fieldsAdd vulnerability.risk.level=if(vulnerability.risk.score>=9,"CRITICAL",else:if(vulnerability.risk.score>=7,"HIGH",else:if(vulnerability.risk.score>=4,"MEDIUM",else:if(vulnerability.risk.score>=0.1,"LOW",else:"NONE"))))| sort {vulnerability.risk.score, direction:"descending"}, {affected_entities, direction:"descending"}
Query result:
Get the top 10 affected entities by the number of open vulnerabilities.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"| summarize {`Affected entity name` = takeFirst(affected_entity.name),Type = takeFirst(affected_entity.type),Vulnerabilities = countDistinctExact(vulnerability.display_id)}, by: {dt.source_entity=affected_entity.id}| sort {Vulnerabilities, direction:"descending"}| limit 10
Query result:
Get the top five process groups by the count of open vulnerabilities, with their respective owners.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"AND affected_entity.type=="PROCESS_GROUP"// summarize per process group| summarize {`Affected entity name` = takeFirst(affected_entity.name),Type = takeFirst(affected_entity.type),Vulnerabilities = countDistinctExact(vulnerability.display_id)}, by: {dt.source_entity=affected_entity.id}| sort {Vulnerabilities, direction:"descending"}| limit 10// add ownership information| lookup [fetch dt.entity.process_group| parse toString(tags), "LD ('owner:'|'owner\\\\:') (SPACE)? LD:Team ('\"')"| fields id, Team=coalesce(Team, "-")], sourceField:dt.source_entity, lookupField:id, fields:{Team}| sort Vulnerabilities, direction:"descending"
Query result:
Get the hosts that are indirectly related to open vulnerabilities on a specific library (in this example, tomcat
), with their respective owners.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"AND related_entities.hosts.count > 0// filter by the vulnerable component nameAND contains(affected_entity.vulnerable_component.name,"tomcat")| expand entity_id=related_entities.hosts.ids| summarize Vulnerabilities=countDistinctExact(vulnerability.display_id), by: {entity_id}//add ownership information| lookup [fetch dt.entity.host| parse toString(tags), "LD ('owner:'|'owner\\\\:') (SPACE)? LD:Team ('\"')"| fields id, Host=entity.name, Team=coalesce(Team, "-")], sourceField:entity_id, lookupField:id, fields: {Host,Team}| sort Vulnerabilities, direction:"descending"
Query result:
Get the vulnerable components of a specific host (in this example, HOST-4CF0F659B8823D74
) with owners.
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"// filter by ID of the related or affected hostAND in("HOST-DBF63A01C27E4B50",related_entities.hosts.ids) or affected_entity.id=="HOST-DBF63A01C27E4B50"| summarize{entities=countDistinctExact(affected_entity.id),vulnerable_functions=arraySize(collectDistinct(affected_entity.vulnerable_functions, expand:true)),vulnerable_component.name=takeAny(affected_entity.vulnerable_component.name)}, by: {dt.entity.software_component=affected_entity.vulnerable_component.id}| filterOut isNull(dt.entity.software_component)// add component information| lookup [fetch dt.entity.software_component| fieldsAdd softwareComponentFileName], sourceField:dt.entity.software_component, lookupField:id, fields:{softwareComponentFileName}| fields dt.entity.software_component, vulnerable_component.name, softwareComponentFileName, entities, vulnerable_functions| sort {entities, direction:"descending"}, {vulnerable_functions, direction:"descending"}
Query result:
Get the vulnerable functions of a specific software component (in this example, SOFTWARE_COMPONENT-1D466FB7ADEBF92E
).
Query example:
fetch events| filter dt.system.bucket=="default_security_events"AND event.provider=="Dynatrace"AND event.type=="VULNERABILITY_STATE_REPORT_EVENT"AND event.level=="ENTITY"// filter for the latest snapshot per entity| dedup {vulnerability.display_id, affected_entity.id}, sort:{timestamp desc}// filter for open non-muted vulnerabilities| filter vulnerability.resolution.status == "OPEN"AND vulnerability.parent.mute.status != "MUTED"AND vulnerability.mute.status != "MUTED"// filter for the software component IDAND affected_entity.vulnerable_component.id=="SOFTWARE_COMPONENT-1D466FB7ADEBF92E"| expand vulnerable_function=affected_entity.vulnerable_functions| filter isNotNull(vulnerable_function)| summarize{Usages=countIf(in(vulnerable_function,affected_entity.vulnerable_functions))}, by: {vulnerable_function}| sort {Usages, direction:"descending"}
Query result:
Get the total number of critical vulnerability findings ingested into Dynatrace.
Query example:
fetch events| filter dt.system.bucket == "default_security_custom_events"AND event.type == "VULNERABILITY_FINDING"AND isNotNull(component.name)// latest findings per affected object, vulnerability and component| dedup {object.id, vulnerability.id, component.name, component.version}, sort: {timestamp desc}// aggregation and custom filtering| filter dt.security.risk.level=="CRITICAL"| summarize {Vulnerabilities=countDistinctExact(vulnerability.id)}
Query result:
Get the total number of container images containing vulnerability findings ingested into Dynatrace.
Query example:
fetch events| filter dt.system.bucket == "default_security_custom_events"AND event.type == "VULNERABILITY_FINDING"AND isNotNull(component.name)// latest findings per affected object, vulnerability and component| dedup {object.id, vulnerability.id, component.name, component.version,container_image.registry, container_image.repository, container_image.tags}, sort: {timestamp desc}// aggregation and custom filtering| summarize {containerImages=countDistinctExact(container_image.digest)}
Query result:
Get the total number of vulnerable components in the container images containing vulnerability findings ingested into Dynatrace.
Query example:
fetch events| filter dt.system.bucket == "default_security_custom_events"AND event.type == "VULNERABILITY_FINDING"AND isNotNull(component.name)// latest findings per affected object, vulnerability and component| dedup {object.id, vulnerability.id, component.name, component.version}, sort: {timestamp desc}// aggregation and custom filtering| summarize {components=countDistinctExact(component.name)}
Query result:
Get the most recent vulnerability findings ingested into Dynatrace.
Query example:
fetch events// data access| filter dt.system.bucket == "default_security_custom_events"AND event.type == "VULNERABILITY_FINDING"AND isNotNull(component.name)// latest findings per affected object, vulnerability and component| dedup {object.id, vulnerability.id, component.name, component.version}, sort: {timestamp desc}| sort timestamp desc
Query result:
Get the total number of ingested container images that have been scanned.
Query example:
fetch events| filter dt.system.bucket == "default_security_custom_events"| filter event.kind == "SECURITY_EVENT"AND object.type == "CONTAINER_IMAGE" // includes both SCAN_EVENTS and VULNERABILITY_FINDINGS without scan events| dedup {container_image.digest}, sort: {timestamp desc}| summarize {containerImages=count()}
Query result:
Get the total number of scan events from ingested container images.
Query example:
fetch events| filter dt.system.bucket == "default_security_custom_events"| filter event.kind == "SECURITY_EVENT"AND event.type == "VULNERABILITY_SCAN"AND object.type == "CONTAINER_IMAGE"| summarize {scanEvents=count()}
Query result: