Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add built-in policies for both subscriptions and management-groups #2788

Merged
117 changes: 117 additions & 0 deletions azurerm/data_source_policy_definition.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package azurerm

import (
"fmt"

"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-05-01/policy"
"github.com/hashicorp/terraform/helper/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate"
)

func dataSourceArmPolicyDefinition() *schema.Resource {
return &schema.Resource{
Read: dataSourceArmPolicyDefinitionRead,
Schema: map[string]*schema.Schema{
"display_name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validate.NoEmptyStrings,
},
lawrenae marked this conversation as resolved.
Show resolved Hide resolved
"management_group_id": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: azure.ValidateResourceIDOrEmpty,
},
lawrenae marked this conversation as resolved.
Show resolved Hide resolved
"name": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
},
"description": {
Type: schema.TypeString,
Computed: true,
},
"policy_type": {
Type: schema.TypeString,
Computed: true,
},
"policy_rule": {
Type: schema.TypeString,
Computed: true,
},
"parameters": {
Type: schema.TypeString,
Computed: true,
},
"metadata": {
Type: schema.TypeString,
Computed: true,
},
lawrenae marked this conversation as resolved.
Show resolved Hide resolved
},
}
}

func dataSourceArmPolicyDefinitionRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).policyDefinitionsClient
ctx := meta.(*ArmClient).StopContext

name := d.Get("display_name").(string)
managementGroupID := d.Get("management_group_id").(string)

var policyDefinitions policy.DefinitionListResultIterator
var err error

if managementGroupID != "" {
policyDefinitions, err = client.ListByManagementGroupComplete(ctx, managementGroupID)
} else {
policyDefinitions, err = client.ListComplete(ctx)
}

if err != nil {
return fmt.Errorf("Error loading Policy Definition List: %+v", err)
}

var policyDefinition policy.Definition

for policyDefinitions.NotDone() {
def := policyDefinitions.Value()
if def.DisplayName != nil && *def.DisplayName == name {
policyDefinition = def
break
}

err = policyDefinitions.NextWithContext(ctx)
if err != nil {
return fmt.Errorf("Error loading Policy Definition List: %s", err)
}
}

if policyDefinition.ID == nil {
return fmt.Errorf("Error loading Policy Definition List: could not find policy '%s'", name)
}

d.SetId(*policyDefinition.ID)
d.Set("name", policyDefinition.Name)
d.Set("display_name", policyDefinition.DisplayName)
d.Set("description", policyDefinition.Description)
d.Set("type", policyDefinition.Type)
d.Set("policy_type", policyDefinition.PolicyType)

if policyRuleStr := flattenJSON(policyDefinition.PolicyRule); policyRuleStr != "" {
d.Set("policy_rule", policyRuleStr)
}

if metadataStr := flattenJSON(policyDefinition.Metadata); metadataStr != "" {
d.Set("metadata", metadataStr)
}

if parametersStr := flattenJSON(policyDefinition.Parameters); parametersStr != "" {
d.Set("parameters", parametersStr)
}

return nil
}
145 changes: 145 additions & 0 deletions azurerm/data_source_policy_definition_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package azurerm

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
)

func TestAccDataSourceAzureRMPolicyDefinition_builtIn(t *testing.T) {
dataSourceName := "data.azurerm_policy_definition.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceBuiltInPolicyDefinition("Allowed resource types"),
Check: resource.ComposeTestCheckFunc(
testAzureRMClientConfigAttr(dataSourceName, "id", "/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c"),
testAzureRMClientConfigAttr(dataSourceName, "name", "a08ec900-254a-4555-9bf5-e42af04b5c5c"),
testAzureRMClientConfigAttr(dataSourceName, "display_name", "Allowed resource types"),
testAzureRMClientConfigAttr(dataSourceName, "type", "Microsoft.Authorization/policyDefinitions"),
testAzureRMClientConfigAttr(dataSourceName, "description", "This policy enables you to specify the resource types that your organization can deploy."),
),
},
},
})
}

