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

Support for Managed Identity on azurerm_policy_assignment #2549

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions azurerm/common_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ func locationSchema() *schema.Schema {
return azure.SchemaLocation()
}

func locationSchemaOptional() *schema.Schema {
return azure.SchemaLocationOptional()
}

func locationForDataSourceSchema() *schema.Schema {
return azure.SchemaLocationForDataSource()
}
Expand Down
10 changes: 10 additions & 0 deletions azurerm/helpers/azure/location.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ func SchemaLocation() *schema.Schema {
}
}

func SchemaLocationOptional() *schema.Schema {
return &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
StateFunc: NormalizeLocation,
DiffSuppressFunc: SuppressLocationDiff,
}
}

func SchemaLocationForDataSource() *schema.Schema {
return &schema.Schema{
Type: schema.TypeString,
Expand Down
86 changes: 82 additions & 4 deletions azurerm/resource_arm_policy_assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import (

func resourceArmPolicyAssignment() *schema.Resource {
return &schema.Resource{
Create: resourceArmPolicyAssignmentCreate,
Create: resourceArmPolicyAssignmentCreateOrUpdate,
Update: resourceArmPolicyAssignmentCreateOrUpdate,
Read: resourceArmPolicyAssignmentRead,
Delete: resourceArmPolicyAssignmentDelete,
Importer: &schema.ResourceImporter{
Expand Down Expand Up @@ -48,13 +49,41 @@ func resourceArmPolicyAssignment() *schema.Resource {
"description": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},

"display_name": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},

"location": locationSchemaOptional(),

"identity": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
string(policy.None),
string(policy.SystemAssigned),
}, false),
},
"principal_id": {
Type: schema.TypeString,
Computed: true,
},
"tenant_id": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
olohmann marked this conversation as resolved.
Show resolved Hide resolved

"parameters": {
Expand All @@ -68,7 +97,7 @@ func resourceArmPolicyAssignment() *schema.Resource {
}
}

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

Expand All @@ -90,6 +119,15 @@ func resourceArmPolicyAssignmentCreate(d *schema.ResourceData, meta interface{})
assignment.AssignmentProperties.Description = utils.String(v)
}

if _, ok := d.GetOk("identity"); ok {
policyIdentity := expandAzureRmPolicyIdentity(d)
assignment.Identity = policyIdentity
}

if v := d.Get("location").(string); v != "" {
assignment.Location = utils.String(azureRMNormalizeLocation(v))
}

if v := d.Get("parameters").(string); v != "" {
expandedParams, err := structure.ExpandJsonFromString(v)
if err != nil {
Expand Down Expand Up @@ -146,6 +184,14 @@ func resourceArmPolicyAssignmentRead(d *schema.ResourceData, meta interface{}) e

d.Set("name", resp.Name)

if err := d.Set("identity", flattenAzureRmPolicyIdentity(resp.Identity)); err != nil {
return fmt.Errorf("Error setting `identity`: %+v", err)
}

if location := resp.Location; location != nil {
d.Set("location", azureRMNormalizeLocation(*location))
}

if props := resp.AssignmentProperties; props != nil {
d.Set("scope", props.Scope)
d.Set("policy_definition_id", props.PolicyDefinitionID)
Expand Down Expand Up @@ -194,3 +240,35 @@ func policyAssignmentRefreshFunc(ctx context.Context, client policy.AssignmentsC
return res, strconv.Itoa(res.StatusCode), nil
}
}

func expandAzureRmPolicyIdentity(d *schema.ResourceData) *policy.Identity {
v := d.Get("identity")
identities := v.([]interface{})
identity := identities[0].(map[string]interface{})

identityType := policy.ResourceIdentityType(identity["type"].(string))

policyIdentity := policy.Identity{
Type: identityType,
}

return &policyIdentity
}

func flattenAzureRmPolicyIdentity(identity *policy.Identity) []interface{} {
if identity == nil {
return make([]interface{}, 0)
}

result := make(map[string]interface{})
result["type"] = string(identity.Type)
if identity.PrincipalID != nil {
result["principal_id"] = *identity.PrincipalID
}

if identity.TenantID != nil {
result["tenant_id"] = *identity.TenantID
}

return []interface{}{result}
}
102 changes: 102 additions & 0 deletions azurerm/resource_arm_policy_assignment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,32 @@ func TestAccAzureRMPolicyAssignment_basic(t *testing.T) {
})
}

func TestAccAzureRMPolicyAssignment_deployIfNotExists_policy(t *testing.T) {
resourceName := "azurerm_policy_assignment.test"

ri := acctest.RandInt()
location := testLocation()

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMPolicyAssignmentDestroy,
Steps: []resource.TestStep{
{
Config: testAzureRMPolicyAssignment_deployIfNotExists_policy(ri, location),
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMPolicyAssignmentExists(resourceName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccAzureRMPolicyAssignment_complete(t *testing.T) {
resourceName := "azurerm_policy_assignment.test"

Expand Down Expand Up @@ -146,6 +172,82 @@ resource "azurerm_policy_assignment" "test" {
`, ri, ri, location, ri, location, ri)
}

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

policy_rule = <<POLICY_RULE
{
"if": {
"field": "type",
"equals": "Microsoft.Sql/servers/databases"
},
"then": {
"effect": "DeployIfNotExists",
"details": {
"type": "Microsoft.Sql/servers/databases/transparentDataEncryption",
"name": "current",
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"existenceCondition": {
"field": "Microsoft.Sql/transparentDataEncryption.status",
"equals": "Enabled"
},
"deployment": {
"properties": {
"mode": "incremental",
"template": {
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"fullDbName": {
"type": "string"
}
},
"resources": [{
"name": "[concat(parameters('fullDbName'), '/current')]",
"type": "Microsoft.Sql/servers/databases/transparentDataEncryption",
"apiVersion": "2014-04-01",
"properties": {
"status": "Enabled"
}
}]
},
"parameters": {
"fullDbName": {
"value": "[field('fullName')]"
}
}
}
}
}
}
}
POLICY_RULE
}

resource "azurerm_resource_group" "test" {
name = "acctestRG-%d"
location = "%s"
}

resource "azurerm_policy_assignment" "test" {
name = "acctestpa-%d"
scope = "${azurerm_resource_group.test.id}"
policy_definition_id = "${azurerm_policy_definition.test.id}"
identity {
type = "SystemAssigned"
}
location = "%s"
}
`, ri, ri, ri, location, ri, location)
}

func testAzureRMPolicyAssignment_complete(ri int, location string) string {
return fmt.Sprintf(`
resource "azurerm_policy_definition" "test" {
Expand Down
29 changes: 28 additions & 1 deletion website/docs/r/policy_assignment.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description: |-

# azurerm_policy_assignment

Configures the specified Policy Definition at the specified Scope.
Configures the specified Policy Definition at the specified Scope. Also, Policy Set Definitions are supported.

## Example Usage

Expand Down Expand Up @@ -79,6 +79,10 @@ The following arguments are supported:

* `policy_definition_id` - (Required) The ID of the Policy Definition to be applied at the specified Scope.

* `identity` - (Optional) An `identity` block.

* `location` - (Optional) The Azure location where this policy assignment should exist. This is required when an Identity is assigned. Changing this forces a new resource to be created.

* `description` - (Optional) A description to use for this Policy Assignment. Changing this forces a new resource to be created.

* `display_name` - (Optional) A friendly display name to use for this Policy Assignment. Changing this forces a new resource to be created.
Expand All @@ -87,12 +91,35 @@ The following arguments are supported:

~> **NOTE:** This value is required when the specified Policy Definition contains the `parameters` field.

---

An `identity` block supports the following:

* `type` - (Required) The Managed Service Identity Type of this Policy Assignment. Possible values are `SystemAssigned` (where Azure will generate a Service Principal for you), or `None` (no use of a Managed Service Identity).

~> **NOTE:** When `type` is set to `SystemAssigned`, identity the Principal ID can be retrieved after the policy has been assigned.

---


## Attributes Reference

The following attributes are exported:

* `id` - The Policy Assignment id.

* `identity` - An `identity` block.

---

An `identity` block exports the following:

* `principal_id` - The Principal ID of this Policy Assignment if `type` is `SystemAssigned`.

* `tenant_id` - The Tenant ID of this Policy Assignment if `type` is `SystemAssigned`.

---

## Import

Policy Assignments can be imported using the `policy name`, e.g.
Expand Down