Audit for specific Azure DNS in a specific region (Azure Policy) - json

I'd like to have an Azure Policy that audits for specific Azure DNS's in the targeted Region. Both should be available in an array so the policy can be scoped multiple times.
So far I've got this, which does not work since it puts the state in compliance by having the right DNS set, but completely ignores the region specified in the array. My goal is to have the policy compliance check for both.
{
"mode": "All",
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/virtualNetworks"
},
{
"anyOf": [
{
"value": "[if(empty(field('Microsoft.Network/virtualNetworks/dhcpOptions.dnsServers')), bool('false'), equals(length(intersection(parameters('dnsSettings'), field('Microsoft.Network/virtualNetworks/dhcpOptions.dnsServers'))), length(parameters('dnsSettings'))))]",
"equals": false
},
{
"value": "[if(empty(field('Microsoft.Network/virtualNetworks/dhcpOptions.dnsServers')), bool('false'), equals(length(field('Microsoft.Network/virtualNetworks/dhcpOptions.dnsServers')),length(parameters('dnsSettings'))))]",
"equals": false
}
]
},
{
"not": {
"allOf": [
{
"field": "location",
"in": "[parameters('location')]"
}
]
}
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
},
"parameters": {
"dnsSettings": {
"type": "Array",
"metadata": {
"displayName": "dnsSettings",
"description": "Audit for specific DNS settings."
}
},
"location": {
"type": "Array",
"metadata": {
"displayName": "Location",
"description": "Choose specific location",
"strongType": "location"
}
},
"effect": {
"type": "String",
"metadata": {
"displayName": "Effects",
"description": "Enable or disable the execution of the Policy."
},
"allowedValues": [
"Audit",
"Disabled"
],
"defaultValue": "Audit"
}
}
}

We can use auditIfNotExists with few logic operations so that this will allow only after the success code, below sample is to understand about .
{
"if": {
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
"then": {
"effect": "auditIfNotExists",
"details": {
"type": "Microsoft.Compute/virtualMachines/extensions",
"existenceCondition": {
"allOf": [{
"field": "Microsoft.Compute/virtualMachines/extensions/publisher",
"equals": "Microsoft.Azure.Security"
},
{
"field": "Microsoft.Compute/virtualMachines/extensions/type",
"equals": "IaaSAntimalware"
}
]
}
}
}
}
Below is the way we can specify the dns, Sample for adding dns:
{
"mode": "All",
"name": "Deny changing VNet DNS settings from pre-defined value",
"description": "This Policy will prevent users from changing DNS settings on a VNet",
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/virtualNetworks"
},
{
"anyOf": [
{
"value": "[if(empty(field('Microsoft.Network/virtualNetworks/dhcpOptions.dnsServers')), bool('false'), equals(length(intersection(parameters('dnsSettings'), field('Microsoft.Network/virtualNetworks/dhcpOptions.dnsServers'))), length(parameters('dnsSettings'))))]",
"equals": false
},
{
"value": "[if(empty(field('Microsoft.Network/virtualNetworks/dhcpOptions.dnsServers')), bool('false'), equals(length(field('Microsoft.Network/virtualNetworks/dhcpOptions.dnsServers')),length(parameters('dnsSettings'))))]",
"equals": false
}
]
}
]
},
"then": {
"effect": "auditIfNotExists"
}
},
"parameters": {
"dnsSettings": {
"type": "array",
"metadata": {
"displayname": "Enforced DNS Settings",
"description": "Users will be unable to change the DNS settings on a VNet from the values defined in this array."
}
}
}
}
Check AzurePolicy.json and AzurePolicy.rules.json to understand about allowing standard dns within application rules. Include location settings in it.

Related

Azure Policy Not Denying Route Creation