func TestAccDataSourceAzureRMPolicyDefinition_builtIn_AtManagementGroup(t *testing.T) {
dataSourceName := "data.azurerm_policy_definition.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceBuiltInPolicyDefinitionAtManagementGroup("Allowed resource types"),
Check: resource.ComposeTestCheckFunc(
testAzureRMClientConfigAttr(dataSourceName, "id", "/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c"),
),
},
},
})
}

func TestAccDataSourceAzureRMPolicyDefinition_custom(t *testing.T) {
ri := tf.AccRandTimeInt()
dataSourceName := "data.azurerm_policy_definition.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceCustomPolicyDefinition(ri),
Check: resource.ComposeTestCheckFunc(
testAzureRMAttrExists(dataSourceName, "id"),
testAzureRMClientConfigAttr(dataSourceName, "name", fmt.Sprintf("acctestpol-%d", ri)),
testAzureRMClientConfigAttr(dataSourceName, "display_name", fmt.Sprintf("acctestpol-%d", ri)),
testAzureRMClientConfigAttr(dataSourceName, "type", "Microsoft.Authorization/policyDefinitions"),
testAzureRMClientConfigAttr(dataSourceName, "policy_type", "Custom"),
testAzureRMClientConfigAttr(dataSourceName, "policy_rule", "{\"if\":{\"not\":{\"field\":\"location\",\"in\":\"[parameters('allowedLocations')]\"}},\"then\":{\"effect\":\"audit\"}}"),
testAzureRMClientConfigAttr(dataSourceName, "parameters", "{\"allowedLocations\":{\"metadata\":{\"description\":\"The list of allowed locations for resources.\",\"displayName\":\"Allowed locations\",\"strongType\":\"location\"},\"type\":\"Array\"}}"),
testAzureRMClientConfigAttr(dataSourceName, "metadata", "{\"note\":\"azurerm acceptance test\"}"),
),
},
},
})
}

func testAccDataSourceBuiltInPolicyDefinition(name string) string {
return fmt.Sprintf(`
data "azurerm_policy_definition" "test" {
display_name = "%s"
}
`, name)
}

func testAccDataSourceBuiltInPolicyDefinitionAtManagementGroup(name string) string {
return fmt.Sprintf(`

data "azurerm_client_config" "current" {}

data "azurerm_policy_definition" "test" {
display_name = "%s"
management_group_id = "${data.azurerm_client_config.current.tenant_id}"
lawrenae marked this conversation as resolved.
Show resolved Hide resolved
}
`, name)
}

func testAccDataSourceCustomPolicyDefinition(ri int) string {
return fmt.Sprintf(`
resource "azurerm_policy_definition" "test_policy" {
name = "acctestpol-%d"
policy_type = "Custom"
mode = "All"
display_name = "acctestpol-%d"

policy_rule = <<POLICY_RULE
{
"if": {
"not": {
"field": "location",
"in": "[parameters('allowedLocations')]"
}
},
"then": {
"effect": "audit"
}
}
POLICY_RULE

parameters = <<PARAMETERS
{
"allowedLocations": {
"type": "Array",
"metadata": {
"description": "The list of allowed locations for resources.",
"displayName": "Allowed locations",
"strongType": "location"
}
}
}
PARAMETERS

metadata = <<METADATA
{
"note":"azurerm acceptance test"
}
METADATA
}

data "azurerm_policy_definition" "test" {
display_name = "${azurerm_policy_definition.test_policy.display_name}"
}

`, ri, ri)
}

