|
1 | 1 | ---
|
2 |
| -title: "Quickstart: New policy assignment with Terraform" |
| 2 | +title: 'Quickstart: New policy assignment with Terraform' |
3 | 3 | description: In this quickstart, you use Terraform and Hashicorp Configuration Language (HCL) syntax to create a policy assignment to identify non-compliant resources.
|
4 |
| -ms.date: 03/04/2025 |
| 4 | +ms.date: 03/26/2025 |
5 | 5 | ms.topic: quickstart
|
6 | 6 | ms.custom: devx-track-terraform
|
7 | 7 | ms.tool: terraform
|
| 8 | +#customer intent: As a Terraform user, I want to see how to assign an Azure policy |
| 9 | +content_well_notification: |
| 10 | + - AI-contribution |
8 | 11 | ---
|
9 | 12 |
|
10 | 13 | # Quickstart: Create a policy assignment to identify non-compliant resources using Terraform
|
11 | 14 |
|
12 |
| -The first step in understanding compliance in Azure is to identify the status of your resources. |
13 |
| -This quickstart steps you through the process of creating a policy assignment to identify virtual |
14 |
| -machines that aren't using managed disks. |
15 |
| - |
16 |
| -At the end of this process, you identify virtual machines that aren't using managed disks across subscription. They're _non-compliant_ with the policy assignment. |
| 15 | +The first step in understanding compliance in Azure is to identify the status of your resources. This quickstart steps you through the process of creating a policy assignment to identify virtual |
| 16 | +machines that aren't using managed disks. At the end of this process, you identify virtual machines that aren't using managed disks across subscription. They're _non-compliant_ with the policy assignment. |
17 | 17 |
|
18 | 18 | [!INCLUDE [azure-policy-version-default](../includes/policy/policy-version-default.md)]
|
19 | 19 |
|
20 |
| -## Prerequisites |
21 |
| - |
22 |
| -- If you don't have an Azure subscription, create a [free](https://azure.microsoft.com/free/) |
23 |
| - account before you begin. |
24 |
| -- [Terraform](https://www.terraform.io/) version 0.12.0 or higher configured in your environment. |
25 |
| - For instructions, see |
26 |
| - [Configure Terraform using Azure Cloud Shell](/azure/developer/terraform/get-started-cloud-shell). |
27 |
| -- This quickstart requires that you run Azure CLI version 2.13.0 or later. To find the version, run |
28 |
| - `az --version`. If you need to install or upgrade, see |
29 |
| - [Install Azure CLI](/cli/azure/install-azure-cli). |
30 |
| - |
31 |
| -## Create the Terraform configuration, variable, and output file |
32 |
| - |
33 |
| -In this quickstart, you create a policy assignment and assign the [Audit VMs that do not use managed disks](https://github.com/Azure/azure-policy/blob/master/built-in-policies/policyDefinitions/Compute/VMRequireManagedDisk_Audit.json) definition. This policy definition identifies resources that aren't compliant to the conditions set in the policy definition. |
34 |
| - |
35 |
| -Configure the Terraform configuration, variable, and output files. The Terraform resources |
36 |
| -for Azure Policy use the [Azure Provider](https://www.terraform.io/docs/providers/azurerm/index.html). |
37 |
| - |
38 |
| -1. Create a new folder named `policy-assignment` and change directories into it. |
39 |
| - |
40 |
| -1. Create `main.tf` with the following code: |
41 |
| - |
42 |
| - > [!NOTE] |
43 |
| - > To create a Policy Assignment at a Management Group use the [azurerm_management_group_policy_assignment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/management_group_policy_assignment) resource, for a Resource Group use the [azurerm_resource_group_policy_assignment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group_policy_assignment) and for a Subscription use the [azurerm_subscription_policy_assignment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subscription_policy_assignment) resource. |
44 |
| -
|
45 |
| - |
46 |
| - ```terraform |
47 |
| - provider "azurerm" { |
48 |
| - features {} |
49 |
| - } |
50 |
| -
|
51 |
| - terraform { |
52 |
| - required_providers { |
53 |
| - azurerm = { |
54 |
| - source = "hashicorp/azurerm" |
55 |
| - version = ">= 2.96.0" |
56 |
| - } |
57 |
| - } |
58 |
| - } |
| 20 | +[!INCLUDE [About Terraform](~/azure-dev-docs-pr/articles/terraform/includes/abstract.md)] |
59 | 21 |
|
60 |
| - resource "azurerm_subscription_policy_assignment" "auditvms" { |
61 |
| - name = "audit-vm-manageddisks" |
62 |
| - subscription_id = var.cust_scope |
63 |
| - policy_definition_id = "/providers/Microsoft.Authorization/policyDefinitions/06a78e20-9358-41c9-923c-fb736d382a4d" |
64 |
| - description = "Shows all virtual machines not using managed disks" |
65 |
| - display_name = "Audit VMs without managed disks assignment" |
66 |
| - } |
67 |
| - ``` |
68 |
| -
|
69 |
| -1. Create `variables.tf` with the following code: |
70 |
| -
|
71 |
| - ```terraform |
72 |
| - variable "cust_scope" { |
73 |
| - default = "{scope}" |
74 |
| - } |
75 |
| - ``` |
76 |
| -
|
77 |
| - A scope determines what resources or grouping of resources the policy assignment gets enforced on. It could range from a management group to an individual resource. Be sure to replace `{scope}` with one of the following patterns based on the declared resource: |
| 22 | +In this article, you learn how to: |
78 | 23 |
|
79 |
| - - Subscription: `/subscriptions/{subscriptionId}` |
80 |
| - - Resource group: `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}` |
81 |
| - - Resource: `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/[{parentResourcePath}/]` |
| 24 | +> [!div class="checklist"] |
| 25 | +> * Retrieve the current Azure client configuration. |
| 26 | +> * Create a Azure resource group with the generated random name. |
| 27 | +> * Create Subscription Policy Assignment to identify virtual machines that aren't using managed disks |
82 | 28 |
|
83 |
| -1. Create `output.tf` with the following code: |
| 29 | +## Prerequisites |
84 | 30 |
|
85 |
| - ```terraform |
86 |
| - output "assignment_id" { |
87 |
| - value = azurerm_subscription_policy_assignment.auditvms.id |
88 |
| - } |
89 |
| - ``` |
| 31 | +- Create an Azure account with an active subscription. You can [create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F). |
90 | 32 |
|
91 |
| -## Initialize Terraform and create plan |
| 33 | +- [Install and configure Terraform](/azure/developer/terraform/quickstart-configure) |
92 | 34 |
|
93 |
| -Initialize Terraform to download the necessary providers and then create a plan. |
| 35 | +## Implement the Terraform code |
94 | 36 |
|
95 |
| -1. Run the [terraform init](https://www.terraform.io/docs/commands/init.html) command. This command |
96 |
| - downloads the Azure modules required to create the Azure resources in the Terraform |
97 |
| - configuration. |
| 37 | +The sample code for this article is located in the [Azure Terraform GitHub repo](https://github.com/Azure/terraform/tree/master/quickstart/101-azure-policy). You can view the log file containing the [test results from current and previous versions of Terraform](https://github.com/Azure/terraform/tree/master/quickstart/101-azure-policy/TestRecord.md). See more [articles and sample code showing how to use Terraform to manage Azure resources](/azure/terraform) |
98 | 38 |
|
99 |
| - ```bash |
100 |
| - terraform init |
101 |
| - ``` |
| 39 | +1. Create a directory in which to test and run the sample Terraform code, and make it the current directory. |
102 | 40 |
|
103 |
| - :::image type="content" source="./media/assign-policy-terraform/terraform-initialize.png" alt-text="Screenshot of running the terraform init command that shows downloading the azurerm module and a success message."::: |
| 41 | +1. Create a file named `providers.tf` and insert the following code. |
| 42 | + :::code language="Terraform" source="~/terraform_samples/quickstart/101-azure-policy/providers.tf"::: |
104 | 43 |
|
105 |
| -1. Authenticate with [Azure CLI](/cli/azure/) for Terraform. For more information, see |
106 |
| - [Azure Provider: Authenticating using the Azure CLI](https://www.terraform.io/docs/providers/azurerm/guides/azure_cli.html). |
| 44 | +1. Create a file named `main.tf` and insert the following code. |
| 45 | + :::code language="Terraform" source="~/terraform_samples/quickstart/101-azure-policy/main.tf"::: |
107 | 46 |
|
108 |
| - ```azurecli |
109 |
| - az login |
110 |
| - ``` |
| 47 | +1. Create a file named `variables.tf` and insert the following code. |
| 48 | + :::code language="Terraform" source="~/terraform_samples/quickstart/101-azure-policy/variables.tf"::: |
111 | 49 |
|
112 |
| -1. Create the execution plan with the |
113 |
| - [terraform plan](https://www.terraform.io/docs/commands/plan.html) command and **out** parameter. |
| 50 | +1. Create a file named `outputs.tf` and insert the following code. |
| 51 | + :::code language="Terraform" source="~/terraform_samples/quickstart/101-azure-policy/outputs.tf"::: |
114 | 52 |
|
115 |
| - ```bash |
116 |
| - terraform plan -out assignment.tfplan |
117 |
| - ``` |
| 53 | +> [!IMPORTANT] |
| 54 | +> If you are using the 4.x azurerm provider, you must [explicitly specify the Azure subscription ID](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/4.0-upgrade-guide#specifying-subscription-id-is-now-mandatory) to authenticate to Azure before running the Terraform commands. |
| 55 | +> |
| 56 | +> One way to specify the Azure subscription ID without putting it in the `providers` block is to specify the subscription ID in an environment variable named `ARM_SUBSCRIPTION_ID`. |
| 57 | +> |
| 58 | +> For more information, see the [Azure provider reference documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs#argument-reference). |
118 | 59 |
|
119 |
| - :::image type="content" source="./media/assign-policy-terraform/terraform-plan-out.png" alt-text="Screenshot of running the terraform plan command and out parameter to show the Azure resource that would be created."::: |
| 60 | +## Specify scope |
120 | 61 |
|
121 |
| - > [!NOTE] |
122 |
| - > For information about persisting execution plans and security, see |
123 |
| - > [Terraform Plan: Security Warning](https://www.terraform.io/docs/commands/plan.html#security-warning). |
| 62 | +A scope determines what resources or grouping of resources the policy assignment gets enforced on. It could range from a management group to an individual resource. To use any of the following scopes, update the `scope` variable in the `variables.tf` file. If you leave the `scope` variable value blank, the "subscription" scope is used. |
124 | 63 |
|
125 |
| -## Apply the Terraform execution plan |
| 64 | +- Subscription: `/subscriptions/<subscription_id>` |
| 65 | +- Resource group: `/subscriptions/<subscription_id>/resourceGroups/<resource_group_name>` |
| 66 | +- Resource: `/subscriptions/<subscription_id>/resourceGroups/<resource_group_name>/providers/<resource_provider_namespace>/[{parentResourcePath}/]` |
126 | 67 |
|
127 |
| -Apply the execution plan. |
| 68 | +## Initialize Terraform |
128 | 69 |
|
129 |
| -Run the [terraform apply](https://www.terraform.io/docs/commands/apply.html) command and specify the |
130 |
| -`assignment.tfplan` already created. |
| 70 | +> [!IMPORTANT] |
| 71 | +> If you are using the 4.x azurerm provider, you must [explicitly specify the Azure subscription ID](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/4.0-upgrade-guide#specifying-subscription-id-is-now-mandatory) to authenticate to Azure before running the Terraform commands. |
| 72 | +> |
| 73 | +> One way to specify the Azure subscription ID without putting it in the `providers` block is to specify the subscription ID in an environment variable named `ARM_SUBSCRIPTION_ID`. |
| 74 | +> |
| 75 | +> For more information, see the [Azure provider reference documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs#argument-reference). |
131 | 76 |
|
132 |
| -```bash |
133 |
| -terraform apply assignment.tfplan |
134 |
| -``` |
| 77 | +[!INCLUDE [terraform-init.md](~/azure-dev-docs-pr/articles/terraform/includes/terraform-init.md)] |
135 | 78 |
|
136 |
| -:::image type="content" source="./media/assign-policy-terraform/terraform-apply.png" alt-text="Screenshot of running the terraform apply command and the resulting resource creation."::: |
| 79 | +## Create a Terraform execution plan |
137 | 80 |
|
138 |
| -With the `Apply complete! Resources: 1 added, 0 changed, 0 destroyed.` message, the policy |
139 |
| -assignment is now created. Since we defined the `outputs.tf` file, the _assignment\_id_ is also |
140 |
| -returned. |
| 81 | +[!INCLUDE [terraform-plan.md](~/azure-dev-docs-pr/articles/terraform/includes/terraform-plan.md)] |
141 | 82 |
|
142 |
| -## Identify non-compliant resources |
| 83 | +## Apply a Terraform execution plan |
143 | 84 |
|
144 |
| -To view the resources that aren't compliant under this new assignment, use the _assignment\_id_ |
145 |
| -returned by ```terraform apply```. With it, run the following command to get the resource IDs of the |
146 |
| -non-compliant resources that are output into a JSON file: |
| 85 | +[!INCLUDE [terraform-apply-plan.md](~/azure-dev-docs-pr/articles/terraform/includes/terraform-apply-plan.md)] |
147 | 86 |
|
148 |
| -```console |
149 |
| -armclient post "/subscriptions/<subscriptionID>/providers/Microsoft.PolicyInsights/policyStates/latest/queryResults?api-version=2019-10-01&$filter=IsCompliant eq false and PolicyAssignmentId eq '<policyAssignmentID>'&$apply=groupby((ResourceId))" > <json file to direct the output with the resource IDs into> |
150 |
| -``` |
| 87 | +## Verify the results |
151 | 88 |
|
152 |
| -Your results resemble the following example: |
| 89 | +1. Get the `_assignment\_id_` returned by `terraform apply`. |
153 | 90 |
|
154 |
| -```json |
155 |
| -{ |
156 |
| - "@odata.context": "https://management.azure.com/subscriptions/<subscriptionId>/providers/Microsoft.PolicyInsights/policyStates/$metadata#latest", |
157 |
| - "@odata.count": 3, |
158 |
| - "value": [ |
159 |
| - { |
160 |
| - "@odata.id": null, |
161 |
| - "@odata.context": "https://management.azure.com/subscriptions/<subscriptionId>/providers/Microsoft.PolicyInsights/policyStates/$metadata#latest/$entity", |
162 |
| - "ResourceId": "/subscriptions/<subscriptionId>/resourcegroups/<rgname>/providers/microsoft.compute/virtualmachines/<virtualmachineId>" |
163 |
| - }, |
164 |
| - { |
165 |
| - "@odata.id": null, |
166 |
| - "@odata.context": "https://management.azure.com/subscriptions/<subscriptionId>/providers/Microsoft.PolicyInsights/policyStates/$metadata#latest/$entity", |
167 |
| - "ResourceId": "/subscriptions/<subscriptionId>/resourcegroups/<rgname>/providers/microsoft.compute/virtualmachines/<virtualmachine2Id>" |
168 |
| - }, |
169 |
| - { |
170 |
| - "@odata.id": null, |
171 |
| - "@odata.context": "https://management.azure.com/subscriptions/<subscriptionId>/providers/Microsoft.PolicyInsights/policyStates/$metadata#latest/$entity", |
172 |
| - "ResourceId": "/subscriptions/<subscriptionName>/resourcegroups/<rgname>/providers/microsoft.compute/virtualmachines/<virtualmachine3ID>" |
173 |
| - } |
174 |
| - ] |
175 |
| -} |
176 |
| -``` |
| 91 | +1. run the following command to view the resources that are not compliant under your new policy assignment. |
177 | 92 |
|
178 |
| -The results are comparable to what you'd typically see listed under **Non-compliant resources** in |
179 |
| -the Azure portal view. |
| 93 | + ```console |
| 94 | + armclient post "/subscriptions/<subscription_id>/providers/Microsoft.PolicyInsights/policyStates/latest/queryResults?api-version=2019-10-01&$filter=IsCompliant eq false and PolicyAssignmentId eq '<policyAssignmentID>'&$apply=groupby((ResourceId))" > <json file to direct the output with the resource IDs into> |
| 95 | + ``` |
| 96 | + |
| 97 | +1. The results are comparable to what you see listed under **Non-compliant resources** in the Azure portal view. |
180 | 98 |
|
181 | 99 | ## Clean up resources
|
182 | 100 |
|
183 |
| -To remove the assignment created, use Azure CLI or reverse the Terraform execution plan with |
184 |
| -`terraform destroy`. |
185 |
| - |
186 |
| -- Azure CLI |
| 101 | +[!INCLUDE [terraform-plan-destroy.md](~/azure-dev-docs-pr/articles/terraform/includes/terraform-plan-destroy.md)] |
187 | 102 |
|
188 |
| - ```azurecli-interactive |
189 |
| - az policy assignment delete --name 'audit-vm-manageddisks' --scope '/subscriptions/<subscriptionID>/<resourceGroupName>' |
190 |
| - ``` |
| 103 | +## Troubleshoot Terraform on Azure |
191 | 104 |
|
192 |
| -- Terraform |
193 |
| - |
194 |
| - ```bash |
195 |
| - terraform destroy |
196 |
| - ``` |
| 105 | +[Troubleshoot common problems when using Terraform on Azure](/azure/developer/terraform/troubleshoot). |
197 | 106 |
|
198 | 107 | ## Next steps
|
199 | 108 |
|
200 |
| -In this quickstart, you assigned a policy definition to identify non-compliant resources in your |
201 |
| -Azure environment. |
202 |
| - |
203 |
| -To learn more about assigning policies to validate that new resources are compliant, continue to the |
204 |
| -tutorial for: |
205 |
| - |
206 | 109 | > [!div class="nextstepaction"]
|
207 | 110 | > [Tutorial: Create and manage policies to enforce compliance](./tutorials/create-and-manage.md)
|
0 commit comments