I want to make an Azure policy that denies anyone trying to create a route to certain prefixes that don't use the next hop virtual appliance parameter and IP that I specify. I have this working with just a single prefix (0.0.0.0/0 internet route) but as soon as I try to define other routes (10.0.0.0/8) it doesn't work. Here is what I have so far:
{
"mode": "All",
"policyRule": {
"if": {
"anyOf": [
{
"allOf": [
{
"field": "type",
"equals": "Microsoft.Network/routeTables"
},
{
"count": {
"field": "Microsoft.Network/routeTables/routes[*]",
"where": {
"anyOf": [
{
"field": "Microsoft.Network/routeTables/routes[*].addressPrefix",
"equals": "0.0.0.0/0"
},
{
"anyOf": [
{
"field": "Microsoft.Network/routeTables/routes[*].nextHopType",
"notEquals": "VirtualAppliance"
},
{
"field": "Microsoft.Network/routeTables/routes[*].nextHopIpAddress",
"notEquals": "[parameters('routeTableSettings')[field('location')].virtualApplianceIpAddress]"
}
]
},
{
"field": "Microsoft.Network/routeTables/routes[*].addressPrefix",
"equals": "10.0.0.0/8"
},
{
"anyOf": [
{
"field": "Microsoft.Network/routeTables/routes[*].nextHopType",
"notEquals": "VirtualAppliance"
},
{
"field": "Microsoft.Network/routeTables/routes[*].nextHopIpAddress",
"notEquals": "[parameters('routeTableSettings')[field('location')].virtualApplianceIpAddress]"
}
]
}
]
}
},
"greater": 0
}
]
},
{
"anyOf": [
{
"field": "type",
"equals": "Microsoft.Network/routeTables/routes"
},
{
"field": "Microsoft.Network/routeTables/routes[*].addressPrefix",
"equals": "0.0.0.0/0"
},
{
"anyOf": [
{
"field": "Microsoft.Network/routeTables/routes/nextHopType",
"notEquals": "VirtualAppliance"
},
{
"field": "Microsoft.Network/routeTables/routes/nextHopIpAddress",
"notEquals": "[parameters('routeTableSettings')[field('location')].virtualApplianceIpAddress]"
}
]
},
{
"field": "type",
"equals": "Microsoft.Network/routeTables/routes"
},
{
"field": "Microsoft.Network/routeTables/routes[*].addressPrefix",
"equals": "10.0.0.0/8"
},
{
"anyOf": [
{
"field": "Microsoft.Network/routeTables/routes/nextHopType",
"notEquals": "VirtualAppliance"
},
{
"field": "Microsoft.Network/routeTables/routes/nextHopIpAddress",
"notEquals": "[parameters('routeTableSettings')[field('location')].virtualApplianceIpAddress]"
}
]
}
]
}
]
},
"then": {
"effect": "deny"
}
},
"parameters": {
"routeTableSettings": {
"type": "Object",
"metadata": {
"displayName": "Route Table Settings",
"description": "Location-specific settings for route tables."
}
}
}
}
Parameters
{
"eastus2": {
"virtualApplianceIpAddress": "10.1.1.1"
},
"disabled": {
"virtualApplianceIpAddress": ""
}
}
To achieve the above requirement we need to use IN clause in our azure policy to deny/not allow the resource type to create .
As suggested by #harshavmb in comment which is correct. Posting it as an answer to help other community members to find fix their issue for the same.
The MS DOC has an example how to use the in with policy rule:
{
"properties": {
"displayName": "Allowed locations",
"description": "This policy enables you to restrict the locations your organization can specify when deploying resources.",
"mode": "Indexed",
"metadata": {
"version": "1.0.0",
"category": "Locations"
},
"parameters": {
"allowedLocations": {
"type": "array",
"metadata": {
"description": "The list of locations that can be specified when deploying resources",
"strongType": "location",
"displayName": "Allowed locations"
},
"defaultValue": [ "westus2" ]
}
},
"policyRule": {
"if": {
"not": {
"field": "location",
"in": "[parameters('allowedLocations')]"
}
},
"then": {
"effect": "deny"
}
}
}
}
Also from Azure portal>Policy> Not allowed resource we can find the json with in clause .
As shown below:
For more information please refer the below links:-
MICROSOFT DOCUMENTATION:- Not_allowed_resource_types
BLOG:- AZURE POLICY TO DENY CREATION OF ALL RESOURCES

Azure Policy for Naming

