← Back to blog

Azure Resource Tagging for Audit and Compliance: Why Activity Logs Aren't Enough

The question you can’t answer

An auditor asks a simple question: who created that production storage account? It has been running for eight months. No one remembers who provisioned it or why. You check the Azure activity log. It is empty — the entries expired after 90 days.

This is not an edge case. Azure activity logs have a hard 90-day retention period. After that window closes, every record of who created, modified, or configured a resource is gone. The resource itself persists indefinitely, but the context behind it — who made it, when, and under what circumstances — evaporates.

For organizations subject to SOC 2, ISO 27001, or internal governance requirements, this creates a gap that gets wider every quarter. Resources accumulate. Ownership becomes unclear. When audit season arrives, teams scramble to reconstruct provenance from memory, Slack threads, and ticket histories. Some resources cannot be attributed at all.

The problem is not that Azure lacks logging. The problem is that logging and permanence are two different things.

Why Azure doesn’t solve this natively

Azure has several features that look like they should solve this, but none of them actually do.

Azure Policy can enforce that tags exist at creation time. You can write a policy that denies resource creation unless a Creator tag is present. But this shifts the burden to the person deploying the resource — they have to manually type their own name into a tag field. In practice, people enter placeholder values, team names, or nothing useful. More importantly, Azure Policy’s modify effect (which can auto-set tags) runs as the policy’s own identity, not the original caller. It cannot populate a tag with the UPN of the person who triggered the deployment.

ARM template deployments compound the problem. When resources are created through CI/CD pipelines, the activity log records the pipeline’s service principal as the caller — not the engineer who triggered the pipeline run. The human identity is buried in the pipeline’s own logs, which may be in a completely different system.

Exporting activity logs to Log Analytics extends retention beyond 90 days, but it does not make creator information easily accessible. Answering “who created this storage account?” requires writing KQL queries against a Log Analytics workspace, correlating operation IDs, and hoping the relevant events were ingested before they expired. This is a research project, not a quick lookup.

There is no built-in mechanism in Azure to permanently, automatically stamp a resource with the identity of the person who created it.

Az-Stamper icon

Tag your Azure resources automatically

Az-Stamper is a free, open-source Azure Functions solution that automatically tags resources with creator identity the moment they are created. It adds five default tags — Creator, CreatedOn, StampedBy, LastModifiedBy, and LastModifiedOn — so the information is permanently attached to the resource, visible in the Azure Portal, and queryable via Azure Resource Graph.

Deploy to Azure

Or deploy manually via CLI for full control.

Deploy once and tags start appearing on every new resource in that subscription. Additional subscriptions can be enrolled individually. Read on for how it works and why it is built the way it is.

How Az-Stamper works

Az-Stamper uses Azure Event Grid to listen for resource write events across your subscription. When someone creates or modifies a resource, Event Grid emits a ResourceWriteSuccess event. An Azure Function receives that event, resolves the caller’s identity, and writes metadata tags to the resource in a single API call.

The tag map is fully configurable. By default, Az-Stamper applies five tags:

  • Creator — the UPN of the user or the display name of the service principal that created the resource. Write-once: the original creator is never overwritten.
  • CreatedOn — ISO 8601 UTC timestamp of the creation event. Also write-once.
  • StampedBy — fixed value Az-Stamper. Write-once. Identifies auto-tagged resources in Azure Resource Graph queries.
  • LastModifiedBy — the identity that most recently modified the resource. Overwrites on every change.
  • LastModifiedOn — timestamp of the most recent modification. Overwrites on every change.

The caller identity resolution chain handles a common challenge in Azure environments: service principals. When a pipeline or automation account creates a resource, the raw principal ID is not human-readable. Az-Stamper resolves this by looking up the service principal’s display name via Microsoft Graph API, which requires the Directory.Read.All application permission (granted by a Global Administrator or Privileged Role Administrator). If that lookup fails — either because the permission has not been granted or the principal is not found — it falls back to the raw principal ID. You still get a traceable identifier either way.

Self-event filtering

Tagging a resource is itself a write operation. Without filtering, Az-Stamper would tag a resource, which would trigger another event, which would trigger another tag write, in an infinite loop. Az-Stamper prevents this with three independent layers:

  1. Event Grid advanced filters — the primary guard. The Event Grid subscription excludes Microsoft.Resources/tags operations before the function is even invoked, so most self-generated events never reach the function.
  2. Application-level ignore patterns — inside the function, a configurable list filters out additional resource types and operations that should not be tagged.
  3. SelfPrincipalId check — an optional defense-in-depth setting. When configured, the function compares the caller’s principal ID against its own managed identity and skips processing if they match.

Multi-subscription support

If your organization uses multiple Azure subscriptions — for example, separate dev, staging, and production — a single Az-Stamper deployment can cover all of them using a hub-and-spoke model. The central Function App receives events from Event Grid subscriptions in each spoke. Each subscription can have its own tag configuration overrides — different tag sets, different overwrite rules, different ignore patterns — while sharing the same compute infrastructure.

Cost

Az-Stamper runs on the Azure Functions Consumption plan, which scales to zero when idle. You pay only for the milliseconds the function runs when processing events. Event Grid costs pennies per million events. The deployment also includes Application Insights and a Log Analytics workspace for monitoring — both have ingestion-based pricing, though the free tier (5 GB/month for Log Analytics) covers most small-to-medium deployments. For a typical subscription, the primary fixed cost is the storage account at approximately $0.02 per month.

Getting started

Prerequisites: An Azure subscription with Owner or Contributor + User Access Administrator role. The Microsoft.EventGrid resource provider must be registered.

Option 1 — One-click deploy (recommended):

Click Deploy to Azure to provision everything in a single deployment — resource group, function app, storage, monitoring, Event Grid subscription, RBAC assignments, and function code.

Deploy to Azure

Tags start appearing on new resources immediately after deployment completes. The deployment also includes a Static Web App configuration UI for managing tag rules and subscription settings from a browser — no CLI required.

Option 2 — Developer setup:

Clone the repo and deploy via CLI or CI/CD for full control over the infrastructure. Requires .NET 8 SDK and Azure CLI. See the Az-Stamper README for step-by-step instructions, CI/CD setup with GitHub Actions, and OIDC federated credentials for zero-secret deployments.

The default tag map is configured through Function App application settings. To add, remove, or modify tags, update the app settings — no code changes required. For multi-subscription environments, per-subscription overrides are configured via a stamper.json file uploaded to the deployment’s blob storage container, with a JSON schema for validation. The configuration guide covers custom tag definitions, per-subscription overrides, and resource type exclusions.

Key takeaways

  • Activity logs expire; tags are permanent. Tags are first-class metadata on Azure resources. They appear in the portal, in Resource Graph queries, and in billing exports. They do not expire.
  • Azure Policy can’t fill this gap. Policy can require tags but cannot auto-populate them with the caller’s identity. Az-Stamper does this automatically via Event Grid.
  • Event-driven, near-zero cost. The Consumption plan means no idle charges. The Azure free tier covers most deployments.
  • Configurable and extensible. The tag map, overwrite rules, and ignore patterns are all configurable without code changes. Multi-subscription support is built in. The StampedBy tag lets you query Azure Resource Graph for all auto-tagged resources across subscriptions.
  • MIT licensed. Free, open-source, no strings attached.

If your organization has ever struggled to answer “who created this resource?” — or if you want to make sure you never have to — Az-Stamper is the fix.