Practical engineering guidance
Azure Policy as a guardrail: audit, deny and deployIfNotExists
Policy is the only control that stops a permitted action producing an unacceptable resource. Deploying it in the wrong order is how you break a platform team's deployments on a Monday.
Series: Azure architecture
Role-based access control decides who may act. Azure Policy decides what the result is allowed to look like. They solve different problems, and the distinction matters because almost every governance requirement people bring to RBAC is actually a policy requirement.
“Contributors must not create storage accounts with public access” is not expressible as a role. It is a policy.
Requirements: what to know before assigning anything
Policy evaluates at creation, at update, and periodically. A new deny assignment blocks non-conforming new deployments immediately. It does not delete existing non-conforming resources — they are simply reported as non-compliant. This asymmetry is what makes a staged rollout possible.
Scope is the management group, subscription or resource group, inheriting downward in the same way as RBAC. Exemptions carve out specific scopes or resources, and unlike RBAC, policy does have a subtraction mechanism.
Remediating effects need an identity. deployIfNotExists and modify act on your
behalf, so the assignment needs a managed identity with sufficient permissions. That identity
is a privileged object and deserves the scrutiny in
Azure RBAC scope decisions.
Design: the effects, and what each is for
The effects are audit, auditIfNotExists, deny, denyAction, deployIfNotExists,
modify, append and disabled. In practice you will use five of them.
audit reports non-compliance and changes nothing. This is where every policy should
start. It costs nothing, breaks nothing, and produces the evidence you need to decide whether
denying is safe.
auditIfNotExists reports when a related resource is missing — diagnostic settings not
configured, an extension not installed. Useful for the “this exists but is not fully
configured” class of finding, which plain audit cannot express.
deny blocks the request. This is the guardrail proper, and the effect that generates
incidents if deployed carelessly.
denyAction blocks a specific action rather than a resource shape — the obvious use
being to block deletion of resources that must not be deleted. Different from deny, and
worth knowing because people reach for resource locks when this is a better fit at scale.
deployIfNotExists deploys a remediating template when the condition is met. This is how
you get diagnostic settings onto every resource without asking teams to remember. Powerful,
and it changes things on your behalf, so it earns the same caution as deny.
modify alters the request as it arrives — adding or replacing tags, for instance. It
runs before the resource is created, which makes it gentler than remediating afterwards.
append adds fields to a request. Largely superseded by modify for most uses.
disabled turns a definition off without removing the assignment, which is your fastest
rollback.
Design: what belongs in a baseline
A useful starting baseline is small and mostly not deny:
- Allowed regions. A
denyon regions outside your data residency requirements. This one is safe to deny early because it is unambiguous and the requirement usually comes from outside IT. - Required tags.
modifyto add a default, rather thandenyfor absence. Denying a deployment because of a missing cost centre tag makes governance the enemy; adding the tag silently does not. - Diagnostic settings.
deployIfNotExiststo send platform logs where they belong. This is the single highest-value remediating policy, because the alternative is discovering during an incident that nothing was logged. - Public network access. Start with
auditacross storage, databases and key vaults. The results will tell you whether adenyis survivable. - Storage and transport security. Secure transfer, minimum TLS version. Usually safe to deny once audited, because non-compliance is rare and clearly wrong.
Use initiatives — policy sets — to group related definitions so that assignment and exemption happen once rather than per definition. The built-in regulatory compliance initiatives are worth assigning in audit mode purely for the visibility, even if you have no compliance obligation.
Deployment: the sequence that avoids an outage
This is the part that matters, and it mirrors the Conditional Access approach in Conditional Access baselines for exactly the same reason: you are deploying an enforcement control into an environment you do not fully know.
- Assign with
audit, at the scope you eventually intend to enforce at. - Wait for evaluation and read the compliance results. Every non-compliant resource is either something to fix, something to exempt, or evidence that the policy is wrong.
- Fix or exempt the existing non-compliance. Exemptions should carry an expiry date and a reason; an exemption without either becomes permanent by neglect.
- Change the effect to
deny, starting at a narrow scope — one non-production subscription — rather than at the management group root. - Widen the scope in stages, watching for deployment failures at each step.
- Only then consider remediating effects for existing resources, and run remediation tasks deliberately rather than leaving them to run automatically the first time.
Microsoft documents a safe deployment practice for policy assignments, and it is worth
following rather than improvising. The failure mode this prevents is specific and common: a
deny assigned at the root management group on a Friday, discovered on Monday when every
pipeline in the organisation fails.
Use the enforcement mode. Assignments can be created with enforcement disabled, which
evaluates and reports without applying deny or remediation. It is the policy equivalent of
report-only and it is underused.
Validation
Compliance percentage is the headline number and the least useful one. What to check instead:
- Deploy a deliberately non-conforming resource into a test scope and confirm it is
actually blocked. A
denypolicy that has never blocked anything may be scoped to nothing. - Deploy a conforming resource and confirm it succeeds. Over-broad policy conditions block legitimate deployments, and this is how you find out before a team does.
- Confirm remediation ran, and check what it created. A
deployIfNotExiststhat silently failed because its managed identity lacked permission is a common and quiet failure. - Check the exemption list and its expiry dates.
- Confirm the policy applies to the deployment methods you actually use. Policy evaluates Resource Manager requests, so ARM templates, Bicep, Terraform via the Azure provider and portal actions are all covered. Changes made through a service’s own data plane are not.
Operations
Exemptions need a lifecycle. Give each one an expiry and an owner. Review them on a schedule and require a fresh justification rather than an extension by default.
Policy definitions are code. Keep custom definitions and assignments in version control and deploy them through a pipeline. Clicking policy assignments into a portal produces an estate nobody can reproduce or review.
Watch for policy as an accidental outage source. When a deployment fails mysteriously, policy should be an early suspect. The activity log records the denying policy assignment by name, which makes this fast once people know to look.
Re-evaluate the baseline when Azure changes. New resource types appear that your policies do not cover, and built-in definitions are updated. A baseline assigned two years ago and never revisited is reporting compliance against a narrower set of resources than you think.
Rollback
Three levels, fastest first: set the effect parameter to disabled, set the assignment’s
enforcement mode to disabled, or delete the assignment. All take effect quickly for new
deployments.
What does not roll back is anything a remediating effect already changed. A modify that
rewrote tags or a deployIfNotExists that created diagnostic settings has altered resources,
and removing the policy does not revert them. That asymmetry is why remediating effects come
last in the sequence above, and why remediation tasks should be run deliberately on a known
scope rather than left to sweep an estate unattended.
Verification and limits
The effect names and their behaviours, evaluation at create and update plus periodic evaluation, the non-deletion of existing non-compliant resources, managed identity requirements for remediating effects, exemptions and enforcement mode were checked against current Microsoft documentation on 20 September 2026. The suggested baseline and the rollout sequence are my own practice.
No policy was assigned to an Azure environment for this article. A deny assignment blocks
deployments as soon as it is in place, and remediating effects change resources: assign in
audit mode first, use enforcement mode while testing, start at a narrow non-production scope,
and confirm the activity log shows what you expect before widening.
References
Reader feedback
Was this article useful?
No ratings yet. Be the first to rate this article.