func testAzureRMAttrExists(name, key string) resource.TestCheckFunc {
return func(s *terraform.State) error {
return resource.TestCheckResourceAttrSet(name, key)(s)
}
}
1 change: 1 addition & 0 deletions azurerm/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ func Provider() terraform.ResourceProvider {
"azurerm_notification_hub_namespace": dataSourceNotificationHubNamespace(),
"azurerm_notification_hub": dataSourceNotificationHub(),
"azurerm_platform_image": dataSourceArmPlatformImage(),
"azurerm_policy_definition": dataSourceArmPolicyDefinition(),
"azurerm_public_ip": dataSourceArmPublicIP(),
"azurerm_public_ips": dataSourceArmPublicIPs(),
"azurerm_recovery_services_vault": dataSourceArmRecoveryServicesVault(),
Expand Down
36 changes: 15 additions & 21 deletions azurerm/resource_arm_policy_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,33 +228,15 @@ func resourceArmPolicyDefinitionRead(d *schema.ResourceData, meta interface{}) e
d.Set("display_name", props.DisplayName)
d.Set("description", props.Description)

if policyRule := props.PolicyRule; policyRule != nil {
policyRuleVal := policyRule.(map[string]interface{})
policyRuleStr, err := structure.FlattenJsonToString(policyRuleVal)
if err != nil {
return fmt.Errorf("unable to flatten JSON for `policy_rule`: %s", err)
}

if policyRuleStr := flattenJSON(props.PolicyRule); policyRuleStr != "" {
d.Set("policy_rule", policyRuleStr)
}

if metadata := props.Metadata; metadata != nil {
metadataVal := metadata.(map[string]interface{})
metadataStr, err := structure.FlattenJsonToString(metadataVal)
if err != nil {
return fmt.Errorf("unable to flatten JSON for `metadata`: %s", err)
}

if metadataStr := flattenJSON(props.Metadata); metadataStr != "" {
d.Set("metadata", metadataStr)
}

if parameters := props.Parameters; parameters != nil {
paramsVal := props.Parameters.(map[string]interface{})
parametersStr, err := structure.FlattenJsonToString(paramsVal)
if err != nil {
return fmt.Errorf("unable to flatten JSON for `parameters`: %s", err)
}

if parametersStr := flattenJSON(props.Parameters); parametersStr != "" {
d.Set("parameters", parametersStr)
}
}
Expand Down Expand Up @@ -348,3 +330,15 @@ func getPolicyDefinition(ctx context.Context, client policy.DefinitionsClient, n

return res, err
}

func flattenJSON(stringMap interface{}) string {
if stringMap != nil {
value := stringMap.(map[string]interface{})
jsonString, err := structure.FlattenJsonToString(value)
if err == nil {
return jsonString
}
}

return ""
}
4 changes: 4 additions & 0 deletions website/azurerm.erb
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@
<a href="/docs/providers/azurerm/d/platform_image.html">azurerm_platform_image</a>
</li>

<li<%= sidebar_current("docs-azurerm-datasource-policy-definition") %>>
<a href="/docs/providers/azurerm/d/policy_definition.html">azurerm_policy_definition</a>
</li>

<li<%= sidebar_current("docs-azurerm-datasource-public-ip-x") %>>
<a href="/docs/providers/azurerm/d/public_ip.html">azurerm_public_ip</a>
</li>
Expand Down
40 changes: 40 additions & 0 deletions website/docs/d/policy_definition.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
layout: "azurerm"
page_title: "Azure Resource Manager: azurerm_policy_definition"
**sidebar_current**: "docs-azurerm-datasource-policy-definition"
description: |-
Get information about a Policy Definition.
---

# Data Source: azurerm_policy_definition

Use this data source to access information about a Policy Definition, both custom and built in. Retrieves Policy Definitions from your current subscription by default.

## Example Usage

```hcl
data "azurerm_policy_definition" "test" {
display_name = "Allowed resource types"
}

output "id" {
value = "${data.azurerm_policy_definition.test.id}"
}
```

## Argument Reference

* `display_name` - (Required) Specifies the name of the Policy Definition.
* `management_group_id` - (Optional) Only retrieve Policy Definitions from this Management Group.


## Attributes Reference

* `id` - The ID of the Policy Definition.
* `name` - The Name of the Policy Definition.
* `type` - The Type of Policy.
* `description` - The Description of the Policy.
* `policy_type` - The Type of the Policy, such as `Microsoft.Authorization/policyDefinitions`.
* `policy_rule` - The Rule as defined (in JSON) in the Policy.
* `parameters` - Any Parameters defined in the Policy.
* `metadata` - Any Metadata defined in the Policy.