Policy-as-Code at enterprise scale
Automating enforcement of 100+ governance and compliance policies across a global tenant with Azure Policy, Terraform, and GitLab CI — and cutting environment onboarding by ~60%.
The problem
At a global commodity trading organization, the platform team was the bottleneck. Over 500 cloud resources existed, and compliance was a ritual that happened after the fact: quarterly security reviews, manual checklists, and an exception process that lived in email threads. When auditors asked "are we compliant right now?", nobody could answer — and worse, a developer who violated a control could still ship, because nothing enforced the rule at the point of change.
The problem was not a lack of rules — it was that the rules were not code. The resolution was to turn governance into a product with a pipeline: policy definitions reviewed, tested, and applied like any other codebase.
The architecture
I designed a Policy-as-Code solution with a clean pipeline:
stages:
- test
- validate
- apply
policy-job:
stage: validate
script:
- terraform validate
- terraform plan -out=tf.plan
- az policy definition list --query "[?displayName like '%' ]"
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
The pipeline runs on GitLab CI/CD. Every change to a policy definition goes through test → validate → apply, and only the main branch can promote to production. Policy definitions are JSON in git; initiatives group them; assignments target management groups so they cascade.
What I built
The system has three layers:
- Definitions — custom policy definitions for the controls that mattered to the business (allowed resource types, mandatory tags, network isolation for sensitive workloads).
- Initiatives — logical bundles so a "finance-grade" or "trading-desk" workload gets the right set of controls assigned once.
- Assignments and exemptions — scoped to management groups or specific subscriptions, with a documented, auditable exemption workflow for legitimate exceptions.
Here is what a definition actually looks like in the repo — a small JSON policy that denies disallowed resource types at the management group scope:
{
"properties": {
"displayName": "Deny disallowed resource types",
"policyType": "Custom",
"mode": "All",
"parameters": {
"listOfResourceTypesNotAllowed": {
"type": "Array",
"defaultValue": ["Microsoft.Sql/servers"]
}
},
"policyRule": {
"if": { "field": "type", "in": "[parameters('listOfResourceTypesNotAllowed')]" },
"then": { "effect": "Deny" }
}
}
}
Exemptions are first-class Terraform resources too, so even the escape hatch is auditable — every waiver has an owner, a reason, and an expiry:
resource "azurerm_management_group_policy_exemption" "legacy_sql" {
name = "legacy-sql-exemption"
management_group_id = data.azurerm_management_group.platform.id
policy_assignment_id = azurerm_management_group_policy_assignment.governance.id
exemption_category = "Waiver"
display_name = "Legacy SQL Server waiver (finance)"
expires_on = "2026-12-31"
}
Alongside the policies I automated Azure Private DNS zone management with Terraform and Python — multi-subscription resolution and private endpoint integration so DNS didn't become the accidental bottleneck of every private network design.
Results
- 100+ policies under continuous enforcement across the entire tenant. Non-compliant changes are blocked or flagged at creation.
- ~60% faster environment onboarding. Teams no longer wait for manual reviews; the policy set is pre-baked into the hierarchy.
- Auditable exemptions. When something needed an exception, it was recorded, approved, and time-boxed — not lost in an inbox.
Lessons learned
- Policy is product. It needs versioning, review, and a changelog like any other codebase.
- Enforce early, refine rarely. Start with a small set of high-value controls. Adding policy is cheap; removing policy that has blocked a team is expensive in trust.
- Exemptions are part of the system. If you pretend exceptions don't exist, teams will route around you. Build the escape hatch with guardrails.
Enterprise governance is not about saying no. Done right, it is the fastest way to say yes safely.