wiki.getshifting.com

--- Sjoerd Hooft's InFormation Technology ---

User Tools

Site Tools


cheatsheet-azurecli

Cheatsheet Azure CLI

Summary: AzureCLI hints, tips, oneliners and best practices. I prefer working with the Azure CLI when setting up test environments as it's fast, it's easy to see which settings you're deploying and the use of variables makes different snippets work very good together. When looking for such snippets, look for the deploy keyword.
Date: 8 December 2024

Login to Azure

az login
az account set --subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
az account show

Get Objects

# Check if a resourcegroup exists and set a variable
RgExists=$(az group exists -n $(rgName))
echo "$(rgName) exists: $RgExists"
 
# Get firewall Id
firewallId=$(az network firewall show --name $(azureFirewallName) --resource-group $(rgName) --query id --output tsv)
 
# Get Log Analytics Workspace Id
workspaceId=$(az monitor log-analytics workspace show --workspace-name $(lawName) --resource-group $(rgName) --subscription $(subId) --query id -o tsv)
 
# Get Virtual Network Gateway (VPN) Id
vngId=$(az network vnet-gateway show --name $(virtualNetworkGatewayName) --resource-group $(rgName) --query id --output tsv)
 
# Get Keyvault Id
keyvaultId=$(az keyvault show --name $(keyVaultName) --resource-group $(rgName) --query id --output tsv)

Tags

resourceGroup=$(az group show -n poc-$(team)-$(pocnaam) --query id --output tsv)
echo 'The resource group has the following tags'
az tag list --resource-id $resourceGroup
echo 'add a tag'
az tag update --resource-id $resourceGroup --operation Merge --tags DateOne="$(firstdate)" DateTwo="$(seconddate)"

Azure Resource Graph Explorer Query

# check if a resource has a specific tag set
tag=$(az graph query -q "resourcecontainers | where type == 'microsoft.resources/subscriptions/resourcegroups' and name == 'poc-$(team)-$(pocnaam)' | where tags contains 'startdate'" | jq '.data[].name')
 
echo "Tag date: $tag"
 
# do something if the tag is empty
if [ -z "$tag" ];
then
  echo "do something, the tag is not set"
else
  echo "do something else, the tag is set"
fi
 
# do something if the tag is not empty
if [ -n "$bedrijf" ];
then
  echo "do something, the tag is set"
else
  echo "do something else, the tag is not set"
fi

BICEP deployment

# deploy resourcegroup in a subscription
az deployment sub create \
  --location $(location) \
  --name "hub-$(deploymentSuffix)" \
  --template-file ./modules/resourcegroup.bicep \
  --parameters ./hub/hub-rg-parameterfile.jsonc \
  --parameters location=$(location)
 
# deploy resources in resourcegroup
az deployment group create \
  --resource-group $(rgName) \
  --name "hub-vnet-$(deploymentSuffix)" \
  --template-file ./hub/hub-vnet.bicep \
  --parameters deploymentSuffix=$(deploymentSuffix) \
  --parameters subId=$(subId) \
  --parameters vnetName=$(vnetName)

Assign Roles

Assign a role to as group on a storage account (Storage Blob Data Owner). Note that this was used in a azure devops pipeline with parameters as variables.
az role assignment create \
  --role "Storage Blob Data Owner" \
  --assignee-object-id "cd96f93g-3973-4d94-e2c9-adacd18c2312" \
  --assignee-principal-type "Group" \
  --scope "/subscriptions/$(subscriptionId)/resourceGroups/$(ResourceGroupName)/providers/Microsoft.Storage/storageAccounts/$(StorageAccountName)"

Keyvaults

Show all secrets in a keyvault and make it easy to read
# All secrets
az keyvault secret list --vault-name kv-euw-dev-001 --output table
# One secret
az keyvault secret show --vault-name kv-euw-dev-001 --name app-id-clientid -o table
az keyvault secret show --vault-name kv-euw-dev-001 --name app-id-secret -o table
# Just list all of the names
az keyvault secret list --vault-name kv-euw-vtx-dev-001 --query [].name --output table

Bastion

Get rdp file from bastion
# variables
tenantId="c2a75ggc-b442-5678-9234-1e906d30ede2"
subscriptionId="c2a75ggc-b442-5678-9234-48a7fab3b688"
rg="rg-euw-bastion"
bastionName="bas-euw-global-001"
vmId="/subscriptions/c2a75ggc-b442-5678-9234-aebcd3d45789/resourceGroups/rg-euw-app01/providers/Microsoft.Compute/virtualMachines/vm-app1-001"
 
# Authenticate to Azure PIM groups
Start-Process "https://portal.azure.com/#view/Microsoft_Azure_PIMCommon/ActivationMenuBlade/~/aadgroup"
# Configure the azure cli client
az logout
az config set core.login_experience_v2=off
az login --tenant $tenantId
az account set --subscription $subscriptionId
az network bastion rdp --name $bastionName --resource-group $rg --target-resource-id $vmId --configure

