Query Details

Multiple Running Container Image Qualys Vulnerability Assessments

Query

// Use here: https://portal.azure.com/#view/HubsExtension/ArgQueryBlade
SecurityResources
| where type =~ "microsoft.security/assessments/subassessments" and id has "41503391-efa5-47ee-9282-4eff6131462c" //and id has "providers/Microsoft.ContainerService/managedClusters"
// | extend assessedResourceType = tostring(properties["additionalData"]["assessedResourceType"])
// | where assessedResourceType == "GeneralVulnerability" // Qualys scanner
| extend
    cluster = extract(@"\/Microsoft\.ContainerService\/managedClusters\/([^\/]+)", 1, id),
    containers = todynamic(tostring(properties["additionalData"]["data"]["Containers"])),
    imageId = tostring(properties["additionalData"]["data"]["ImageId"])
| extend
    registryHost = extract(@"^([^\/]+)\/", 1, imageId),
    repositoryName = extract(@"^[^\/]+\/([^\@]+)\@", 1, imageId),
    imageDigest = extract(@"^[^\/]+\/[^\@]+\@(.+)$", 1, imageId),
    imageTag = tostring(properties["additionalData"]["data"]["Tag"]),
    imageOs = tostring(todynamic(tostring(properties["additionalData"]["data"]["ImageDetails"]))["OS"]),
    imageOsDetails = tostring(todynamic(tostring(properties["additionalData"]["data"]["ImageDetails"]))["OSDetails"]),
    //source = tostring(properties["additionalData"]["data"]["InventorySource"]),
    timeGenerated = todatetime(properties["timeGenerated"]),
    status = tostring(properties["status"]["code"]),
    statusCause = tostring(properties["status"]["cause"]),
    patchable = toboolean(properties["additionalData"]["data"]["Patchable"]),
    //assessmentType = tostring(properties["additionalData"]["data"]["Type"]),
    severity = tostring(properties["status"]["severity"]),
    category = tostring(properties["category"]),
    displayName = tostring(properties["displayName"]),
    description = tostring(properties["description"]),
    impact = tostring(properties["impact"]),
    remediation = tostring(properties["remediation"]),
    cvssv2 = tostring(todynamic(tostring(properties["additionalData"]["data"]["Cvss"]))["2.0"]["base"]),
    cvssv2Vector = tostring(todynamic(tostring(properties["additionalData"]["data"]["Cvss"]))["2.0"]["cvssVectorString"]),
    cvssv3 = tostring(todynamic(tostring(properties["additionalData"]["data"]["Cvss"]))["3.0"]["base"]),
    cvssv3Vector = tostring(todynamic(tostring(properties["additionalData"]["data"]["Cvss"]))["3.0"]["cvssVectorString"]),
    resourceId = tostring(properties["resourceDetails"]["id"]),
    assessmentId = toint(properties["id"]),
    cve = todynamic(tostring(properties["additionalData"]["data"]["Cve"]))
| mv-expand containers = iff(array_length(containers) == 0, dynamic([""]), containers)
| extend container = tostring(containers["Name"])
| mv-expand cve = iff(array_length(cve) == 0, dynamic([""]), cve)
| extend cveId = tostring(cve["Id"])
| summarize
    Vulnerabilities = make_set_if(pack(
        "CVE", cveId,
        "Category", category,
        "DisplayName", displayName,
        //"Description", description,
        //"Impact", impact,
        //"Remediation", remediation,
        "Severity", severity,
        "CVSSv2", cvssv2,
        //"CVSSv2Vector", cvssv2Vector,
        "CVSSv3", cvssv3,
        //"CVSSv3Vector", cvssv3Vector,
        "Patchable", patchable,
        "AssessmentId", assessmentId
    ), status == "Unhealthy"),
    container = make_set(container),
    arg_max(timeGenerated, registryHost, repositoryName, imageDigest, imageOs, imageOsDetails)
        //severity, category, description, impact, remediation, cvssv2, cvssv2Vector, cvssv3, cvssv3Vector)
    by status, statusCause, tenantId, subscriptionId, resourceGroup, cluster, resourceId, imageTag
        //, assessmentId, displayName, cveId
| join kind=leftouter (
    ResourceContainers
    | where type == "microsoft.resources/subscriptions"
    | project subscriptionId, subscriptionName = name
    ) on subscriptionId
// The same image can be used in different clusters
| summarize
    Containers = make_list(pack(
        "subscriptionName", subscriptionName,
        "resourceGroup", resourceGroup,
        "cluster", cluster,
        "containers", container
        )),
    arg_max(timeGenerated, registryHost, repositoryName, imageDigest, imageOs, imageOsDetails,
        Vulnerabilities)
        //severity, category, description, impact, remediation, cvssv2, cvssv2Vector, cvssv3, cvssv3Vector)
    by status, statusCause, tenantId, resourceId, imageTag
        //, assessmentId, displayName, cveId
| sort by tenantId asc, status asc, resourceId asc
| project
    tenantId,
    resourceId,
    Containers,
    registryHost,
    repositoryName,
    imageDigest,
    imageTag,
    imageOs,
    imageOsDetails,
    status,
    statusCause,
    Vulnerabilities

Explanation

This query retrieves security assessment data for Microsoft Container Service managed clusters. It extracts various properties related to the containers and images, such as registry host, repository name, image digest, image tag, image OS, and image OS details. It also includes information about the status, severity, category, display name, description, impact, remediation, CVSS scores, patchability, assessment ID, and CVEs associated with the assessments. The query then summarizes the data by grouping it based on the status, status cause, tenant ID, resource ID, image tag, and other relevant fields. It also joins the data with the subscription information from the ResourceContainers table. Finally, the query sorts the results and projects the desired fields for further analysis.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: October 4, 2023

Tables

SecurityResourcesResourceContainers

Keywords

Devices,Intune,User

Operators

wherehasextracttodynamictostringtodatetimetobooleanarray_lengthiffmv-expandsummarizemake_set_ifpackmake_setarg_maxbyjoinprojectsort

Actions