Monday, June 10, 2024

Azure policy: Deny VNet peering to non-approved VNets

 As part of the Azure Landing Zone architecture, there is a policy that denies the creation of VNet peerings to non-allowed VNets, see policy here.

This policy is relevant to a apply in a hub-spoke setup where you want to avoid that spoke VNets, or spoke landing zones, can create VNet peerings to anything other than the defined Hub VNets.

At current client we've been running this policy since December, 2023 and it's been working fine.

However, about a month ago some policy evaluation behavior changed (the policy itself or the templates have not changed) and now for certain bicep files, the policy blocks deployments even when using approved VNets for the peering. It wasn't for all bicep files and ARM templates still worked.

Microsoft Support came up with a minor update to the policy definition to effectively have the same rule but the syntax is slightly different. This works.

We haven't found an explanation yet as to why there was a change in policy evaluation behavior.

But the updated policy can be found here on Github.

Tuesday, June 4, 2024

Azure policy: Auto create DNS records in private DNS zones using multiple zones

 There are certain Azure PaaS services that when used together with private endpoints, require not just one A record in one DNS (as is the case for most PaaS services) but multiple A records in multiple private DNS zones (PDNS).

Examples of PaaS services that require this are (see here for full list): 

  • Azure Monitor
  • Power BI
  • Azure Data Explorer
  • Azure Arc
  • Azure Health Data Services

When using private endpoints at scale, MSFT recommends using Azure Policy for the A record creation. I've described this in a previous article, see here.

But the MSFT policy to create DNS records can only handle a single PDNS zone, not multiple PDNS zones.