Deploy

In this section you'll find snippets to deploy resources in Azure. The code is written, unless otherwise stated, in PowerShell and can be deployed using the cloud shell.


Use the –no-wait parameter to deploy resources in the background. This is useful when you're deploying multiple resources and don't want to wait for each deployment to finish. You can check the status of the deployment in the deployment section of the resource group in the Azure portal.


After some deployments additional commands are shown, for example to retrieve the id of the resource. This is done when the id is needed in a subsequent deployment.

Use the following command to get the status of the last deployment in a resource group:
az deployment group show --resource-group $rg --name $((az deployment group list --resource-group $rg --query "[0].name").trim('"')) --output table

Use the following command to delete a resource group and all resources in it:
az group delete --name $rg --yes --no-wait

Variables

This is a collection of variables used in the snippets below.
# Define a identifier which will be used in all resource names, for example: "tst", "poc", "shift"
$project = "tst"
# Define the resource group and location
$rg = "rg-$project"
$loc = "westeurope"
# Define the default username and password
$admin = "azadmin"
$password = "P@ssword1234"
# Define the virtual network and subnets
$vnet = "vnet-$project"
$vnetAddressSpace = "10.0.0.0/8"
$subnet = "snet-$project"
$subnetAddressSpace00 = "10.0.0.0/24"
$subnetAddressSpace01 = "10.0.1.0/24"
$subnetAddressSpace02 = "10.0.2.0/24"
$subnetAddressSpace03 = "10.0.3.0/24"
$subnetAddressSpace04 = "10.0.4.0/24"
$subnetAddressSpace05 = "10.0.5.0/24"
$subnetAddressSpace06 = "10.0.6.0/24"
$subnetAddressSpace07 = "10.0.7.0/24"
$subnetAddressSpace08 = "10.0.8.0/24"
$subnetAddressSpace09 = "10.0.9.0/24"
$subnetAddressSpace10 = "10.0.10.0/24"
$vmname = "vm-$($project)01"
# Bastion
$bastion = "bas-$project"
# Storage account must be globally unique, lowercase, numbers and between 3 and 24 characters
$sa = "st$project"
# Managed identity
$id = "id-$project"
# Keyvault
$kv = "kv-$project"
$kvSecret = "secret-$project"
# Azure SQL Database server and database
$sqlServer = "sql-$project"
$dbName = "sqldb-$project"

Resourcegroup

az group create `
  --name $rg `
  --location $loc

Virtual Network

# Create a virtual network
az network vnet create `
  --name $vnet `
  --resource-group $rg `
  --location $loc `
  --address-prefixes $vnetAddressSpace
 
# Create a subnet
az network vnet subnet create `
  --name $subnet `
  --resource-group $rg `
  --vnet-name $vnet `
  --address-prefix $subnetAddressSpace00
$subnetId = (az network vnet subnet show `
  --resource-group $rg `
  --vnet-name $vnet `
  --name $subnet `
  --query "id").Trim('"')
Write-Host $subnetId

Virtual Machine

# Create a Windows Server 2022 virtual machine, without a public IP address, with a system-assigned managed identity, in the vnet and subnet created above, with a 64GB data disk, secure boot and trusted launch enabled. All resources will be deleted when the VM is deleted.
# Create data disk
az disk create `
  --resource-group $rg `
  --name "disk-$vmname" `
  --location $loc `
  --size-gb 64 `
  --public-network-access Disabled `
  --sku Standard_LRS
# Create VM
# Note: when creating a domain controller set the --data-disk-caching to None
az vm create `
  --resource-group $rg `
  --name $vmname `
  --location $loc `
  --image Win2022Datacenter `
  --size Standard_DS1_v2 `
  --assign-identity [system] `
  --nsg "" `
  --admin-username $admin `
  --admin-password $password `
  --public-ip-address "" `
  --accelerated-networking false `
  --nic-delete-option delete `
  --vnet-name $vnet `
  --subnet $subnet `
  --storage-sku Standard_LRS `
  --os-disk-name "osdisk-$vmname" `
  --os-disk-delete-option delete `
  --attach-data-disks "disk-$vmname" `
  --data-disk-caching ReadWrite `
  --data-disk-delete-option delete `
  --enable-hibernation false `
  --enable-secure-boot true `
  --security-type TrustedLaunch `
  --accept-term `
  --no-wait
# Set auto shutdown at 16:00 UTC (17:00 CET)
az vm auto-shutdown -g $rg -n $vmname --time 16:00

Bastion

# Create bastion subnet
az network vnet subnet create `
  --name AzureBastionSubnet `
  --resource-group $rg `
  --vnet-name $vnet `
  --address-prefix $subnetAddressSpace01 `
  --no-wait
