Resource Organization
How to structure naming conventions, tagging, and resource groups for Azure at scale.
The Three Pillars
Naming Convention
Core Principles
- Unique - Globally or regionally unique as required
- Descriptive - Conveys resource purpose
- Consistent - Same pattern across all resources
- Short - Respects character limits
- Automation-friendly - Parseable by scripts
Recommended Format
{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
| Component | Description | Examples |
|---|---|---|
resource-type | Azure resource abbreviation | rg, vnet, kv, st |
workload | Application or service name | sap, finance, web |
environment | Lifecycle stage | prod, dev, test, sandbox |
region | Azure region | eastus, westeurope, australiaeast |
instance | Instance number | 001, 002 |
Resource Type Abbreviations
| Resource | Abbreviation | Example |
|---|---|---|
| Resource Group | rg | rg-sap-prod-001 |
| Virtual Network | vnet | vnet-hub-prod-001 |
| Subnet | snet | snet-app-001 |
| Network Security Group | nsg | nsg-web-001 |
| Public IP | pip | pip-agw-001 |
| Load Balancer | lb | lb-web-001 |
| Application Gateway | agw | agw-web-001 |
| Virtual Machine | vm | vm-sql-001 |
| Storage Account | st | stapp1prod001 |
| Key Vault | kv | kv-app1-prod-001 |
| SQL Database | sqldb | sqldb-app1-prod |
| App Service | app | app-api-prod-001 |
| Function App | func | func-process-prod-001 |
| AKS Cluster | aks | aks-platform-prod-001 |
| Log Analytics | log | log-platform-001 |
Character Limits
| Resource | Min | Max | Constraints |
|---|---|---|---|
| Resource Group | 1 | 90 | Alphanumeric, hyphen, underscore |
| Storage Account | 3 | 24 | Lowercase letters and numbers only |
| Key Vault | 3 | 24 | Alphanumeric and hyphens |
| Virtual Machine | 1 | 64 | Varies by OS (15 for Windows) |
| Virtual Network | 2 | 64 | Alphanumeric, hyphen, underscore |
| App Service | 2 | 60 | Alphanumeric 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
| Tag | Description | Example Values |
|---|---|---|
Environment | Deployment stage | Production, Development, Test |
CostCenter | Billing code | CC-12345 |
Owner | Primary contact | john@contoso.com |
Application | Workload name | SAP-Finance |
DataClassification | Security level | Public, Internal, Confidential |
Recommended Tags
| Tag | Description | Example Values |
|---|---|---|
Department | Business unit | Finance, HR, IT |
Project | Initiative name | CloudMigration2024 |
Criticality | Business impact | Mission-Critical, Business-Critical, Low |
SupportTeam | Ops contact | platform-team@contoso.com |
CreatedBy | Creation method | terraform, manual, arm |
MaintenanceWindow | Patching schedule | Sunday-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
- Lifecycle-based - Resources that deploy/delete together
- RBAC boundary - Common access requirements
- Region-specific - RG is in a region, but can contain resources from any region
- 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 Level | Prevents |
|---|---|
CanNotDelete | Deletion only |
ReadOnly | Modifications 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
| Concept | Best Practice |
|---|---|
| Naming | {type}-{workload}-{env}-{region}-{instance} |
| Tags | Required: Environment, CostCenter, Owner, Application |
| Resource Groups | Group by lifecycle and access requirements |
| Locks | CanNotDelete on production resource groups |
| Storage Names | Lowercase, 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.