I'm doing something incorrectly here regarding an Azure Policy I'm creating. Trying to create a naming policy that blocks creation of a resource (in this case a resource group) that doesn't match.
{
"properties": {
"mode": "All",
"displayName": "Company Naming Convention - Resource Groups",
"description": "This policy governs the naming standard for resource groups and should be assigned at the resource group scope. The naming scheme is rg-region-workload name-environment-optional instance number'.",
"metadata": {
"category": "Governance"
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Resources/resourceGroups"
},
{
"allOf": [
{
"field": "name",
"notLike": "rg-useast-*"
},
{
"field": "name",
"notLike": "rg-useast2-*"
},
{
"field": "name",
"notLike": "rg-uscentral-*"
},
{
"field": "name",
"notLike": "rg-uksouth-*"
}
]
},
{
"allOf": [
{
"field": "name",
"notLike": "*-production.###"
},
{
"field": "name",
"notLike": "*-development.###"
},
{
"field": "name",
"notLike": "*-qualityassurance.###"
},
{
"field": "name",
"notLike": "*-testing.###"
}
]
}
]
},
"then": {
"effect": "deny"
}
}
}
}
I'd ALSO like to create a policy to audit existing resources that don't match this name, but I can address that later. Anyone have a suggestion what I'm doing wrong or a better way to go about this?
Ok... so the original policy works great... if I actually looked at the right resource. Should be "Microsoft.Resources/subscriptions/resourceGroups" not "Microsoft.Resources/resourceGroups". Dang do I feel like an idiot...
You are using incorrect syntax in your Azure Policy Definition. The allOf syntax requires all conditions to be true and you can keep all the conditions in single allOf Operator.
Modified version of Policy for reference :
{
"properties": {
"mode": "All",
"displayName": "Company Naming Convention - Resource Groups",
"description": "This policy governs the naming standard for resource groups and should be assigned at the resource group scope. The naming scheme is rg-region-workload name-environment-optional instance number'.",
"metadata": {
"category": "Governance"
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Resources/subscriptions/resourceGroups"
},
{
"field": "name",
"notLike": "rg-useast-*"
},
{
"field": "name",
"notLike": "rg-useast2-*"
},
{
"field": "name",
"notLike": "rg-uscentral-*"
},
{
"field": "name",
"notLike": "rg-uksouth-*"
},
{
"field": "name",
"notLike": "*-production.###"
},
{
"field": "name",
"notLike": "*-development.###"
},
{
"field": "name",
"notLike": "*-qualityassurance.###"
},
{
"field": "name",
"notLike": "*-testing.###"
}
]
},
"then": {
"effect": "deny"
}
}
}
}
Also note, it takes around 30 minutes for the assignment to be applied to the defined scope. For more information on evaluation cycle of Azure Policy, refer this document.
For on-demand evaluation , use az cli command : az policy state trigger-scan

How to enforce Tag value pattern in Azure policy?

I'd like to enforce tag value pattern "RJGVM-###" for a Tag which will be required for resource groups.
I manage to make it required, but whenever I put in any value it still passes.
{
"mode": "All",
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Resources/subscriptions/resourceGroups"
},
{
"not": {
"field": "[concat('tags[',parameters('tagName'), ']')]",
"exists": "true"
}
},
{
"value": "[resourceGroup().tags[parameters('tagName')]]",
"notMatch": "RJGVM-###"
}
]
},
"then": {
"effect": "deny"
}
},
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag, such as 'environment'"
}
}
}
}
Please refer this example mentioned in the below link to ensure match pattern on tag value :
https://github.com/Azure/azure-policy/tree/master/samples/TextPatterns/enforce-tag-match-pattern

Error while deploying Azure Json policy using powershell

I am trying to create a policy for Azure CIS, and getting the following error when I attempt to deploy it via powershell on the management group level - im trying to figure out what is missing as it says invalid template.
It looks like the error is related to something to do with the scope, but not sure what exactly is going on:
New-AzManagementGroupDeployment : 1:19:17 AM - The deployment 'cis1.23-azurepolicy' failed with error(s). Showing 1 out of 1 error(s).
Status Message: Unable to process template language expressions for resource
'/providers/Microsoft.Management/managementGroups/MGName/providers/Microsoft.Authorization/policyDefinitions/CIS1.23-EnsureNoCustomerOwnerRoles' at line '23' and
column '9'. 'The deployment metadata 'SUBSCRIPTION' is not valid.' (Code:InvalidTemplate)
Here is the template:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"effect": {
"type": "string",
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy"
},
"allowedValues": [
"Audit",
"Disabled"
],
"defaultValue": "Audit"
}
},
"variables": {},
"resources": [
{
"name": "CIS1.23-EnsureNoCustomerOwnerRoles",
"type": "Microsoft.Authorization/policyDefinitions",
"apiVersion": "2018-03-01",
"properties": {
"policyType": "Custom",
"displayName": "CIS 1.23 Custom Owner Roles should not exist (Not Scored)",
"description": "This policy checks that Custom Roles with Owner privileges are removed",
"mode": "all",
"metadata": {
"category": "Identity"
},
"parameters": {
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy"
},
"allowedValues": [
"Audit",
"Disabled"
],
"defaultValue": "Audit"
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Authorization/roleDefinitions"
},
{
"field": "Microsoft.Authorization/roleDefinitions/type",
"equals": "CustomRole"
},
{
"anyOf": [
{
"not": {
"field": "Microsoft.Authorization/roleDefinitions/permissions[*].actions[*]",
"notEquals": "*"
}
},
{
"not": {
"field": "Microsoft.Authorization/roleDefinitions/permissions.actions[*]",
"notEquals": "*"
}
}
]
},
{
"anyOf": [
{
"not": {
"field": "Microsoft.Authorization/roleDefinitions/assignableScopes[*]",
"notIn": [
"[concat(subscription().id,'/')]",
"[subscription().id]",
"/"
]
}
},
{
"not": {
"field": "Microsoft.Authorization/roleDefinitions/assignableScopes[*]",
"notLike": "/providers/Microsoft.Management/*"
}
}
]
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
}
}
}
You are deploying the ARM template to a management group, but you are referencing the ARM template subscription() function. The subscription() function is only valid when deploying to a subscription or resource group. When deploying to a management group then there is no subscription that could be referenced.
To resolve this you need to deploy this policy to a subscription, not to a management group.