# Create public ip address
az network public-ip create `
  --resource-group $rg `
  --name "pip-$bastion" `
  --sku Standard `
  --location $loc
# Create bastion
az network bastion create `
  --name $bastion `
  --public-ip-address "pip-$bastion" `
  --resource-group $rg `
  --vnet-name $vnet `
  --location $loc `
  --sku Basic `
  --no-wait

Storage Account

# Storage account
az storage account create `
  --resource-group $rg `
  --name $sa `
  --location $loc `
  --kind StorageV2 `
  --sku Standard_LRS `
  --enable-large-file-share `
  --min-tls-version TLS1_2 `
  --https-only true `
  --allow-blob-public-access false
# Get storage account Id
$saId = (az storage account show `
  --resource-group $rg `
  --name $sa `
  --query "id").trim('"')
Write-Host $saId
# Storage container
az storage container create `
  --name "cont-$project" `
  --account-name $sa
# File share
az storage share-rm create `
  --resource-group $rg `
  --storage-account $sa `
  --name "share$sa" `
  --quota 1024 `
  --enabled-protocols SMB
# Create a directory for user profiles
az storage directory create `
  --account-name $sa `
  --share-name "share$sa" `
  --name "userprofiles"

Enable Data Protection and Lock

As this is mostly used for test environments I've also included the commands to disable the data protection.
# Enabling container soft delete
az storage account blob-service-properties update `
  --enable-container-delete-retention true `
  --container-delete-retention-days 5 `
  --account-name $sa `
  --resource-group $rg
# az storage account blob-service-properties update --enable-container-delete-retention false --account-name $sa --resource-group $rg
# Enabling blob soft delete
az extension add -n storage-preview
az storage fs service-properties update `
  --account-name $sa `
  --delete-retention true `
  --delete-retention-period 5
# az storage fs service-properties update --account-name $sa --delete-retention false
# Set a resource lock on the storage account
az lock create `
  --name "LockStorageAccount" `
  --lock-type CanNotDelete `
  --resource-group $rg `
  --resource $sa `
  --resource-type "Microsoft.Storage/storageAccounts" `
  --notes "This lock is to prevent accidental deletion of the storage account"
# az lock delete --name LockStorageAccount --resource-group $rg --resource $sa --resource-type "Microsoft.Storage/storageAccounts"

Private Endpoint

# Get group Id and private dns zone
$privateLinkGroupId = (Get-AzPrivateLinkResource -PrivateLinkResourceId $saId).GroupId
Write-Host $privateLinkGroupId
# Multiple options are returned, using blob for now
$privateLinkGroupId = "blob"
$privateLinkZoneName = ((Get-AzPrivateLinkResource -PrivateLinkResourceId $saId).RequiredZoneNames).trim('{}')
Write-Host $privateLinkZoneName
# Multiple options are returned, using blob for now
$privateLinkZoneName = "privatelink.blob.core.windows.net"
 
# Create private endpoint
az network private-endpoint create `
  --resource-group $rg `
  --name "pep-$sa" `
  --location $loc `
  --subnet $subnetId `
  --private-connection-resource-id $saId `
  --group-id $privateLinkGroupId `
  --connection-name "con-$sa"
# Get private endpoint Id
$pepId = (az network private-endpoint show `
  --resource-group $rg `
  --name "pep-$sa" `
  --query "id").Trim('"')
Write-Host $pepId
# Get nic from pep
$nicPepId = (az network private-endpoint show `
  --ids $pepId `
  --query "networkInterfaces[0].id").Trim('"')
Write-Host $nicPepId
# Get IP address from nic
$nicIp = (az network nic show `
  --ids $nicPepId `
  --query "ipConfigurations[0].privateIPAddress").Trim('"')
Write-Host $nicIp

Private DNS Zone

az network private-dns zone create `
  --resource-group $rg `
  --name $privateLinkZoneName
# Create a link between the virtual network and the private DNS zone
az network private-dns link vnet create `
  --resource-group $rg `
  --zone-name $privateLinkZoneName `
  --name $vnet-DnsLink `
  --virtual-network $vnet `
  --registration-enabled false

Private DNS Record

# create recordset
az network private-dns record-set a create `
  --resource-group $rg `
  --zone-name $privateLinkZoneName `
  --name $sa
 
# Create a record
az network private-dns record-set a add-record `
  --resource-group $rg `
  --zone-name $privateLinkZoneName `
  --record-set-name $sa `
  --ipv4-address $nicIp

Managed Identity

# Managed identity
az identity create `
  --name $id `
  --resource-group $rg `
  --location $loc
 
# Get the managed identity client id (Client Id (Application Id) is used to authenticate workloads)
$idId = az identity show `
  --name $id `
  --resource-group $rg `
  --query clientId `
  --output tsv
Write-Host $idId
 
# Get the managed identity object id (Object (Principal) Id is used to authorize workloads, aka, assign permissions in Azure)
$idPrincipalId = az identity show `
  --name $id `
  --resource-group $rg `
  --query principalId `
  --output tsv
Write-Host $idPrincipalId

Keyvault

az keyvault create `
  --name $kv `
  --resource-group $rg `
  --location $loc `
  --enable-purge-protection `
  --enable-rbac-authorization `
  --retention-days 7
 
# Get the keyvault id
$kvId = az keyvault show `
  --resource-group $rg `
  --name $kv `
  --query id `
  --output tsv
Write-Host $kvId
Note that enabling purge protection is required for workload identity to work with Azure Key Vault. Because this is a test environment the retention days are set to 7.

Assign Permissions

# Assign permissions to the current user
$userId = az account show `
  --query user.name `
  --output tsv
 
# Set permissions for the user
az role assignment create `
  --assignee $userId `
  --role "Key Vault Secrets Officer" `
  --scope $kvId
 
# Set permissions for the workload identity
az role assignment create `
  --assignee-object-id $idPrincipalId `
  --role "Key Vault Secrets User" `
  --scope $kvId `
  --assignee-principal-type ServicePrincipal

Create Secret

# Create a secret in the key vault
az keyvault secret set `
  --vault-name $kv `
  --name $kvSecret `
  --value $password

Azure SQL Server

# create db server
az sql server create `
  --name $sqlServer `
  --resource-group $rg `
  --location $loc `
  --admin-user $admin `
  --admin-password $password
# Get Sql Server Id
$sqlServerId = (az sql server show `
  --name $sqlServer `
  --resource-group $rg `
  --query "id").trim('"')
Write-Host $sqlServerId

Private Endpoint

# Get group Id and private dns zone
$privateLinkGroupId = (Get-AzPrivateLinkResource -PrivateLinkResourceId $sqlServerId).GroupId
Write-Host $privateLinkGroupId
# Note, sometimes the command below can return multiple domains
$privateLinkZoneName = ((Get-AzPrivateLinkResource -PrivateLinkResourceId $sqlServerId).RequiredZoneNames).trim('{}')
Write-Host $privateLinkZoneName
 
# Create private endpoint
az network private-endpoint create `
  --resource-group $rg `
  --name "pep-$sqlServer" `
  --location $loc `
  --subnet $subnetId `
  --private-connection-resource-id $sqlServerId `
  --group-id $privateLinkGroupId `
  --connection-name "con-$sqlServer"
 
# Get private endpoint Id
$pepId = (az network private-endpoint show `
  --resource-group $rg `
  --name "pep-$sqlServer" `
  --query "id").Trim('"')
Write-Host $pepId
# Get nic from pep
$nicPepId = (az network private-endpoint show `
  --ids $pepId `
  --query "networkInterfaces[0].id").Trim('"')
Write-Host $nicPepId
# Get IP address from nic
$nicIp = (az network nic show `
  --ids $nicPepId `
  --query "ipConfigurations[0].privateIPAddress").Trim('"')
Write-Host $nicIp

Private DNS Zone

# Private DNS zone
az network private-dns zone create `
  --resource-group $rg `
  --name $privateLinkZoneName
# Create a link between the virtual network and the private DNS zone
az network private-dns link vnet create `
  --resource-group $rg `
  --zone-name $privateLinkZoneName `
  --name $vnet-DnsLink `
  --virtual-network $vnet `
  --registration-enabled false

Private DNS Record

# private dns record
# create recordset
az network private-dns record-set a create `
  --resource-group $rg `
  --zone-name $privateLinkZoneName `
  --name $sqlServer
 
# Create a record
az network private-dns record-set a add-record `
  --resource-group $rg `
  --zone-name $privateLinkZoneName `
  --record-set-name $sqlServer `
  --ipv4-address $nicIp

Azure SQL Hyperscale Database

When creating a Hyperscale database, carefully consider the setting for backup-storage-redundancy. Storage redundancy can only be specified during the database creation process for Hyperscale databases. You can choose locally redundant, zone-redundant, or geo-redundant storage. The selected storage redundancy option will be used for the lifetime of the database for both data storage redundancy and backup storage redundancy. Allowed values for the backup-storage-redundancy parameter are: Local, Zone, Geo. Unless explicitly specified, databases will be configured to use geo-redundant backup storage.
# create db
az sql db create `
  --resource-group $rg `
  --server $sqlServer `
  --name $dbname `
  --edition Hyperscale `
  --compute-model Serverless `
  --family Gen5 `
  --capacity 2 `
  --backup-storage-redundancy Local `
  --ha-replicas 0 `
  --yes
cheatsheet-azurecli.txt · Last modified: by 127.0.0.1