Skip to main content

Resource Organization

How to structure naming conventions, tagging, and resource groups for Azure at scale.

The Three Pillars

Naming Convention

Core Principles

  1. Unique - Globally or regionally unique as required
  2. Descriptive - Conveys resource purpose
  3. Consistent - Same pattern across all resources
  4. Short - Respects character limits
  5. Automation-friendly - Parseable by scripts
{resource-type}-{workload}-{environment}-{region}-{instance}

Examples:
rg-sap-prod-eastus-001
vnet-hub-prod-eastus-001
kv-finance-prod-eastus-001
st-app1-prod-eastus-001

Component Definitions

ComponentDescriptionExamples
resource-typeAzure resource abbreviationrg, vnet, kv, st
workloadApplication or service namesap, finance, web
environmentLifecycle stageprod, dev, test, sandbox
regionAzure regioneastus, westeurope, australiaeast
instanceInstance number001, 002

Resource Type Abbreviations

ResourceAbbreviationExample
Resource Grouprgrg-sap-prod-001
Virtual Networkvnetvnet-hub-prod-001
Subnetsnetsnet-app-001
Network Security Groupnsgnsg-web-001
Public IPpippip-agw-001
Load Balancerlblb-web-001
Application Gatewayagwagw-web-001
Virtual Machinevmvm-sql-001
Storage Accountststapp1prod001
Key Vaultkvkv-app1-prod-001
SQL Databasesqldbsqldb-app1-prod
App Serviceappapp-api-prod-001
Function Appfuncfunc-process-prod-001
AKS Clusteraksaks-platform-prod-001
Log Analyticsloglog-platform-001

Character Limits

ResourceMinMaxConstraints
Resource Group190Alphanumeric, hyphen, underscore
Storage Account324Lowercase letters and numbers only
Key Vault324Alphanumeric and hyphens
Virtual Machine164Varies by OS (15 for Windows)
Virtual Network264Alphanumeric, hyphen, underscore
App Service260Alphanumeric and hyphens

Handling Storage Account Limits

Storage accounts have strict naming rules (lowercase, no hyphens, 24 chars):

Standard:  st{workload}{env}{region}{instance}
Examples:
- stapp1prodeastus001 (20 chars)
- stsapprodeus001 (15 chars - abbreviated)
- stfinancedevweu001 (18 chars)

Sample: Naming Module (Bicep)

@description('Workload name')
param workload string

@description('Environment')
@allowed(['prod', 'dev', 'test', 'sandbox'])
param environment string

@description('Azure region')
param location string = resourceGroup().location

// Region abbreviations
var regionAbbreviations = {
eastus: 'eus'
eastus2: 'eus2'
westus: 'wus'
westus2: 'wus2'
westeurope: 'weu'
northeurope: 'neu'
australiaeast: 'aue'
}

var regionAbbr = regionAbbreviations[location]

// Generate names
output resourceGroupName string = 'rg-${workload}-${environment}-${regionAbbr}-001'
output vnetName string = 'vnet-${workload}-${environment}-${regionAbbr}-001'
output storageAccountName string = 'st${workload}${environment}${regionAbbr}001'
output keyVaultName string = 'kv-${workload}-${environment}-${regionAbbr}-001'

Tagging Strategy

Tag Categories

Required Tags

TagDescriptionExample Values
EnvironmentDeployment stageProduction, Development, Test
CostCenterBilling codeCC-12345
OwnerPrimary contactjohn@contoso.com
ApplicationWorkload nameSAP-Finance
DataClassificationSecurity levelPublic, Internal, Confidential
TagDescriptionExample Values
DepartmentBusiness unitFinance, HR, IT
ProjectInitiative nameCloudMigration2024
CriticalityBusiness impactMission-Critical, Business-Critical, Low
SupportTeamOps contactplatform-team@contoso.com
CreatedByCreation methodterraform, manual, arm
MaintenanceWindowPatching scheduleSunday-02:00-UTC

Tag Enforcement with Policy

targetScope = 'managementGroup'

resource requireTagPolicy 'Microsoft.Authorization/policyDefinitions@2021-06-01' = {
name: 'require-costcenter-tag'
properties: {
displayName: 'Require CostCenter tag'
policyType: 'Custom'
mode: 'Indexed'
parameters: {}
policyRule: {
if: {
field: 'tags[\'CostCenter\']'
exists: false
}
then: {
effect: 'Deny'
}
}
}
}

Tag Inheritance

Tags can inherit from resource groups:

resource tagInheritPolicy 'Microsoft.Authorization/policyDefinitions@2021-06-01' = {
name: 'inherit-tag-from-rg'
properties: {
displayName: 'Inherit tag from resource group'
policyType: 'Custom'
mode: 'Indexed'
parameters: {
tagName: {
type: 'String'
metadata: {
displayName: 'Tag name'
}
}
}
policyRule: {
if: {
allOf: [
{
field: '[concat(\'tags[\', parameters(\'tagName\'), \']\')]'
exists: false
}
{
value: '[resourceGroup().tags[parameters(\'tagName\')]]'
notEquals: ''
}
]
}
then: {
effect: 'Modify'
details: {
roleDefinitionIds: [
'/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c'
]
operations: [
{
operation: 'addOrReplace'
field: '[concat(\'tags[\', parameters(\'tagName\'), \']\')]'
value: '[resourceGroup().tags[parameters(\'tagName\')]]'
}
]
}
}
}
}
}

