internal/scanners/defender.go (119 lines of code) (raw):

// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. package scanners import ( "context" "fmt" "github.com/Azure/azqr/internal/graph" "github.com/Azure/azqr/internal/models" "github.com/Azure/azqr/internal/to" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/rs/zerolog/log" ) // DefenderScanner - Defender scanner type DefenderScanner struct{} func (s *DefenderScanner) Scan(ctx context.Context, scan bool, cred azcore.TokenCredential, subscriptions map[string]string, filters *models.Filters) []models.DefenderResult { models.LogResourceTypeScan("Defender Status") resources := []models.DefenderResult{} if scan { graphClient := graph.NewGraphQuery(cred) query := ` SecurityResources | join kind=inner ( resourcecontainers | where type == 'microsoft.resources/subscriptions' | project subscriptionId, subscriptionName = name) on subscriptionId | where type == 'microsoft.security/pricings' | project SubscriptionId = subscriptionId, SubscriptionName = subscriptionName, Name = name, Tier = properties.pricingTier ` log.Debug().Msg(query) subs := make([]*string, 0, len(subscriptions)) for s := range subscriptions { subs = append(subs, &s) } result := graphClient.Query(ctx, query, subs) resources = []models.DefenderResult{} if result.Data != nil { for _, row := range result.Data { m := row.(map[string]interface{}) if filters.Azqr.IsSubscriptionExcluded(to.String(m["SubscriptionId"])) { continue } resources = append(resources, models.DefenderResult{ SubscriptionID: to.String(m["SubscriptionId"]), SubscriptionName: to.String(m["SubscriptionName"]), Name: to.String(m["Name"]), Tier: to.String(m["Tier"]), }) } } } return resources } func (s *DefenderScanner) GetRecommendations(ctx context.Context, scan bool, cred azcore.TokenCredential, subscriptions map[string]string, filters *models.Filters) []models.DefenderRecommendation { models.LogResourceTypeScan("Defender Recommendations") resources := []models.DefenderRecommendation{} if scan { graphClient := graph.NewGraphQuery(cred) query := ` SecurityResources | where type == 'microsoft.security/assessments' | where properties.status.code == 'Unhealthy' | mvexpand Category = properties.metadata.categories | extend AssessmentId = id, AssessmentKey = name, ResourceId = properties.resourceDetails.Id, ResourceIdsplit = split(properties.resourceDetails.Id, '/'), RecommendationName = properties.displayName, RecommendationState = properties.status.code, ActionDescription = properties.metadata.description, RemediationDescription = properties.metadata.remediationDescription, RecommendationSeverity = properties.metadata.severity, PolicyDefinitionId = properties.metadata.policyDefinitionId, AssessmentType = properties.metadata.assessmentType, Threats = properties.metadata.threats, UserImpact = properties.metadata.userImpact, AzPortalLink = tostring(properties.links.azurePortal) | extend ResourceSubId = tostring(ResourceIdsplit[2]), ResourceGroupName = tostring(ResourceIdsplit[4]), ResourceType = tostring(ResourceIdsplit[6]), ResourceName = tostring(ResourceIdsplit[8]) | join kind=leftouter (resourcecontainers | where type == 'microsoft.resources/subscriptions' | project SubscriptionName = name, subscriptionId) on subscriptionId | project SubscriptionId=subscriptionId, SubscriptionName, ResourceGroupName, ResourceType, ResourceName, Category, RecommendationSeverity, RecommendationName, ActionDescription, RemediationDescription, AzPortalLink, ResourceId ` log.Debug().Msg(query) subs := make([]*string, 0, len(subscriptions)) for s := range subscriptions { subs = append(subs, &s) } result := graphClient.Query(ctx, query, subs) resources = []models.DefenderRecommendation{} if result.Data != nil { for _, row := range result.Data { m := row.(map[string]interface{}) if filters.Azqr.IsServiceExcluded(to.String(m["ResourceId"])) { continue } resources = append(resources, models.DefenderRecommendation{ SubscriptionId: to.String(m["SubscriptionId"]), SubscriptionName: to.String(m["SubscriptionName"]), ResourceGroupName: to.String(m["ResourceGroupName"]), ResourceType: to.String(m["ResourceType"]), ResourceName: to.String(m["ResourceName"]), Category: to.String(m["Category"]), RecommendationSeverity: to.String(m["RecommendationSeverity"]), RecommendationName: to.String(m["RecommendationName"]), ActionDescription: to.String(m["ActionDescription"]), RemediationDescription: to.String(m["RemediationDescription"]), AzPortalLink: fmt.Sprintf("https://%s", to.String(m["AzPortalLink"])), ResourceId: to.String(m["ResourceId"]), }) } } } return resources }