How to fix deployIfNotExists policy for Key Vault

Trying to create a DeployIfNotExists policy that will automatically set the "networkACLs" properties on all key vaults but after battling with that for a couple of weeks, I decided to try to manipulate a simpler boolean property instead of a complex object property. The property I chose is "enabledForDeployment". The policy does properly find the non-compliant key vaults but the deployment is not working.
Once I get this "easy" policy working, I will go back and attempt to set the "networkACLs" property to the following:
"networkAcls": {
"defaultAction": "Deny",
"bypass": "None",
"ipRules": [
{"value": "1.1.1.0/24"},
{"value":"2.2.2.0/24"}
],
"virtualNetworkRules": []
}
The policy code is below...
{
"mode": "All",
"policyRule": {
"if": {
"allof": [
{
"field": "type",
"equals": "Microsoft.KeyVault/vaults"
},
{
"not": {
"field": "Microsoft.KeyVault/vaults/enabledForDeployment",
"equals": true
}
}
]
},
"then": {
"effect": "deployIfNotExists",
"details": {
"type": "Microsoft.KeyVault/vaults",
"name": "[field('name')]",
"existenceCondition": {
"field": "Microsoft.KeyVault/vaults/enabledForDeployment",
"equals": "true"
},
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"deployment": {
"location": "[field('location')]",
"properties": {
"mode": "incremental",
"template": {
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"Name": {
"type": "string"
},
"location": {
"type": "string"
}
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"name": "[parameters('Name')]",
"location": "[parameters('location')]",
"properties": {
"enabledForDeployment": true
}
}
],
"outputs": {
"policy": {
"type": "string",
"value": "done"
}
}
},
"parameters": {
"location": {
"value": "[field('location')]"
},
"Name": {
"value": "[field('name')]"
}
}
}
}
}
}
},
"parameters": {}
}
I'm currently getting an "internalServerError" message. Any ideas?
#Kemley you are correct. My ARM template was incorrect. It was missing a few required fields (Sku, Access Policies, etc). Below is the final policy that updates the NetworkACLs if the default network allow all is set.
{
"properties": {
"displayName": "Vzn Deploy Key Vault NetworkAcls defaultAction",
"policyType": "Custom",
"mode": "All",
"description": "Removes the default allow all networks. Manually sets 2 firewall rules",
"parameters": {
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "Enable or disable the execution of the policy"
},
"allowedValues": [
"deployIfNotExists",
"disabled"
],
"defaultValue": "deployIfNotExists"
}
},
"policyRule": {
"if": {
"field": "type",
"equals": "Microsoft.KeyVault/vaults"
},
"then": {
"effect": "[parameters('effect')]",
"details": {
"type": "Microsoft.KeyVault/vaults",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/f25e0fa2-a7c8-4377-a976-54943a77a395"
],
"existenceCondition": {
"field": "Microsoft.KeyVault/vaults/networkAcls.defaultAction",
"equals": "Deny"
},
"deployment": {
"properties": {
"mode": "incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"keyvaultname": {
"type": "string"
},
"locationname": {
"type": "string"
},
"skuname": {
"type": "string"
},
"accessPoliciesname": {
"type": "array"
}
},
"resources": [
{
"name": "[parameters('keyvaultname')]",
"location": "[parameters('locationname')]",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"properties": {
"tenantId": "be42d65b-eb64-4a64-8aa3-ae47eef3af3e",
"accessPolicies": "[parameters('accessPoliciesname')]",
"sku": {
"name": "[parameters('skuname')]",
"family": "A"
},
"networkAcls": {
"defaultAction": "Deny",
"bypass": "None",
"ipRules": [
{
"value": "1.2.3.0/27"
},
{
"value": "1.5.6.0/24"
}
]
}
}
}
]
},
"parameters": {
"keyvaultname": {
"value": "[field('name')]"
},
"locationname": {
"value": "[field('location')]"
},
"skuname": {
"value": "[field('Microsoft.KeyVault/vaults/sku.name')]"
},
"accessPoliciesname": {
"value": "[field('Microsoft.KeyVault/vaults/accessPolicies')]"
}
}
}
},
"name": "[field('name')]"
}
}
}
}
}
I would recommend checking your ARM template to make sure that it is correct. Sometimes when you use the export a template function the ARM template might not work without testing. If you have an issue with the ARM template, I would direct your questions to them