Resource Group Design

Core Principles

  1. Lifecycle-based - Resources that deploy/delete together
  2. RBAC boundary - Common access requirements
  3. Region-specific - RG is in a region, but can contain resources from any region
  4. Deletion scope - Deleting RG deletes all contents

Resource Group Patterns

Pattern 1: Application-Centric

rg-sap-prod-eastus-001/
├── vm-sap-app-001
├── vm-sap-app-002
├── vm-sap-db-001
├── nsg-sap-app
├── lb-sap-app
└── st-sap-prod-001

Best for: Traditional applications with shared lifecycle

Pattern 2: Layer-Based

rg-app1-compute-prod-001/
├── vm-app1-web-001
├── vm-app1-web-002
└── lb-app1-web

rg-app1-data-prod-001/
├── sqldb-app1-prod
└── st-app1-prod-001

rg-app1-network-prod-001/
├── vnet-app1-prod
├── nsg-app1-web
└── nsg-app1-data

Best for: Different teams managing different layers

Pattern 3: Component-Based (Microservices)

rg-orders-service-prod-001/
├── aks-orders-prod
├── kv-orders-prod
└── appi-orders-prod

rg-inventory-service-prod-001/
├── aks-inventory-prod
├── kv-inventory-prod
└── appi-inventory-prod

Best for: Microservices with independent deployments

Resource Group Naming

rg-{workload}-{component}-{environment}-{region}-{instance}

Examples:
rg-sap-all-prod-eastus-001 (all SAP resources)
rg-ecommerce-api-prod-eastus-001 (API layer)
rg-platform-network-prod-eastus-001 (shared networking)

Anti-Patterns to Avoid

❌ One RG for Everything

❌ RG per Resource

Resource Group Locks

Protect critical resources from accidental deletion:

resource rgLock 'Microsoft.Authorization/locks@2020-05-01' = {
name: 'CanNotDelete'
properties: {
level: 'CanNotDelete'
notes: 'Production resources - do not delete'
}
}
Lock LevelPrevents
CanNotDeleteDeletion only
ReadOnlyModifications and deletion

Complete Organization Example

Subscription Structure

sub-sap-prod-001/

├── rg-sap-network-prod-eastus-001/
│ ├── vnet-sap-prod-eastus-001
│ ├── snet-sap-app-001
│ ├── snet-sap-data-001
│ ├── nsg-sap-app-001
│ └── nsg-sap-data-001

├── rg-sap-compute-prod-eastus-001/
│ ├── vm-sap-app-001
│ ├── vm-sap-app-002
│ ├── vm-sap-db-001
│ ├── avset-sap-app-001
│ └── lb-sap-app-001

├── rg-sap-data-prod-eastus-001/
│ ├── st-sapprodeus001
│ └── kv-sap-prod-eastus-001

└── rg-sap-monitor-prod-eastus-001/
├── log-sap-prod-eastus-001
└── appi-sap-prod-eastus-001

Tag Assignment

{
"resourceGroup": "rg-sap-compute-prod-eastus-001",
"tags": {
"Environment": "Production",
"CostCenter": "CC-SAP-12345",
"Owner": "sap-team@contoso.com",
"Application": "SAP-Finance",
"Department": "Finance",
"DataClassification": "Confidential",
"Criticality": "Mission-Critical",
"SupportTeam": "sap-ops@contoso.com",
"MaintenanceWindow": "Sunday-02:00-UTC",
"CreatedBy": "terraform-pipeline"
}
}

Automation: Resource Organization Module

// modules/resource-organization.bicep
@description('Workload name')
param workload string

@description('Environment')
param environment string

@description('Region')
param location string

@description('Tags')
param tags object = {}

// Standard tags
var standardTags = {
Application: workload
Environment: environment
ManagedBy: 'Bicep'
LastUpdated: utcNow('yyyy-MM-dd')
}

var allTags = union(standardTags, tags)

// Resource group for network
resource networkRg 'Microsoft.Resources/resourceGroups@2022-09-01' = {
name: 'rg-${workload}-network-${environment}-${location}-001'
location: location
tags: allTags
}

// Resource group for compute
resource computeRg 'Microsoft.Resources/resourceGroups@2022-09-01' = {
name: 'rg-${workload}-compute-${environment}-${location}-001'
location: location
tags: allTags
}

// Resource group for data
resource dataRg 'Microsoft.Resources/resourceGroups@2022-09-01' = {
name: 'rg-${workload}-data-${environment}-${location}-001'
location: location
tags: allTags
}

output networkResourceGroup string = networkRg.name
output computeResourceGroup string = computeRg.name
output dataResourceGroup string = dataRg.name

Quick Reference Card

ConceptBest Practice
Naming{type}-{workload}-{env}-{region}-{instance}
TagsRequired: Environment, CostCenter, Owner, Application
Resource GroupsGroup by lifecycle and access requirements
LocksCanNotDelete on production resource groups
Storage NamesLowercase, no hyphens, max 24 chars

Governance Checklist

Naming Convention

  • Documented and approved
  • Covers all resource types
  • Handles character limits
  • Automation-friendly

Tagging Strategy

  • Required tags defined
  • Policy enforcement enabled
  • Tag inheritance configured
  • Cost allocation mapped

Resource Groups

  • Lifecycle-based grouping
  • Consistent naming
  • Locks on production
  • Clear ownership

Next Steps

Continue to Identity & Access to learn about Azure AD, RBAC, and privileged access management.