Most teams think they’ve built a landing zone when the structure is in place.
Management groups exist.
Subscriptions are organized.
Terraform pipelines are running.
It looks right.
Then the environment starts drifting.
A storage account gets deployed with public access enabled.
Resources show up in regions nobody approved.
Tags disappear because pipelines don’t enforce them consistently.
Nothing stops it.
That’s the part most teams don’t want to admit:
A landing zone without Azure Policy isn’t a platform.
It’s a diagram.
The Moment It Breaks
Early on, everything works because the system is small.
Standards exist. People follow them. Deployments are predictable.
Then scale shows up.
More engineers. More repositories. More pipelines. More pressure.
And now behavior starts to diverge:
- pipelines get copied and modified
- engineers bypass standards to move faster
- new services appear without guardrails
Nothing fails immediately.
That’s what makes it dangerous.
The environment doesn’t collapse—it degrades.
Until the day it matters.
A Real Failure Scenario
A team deploys a storage account for a quick integration. It’s non-production, so nobody is worried. Public access is enabled because it’s easier.
No policy blocks it.
That deployment pattern gets copied. Then reused. Then normalized.
Weeks later, a similar deployment happens in production.
Same defaults. Same exposure. Still no policy.
Now you have a publicly accessible storage account in production holding data it was never meant to expose.
Nobody notices until:
- a security scan flags it
- or someone external finds it first
At that point, the question isn’t “how did this happen?”
It’s:
Why did your platform allow it?
And the answer is simple.
Nothing enforced behavior.
Policy would have stopped it on day one.
What Azure Policy Actually Does
Azure Policy is not about visibility.
It’s about control.
Every policy evaluates a resource and applies an effect. That effect determines whether behavior is allowed, modified, or corrected.
That’s the mechanism that turns architecture into something real.
The Effects That Matter in Practice
You don’t need every feature.
You need to understand how these work together.
Audit — Establish Reality
Audit shows you what’s actually happening.
Not what your diagrams say. Not what your standards say.
Reality.
You use it to answer:
- where are we exposed?
- what are we missing?
- how are engineers actually deploying?
Skip this, and everything that follows is guesswork.
Deny — Set the Boundary
Deny is the line.
Once it’s applied, behavior changes immediately.
Deployments fail. Pipelines break. Engineers adjust.
Use it for things that cannot be negotiable:
- public exposure
- unapproved regions
- missing required tags
Used correctly, Deny creates clarity.
Used poorly, it creates friction.
Append — Remove Human Error
Append enforces consistency without blocking work.
Instead of relying on engineers to remember requirements, you make them automatic.
Tags. Settings. Baseline configurations.
This is how you reduce variance across environments without slowing teams down.
DeployIfNotExists — Guarantee the Baseline
This is where platforms mature.
If something is missing, Azure deploys it automatically.
Logging. Diagnostics. Security controls.
At this point, you’re not asking engineers to do the right thing.
You’re making the right thing happen.
How These Work Together (This Is What Most People Miss)

Individually, these effects are useful.
Together, they define behavior.
A real policy initiative doesn’t rely on one effect. It combines them.
Example: Storage Security Initiative
- Deny
- Public network access enabled
- Deployment outside approved regions
- Append
- Required tags (environment, owner, cost center)
- DeployIfNotExists
- Diagnostic settings to Log Analytics
- Defender for Storage enabled
- Audit
- Legacy resources not yet compliant
Now you have a system:
- bad configurations are blocked
- required standards are enforced automatically
- missing controls are deployed
- existing gaps are visible
That’s not policy as a feature.
That’s policy as a platform.
Scope: Where Policy Actually Gets Its Power
Policy without scope is noise.
Where you assign it determines how it behaves.
Root / Tenant
Minimal, high-impact controls.
This is where you prevent the worst mistakes:
- disallowed regions
- critical security violations
Too much here breaks everything downstream.
Platform Management Group
This defines your baseline.
Logging. Security. Identity.
Every subscription under this inherits expectations automatically.
Production
This is where enforcement tightens.
Deny becomes standard for critical controls.
Because this is where mistakes turn into incidents.
Non-Production
Same intent. Different enforcement.
Audit instead of Deny where possible.
Engineers need space to test without breaking the platform.
Sandbox
Minimal restriction.
Focus on visibility and cost awareness.
If engineers can’t experiment here, they’ll bypass your platform entirely.
How Governance Actually Gets Implemented
This is where most teams fail.
They try to enforce everything at once.
That doesn’t work.
Phase 1 — Visibility
Start with Audit.
Let it run long enough to understand behavior.
Not assumptions. Actual behavior.
Phase 2 — Fix the System
Fix:
- Terraform modules
- pipeline templates
- deployment patterns
If compliance requires manual effort, it will fail.
Phase 3 — Enforce Selectively
Introduce Deny where it matters most:
- public exposure
- region restrictions
- required metadata
Don’t enforce everything.
Enforce what matters.
Phase 4 — Automate the Baseline
Use:
- Append for consistency
- DeployIfNotExists for guarantees
Now governance isn’t something engineers think about.
It’s something the platform handles.
Terraform: Where Governance Stops Being Optional
If your policy isn’t in Terraform, it isn’t part of your platform.
It’s configuration.
Configuration drifts.
Platforms don’t.
Example: Management Group Policy Assignment
resource "azurerm_management_group_policy_assignment" "security_baseline" { name = "mg-security-baseline" display_name = "Management Group Security Baseline" policy_definition_id = var.security_initiative_id management_group_id = var.management_group_id location = var.location identity { type = "SystemAssigned" }}
This is where governance becomes:
- versioned
- reviewable
- repeatable
No ambiguity. No drift.
Why Modules Are the Difference
Most environments don’t fail because they lack policy.
They fail because they lack consistency.
Policy gets copied. Modified. Forgotten.
Now every environment behaves differently.
Modules eliminate that.
Check out some examples of terraform modules:
https://github.com/Tech-Skills-Academy/tf-modules
Microsoft also offers verified terraform modules
https://github.com/Azure/terraform-azure-modules
Isn’t reuse.
It’s standardization.
At scale.
Why Governance Fails
The same patterns show up everywhere.
Enforcing Too Early
Deny before understanding behavior breaks trust in the platform.
Once that happens, engineers work around you.
Treating Policy as Optional
If it doesn’t enforce behavior, it doesn’t matter.
Documentation doesn’t scale.
Ignoring Scope
Wrong scope means wrong outcome.
Too restrictive or too loose.
Both fail.
Not Fixing the System
If Terraform and pipelines don’t align with policy, you’re fighting your own environment.
That’s not sustainable.
Final Thought
Your architecture is only as strong as what it refuses to allow.
Not what it suggests.
Not what it documents.
Not what it hopes engineers will follow.
What it enforces.
Because under pressure, nobody follows the diagram.
They follow the path of least resistance.
And if your platform doesn’t control that path, you don’t have governance.
You have drift.



Drop me a note, and let me know what you think