- Repo Folder Structure
- Policy Definitions Module
- Policy Initiative (Set Definitions) Module
- Policy Definition Assignment Module
- Policy Initiative Assignment Module
- Policy Exemption Module
- Assignment Effects
- Definition and Assignment Scopes
- Limitations
- Useful Resources
- Known Issues
📦examples
├──📜assignments_mg.tf
├──📜backend.tf
├──📜data.tf
├──📜definitions.tf
├──📜initiatives.tf
├──📜variables.tf
📦modules
└──📂def_assignment
├──📜main.tf
├──📜outputs.tf
└──📜variables.tf
└──📂definition
├──📜main.tf
├──📜outputs.tf
└──📜variables.tf
└──📂exemption
├──📜exemptions.json
├──📜main.tf
├──📜outputs.tf
└──📜variables.tf
└──📂initiative
├──📜main.tf
├──📜outputs.tf
└──📜variables.tf
└──📂set_assignment
├──📜main.tf
├──📜outputs.tf
└──📜variables.tf
📦policies
└──📂policy_category (e.g. General, should correspond to [var.policy_category])
└──📜policy_name.json (e.g. whitelist_regions, should correspond to [var.policy_name])
📦scripts
├──📂dsc_examples
├──📜build_guest_config_packages.ps1 (build and publish azure policy guest configuration packages)
└──📜convert_to_v2.ps1 (converts policies to version 2 of the repo library)
module whitelist_regions {
source = "gettek/policy-as-code/azurerm//modules/definition"
version = "2.3.1"
policy_name = "whitelist_regions"
display_name = "Allow resources only in whitelisted regions"
policy_category = "General"
management_group_name = local.default_management_group_scope_name
}
đź’ˇ Note:
policy_name
should match the JSON filename. The module assumes thatpolicy_category
is also the category folder name which is a child of the policies folder. Template files can also be parsed in at runtime, see the definition module readme for more information on acceptable inputs.
đź’ˇ Note: Specify the
policy_mode
variable if you wish to change the mode of a definition from the module defaultAll
toIndexed
.
Policy Initiatives are used to combine sets of definitions in order to simplify their assignment
module platform_baseline_initiative {
source = "gettek/policy-as-code/azurerm//modules/initiative"
version = "2.3.1"
initiative_name = "platform_baseline_initiative"
initiative_display_name = "[Platform]: Baseline Policy Set"
initiative_description = "Collection of policies representing the baseline platform requirements"
initiative_category = "General"
management_group_name = local.default_management_group_scope_name
member_definition_ids = [
module.whitelist_resources.definition,
module.whitelist_regions.definition
]
}
⚠️ Warning: If any twomember_definition_ids
contain the same parameters then they will bemerged()
by this module, in most cases this is beneficial but if unique values are required it may be best practice to set unique keys such as[parameters('whitelist_resources_effect')]
instead of[parameters('effect')]
.
module org_mg_whitelist_regions {
source = "gettek/policy-as-code/azurerm//modules/def_assignment"
version = "2.3.1"
definition = module.whitelist_regions.definition
assignment_scope = local.default_assignment_scope
assignment_effect = "Deny"
assignment_parameters = {
"listOfRegionsAllowed" = [
"UK South",
"UK West",
"Global"
]
}
}
module org_mg_platform_diagnostics_initiative {
source = "gettek/policy-as-code/azurerm//modules/set_assignment"
version = "2.3.1"
initiative = module.platform_diagnostics_initiative.initiative
assignment_scope = local.default_assignment_scope
assignment_effect = "DeployIfNotExists"
skip_remediation = var.skip_remediation
skip_role_assignment = false
role_definition_ids = module.platform_diagnostics_initiative.role_definition_ids
assignment_parameters = {
workspaceId = azurerm_log_analytics_workspace.workspace.id
storageAccountId = azurerm_storage_account.sa.id
eventHubName = azurerm_eventhub_namespace.ehn.name
eventHubAuthorizationRuleId = azurerm_eventhub_namespace_authorization_rule.ehnar.id
metricsEnabled = "True"
logsEnabled = "True"
}
depends_on = [
module.deploy_subscription_diagnostic_setting,
module.deploy_resource_diagnostic_setting
]
}
Use the exemption module to create an auditable and time-sensitive not_scope
Policy exemption:
data azurerm_resources keyvaults {
type = "Microsoft.KeyVault/vaults"
resource_group_name = "rg-dev-uks-vaults"
}
module exemption_team_a_mg_key_vaults_require_purge_protection {
source = "gettek/policy-as-code/azurerm//modules/exemption"
for_each = toset(data.azurerm_resources.keyvaults.resources.*.id)
providers = {
azurerm = azurerm.team_a
}
name = "Key vaults should have purge protection enabled Exemption"
scope = each.value
policy_assignment_id = module.team_a_mg_key_vaults_require_purge_protection.id
exemption_category = "Waiver"
expires_on = "2022-05-31"
display_name = "Exempted for testing"
description = "Do not require purge protection on KVs while testing"
}
Azure Policy supports the following types of effect:
đź’ˇ Note: If you're managing tags, it's recommended to use
Modify
instead ofAppend
as Modify provides additional operation types and the ability to remediate existing resources. However, Append is recommended if you aren't able to create a managed identity or Modify doesn't yet support the alias for the resource property.
The def_assignment
and set_assignment
modules will automatically create remediation tasks for policies with effects of DeployIfNotExists
and Modify
. The task name is suffixed with a timestamp to ensure a new task gets created on each terraform apply
. This can be prevented with -var "skip_remediation=true"
.
đź’ˇ Note: The required Role Definitions for the System Assigned Identity will be scoped at the policy assignment by default, you can override these as seen here or specify
skip_role_assignment=true
to omit creation.
- Should be Defined as high up in the hierarchy as possible
- Should be Assigned as low down in the hierarchy as possible
assignment_not_scopes
such as child resource groups, individual resources or entire subscriptions, can be specified as enforcement exemptions- Policy overrides RBAC so even Subscription owners fall under the same compliance enforcements assigned at a higher scope (does not apply if assigned at subscription scope)
⚠️ Requirement: Ensure the deployment account has at least Resource Policy Contributor role at thedefinition_scope
andassignment_scope
DefinitionName
has a maximum length of 64 characters andAssignmentName
a maximum length of 24 charactersDisplayName
has a maximum length of 128 characters anddescription
a maximum length of 512 characters- There's a maximum count for each object type for Azure Policy. For definitions, an entry of Scope means the management group or subscription. For assignments and exemptions, an entry of Scope means the management group, subscription, resource group, or individual resource:
Where | What | Maximum count |
---|---|---|
Scope | Policy definitions | 500 |
Scope | Initiative definitions | 200 |
Tenant | Initiative definitions | 2,500 |
Scope | Policy or initiative assignments | 200 |
Scope | Exemptions | 1000 |
Policy definition | Parameters | 20 |
Initiative definition | Policies | 1000 |
Initiative definition | Parameters | 100 |
Policy or initiative assignments | Exclusions (notScopes) | 400 |
Policy rule | Nested conditionals | 512 |
Remediation task | Resources | 500 |
- GitHub Repo: Azure Built-In Policies and Samples
- GitHub Repo: Contribute to Community Policies
- Microsoft Docs: Azure Policy Home
- Microsoft Docs: List of Builtin Policies
- Microsoft Docs: Index of Azure Policy Samples
- Microsoft Docs: Design Azure Policy as Code workflows
- Microsoft Docs: Evaluate the impact of a new Azure Policy definition
- Microsoft Docs: Author policies for array properties on Azure resources
- Microsoft Docs: Azure Policy Regulatory Compliance (Benchmarks)
- Microsoft Docs: Azure Policy Exemption (preview)
- Microsoft Tutorial: Build policies to enforce compliance
- Microsoft Tutorial: Security Center - Working with security policies
- VSCode Marketplace: Azure Policy Extension
- Terraform Provider: azurerm_policy_definition
- Terraform Provider: azurerm_policy_set_definition
- Terraform Provider: there are multiple assignment resources beginning with: azurerm_management_group_policy_assignment
- Terraform Provider: azurerm_policy_remediation
You may experience plan/apply issues when running an initial deployment of the set_assignment
module. This is because azurerm_role_assignment.rem_role
and azurerm_policy_remediation.rem
depend on resources to exist before producing a successful continuos deployment. To overcome this, set the flag -var "skip_remediation=true"
and omit for consecutive builds. This may also be required for destroy tasks.
Updating Initiatives can become tricky when parameter counts are increased or decreased when member_definitions
are added or removed, in most cases you will need to recreate the initiative before a successful set_assignment
e.g: terraform apply -var "skip_remediation=true" -target module.example_initiative