Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Security recommendations in Microsoft Defender for Cloud help you improve and harden your security posture. Recommendations are based on assessments against security standards defined for Azure subscriptions, Amazon Web Services (AWS) accounts, and Google Cloud Platform (GCP) projects that have Defender for Cloud enabled.
This article describes how to:
- Create custom recommendations for all clouds (Azure, AWS, and GCP) with a Kusto Query Language (KQL) query.
- Assign custom recommendations to a custom security standard.
Before you start
- You need Owner permissions on the subscription to create a new security standard.
- You need Security Admin permissions to create custom recommendations.
- To create custom recommendations based on Kusto Query Language (KQL), you must have the Defender Cloud Security Posture Management (CSPM) plan enabled. All customers can create custom recommendations based on Azure Policy.
- Review support in Azure clouds for custom recommendations.
We recommend watching this episode of Defender for Cloud in the field to learn more about custom recommendations and how to write KQL queries.
Create a custom recommendation
Create custom recommendations, including steps for remediation, severity, and the standards to which the recommendation should be assigned. You add recommendation logic with KQL. You can use a simple query editor with built-in query templates that you can tweak as needed, or you can write your KQL query from scratch.
To create a custom recommendation:
Sign in to the Azure portal.
Go to Microsoft Defender for Cloud > Environment settings > the relevant subscription.
Select Security policies > + Create custom recommendation.
Enter the details: Required: Name, Scope, Severity, and Security issue. Optional: Description, Remediation.
Select Next.
Enter a KQL query, or select Open query editor.
Select Next.
Select the relevant standards for the recommendation.
Select Next.
Select the custom standards to assign.
Select Review and create.
Review the recommendation details.
Select Create.
Use the query editor
We recommend using the query editor to create a recommendation query. You can also use the provided query templates and examples to view sample queries and learn how to build your own.
- Using the editor helps you to build and test your query before you start using it.
- Select How to to get help on structuring the query, and additional instructions and links.
- The editor contains built-in recommendation query examples that you can use to help build your own query. The data appears in the same structure as in the API.
Select New query.
Use the example query template with its instructions, or select an example built-in recommendation query from the lower part of the page, to get started.
Select Run query to test the query you created.
When the query is ready, cut and paste it from the editor into the Recommendation query pane.
Continue with step 7 from the Create a custom recommendation section.
Query templates and examples
The query editor includes built-in examples, and the templates in this section show how to structure common security checks. Each template returns resources in scope and marks non-compliant resources as UNHEALTHY. In this template pattern, edit only the condition expression and keep the HealthStatus line unchanged.
Note
The templates in this section use Azure resource types. For AWS and GCP resources, change Environment == 'Azure' to Environment == 'AWS' or Environment == 'GCP' and update Identifiers.Type to match the resource type in your environment.
KQL output schema requirements
Before you write your query, understand the required output schema. This is how Microsoft Defender for Cloud interprets your results and maps findings to resources.
Required output columns:
| Column | Type | Purpose |
|---|---|---|
Id |
String (required) | Resource identifier used by Defender for Cloud to reference the resource. |
Name |
String (required) | Human-readable resource name displayed in findings. |
Environment |
String (required) | Cloud environment: Azure, AWS, or GCP. |
Identifiers |
Dynamic (required) | Resource type and identifiers passed through from the source record. |
AdditionalData |
Dynamic (required) | Supplementary resource metadata passed through from the source record. |
Record |
Dynamic (required) | Full resource record containing all properties. |
HealthStatus |
String (required) | Assessment result: UNHEALTHY (non-compliant) or HEALTHY (compliant). |
Always end your query with: | project Id, Name, Environment, Identifiers, AdditionalData, Record, HealthStatus
Assessment mapping:
Every query must set a HealthStatus value for each resource. Use the iff() function to evaluate your condition and assign the status:
| extend condition = (your condition here)
| extend HealthStatus = iff(condition, 'UNHEALTHY', 'HEALTHY')
In this pattern, edit only the condition expression. Keep the HealthStatus line unchanged:
| extend HealthStatus = iff(condition, 'UNHEALTHY', 'HEALTHY')
Resources where HealthStatus is UNHEALTHY appear as non-compliant findings in Defender for Cloud. Resources where HealthStatus is HEALTHY are compliant and don't appear in findings.
Important
Always set HealthStatus to either 'UNHEALTHY' or 'HEALTHY'. Return all resources in scope. Defender for Cloud uses the HealthStatus column to determine compliance. Omitting resources from the result set is treated as no data, not as healthy.
Common errors and fixes:
- Missing required columns: If any of the seven required columns are missing, the query fails. Always end with
| project Id, Name, Environment, Identifiers, AdditionalData, Record, HealthStatus. - Wrong
HealthStatusvalues: Only'UNHEALTHY'and'HEALTHY'are valid values (case-sensitive). Other values or null cause parsing errors. - Incorrect property paths: Properties are accessed via
Record.properties.*, not directly. For example, useRecord.properties.httpsOnly, notproperties.httpsOnly. - Resource type case sensitivity: Use
=~(case-insensitive match) forIdentifiers.Typecomparisons. For example,Identifiers.Type =~ 'Microsoft.Storage/storageAccounts'. - Null properties across subscriptions: Test your query across subscriptions with varied configurations. Use
isnull()checks where properties may be absent.
Use custom recommendations at scale
Creating custom recommendations in the Azure portal is best for most users. The interface provides a convenient KQL editor and built-in validation tools. A programmatic approach can also be useful when you need to deploy recommendations across many environments or subscriptions.
Automate via the API
If you prevalidated KQL queries and want to automate creating custom recommendations, you can use the Microsoft Defender for Cloud API. This method lets you deploy recommendations quickly, ensuring they're consistent and scalable across your cloud environments.
- Advantages: You can automate and scale the deployment of custom recommendations.
- When to use: This method is ideal for large-scale implementations where you need to apply recommendations consistently across multiple environments.
For more information about using the API to manage custom recommendations, see the Defender for Cloud Composite API reference.
Create a custom standard
Custom recommendations can be assigned to one or more custom standards.
To create a custom standard:
Sign in to the Azure portal.
Go to Microsoft Defender for Cloud > Environment settings > the relevant subscription.
Select Security policies > + Create > Standard.
Select the recommendations that you want to add to the custom standard.
(Optional) For Azure subscriptions, review the Source column.
Select Create.
Create and enhance custom recommendations with Azure Policy (legacy)
For Azure subscriptions, you can create custom recommendations and standards, and enhance them, using Azure Policy. This is a legacy feature, and we recommend using the new custom recommendations feature.
Create a custom recommendation and standard (legacy)
You can create custom recommendations and standards in Defender for Cloud by creating policy definitions and initiatives in Azure Policy, and onboarding them in Defender for Cloud.
To create a custom recommendation or standard with Azure Policy (legacy):
- Create one or more policy definitions in the Azure Policy portal, or programmatically.
- Create a policy initiative that contains the custom policy definitions.
Onboard the initiative as a custom standard (legacy)
Policy assignments are used by Azure Policy to assign Azure resources to a policy or initiative.
To onboard an initiative to a custom security standard in Defender for Cloud, you need to include "ASC":"true" in the request body as shown here. The ASC field onboards the initiative to Microsoft Defender for Cloud.
To onboard a custom initiative:
Example to onboard a custom initiative
PUT https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Authorization/policySetDefinitions/{policySetDefinitionName}?api-version=2021-06-01
Request body (JSON):
{
"properties": {
"displayName": "Cost Management",
"description": "Policies to enforce low cost storage SKUs",
"metadata": {
"category": "Cost Management",
"ASC":"true"
},
"parameters": {
"namePrefix": {
"type": "String",
"defaultValue": "myPrefix",
"metadata": {
"displayName": "Prefix to enforce on resource names"
}
}
},
"policyDefinitions": [
{
"policyDefinitionId": "/subscriptions/<Subscription ID>/providers/Microsoft.Authorization/policyDefinitions/7433c107-6db4-4ad1-b57a-a76dce0154a1",
"policyDefinitionReferenceId": "Limit_Skus",
"parameters": {
"listOfAllowedSKUs": {
"value": [
"Standard_GRS",
"Standard_LRS"
]
}
}
},
{
"policyDefinitionId": "/subscriptions/<Subscription ID>/providers/Microsoft.Authorization/policyDefinitions/ResourceNaming",
"policyDefinitionReferenceId": "Resource_Naming",
"parameters": {
"prefix": {
"value": "[parameters('namePrefix')]"
},
"suffix": {
"value": "-LC"
}
}
}
]
}
}
Example to remove an assignment
This example shows you how to remove an assignment:
DELETE https://management.azure.com/{subscription}/providers/Microsoft.Authorization/policyAssignments/{policyAssignmentName}?api-version=2018-05-01
Enhance custom recommendations (legacy)
The built-in recommendations supplied with Microsoft Defender for Cloud include details such as severity levels and remediation instructions. If you want to add this type of information to custom recommendations for Azure, use the REST API.
The two types of information you can add are:
- RemediationDescription – String
- Severity – Enum [Low, Medium, High]
The metadata should be added to the policy definition for a policy that is part of the custom initiative. It should be in the 'securityCenter' property, as shown:
{
"metadata": {
"securityCenter": {
"RemediationDescription": "Custom description goes here",
"Severity": "High"
}
}
}
Here's another example of a custom policy including the metadata/securityCenter property:
{
"properties": {
"displayName": "Security - ERvNet - AuditRGLock",
"policyType": "Custom",
"mode": "All",
"description": "Audit required resource groups lock",
"metadata": {
"securityCenter": {
"RemediationDescription": "Resource Group locks can be set via Azure Portal -> Resource Group -> Locks",
"Severity": "High"
}
},
"parameters": {
"expressRouteLockLevel": {
"type": "String",
"metadata": {
"displayName": "Lock level",
"description": "Required lock level for ExpressRoute resource groups."
},
"allowedValues": [
"CanNotDelete",
"ReadOnly"
]
}
},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.Resources/subscriptions/resourceGroups"
},
"then": {
"effect": "auditIfNotExists",
"details": {
"type": "Microsoft.Authorization/locks",
"existenceCondition": {
"field": "Microsoft.Authorization/locks/level",
"equals": "[parameters('expressRouteLockLevel')]"
}
}
}
}
}
}
For another securityCenter property example, see REST API examples for assessments metadata.
Next steps
You can use the following links to learn more about Kusto queries: