Welcome back to the Azure Virtual Datacenter Concept blog post series.
In our previous posts about naming conventions and Azure Governance, we’ve defined our rules of play. Now it’s time to start populating our Azure environment with some Resource Groups.

Let’s talk resources!
When deploying new resources in Azure, they reside in the Azure Resource Manager model. The Azure Resource Manager model is the successor of the Azure Service Management model which is often referred to as Azure v1 or Azure Classic. Since we are deploying resources in Azure, we want some kind of containerization or logical management layer on top of that. And that is exactly why we need a resource group before we can deploy a resource in Azure.
A resource group is a logical boundary that can organize your resources based on the environment, application or other specific characteristics. We can harden our resource group from unwanted changes by implementing role based access controls and resource locks.

Stuff to think about
Prior to deploying our first resource in a resource group, we have a couple of recommendations and/or limitations that we need to take care of:
- A resource can only exist in one resource group
- Resources can be moved from one resource group to another group
- Resources are able to communicate or connect to other resource groups
- Resource groups can be controlled by specific RBAC controls or resource locks.
- Takeway: Our advice is to assign specific roles of access to the resource groups and apply a delete lock by default.
- Tip: We can force these roles and locks with Azure Policy
- Resource groups can contain resources that are located in different regions
- Takeaway: Our advice is to keep your resources within the same region as your resource group.
- Tip: We can force this behavior via Azure Policy
Ready, set, GO? STOP! Let’s first take a couple of design decisions.
Taking the above information into account, we don’t want to go and start deploying resources and resource groups via the Azure Portal. Rule of thumb is to use the Azure Portal as much as you can for view / read only actions and perform your deployments with ARM templates, powershell or CLI.
Now before we are going to deploy our base set of resource groups, let’s have some thought on which resource groups we are going to deploy and why. Below table gives you an example that you can use in any of your Azure designs to provide an holistic overview of the required resource groups. Have a look here at how naming conventions are provisioned / enforced.
Resource Group Name | Resources |
HUB | |
<cus>-hub-storage-rg | All components related to central storage |
<cus>-hub-management-rg | All components related to central management tools |
<cus>-hub-network-rg | All components related to central networking |
<cus>-hub-mig-rg | All components related to migration workloads |
<cus>-hub-backup-rg | All components related to the central backup instance |
<cus>-hub-identity-rg | All components related to the central Identity instance |
ENV | |
<cus>-dev-app-rg | All components related to the development application tier |
<cus>-dev-web-rg | All components related to the development web tier |
<cus>-dev-network-rg | All components related to the development network tier |
<cus>-dev-db-rg | All components related to the development database tier |
<cus>-dev-storage-rg | All components related to the development storage tier |
The table above gives you guidance on how to deploy a central HUB for resources and create a set of resource groups per environment.
Our environment specific resource groups are designed in a way that we can re-utilize them for multiple purposes.
Design ready, let’s go!
Below PowerShell script can be used to deploy a tier based environment starting from a simple hub and production approach to a full blow DTAP (Development, Test, Acceptance, Production) environment.
Powershell Script
################## Param( [string]$RG_PurposeHUB, [string]$RG_PurposePRD, [string]$RG_PurposeACC, [string]$RG_PurposeTST, [string]$RG_PurposeDEV, [string]$Cus, [string]$fullLocation, [string]$owner, [string]$EnvironmentTier ) ##################################################################################### ######## START OF NAMING CONVENTION RESOURCE GROUPS HUB,PRD,DEV,TST ######## ##################################################################################### ################### HUB $HUBRGID = $Cus + '-' + $RG_PurposeHUB + '-' + 'identity' + '-rg' $HUBRGSTOR = $Cus + '-' + $RG_PurposeHUB + '-' + 'storage' + '-rg' $HUBRGMGM = $Cus + '-' + $RG_PurposeHUB + '-' + 'management' + '-rg' $HUBRGNET = $Cus + '-' + $RG_PurposeHUB + '-' + 'network' + '-rg' $HUBRGMIG = $Cus + '-' + $RG_PurposeHUB + '-' + 'mig' + '-rg' $HUBRGRSV = $Cus + '-' + $RG_PurposeHUB + '-' + 'backup' + '-rg' ################### PRD $PRDRGAPP = $Cus + '-' + $RG_PurposePRD + '-' + 'app' + '-rg' $PRDRGDB = $Cus + '-' + $RG_PurposePRD + '-' + 'db' + '-rg' $PRDRGSTOR = $Cus + '-' + $RG_PurposePRD + '-' + 'storage' + '-rg' $PRDRGNET = $Cus + '-' + $RG_PurposePRD + '-' + 'network' + '-rg' $PRDRGWEB = $Cus + '-' + $RG_PurposePRD + '-' + 'web' + '-rg' ################### ACC $ACCRGAPP = $Cus + '-' + $RG_PurposeACC + '-' + 'app' + '-rg' $ACCRGDB = $Cus + '-' + $RG_PurposeACC + '-' + 'db' + '-rg' $ACCRGSTOR = $Cus + '-' + $RG_PurposeACC + '-' + 'storage' + '-rg' $ACCRGNET = $Cus + '-' + $RG_PurposeACC + '-' + 'network' + '-rg' $ACCRGWEB = $Cus + '-' + $RG_PurposeACC + '-' + 'web' + '-rg' ################### TST $TSTRGAPP = $Cus + '-' + $RG_PurposeTST + '-' + 'app' + '-rg' $TSTRGDB = $Cus + '-' + $RG_PurposeTST + '-' + 'db' + '-rg' $TSTRGSTOR = $Cus + '-' + $RG_PurposeTST + '-' + 'storage' + '-rg' $TSTRGNET = $Cus + '-' + $RG_PurposeTST + '-' + 'network' + '-rg' $TSTRGWEB = $Cus + '-' + $RG_PurposeTST + '-' + 'web' + '-rg' ################### DEV $DEVRGAPP = $Cus + '-' + $RG_PurposeDEV + '-' + 'app' + '-rg' $DEVRGDB = $Cus + '-' + $RG_PurposeDEV + '-' + 'db' + '-rg' $DEVRGSTOR = $Cus + '-' + $RG_PurposeDEV + '-' + 'storage' + '-rg' $DEVRGNET = $Cus + '-' + $RG_PurposeDEV + '-' + 'network' + '-rg' $DEVRGWEB = $Cus + '-' + $RG_PurposeDEV + '-' + 'web' + '-rg' ##################################################################################### ######## END OF NAMING CONVENTION RESOURCE GROUPS HUB,PRD,DEV,TST ######## ##################################################################################### ##################################################################################### ######## START OF CREATION RESOURCE GROUPS HUB,PRD,DEV,TST,ACC ######## ##################################################################################### function new-resourcegroups { Param ([string]$fullLocation,[string]$owner,[string]$rsgapp,[string]$rsgdb,[string]$rsgstor,[string]$rsgnet,[string]$rsgweb,[string]$rsgpurpose) New-AzResourceGroup -Name $rsgapp -Location $fullLocation -Tag @{Environment="$rsgpurpose";Purpose="Application";Owner="$owner"} New-AzResourceGroup -Name $rsgdb -Location $fullLocation -Tag @{Environment="$rsgpurpose";Purpose="Database";Owner="$owner"} New-AzResourceGroup -Name $rsgstor -Location $fullLocation -Tag @{Environment="$rsgpurpose";Purpose="Storage";Owner="$owner"} New-AzResourceGroup -Name $rsgnet -Location $fullLocation -Tag @{Environment="$rsgpurpose";Purpose="Networking";Owner="$owner"} New-AzResourceGroup -Name $rsgweb -Location $fullLocation -Tag @{Environment="$rsgpurpose";Purpose="Web";Owner="$owner"} } function new-hubresourcegroups { Param ([string]$fullLocation,[string]$owner,[string]$rsgmgm,[string]$rsgdb,[string]$rsgstor,[string]$rsgnet,[string]$rsgweb,[string]$rsgpurpose,[string]$rsgmig,[string]$rsgrsv,[string]$rsgidentity) ### HUB AZ Powershell New-AzResourceGroup -Name $rsgstor -Location $fullLocation -Tag @{Environment="$RG_PurposeHUB";Purpose="Storage";Owner="$owner"} New-AzResourceGroup -Name $rsgmgm -Location $fullLocation -Tag @{Environment="$RG_PurposeHUB";Purpose="Management";Owner="$owner"} New-AzResourceGroup -Name $rsgnet -Location $fullLocation -Tag @{Environment="$RG_PurposeHUB";Purpose="Networking";Owner="$owner"} New-AzResourceGroup -name $rsgmig -Location $fullLocation -Tag @{Environment="$RG_PurposeHUB";Purpose="Migration";Owner="$owner"} New-AzResourceGroup -Name $rsgidentity -Location $fullLocation -Tag @{Environment="$rsgpurposeHUB";Purpose="Identity";Owner="$owner"} New-AzResourceGroup -Name $rsgrsv -Location $fullLocation -Tag @{Environment="$rsgpurpose";Purpose="Backup";Owner="$owner"} } $EnvironmentTier # Select the setup steps required for this environment Switch ($EnvironmentTier) { 1 { # new HUB Resource Groups new-hubresourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $HUBRGAPP -rsgdb $HUBRGDB -rsgstor $HUBRGSTOR -rsgnet $HUBRGNET -rsgweb $HUBRGWEB -rsgpurpose $RG_PurposeHUB -rsgmgm $HUBRGMGM -rsgmig $HUBRGMIG -rsgidentity $HUBRGID -rsgrsv $HUBRGRSV # new PRD Resource Groups new-resourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $PRDRGAPP -rsgdb $PRDRGDB -rsgstor $PRDRGSTOR -rsgnet $PRDRGNET -rsgweb $PRDRGWEB -rsgpurpose $RG_PurposePRD } 2 { # new HUB Resource Groups new-hubresourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $HUBRGAPP -rsgdb $HUBRGDB -rsgstor $HUBRGSTOR -rsgnet $HUBRGNET -rsgweb $HUBRGWEB -rsgpurpose $RG_PurposeHUB -rsgmgm $HUBRGMGM -rsgmig $HUBRGMIG -rsgidentity $HUBRGID -rsgrsv $HUBRGRSV # new PRD Resource Groups new-resourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $PRDRGAPP -rsgdb $PRDRGDB -rsgstor $PRDRGSTOR -rsgnet $PRDRGNET -rsgweb $PRDRGWEB -rsgpurpose $RG_PurposePRD # new ACC Resource Groups new-resourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $ACCRGAPP -rsgdb $ACCRGDB -rsgstor $ACCRGSTOR -rsgnet $ACCRGNET -rsgweb $ACCRGWEB -rsgpurpose $RG_PurposeACC } 3 { # new HUB Resource Groups new-hubresourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $HUBRGAPP -rsgdb $HUBRGDB -rsgstor $HUBRGSTOR -rsgnet $HUBRGNET -rsgweb $HUBRGWEB -rsgpurpose $RG_PurposeHUB -rsgmgm $HUBRGMGM -rsgmig $HUBRGMIG -rsgidentity $HUBRGID -rsgrsv $HUBRGRSV # new PRD Resource Groups new-resourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $PRDRGAPP -rsgdb $PRDRGDB -rsgstor $PRDRGSTOR -rsgnet $PRDRGNET -rsgweb $PRDRGWEB -rsgpurpose $RG_PurposePRD # new ACC Resource Groups new-resourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $ACCRGAPP -rsgdb $ACCRGDB -rsgstor $ACCRGSTOR -rsgnet $ACCRGNET -rsgweb $ACCRGWEB -rsgpurpose $RG_PurposeACC # new TST Resource Groups new-resourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $TSTRGAPP -rsgdb $TSTRGDB -rsgstor $TSTRGSTOR -rsgnet $TSTRGNET -rsgweb $TSTRGWEB -rsgpurpose $RG_PurposeTST } 4 { # new HUB Resource Groups new-hubresourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $HUBRGAPP -rsgdb $HUBRGDB -rsgstor $HUBRGSTOR -rsgnet $HUBRGNET -rsgweb $HUBRGWEB -rsgpurpose $RG_PurposeHUB -rsgmgm $HUBRGMGM -rsgmig $HUBRGMIG -rsgidentity $HUBRGID -rsgrsv $HUBRGRSV # new PRD Resource Groups new-resourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $PRDRGAPP -rsgdb $PRDRGDB -rsgstor $PRDRGSTOR -rsgnet $PRDRGNET -rsgweb $PRDRGWEB -rsgpurpose $RG_PurposePRD # new ACC Resource Groups new-resourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $ACCRGAPP -rsgdb $ACCRGDB -rsgstor $ACCRGSTOR -rsgnet $ACCRGNET -rsgweb $ACCRGWEB -rsgpurpose $RG_PurposeACC # new TST Resource Groups new-resourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $TSTRGAPP -rsgdb $TSTRGDB -rsgstor $TSTRGSTOR -rsgnet $TSTRGNET -rsgweb $TSTRGWEB -rsgpurpose $RG_PurposeTST # new DEV Resource Groups new-resourcegroups -fullLocation $fullLocation -owner $owner -rsgapp $DEVRGAPP -rsgdb $DEVRGDB -rsgstor $DEVRGSTOR -rsgnet $DEVRGNET -rsgweb $DEVRGWEB -rsgpurpose $RG_PurposeDEV } } ##################################################################################### ######## END OF CREATION RESOURCE GROUPS HUB,PRD,DEV,TST ######## #####################################################################################
If we save the script as “1._Create_Az_ResourceGroups_v2.ps1” and run it with the parameters below this should give us the following result.
.\1._Create_Az_ResourceGroups_v2.ps1 -RG_PurposeHUB "hub" -RG_PurposePRD "prd" -RG_PurposeACC "acc" -RG_PurposeTST "tst" -RG_PurposeDEV "dev" -Cus "cus" -fullLocation "westeurope" -owner "Yannick Dils" -EnvironmentTier 4

View / Read-only on the Azure Portal


Summary
Thank you for reading through the resource groups blog post, our aim was to give you an overview and set of best practices on how to implement resource groups based on a couple of design standards. When looking at the virtual datacenter concept. We now have a clear naming standard with a set of policies that are being applied to our management groups, subscriptions and resource groups. Our resource groups have been pre-configured in order to facilitate the deployment of our future resources.
What’s next?
The following aspects of the virtual datacenter concept will be highlighted in the following upcoming posts:
- Virtual Datacenter Concept – 4 of 10 – Virtual Networking
- Virtual Datacenter Concept – 5 of 10 – Cloud Storage
- Virtual Datacenter Concept – 6 of 10 – Identity Options
- Virtual Datacenter Concept – 7 of 10 – Log Analytics
- Virtual Datacenter Concept – 8 of 10 – Security
- Virtual Datacenter Concept – 9 of 10 – Business Continuity
- Virtual Datacenter Concept – 10 of 10 – Automation
Missed a part or want to review a previous section? Be sure to check out my previous posts: