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

azurerm_role_management_policy - Support for resource scope #27205

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
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import (
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies"
"github.com/hashicorp/terraform-provider-azurerm/helpers/azure"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
billingValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/billing/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
)
Expand Down Expand Up @@ -109,9 +111,16 @@ func (r RoleManagementPolicyDataSource) Arguments() map[string]*pluginsdk.Schema
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.Any(
// Elevated access for a global admin is needed to assign roles in this scope:
// https://docs.microsoft.com/en-us/azure/role-based-access-control/elevate-access-global-admin#azure-cli
// It seems only user account is allowed to be elevated access.
validation.StringMatch(regexp.MustCompile("/providers/Microsoft.Subscription.*"), "Subscription scope is invalid"),

billingValidate.EnrollmentID,
commonids.ValidateManagementGroupID,
commonids.ValidateResourceGroupID,
commonids.ValidateSubscriptionID,
commonids.ValidateResourceGroupID,
azure.ValidateResourceID,
),
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ func TestAccRoleManagementPolicyDataSource_subscription(t *testing.T) {
})
}

func TestAccRoleManagementPolicyDataSource_resource(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_role_management_policy", "test")
r := RoleManagementPolicyDataSource{}

data.DataSourceTest(t, []acceptance.TestStep{
{
Config: r.resource(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("name").Exists(),
),
},
})
}

func (RoleManagementPolicyDataSource) managementGroup(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {}
Expand Down Expand Up @@ -116,3 +130,32 @@ data "azurerm_role_management_policy" "test" {
}
`
}

func (RoleManagementPolicyDataSource) resource(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {}

resource "azurerm_resource_group" "test" {
name = "acctestRG-%[1]s"
location = "%[2]s"
}

resource "azurerm_storage_account" "test" {
name = "accteststg%[1]s"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
account_tier = "Standard"
account_replication_type = "LRS"
}

data "azurerm_role_definition" "contributor" {
name = "Contributor"
scope = azurerm_resource_group.test.id
}

data "azurerm_role_management_policy" "test" {
role_definition_id = data.azurerm_role_definition.contributor.id
scope = azurerm_storage_account.test.id
}
`, data.RandomString, data.Locations.Primary)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ package authorization
import (
"context"
"fmt"
"regexp"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies"
"github.com/hashicorp/terraform-provider-azurerm/helpers/azure"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/authorization/parse"
billingValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/billing/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
)
Expand Down Expand Up @@ -111,9 +114,16 @@ func (r RoleManagementPolicyResource) Arguments() map[string]*pluginsdk.Schema {
Required: true,
ForceNew: true,
ValidateFunc: validation.Any(
// Elevated access for a global admin is needed to assign roles in this scope:
// https://docs.microsoft.com/en-us/azure/role-based-access-control/elevate-access-global-admin#azure-cli
// It seems only user account is allowed to be elevated access.
validation.StringMatch(regexp.MustCompile("/providers/Microsoft.Subscription.*"), "Subscription scope is invalid"),

billingValidate.EnrollmentID,
commonids.ValidateManagementGroupID,
commonids.ValidateResourceGroupID,
commonids.ValidateSubscriptionID,
commonids.ValidateResourceGroupID,
azure.ValidateResourceID,
),
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,36 @@ func TestAccRoleManagementPolicy_subscription(t *testing.T) {
})
}

func TestAccRoleManagementPolicy_resource(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_role_management_policy", "test")
r := RoleManagementPolicyResource{}

// Ignore the dangling resource post-test as the policy remains while the resource exists, or is in a pending deletion state
data.ResourceTestSkipCheckDestroyed(t, []acceptance.TestStep{
{
Config: r.resource(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("active_assignment_rules.0.expire_after").HasValue("P30D"),
check.That(data.ResourceName).Key("eligible_assignment_rules.0.expiration_required").HasValue("false"),
check.That(data.ResourceName).Key("notification_rules.0.eligible_assignments.0.approver_notifications.0.notification_level").HasValue("All"),
),
},
data.ImportStep(),
{
Config: r.resourceUpdate(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("active_assignment_rules.0.expire_after").HasValue("P15D"),
check.That(data.ResourceName).Key("eligible_assignment_rules.0.expiration_required").HasValue("true"),
check.That(data.ResourceName).Key("activation_rules.0.approval_stage.0.primary_approver.0.type").HasValue("Group"),
check.That(data.ResourceName).Key("notification_rules.0.eligible_assignments.0.approver_notifications.0.notification_level").HasValue("Critical"),
),
},
data.ImportStep(),
})
}

