Skip to content

Commit

Permalink
add built-in policies for both subscriptions and management-groups (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
lawrenae authored and katbyte committed Feb 5, 2019
1 parent 4969099 commit 815e3eb
Show file tree
Hide file tree
Showing 6 changed files with 322 additions and 21 deletions.
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,
},
"management_group_id": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: azure.ValidateResourceIDOrEmpty,
},
"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,
},
},
}
}

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}"
}
`, 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.

0 comments on commit 815e3eb

Please sign in to comment.