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:



Thursday, November 30, 2023

Installing tools on Windows with Chocolatey - a package manager

 Chocolatey is a useful tool to install apps and tools on a fresh laptop or developer VM via command line.

Install Chocolatey

To install Chocolatey, follow below steps:

  • Install PowerShell 7, see link
  • Open PowerShell 7 as administrator
  • Run the following command to install Chocolatey (copied from the official install instructions)
    • Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
  • Close and re-open the PowerShell 7 window, again as administrator
  • Run the following command to verify that install is succesful:
    • choco upgrade all
  • Enable long paths in PowerShell (command copied from here):
    • New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force

Install apps with Chocolatey

Below are some commands for common tools:

  • choco install -y notepadplusplus
  • choco install -y git
  • choco install -y vscode
  • choco install -y 7zip
  • choco install -y kubernetes-cli
  • choco install -y kubernetes-helm
  • choco install -y azure-cli
  • choco install -y az.powershell
  • choco install -y bicep
  • choco install -y terraform
  • choco install -y firefox
You can see a list of available apps here (and search as well, there are many)

Here's instructions on initial config for Git (set user.name and user.email)

Friday, October 20, 2023

Git commands - for setup and daily work

 This article is just to collect some of the Git commands that are being used on a regular basis.

Git commands for daily work

git clone <https link to repo> (clone a remote repo. Make sure you’re in the correct directory when running)

git pull (sync the latest changes from remote repo)

git checkout -b feature/new_branch_name (create new feature branch)
git switch -c feature/new_branch_name (create new feature branch)

git checkout main (switch to main branch)
git switch main (switch to main branch)

git add -A (pre-commit/stage command to add all new/modified/deleted files to local staging for whole repo, run this before local commit)

git add . (same as -A but for current directory and sub directories only)

git add -u (stages all modified and deleted files but leaves new and untracked files)

git commit -a -m "adding a test file" (commit all files to local branch and add a message)

git push --set-upstream origin feature/testingbranch (publish local branch to remote repo, use the same name as the current feature branch)

The git push command can be simplified further, see below around the push.autoSetupRemote setting (then you can just use git push).

git add -A && git commit -a -m "adding a test file" (combine git add and git commit and run sequentially)

git checkout main && git pull (combine switch to main branch and run git pull)

git branch -d localBranchName (delete local branch)

git push origin --delete remoteBranchName (delete branch remotely)

git branch -l (list local branches)

git branch --all (see all branches including remote)

Undo last commit

If you've pushed a local repo to a remote repo and also created a PR in e.g. Azure DevOps (but not yet merged changes to main), you can undo the last commit, make some changes or remove/add files and re-push the changes:

git reset --soft HEAD~1 (undo last commit but keep changes staged)

git reset (unstage currently staged changes)

git add . (run this after changes have been made to re-stage)

git commit -m "updated commmit message"

git push --force (this will overwrite the remote branch history. If you don't use --force it will throw an error that remote branch is ahead)

Load everything from remote branch and overwrite local branch

git switch my-local-branch

git fetch origin

git reset --hard origin/my-remote-branch

Sync latest changes from main branch into your current feature branch

This can be done using git rebase which will keep the commit history clean, see link here.

Git commands configuring Git

git config --global user.name "First Last" (user name and email should be set up as a one time config)

git config --global user.email <user@email.com>

git config --global core.longpaths true (fixes an error with long path names)

git config --list (show git config)

git config --list --show-origin (show git config including where variables are defined)

git config --global http.https://dev.azure.com/.proxy https://someaddress (this is a proxy related setting)

git config --global http.https://dev.azure.com/.proxyauthmethod negotiate (this is a proxy related setting)

git config --global http.https://dev.azure.com/.emptyAuth true (this is a proxy related setting)

git config --global --edit (edit the global config file in VI editor)

git config --global --replace-all user.name "username" (replaces current user name)

git config --global --replace-all user.email <user@email.com>

git config --unset-all credential.helper (unset named settings)

git config --global --set credential.helper (set the credentials helper type)

Note, that if you set push.autoSetupRemote to true with the below command, it is enough to just run: git push and you don't have to specify (--set-upstream origin feature/testingbranch) and it will automatically create a remote branch with same name as current local branch and enable tracking, see more info here:   

git config --global --add --bool push.autoSetupRemote true

   


Tuesday, October 10, 2023

Add custom rule to new NSGs via Azure Policy

 For governance, or operational, reasons there may be a need to ensure that certain rules are applied to all NSGs that are created within a certain scope.

This can be achieved using Azure Policy with a deployIfNotExist function.

Such a policy has already been created and is ready to use from AzAdvertizer.net, see link here:

I ran a quick test to verify the functionality and it works as expected. At the time of creation of the NSG, the policy kicks in an applies the rule right away.

The policy will let you specify one rule. So for multiple rules additional assignments can be created.

The policy looks for a suffix (the last part of the name) in the NSG name and only applies the rule if there's a match. You can re-arrange the check and have it look for a prefix instead, I have uploaded an example here on Github (can be copied in as a new definition via Azure Portal -> Policy -> Definitions).

If you want to apply the rule to all NSGs, then simply remove this check, see marked part below:


The policy is parameterized, so when you create an assignment it will request you to add all relevant parameters. See example below:

Note that some of the parameters such as destinationPortRange are arrays. They should be added in the format ["3389"] (for port 3389..).


Below is a screenshot of the inbound rule added post NSG deployment:


Since this is a deployIfNotExist policy, this means the Assignment requires a system assigned managed identity (or a user assigned managed identity) with Network Contributor permissions which will be automatically created when you create the assignment if you have enough permissions.