func (RoleManagementPolicyResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) {
client := clients.Authorization.RoleManagementPoliciesClient

Expand Down Expand Up @@ -451,3 +481,111 @@ resource "azurerm_role_management_policy" "test" {
}
`, r.resourceGroupTemplate(data), data.RandomString, requireApproval)
}

func (RoleManagementPolicyResource) resourceTemplate(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {}

resource "azurerm_resource_group" "test" {
name = "acctestRG-%[1]s"
location = "%[2]s"
}

resource "azurerm_storage_account" "test" {
name = "accteststg%[1]s"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
account_tier = "Standard"
account_replication_type = "LRS"
}

data "azurerm_role_definition" "contributor" {
name = "Contributor"
scope = azurerm_storage_account.test.id
}
`, data.RandomString, data.Locations.Primary)
}

func (r RoleManagementPolicyResource) resource(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s

resource "azurerm_role_management_policy" "test" {
scope = azurerm_storage_account.test.id
role_definition_id = data.azurerm_role_definition.contributor.id

active_assignment_rules {
expire_after = "P30D"
}

eligible_assignment_rules {
expiration_required = false
}

notification_rules {
eligible_assignments {
approver_notifications {
notification_level = "All"
default_recipients = false
additional_recipients = ["[email protected]"]
}
}
}
}
`, r.resourceTemplate(data), data.RandomString)
}

func (r RoleManagementPolicyResource) resourceUpdate(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s

provider "azuread" {}

resource "azuread_group" "approver" {
display_name = "PIM Approver Test %[2]s"
mail_enabled = false
security_enabled = true
}

resource "azurerm_role_management_policy" "test" {
scope = azurerm_storage_account.test.id
role_definition_id = data.azurerm_role_definition.contributor.id

active_assignment_rules {
expire_after = "P15D"
}

eligible_assignment_rules {
expiration_required = true
}

activation_rules {
maximum_duration = "PT1H"
require_approval = true
approval_stage {
primary_approver {
object_id = azuread_group.approver.object_id
type = "Group"
}
}
}

notification_rules {
eligible_assignments {
approver_notifications {
notification_level = "Critical"
default_recipients = false
additional_recipients = ["[email protected]"]
}
}
eligible_activations {
assignee_notifications {
notification_level = "All"
default_recipients = true
additional_recipients = ["[email protected]"]
}
}
}
}
`, r.resourceTemplate(data), data.RandomString)
}
2 changes: 1 addition & 1 deletion website/docs/d/role_management_policy.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ data "azurerm_role_management_policy" "example" {
## Argument Reference

* `role_definition_id` - (Required) The scoped Role Definition ID of the role for which this policy applies.
* `scope` - (Required) The scope to which this Role Management Policy applies. Can refer to a management group, a subscription or a resource group.
* `scope` - (Required) The scope to which this Role Management Policy applies. Can refer to a management group, a subscription, a resource group or a resource.

## Attributes Reference

Expand Down
2 changes: 1 addition & 1 deletion website/docs/r/role_management_policy.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ resource "azurerm_role_management_policy" "example" {
* `eligible_assignment_rules` - (Optional) An `eligible_assignment_rules` block as defined below.
* `notification_rules` - (Optional) A `notification_rules` block as defined below.
* `role_definition_id` - (Required) The scoped Role Definition ID of the role for which this policy will apply. Changing this forces a new resource to be created.
* `scope` - (Required) The scope to which this Role Management Policy will apply. Can refer to a management group, a subscription or a resource group. Changing this forces a new resource to be created.
* `scope` - (Required) The scope to which this Role Management Policy will apply. Can refer to a management group, a subscription, a resource group or a resource. Changing this forces a new resource to be created.

---

Expand Down
Loading