I found a fix to this on the 'Blog Cloud63' in this post (and here's a direct link to his policy definition), so thanks goes to Vincent Misson for that.

He basically expands on the MSFT policy for the resource 'privateDnsZoneGroups' by adding a copy loop to the properties of the resource. The copy loop then goes through an array of PDNS zone resource IDs and adds multiple items under properties. The privateDnsZoneGroups resource is what actually creates the A record in the PDNS zones.

Below you can see snippet of the code with the copy loop (modified policy):


And without the copy loop (default MSFT policy)


I have uploaded my slightly modified version of the policy to Github.

It has been tested with Azure Monitor, specifically with private endpoints for Azure Monitor Private Link Scope (AMPLS) and it works as expected (11 records are created in 5 separate PDNS zones).



Saturday, January 13, 2024

Azure: Subnets with multiple IP address spaces?

 We were having a look today at the Azure documentation for virtual networks and subnets specifically. Both for Bicep and ARM there are two options to specify the addressprefix (address space) for a subnet. The first one is "addressPrefix" which takes a string as input and the second one is "addressPrefixes" which takes an array, see below. This leads one to expect that you can provide multiple IP address ranges for the subnet in the array in the same way that it can be done for VNets.


If you try to manually add an additional IP range to an existing subnet via the portal, it will show an error.

If you try to deploy multiple ranges via an ARM template, it still throws an error but we get a bit more information in the error message, see below:


The error states that the subscription is not registered for the following feature:

Microsoft.Network/AllowMultipleAddressPrefixesOnSubnet

This is usually handled under Resource Providers for the subscription. If you go to subscriptions -> resource providers in the Portal, this feature is not there to enable, though.


It is possible however, to register the feature via Azure CLI. But when you run the command, this feature goes from "not registered" to "pending" and then it will just stay like that and never move to registered.

It looks like below:



The commands are:

az feature register --namespace Microsoft.Network -n AllowMultipleAddressPrefixesOnSubnet --subscription <subscriptionId>

and:

az feature show --namespace Microsoft.Network -n AllowMultipleAddressPrefixesOnSubnet --subscription <subscriptionId>

It turns out that this feature is available only to MSFT developers and is not available either in public or private preview. There is not much info around this, as I suppose it is not really a sought after feature.

I found this explanation and also response from MSFT, see link here.

And then another person had the same issue as late as Jan 8, 2024, see link here.

Friday, December 22, 2023

Add resource locks to individual records in a private DNS zone

 It is possible to add resource locks to individual records in private DNS zones. A scenario for this could be a critical or central A record that you don't want to be changed by mistake while still allowing for ongoing updates to the private DNS zone as part of daily operations.

If you have a centralized private DNS zone setup with Azure policy handling the DNS record creation and you also use private endpoints (PE), then there is a (perhaps small) risk that A records can be overwritten. This is the case if someone creates a new PE and associates with the same resource. The DeployIfNotExist policy will run on PE creation and replace the existing record and so that the PaaS service will resolve to a new local IP (note that if you delete the new PE again, the A record will also be deleted and the original PE will no longer have an A record and so will have to be recreated or the A record re-added).

Adding locks to individual records is described in further detail here. Note that this can currently only be done using PowerShell and can't be done via the Azure portal.

The example from MSFT looks like below:


An actual example is shown below:

# Lock a DNS record set

$lvl = "ReadOnly"

$lnm = "dontChangeMe"

$rsc = "privatelink.blob.core.windows.net/testaccountdelete001"

$rty = "Microsoft.Network/privateDNSZones/A"

$rsg = "rg-dns-conn-001"

 

New-AzResourceLock -LockLevel $lvl -LockName $lnm -ResourceName $rsc -ResourceType $rty -ResourceGroupName $rsg

Note that the MSFT example uses a regular DNS zone whereas my example uses private DNS zones (marked in bold above).

See example below for when lock is applied:


Once applied, you can see (and edit and delete) the lock in the portal under the private DNS zone -> "you're private DNS zone, e.g. for blob" -> Locks, see below:



The reason that the lock type is set to ReadOnly and not CannotDelete is that the latter option will  allow the records to be overwritten which we don't want.


Azure policy: Deploy CanNotDelete locks to resource groups

 You can use Azure policy to apply resource locks to all resource groups in a defined scope. This can be useful to ensure that critical resources are not deleted by mistake. See general description of resource locks here. Note that applying locks in the environment can create unforeseen problems so it's good to proceed with a bit of caution. 

The policy in this post is based on a slightly modified version from AzAdvertizer, that can be found here. The original policy will apply locks to a list of resource group names that is specified in an array.

The modified version, which can be found here on Github, applies locks to all resource groups but excludes resource groups which are specified in the array.

Note that the only built-in roles (for the system assigned managed identity, SAMI) that can apply locks are Owner and User Access Administrator. Owner has typically too many permissions and User Access Administrator does not have the policy deployment permissions. So a custom RBAC is required.

To create a custom RBAC, go the the subscription or management group level where the policy will be applied, go to Access Control (IAM) -> Roles. From here click +Add to a new role. Add the following permissions:

"Microsoft.Resources/deployments/write",
"Microsoft.Authorization/locks/*",
"Microsoft.Authorization/policies/deployIfNotExists/action",
"Microsoft.Resources/checkPolicyCompliance/read"

The full RBAC role in JSON can be found here on Github (make sure to update the management group or subscription under assignableScopes).

When you assign the policy definition, make sure to choose the new RBAC role when creating the SAMI, see below:





Azure policy: Reducing the default evaluation time for auto A record creation for private endpoints

 I have previously written about the use of Azure policy to automatically create A records for private endpoints in centrally managed private DNS zones. You can see more here and here. And the general recommended setup from MSFT is available here.

One of the slightly annoying things about the standard Azure policies is that they use the default evaluation delay time (10 minutes) for when a DeployIfNotExist policy runs. This means that when you create a private endpoint, it takes around 10 minutes before the A record is created in the private DNS zone. This creates, in addition to the added wait time, some confusion from users as they don't know whether their deployments work or not.

This evaluation delay time can be minimized by using the optional property for DeployIfNotExist type policies called EvaluationDelay. This is described in more detail here.

There are different values that can be set for this property, but to get the best effect, I'd recommend using AfterProvisioningSuccess. This will run the policy as soon as the private endpoint has been successfully deployed.

You can see an example of a policy using this property here on Github. And below is an example as well.

Note that this property does not only apply to DNS record creation. It can be used for other DeployIfNotExist policies as well where you want the resources deployed right away.



Monday, December 11, 2023

Azure policy: Auto create DNS records using both subResource and private link resource type

 When using private endpoints at scale, the recommended setup from Microsoft is to use Azure Policy to automatically create the DNS records in the central private DNS zones when the private endpoints are created. The reason for this is that users or owners of the spokes or landing zones do not have permissions to create A records in the central private DNS zones in the Hub.

For most private DNS zones, the regular Azure policy can be used which checks for private DNS zone name and subResource id, see list here. However, there are scenarios where this is not sufficient. For example, if a region has to be specified using Recovery Services Vault, see more on that here.

Another example, and the scope of this post, is when there are overlapping subResource values such as for Synapse Analytics and Cosmos DB (which both use 'sql') or Synapse Studio and Storage accounts Web (which both use 'web'). If multiple policies are created using the same subResource, you don't know in which private DNS zone that the A record will be created and you can experience records being created first in one zone and then the other whichever policy is evaluated first.

To address this, Microsoft has created a policy that, in addition to the subResource, adds a parameter that matches on the private link resource type (also referred to as privateLinkServiceId). The policy can be found here.

The private link resource type is found in the first column in the table of private DNS zones, here. Examples of values are:

  • Microsoft.Synapse/privateLinkHubs
  • Microsoft.Synapse/workspaces
  • Microsoft.DocumentDB/databaseAccounts

For some odd reason, MSFT hardcodes the value of the private link reosurce type in the policy. I've updated the policy slightly to parameterize that value. The updated policy can be found on here on Github.

Below you can see an example of what it looks like when the policy is assigned in the portal: