Tagging Standard¶
Every resource and resource group carries a fixed set of eleven tags. Together they answer who owns a resource, what it is for, how it was built and who pays for it. Terraform modules apply the tags automatically, and Azure Policy checks for them.
Status: tags applied by Terraform, policy is audit-only
The platform's Terraform modules apply all eleven tags. The policy that checks them, psa-tags-enforce-001, runs with effect: Audit and enforcementMode: DoNotEnforce. It reports missing tags but does not block untagged resources. Some older documents, including the repository's CLAUDE.md, describe this as "enforced Deny". That is not the current state.
The tags¶
| Tag | Meaning | Example |
|---|---|---|
Environment |
Lifecycle stage | prod, dev, sandbox |
WorkloadOwner |
The business team that owns the workload | platform-team, web-team |
PlatformOwner |
The team that runs the platform. Always the same value. | platform-team |
Workload |
The workload or service the resource belongs to | mkdocs, monitoring |
ManagedBy |
How the resource is managed. Always Terraform. | terraform |
LastChangedBy |
Who or what last changed the resource. Set by CI. | the pipeline or user identity |
LastChangedDate |
When it was last changed | ISO date |
IaCModule |
The Terraform module that created it | terraform-azurerm-log-analytics-workspace |
IaCModuleVersion |
That module's version | v1.0.0 |
IaCRepo |
The repository that deployed it | the GitLab project path |
FinOpsId |
The cost allocation key. A random UUID created once per subscription by subscription vending, which never changes. | 3f2a… (a UUID) |
LastChangedBy and LastChangedDate replaced the earlier CreatedBy and CreatedDate. A "created" tag is only accurate if it is fixed at true creation, which isn't possible for resources that existed before the standard.
How tags are applied¶
- Terraform modules add them. Each resource module sets the provenance tags (
IaCModule,IaCModuleVersion,IaCRepo,ManagedBy). The deployment supplies the ownership and cost tags. - CI sets
LastChangedBythroughTF_VAR_last_changed_by. - Resources created outside Terraform won't have them. This is intended. A missing
ManagedBy = terraformtag is the quickest way to spot something created by hand.
How tags are checked¶
The psa-tags-enforce-001 assignment uses the custom initiative Tags - Enforcement (psd-tags-Enforcement). It has two checks per tag, one for resource groups and one for resources, and applies at mg-intermediate-root with no exclusions.
To make it blocking, follow the ADR-0001 promotion path: set the effect to Deny and the enforcementMode to Default in a separate MR. Two things to be aware of first:
- Updates are blocked too.
Denyblocks any update to an existing untagged resource until the tags are added. Fix the existing non-compliant resources first. - There is no inheritance. The initiative doesn't copy tags from a resource group to its resources. Every resource must be tagged directly.
Lesson from a past incident
In an earlier change, a new audit-only tag set was added by editing the existing enforcing assignment instead of adding a separate one. That silently removed the Deny enforcement. It was only noticed during a manual tag review. Add new policy behaviour as a new assignment or child node. Never repurpose one that is already enforcing.