diff --git a/internal/services/authorization/client/client.go b/internal/services/authorization/client/client.go index 457bab92b906..2a2e980f3c14 100644 --- a/internal/services/authorization/client/client.go +++ b/internal/services/authorization/client/client.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/roleassignmentschedulerequests" "github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/roleeligibilityscheduleinstances" "github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/roleeligibilityschedulerequests" + "github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies" "github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2022-04-01/roleassignments" "github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2022-04-01/roledefinitions" "github.com/hashicorp/terraform-provider-azurerm/internal/common" @@ -25,6 +26,7 @@ type Client struct { RoleEligibilityScheduleInstancesClient *roleeligibilityscheduleinstances.RoleEligibilityScheduleInstancesClient ScopedRoleAssignmentsClient *roleassignments.RoleAssignmentsClient ScopedRoleDefinitionsClient *roledefinitions.RoleDefinitionsClient + RoleManagementPoliciesClient *rolemanagementpolicies.RoleManagementPoliciesClient } func NewClient(o *common.ClientOptions) (*Client, error) { @@ -71,9 +73,16 @@ func NewClient(o *common.ClientOptions) (*Client, error) { } o.Configure(scopedRoleDefinitionsClient.Client, o.Authorizers.ResourceManager) + roleManagementPoliciesClient, _ := rolemanagementpolicies.NewRoleManagementPoliciesClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Role Managemetn Policies Client: %+v", err) + } + o.Configure(roleManagementPoliciesClient.Client, o.Authorizers.ResourceManager) + return &Client{ RoleAssignmentsClient: &roleAssignmentsClient, RoleDefinitionsClient: &roleDefinitionsClient, + RoleManagementPoliciesClient: roleManagementPoliciesClient, RoleAssignmentScheduleRequestClient: roleAssignmentScheduleRequestsClient, RoleAssignmentScheduleInstancesClient: roleAssignmentScheduleInstancesClient, RoleEligibilityScheduleRequestClient: roleEligibilityScheduleRequestClient, diff --git a/internal/services/authorization/parse/role_management_policy.go b/internal/services/authorization/parse/role_management_policy.go new file mode 100644 index 000000000000..aa2031f816a6 --- /dev/null +++ b/internal/services/authorization/parse/role_management_policy.go @@ -0,0 +1,66 @@ +package parse + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies" +) + +type RoleManagementPolicyID struct { + Scope string + RoleManagementPolicyName string + RoleDefinitionId string +} + +func NewRoleManagementPolicyID(scope string, roleManagementPolicyName string, roleDefinitionId string) RoleManagementPolicyID { + return RoleManagementPolicyID{ + Scope: scope, + RoleManagementPolicyName: roleManagementPolicyName, + RoleDefinitionId: roleDefinitionId, + } +} + +func (id RoleManagementPolicyID) ID() string { + fmtString := "%s/providers/Microsoft.Authorization/roleManagementPolicies/%s|%s" + return fmt.Sprintf(fmtString, id.Scope, id.RoleManagementPolicyName, id.RoleDefinitionId) +} + +func (id RoleManagementPolicyID) ScopedRoleManagementPolicyId() rolemanagementpolicies.ScopedRoleManagementPolicyId { + return rolemanagementpolicies.NewScopedRoleManagementPolicyID(id.Scope, id.RoleManagementPolicyName) +} + +func (id RoleManagementPolicyID) String() string { + segments := []string{ + fmt.Sprintf("RoleManagementPolicyName %q", id.RoleManagementPolicyName), + fmt.Sprintf("Scope %q", id.Scope), + fmt.Sprintf("Role Definition Id %q", id.RoleDefinitionId), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Role Management Policy", segmentsStr) +} + +// RoleManagementPolicyId is a pseudo ID for storing Role Definition ID parameter as this it not retrievable from API +// It is formed of the Azure Resource ID for the Role Management Policy ID and the Role Definition ID it is created against +func RoleManagementPolicyId(input string) (*RoleManagementPolicyID, error) { + parts := strings.Split(input, "|") + if len(parts) != 2 { + return nil, fmt.Errorf("could not parse Role Management Policy ID, invalid format %q", input) + } + + roleManagementPolicyID := RoleManagementPolicyID{} + + rawRoleManagementPolicyId := parts[0] + rawRoleDefinitionId := parts[1] + + roleManagementPolicyId, err := rolemanagementpolicies.ParseScopedRoleManagementPolicyID(rawRoleManagementPolicyId) + if err != nil { + return nil, err + } + roleManagementPolicyID.Scope = roleManagementPolicyId.Scope + roleManagementPolicyID.RoleManagementPolicyName = roleManagementPolicyId.RoleManagementPolicyName + + roleManagementPolicyID.RoleDefinitionId = rawRoleDefinitionId + + return &roleManagementPolicyID, nil +} diff --git a/internal/services/authorization/pim_active_role_assignment_resource.go b/internal/services/authorization/pim_active_role_assignment_resource.go index 4523d2731827..86aa03325a2b 100644 --- a/internal/services/authorization/pim_active_role_assignment_resource.go +++ b/internal/services/authorization/pim_active_role_assignment_resource.go @@ -74,6 +74,7 @@ func (PimActiveRoleAssignmentResource) Arguments() map[string]*pluginsdk.Schema Type: pluginsdk.TypeList, MaxItems: 1, Optional: true, + Computed: true, ForceNew: true, Description: "The schedule details of this role assignment.", Elem: &pluginsdk.Resource{ diff --git a/internal/services/authorization/pim_active_role_assignment_test.go b/internal/services/authorization/pim_active_role_assignment_test.go index bccc425cca08..f6616d4e316d 100644 --- a/internal/services/authorization/pim_active_role_assignment_test.go +++ b/internal/services/authorization/pim_active_role_assignment_test.go @@ -17,23 +17,21 @@ import ( type PimActiveRoleAssignmentResource struct{} -// TODO: update the management policy configuration so that it can have no expiration -// Depends on new resource - azurerm_role_management_policy - https://github.com/hashicorp/terraform-provider-azurerm/pull/20496 -// func TestAccPimActiveRoleAssignment_noExpiration(t *testing.T) { -// data := acceptance.BuildTestData(t, "azurerm_pim_active_role_assignment", "test") -// r := PimActiveRoleAssignmentResource{} - -// data.ResourceTest(t, r, []acceptance.TestStep{ -// { -// Config: r.noExpirationConfig(), -// Check: acceptance.ComposeTestCheckFunc( -// check.That(data.ResourceName).ExistsInAzure(r), -// check.That(data.ResourceName).Key("scope").Exists(), -// ), -// }, -// data.ImportStep("schedule.0.start_date_time"), -// }) -// } +func TestAccPimActiveRoleAssignment_noExpiration(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_pim_active_role_assignment", "test") + r := PimActiveRoleAssignmentResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.noExpirationConfig(), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + ), + }, + data.ImportStep("schedule.0.start_date_time"), + }) +} func TestAccPimActiveRoleAssignment_expirationByDurationHoursConfig(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_pim_active_role_assignment", "test") @@ -154,30 +152,48 @@ func (r PimActiveRoleAssignmentResource) Exists(ctx context.Context, client *cli return utils.Bool(foundDirectAssignment), nil } -// func (PimActiveRoleAssignmentResource) noExpirationConfig() string { -// return ` -// data "azurerm_subscription" "primary" {} +func (PimActiveRoleAssignmentResource) noExpirationConfig() string { + return ` +data "azurerm_subscription" "primary" {} + +data "azurerm_client_config" "test" {} + +data "azurerm_role_definition" "test" { + name = "Monitoring Data Reader" +} + +resource "azurerm_role_management_policy" "test" { + scope = data.azurerm_subscription.primary.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" -// data "azurerm_client_config" "test" {} + assignment { + eligible { + allow_permanent = true + } + active { + allow_permanent = true + } + } +} -// data "azurerm_role_definition" "test" { -// name = "Monitoring Data Reader" -// } +resource "azurerm_pim_active_role_assignment" "test" { + scope = data.azurerm_subscription.primary.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + principal_id = data.azurerm_client_config.test.object_id -// resource "azurerm_pim_active_role_assignment" "test" { -// scope = data.azurerm_subscription.primary.id -// role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" -// principal_id = data.azurerm_client_config.test.object_id + justification = "No Expiration" -// justification = "No Expiration" + ticket { + number = "1" + system = "example ticket system" + } -// ticket { -// number = "1" -// system = "example ticket system" -// } -// } -// ` -// } + depends_on = [ # Wait for policy to be defined for no expiration + azurerm_role_management_policy.test + ] +} +` +} func (PimActiveRoleAssignmentResource) expirationByDurationHoursConfig(data acceptance.TestData) string { return fmt.Sprintf(` diff --git a/internal/services/authorization/pim_eligible_role_assignment_resource.go b/internal/services/authorization/pim_eligible_role_assignment_resource.go index 099ffe130a26..c3d24437d736 100644 --- a/internal/services/authorization/pim_eligible_role_assignment_resource.go +++ b/internal/services/authorization/pim_eligible_role_assignment_resource.go @@ -74,6 +74,7 @@ func (PimEligibleRoleAssignmentResource) Arguments() map[string]*pluginsdk.Schem Type: pluginsdk.TypeList, MaxItems: 1, Optional: true, + Computed: true, ForceNew: true, Description: "The schedule details of this eligible role assignment.", Elem: &pluginsdk.Resource{ @@ -587,6 +588,9 @@ func (r PimEligibleRoleAssignmentResource) mapRoleEligibilityScheduleRequestProp } output.DurationDays = days } + } else { + output.DurationDays = 0 + output.DurationHours = 0 } output.EndDateTime = pointer.From(input.EndDateTime) diff --git a/internal/services/authorization/pim_eligible_role_assignment_test.go b/internal/services/authorization/pim_eligible_role_assignment_test.go index 2f6fde637886..c5f9c145d533 100644 --- a/internal/services/authorization/pim_eligible_role_assignment_test.go +++ b/internal/services/authorization/pim_eligible_role_assignment_test.go @@ -17,23 +17,21 @@ import ( type PimEligibleRoleAssignmentResource struct{} -// TODO: update the management policy configuration so that it can have no expiration -// Depends on new resource - azurerm_role_management_policy - https://github.com/hashicorp/terraform-provider-azurerm/pull/20496 -// func TestAccPimEligibleRoleAssignment_noExpiration(t *testing.T) { -// data := acceptance.BuildTestData(t, "azurerm_pim_eligible_role_assignment", "test") -// r := PimEligibleRoleAssignmentResource{} - -// data.ResourceTest(t, r, []acceptance.TestStep{ -// { -// Config: r.noExpirationConfig(data), -// Check: acceptance.ComposeTestCheckFunc( -// check.That(data.ResourceName).ExistsInAzure(r), -// check.That(data.ResourceName).Key("scope").Exists(), -// ), -// }, -// data.ImportStep("schedule.0.start_date_time"), -// }) -// } +func TestAccPimEligibleRoleAssignment_noExpiration(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_pim_eligible_role_assignment", "test") + r := PimEligibleRoleAssignmentResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.noExpirationConfig(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + ), + }, + data.ImportStep("schedule.0.start_date_time"), + }) +} func TestAccPimEligibleRoleAssignment_expirationByDurationHoursConfig(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_pim_eligible_role_assignment", "test") @@ -192,32 +190,50 @@ resource "azuread_group" "test" { `, data.RandomInteger, data.RandomString) } -// func (PimEligibleRoleAssignmentResource) noExpirationConfig(data acceptance.TestData) string { -// return fmt.Sprintf(` -// data "azurerm_subscription" "primary" {} +func (PimEligibleRoleAssignmentResource) noExpirationConfig(data acceptance.TestData) string { + return fmt.Sprintf(` +data "azurerm_subscription" "primary" {} -// data "azurerm_client_config" "test" {} +data "azurerm_client_config" "test" {} -// data "azurerm_role_definition" "test" { -// name = "Disk Backup Reader" -// } +data "azurerm_role_definition" "test" { + name = "Load Test Reader" +} -// %s +resource "azurerm_role_management_policy" "test" { + scope = data.azurerm_subscription.primary.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" -// resource "azurerm_pim_eligible_role_assignment" "test" { -// scope = data.azurerm_subscription.primary.id -// role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" -// principal_id = azuread_user.test.object_id + assignment { + eligible { + allow_permanent = true + } + active { + allow_permanent = true + } + } +} + +%s -// justification = "No Expiration" +resource "azurerm_pim_eligible_role_assignment" "test" { + scope = data.azurerm_subscription.primary.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + principal_id = azuread_user.test.object_id -// ticket { -// number = "1" -// system = "example ticket system" -// } -// } -// `, aadUser(data)) -// } + justification = "No Expiration" + + ticket { + number = "1" + system = "example ticket system" + } + + depends_on = [ # Wait for policy to be defined for no expiration + azurerm_role_management_policy.test + ] +} +`, aadUser(data)) +} func (PimEligibleRoleAssignmentResource) expirationByDurationHoursConfig(data acceptance.TestData) string { return fmt.Sprintf(` diff --git a/internal/services/authorization/registration.go b/internal/services/authorization/registration.go index 00c694b6a520..0237800588e3 100644 --- a/internal/services/authorization/registration.go +++ b/internal/services/authorization/registration.go @@ -13,6 +13,7 @@ type Registration struct { var _ sdk.TypedServiceRegistrationWithAGitHubLabel = Registration{} var _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} +var _ sdk.TypedServiceRegistrationWithAGitHubLabel = Registration{} func (r Registration) AssociatedGitHubLabel() string { return "service/authorization" @@ -55,6 +56,7 @@ func (r Registration) Resources() []sdk.Resource { PimActiveRoleAssignmentResource{}, PimEligibleRoleAssignmentResource{}, RoleAssignmentMarketplaceResource{}, + RoleManagementPolicyResource{}, } return resources } diff --git a/internal/services/authorization/role_management_policy.go b/internal/services/authorization/role_management_policy.go new file mode 100644 index 000000000000..e92c287ee7e0 --- /dev/null +++ b/internal/services/authorization/role_management_policy.go @@ -0,0 +1,1417 @@ +package authorization + +import ( + "context" + "fmt" + "log" + "regexp" + "strconv" + "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-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/locks" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/authorization/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/authorization/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +var _ sdk.Resource = RoleManagementPolicyResource{} + +var _ sdk.ResourceWithUpdate = RoleManagementPolicyResource{} + +var _ sdk.ResourceWithCustomizeDiff = RoleManagementPolicyResource{} + +type RoleManagementPolicyResource struct{} + +func (r RoleManagementPolicyResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "scope": { + Type: pluginsdk.TypeString, + Required: true, + Description: "The scope.", + }, + "role_definition_id": { + Type: pluginsdk.TypeString, + Required: true, + Description: "The role definition id.", + }, + "activation": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Description: "The activation settings for PIM on the scope and role definition.", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "maximum_duration_hours": { + Type: pluginsdk.TypeInt, + Optional: true, + Computed: true, + Description: "The maximum duration in hours for an activation.", + }, + "require_multi_factor_authentication": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Description: "Is Multi Factor Authentication required for an activation?", + }, + "require_justification": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Description: "Is Justification required for an activation?", + }, + "require_ticket_information": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Description: "Is Ticket Information required for an activation?", + }, + "approvers": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Description: "A list of approvers for activation.", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "group": { + Type: pluginsdk.TypeList, + Optional: true, + Description: "An approval group", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "id": { + Type: pluginsdk.TypeString, + Required: true, + Description: "The object id of the AAD group.", + }, + "name": { + Type: pluginsdk.TypeString, + Required: true, + Description: "The name of the AAD group.", + }, + }, + }, + }, + "user": { + Type: pluginsdk.TypeList, + Optional: true, + Description: "An approval user", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "id": { + Type: pluginsdk.TypeString, + Required: true, + Description: "The object id of a user.", + }, + "name": { + Type: pluginsdk.TypeString, + Required: true, + Description: "The name of a user.", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "assignment": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Description: "The assignment settings for PIM on the scope and role definition.", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "eligible": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Description: "The eligible settings for an assignment.", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "allow_permanent": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Description: "Allow permanent eligible assignment.", + ConflictsWith: []string{ + "assignment.0.eligible.0.expire_after_hours", + "assignment.0.eligible.0.expire_after_days", + }, + }, + "expire_after_hours": { + Type: pluginsdk.TypeInt, + Optional: true, + Computed: true, + Description: "The number of hours after an eligible assignments is expired.", + ConflictsWith: []string{ + "assignment.0.eligible.0.allow_permanent", + "assignment.0.eligible.0.expire_after_days", + }, + }, + "expire_after_days": { + Type: pluginsdk.TypeInt, + Optional: true, + Computed: true, + Description: "The number of days after an eligible assignments is expired.", + ConflictsWith: []string{ + "assignment.0.eligible.0.allow_permanent", + "assignment.0.eligible.0.expire_after_hours", + }, + }, + }, + }, + }, + "active": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Description: "The active settings for an assignment.", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "allow_permanent": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Description: "Allow permanent active assignment.", + ConflictsWith: []string{ + "assignment.0.active.0.expire_after_days", + "assignment.0.active.0.expire_after_hours", + }, + }, + "expire_after_hours": { + Type: pluginsdk.TypeInt, + Optional: true, + Computed: true, + Description: "The number of hours after an active assignments is expired.", + ConflictsWith: []string{ + "assignment.0.active.0.allow_permanent", + "assignment.0.active.0.expire_after_days", + }, + }, + "expire_after_days": { + Type: pluginsdk.TypeInt, + Optional: true, + Computed: true, + Description: "The number of days after an active assignments is expired.", + ConflictsWith: []string{ + "assignment.0.active.0.allow_permanent", + "assignment.0.active.0.expire_after_hours", + }, + }, + "require_multi_factor_authentication": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Description: "Is Multi Factor Authentication required for an active assignment?", + }, + "require_justification": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Description: "Is Justification required for an active assignment?", + }, + }, + }, + }, + }, + }, + }, + "notifications": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Description: "The notification settings for PIM on the scope and role definition.", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "member_assigned_eligible": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notifications settings when members are assigned as eligible to this role.", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "role_assignment_alert": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notification settings for the Role assignment alerts.", + Elem: notificationConfiguration(), + }, + "assigned_user": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notification settings for the assigned user (assignee).", + Elem: notificationConfiguration(), + }, + "request_for_extension_or_approval": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notification settings for the Request to approve a role assignment renewal/extension.", + Elem: notificationConfiguration(), + }, + }, + }, + }, + "member_assigned_active": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notifications settings when members are assigned as active to this role. ", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "role_assignment_alert": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notification settings for the Role assignment alerts.", + Elem: notificationConfiguration(), + }, + "assigned_user": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notification settings for the assigned user (assignee).", + Elem: notificationConfiguration(), + }, + "request_for_extension_or_approval": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notification settings for the Request to approve a role assignment renewal/extension.", + Elem: notificationConfiguration(), + }, + }, + }, + }, + "eligible_member_activate": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notifications settings when eligible members activate this role.", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "role_assignment_alert": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notification settings for the Role assignment alerts.", + Elem: notificationConfiguration(), + }, + "assigned_user": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notification settings for the assigned user (assignee).", + Elem: notificationConfiguration(), + }, + "request_for_extension_or_approval": { + Type: pluginsdk.TypeList, + MaxItems: 1, + Optional: true, + Computed: true, + Description: "Notification settings for the Request to approve a role assignment renewal/extension.", + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "default_recipients": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Description: "Will notifications be sent to the default recipients?", + }, + "critical_emails_only": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Description: "Will critical emails only be sent?", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func (r RoleManagementPolicyResource) CustomizeDiff() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + rd := metadata.ResourceDiff + // custom validation for multiple properties + + if rd.HasChange("notifications.0.eligible_member_activate.0.request_for_extension_or_approval") { + _, criticalEmailsAfter := rd.GetChange("notifications.0.eligible_member_activate.0.request_for_extension_or_approval.0.critical_emails_only") + _, defaultRecipientsAfter := rd.GetChange("notifications.0.eligible_member_activate.0.request_for_extension_or_approval.0.default_recipients") + + if criticalEmailsAfter.(bool) && !defaultRecipientsAfter.(bool) { + return fmt.Errorf("cannot enable critical emails and disable default recipients for `request_for_extension_or_approval` on `eligible_member_activate`") + } + } + + if rd.HasChange("assignment.0.eligible") { + _, assignmentEligibleAllowPermanent := rd.GetChange("assignment.0.eligible.0.allow_permanent") + _, assignmentEligibleExpireAfterHours := rd.GetChange("assignment.0.eligible.0.expire_after_hours") + _, assignmentEligibleExpireAfterDays := rd.GetChange("assignment.0.eligible.0.expire_after_days") + + if !assignmentEligibleAllowPermanent.(bool) && assignmentEligibleExpireAfterHours.(int) == 0 && assignmentEligibleExpireAfterDays.(int) == 0 { + return fmt.Errorf("cannot set allow permanent to false when expire after days and hours is 0 on `assignment` for `eligible`") + } + } + + if rd.HasChange("assignment.0.active") { + _, assignmentActiveAllowPermanent := rd.GetChange("assignment.0.active.0.allow_permanent") + _, assignmentActiveExpireAfterHours := rd.GetChange("assignment.0.active.0.expire_after_hours") + _, assignmentActiveExpireAfterDays := rd.GetChange("assignment.0.active.0.expire_after_days") + + if !assignmentActiveAllowPermanent.(bool) && assignmentActiveExpireAfterHours.(int) == 0 && assignmentActiveExpireAfterDays.(int) == 0 { + return fmt.Errorf("cannot set allow permanent to false when expire after days and hours is 0 on `assignment` for `active`") + } + } + + return nil + }, + } +} + +func notificationConfiguration() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "default_recipients": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Description: "Will notifications be sent to the default recipients?", + }, + "additional_recipients": { + Type: pluginsdk.TypeSet, + Optional: true, + Computed: true, + Description: "List of additional recipients to email notifications", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "critical_emails_only": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Description: "Will critical emails only be sent?", + }, + }, + } +} + +func (r RoleManagementPolicyResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (r RoleManagementPolicyResource) ModelObject() interface{} { + return &RoleManagementPolicyResourceSchema{} +} + +func (r RoleManagementPolicyResource) ResourceType() string { + return "azurerm_role_management_policy" +} + +func (r RoleManagementPolicyResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + + Func: r.createUpdate, + } +} + +func (r RoleManagementPolicyResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + + Func: r.createUpdate, + } +} + +func (r RoleManagementPolicyResource) createUpdate(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Authorization.RoleManagementPoliciesClient + + var id rolemanagementpolicies.ScopedRoleManagementPolicyId + + roleDefinitionId := metadata.ResourceData.Get("role_definition_id").(string) + scope := metadata.ResourceData.Get("scope").(string) + + lockId := fmt.Sprintf("%s|%s", scope, roleDefinitionId) + + locks.ByName(lockId, r.ResourceType()) + defer locks.UnlockByName(lockId, r.ResourceType()) + + scopeId := &commonids.ScopeId{ + Scope: scope, + } + + filter := &rolemanagementpolicies.ListForScopeOperationOptions{ + Filter: pointer.To("(roleDefinitionId eq '" + roleDefinitionId + "')"), + } + + // filter by role definition + result, err := client.ListForScopeComplete(ctx, *scopeId, *filter) + if err != nil { + return fmt.Errorf("loading finding role management policy %q: %+v", scopeId, err) + } + + if len(result.Items) != 1 { + return fmt.Errorf("loading finding role management policy %q: %+v", scopeId, err) + } + + roleManagementPolicyId := *result.Items[0].Name + id = rolemanagementpolicies.NewScopedRoleManagementPolicyID(scope, roleManagementPolicyId) + + var config RoleManagementPolicyResourceSchema + if err := metadata.Decode(&config); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + var payload rolemanagementpolicies.RoleManagementPolicy + + if err := r.mapRoleManagementPolicyResourceSchemaToRoleManagementPolicy(config, &payload); err != nil { + return fmt.Errorf("mapping schema model to sdk model: %+v", err) + } + + res, err := client.Update(ctx, id, payload) + if err != nil { + return fmt.Errorf("updating %q: %+v", id.ID(), err) + } + + if res.Model == nil { + return fmt.Errorf("could not get role management policy") + } + policyID := res.Model.Name + stateId := parse.NewRoleManagementPolicyID(scope, *policyID, roleDefinitionId) + + metadata.ResourceData.SetId(stateId.ID()) + + return nil +} + +func (r RoleManagementPolicyResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Authorization.RoleManagementPoliciesClient + schema := RoleManagementPolicyResourceSchema{} + + id, err := parse.RoleManagementPolicyId(metadata.ResourceData.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ScopedRoleManagementPolicyId()) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + log.Printf("[DEBUG] Role Management Policy %q was not found - removing from state", id) + err = metadata.MarkAsGone(id) + if err != nil { + return err + } + + return nil + } + + return fmt.Errorf("loading Role Management Policy %q: %+v", id, err) + } + + if model := resp.Model; model != nil { + schema.Scope = id.Scope + schema.RoleDefinitionID = id.RoleDefinitionId + + var config RoleManagementPolicyResourceSchema + if err := metadata.Decode(&config); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + if err := r.mapRoleManagementPolicyToRoleManagementPolicyResourceSchema(*model, &schema, &config); err != nil { + return fmt.Errorf("flattening model: %+v", err) + } + } + + return metadata.Encode(&schema) + }, + } +} + +func (r RoleManagementPolicyResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + // nothing to delete + id, err := parse.RoleManagementPolicyId(metadata.ResourceData.Id()) + if err != nil { + return fmt.Errorf("error parsing role management id: %v", err) + } + + err = metadata.MarkAsGone(id) + if err != nil { + return err + } + + return nil + }, + } +} + +func (r RoleManagementPolicyResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return validate.ValidateRoleManagementPolicyId +} + +// functions to convert data from terraform structs to azure structs + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyResourceSchemaToRoleManagementPolicy(input RoleManagementPolicyResourceSchema, output *rolemanagementpolicies.RoleManagementPolicy) error { + + if output.Properties == nil { + output.Properties = &rolemanagementpolicies.RoleManagementPolicyProperties{} + } + if err := r.mapRoleManagementPolicyResourceSchemaToProperties(input, output.Properties); err != nil { + return err + } + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyResourceSchemaToProperties(input RoleManagementPolicyResourceSchema, output *rolemanagementpolicies.RoleManagementPolicyProperties) error { + output.Scope = &input.Scope + + if output.Rules == nil { + rules := make([]rolemanagementpolicies.RoleManagementPolicyRule, 0) + output.Rules = &rules + } + + if len(input.Activation) == 1 { + if err := r.mapRoleManagementPolicyResourceActivationSchemaToRoleManagementPolicyProperties(input.Activation[0], output); err != nil { + return err + } + } + if len(input.Assignment) == 1 { + if err := r.mapRoleManagementPolicyResourceAssignmentSchemaToRoleManagementPolicyProperties(input.Assignment[0], output); err != nil { + return err + } + } + if len(input.Notifications) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaNotificationsToRoleManagementPolicyProperties(input.Notifications[0], output); err != nil { + return err + } + } + + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyResourceActivationSchemaToRoleManagementPolicyProperties(input RoleManagementPolicyResourceSchemaActivation, output *rolemanagementpolicies.RoleManagementPolicyProperties) error { + if input.MaximumDurationHours > 0 { + expirationRule := ExpirationRule{ + Id: "Expiration_EndUser_Assignment", + RuleType: "RoleManagementPolicyExpirationRule", + MaximumDuration: fmt.Sprintf("PT%dH", input.MaximumDurationHours), + IsExpirationRequired: true, + Target: &Target{ + Caller: "EndUser", + Operations: []string{"All"}, + Level: "Eligibility", + TargetObjects: nil, + InheritableSettings: nil, + EnforceSettings: nil, + }, + } + *output.Rules = append(*output.Rules, expirationRule) + } + + enabledRules := make([]string, 0) + + if input.RequireJustification { + enabledRules = append(enabledRules, "Justification") + } + if input.RequireMultiFactorAuthentication { + enabledRules = append(enabledRules, "MultiFactorAuthentication") + } + if input.RequireTicketInformation { + enabledRules = append(enabledRules, "Ticketing") + } + + enablementRule := EnablementRule{ + Id: "Enablement_EndUser_Assignment", + RuleType: "RoleManagementPolicyEnablementRule", + + EnabledRules: enabledRules, + + Target: &Target{ + Caller: "EndUser", + Operations: []string{"All"}, + Level: "Assignment", + TargetObjects: nil, + InheritableSettings: nil, + EnforceSettings: nil, + }, + } + *output.Rules = append(*output.Rules, enablementRule) + + primaryApprovers := make([]PrimaryApprovers, 0) + + if input.Approvers != nil && len(input.Approvers) > 0 { + approvers := input.Approvers[0] + + if approvers.Groups != nil { + for _, approver := range approvers.Groups { + primaryApprovers = append(primaryApprovers, PrimaryApprovers{ + Id: approver.Id, + Description: approver.Name, + IsBackup: false, + UserType: "Group", + }) + } + } + + if approvers.Users != nil { + for _, approver := range approvers.Users { + primaryApprovers = append(primaryApprovers, PrimaryApprovers{ + Id: approver.Id, + Description: approver.Name, + IsBackup: false, + UserType: "User", + }) + } + } + } + + isApprovalRequired := len(primaryApprovers) > 0 + approvalStages := make([]ApprovalStages, 1) + approvalStages[0] = ApprovalStages{ + ApprovalStageTimeOutInDays: 1, + EscalationTimeInMinutes: 0, + IsEscalationEnabled: false, + IsApproverJustificationRequired: true, + PrimaryApprovers: &primaryApprovers, + } + approvalRule := ApprovalRule{ + Id: "Approval_EndUser_Assignment", + RuleType: "RoleManagementPolicyApprovalRule", + Setting: &Settings{ + ApprovalMode: "SingleStage", + IsApprovalRequired: isApprovalRequired, + IsApprovalRequiredForExtension: false, + IsRequestorJustificationRequired: true, + ApprovalStages: approvalStages, + }, + Target: &Target{ + Caller: "EndUser", + Operations: []string{"All"}, + Level: "Assignment", + TargetObjects: nil, + InheritableSettings: nil, + EnforceSettings: nil, + }, + } + *output.Rules = append(*output.Rules, approvalRule) + + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyResourceAssignmentSchemaToRoleManagementPolicyProperties(input RoleManagementPolicyResourceSchemaAssignment, output *rolemanagementpolicies.RoleManagementPolicyProperties) error { + if len(input.Active) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaAssignmentActiveToRoleManagementPolicyProperties(input.Active[0], output); err != nil { + return err + } + } + + if len(input.Eligible) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaAssignmentEligibleToRoleManagementPolicyProperties(input.Eligible[0], output); err != nil { + return err + } + } + + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyResourceSchemaAssignmentActiveToRoleManagementPolicyProperties(input RoleManagementPolicyResourceSchemaAssignmentActive, output *rolemanagementpolicies.RoleManagementPolicyProperties) error { + maximumDuration := "" + if input.ExpireAfterDays > 0 { + maximumDuration = fmt.Sprintf("P%dD", input.ExpireAfterDays) + } else if input.ExpireAfterHours > 0 { + maximumDuration = fmt.Sprintf("PT%dH", input.ExpireAfterHours) + } + expirationRule := ExpirationRule{ + Id: "Expiration_Admin_Assignment", + RuleType: "RoleManagementPolicyExpirationRule", + MaximumDuration: maximumDuration, + IsExpirationRequired: !input.AllowPermanent, + Target: &Target{ + Caller: "Admin", + Operations: []string{"All"}, + Level: "Assignment", + TargetObjects: nil, + InheritableSettings: nil, + EnforceSettings: nil, + }, + } + *output.Rules = append(*output.Rules, expirationRule) + + enabledRules := make([]string, 0) + + if input.RequireJustification { + enabledRules = append(enabledRules, "Justification") + } + if input.RequireMultiFactorAuthentication { + enabledRules = append(enabledRules, "MultiFactorAuthentication") + } + + enablementRule := EnablementRule{ + Id: "Enablement_Admin_Assignment", + RuleType: "RoleManagementPolicyEnablementRule", + + EnabledRules: enabledRules, + + Target: &Target{ + Caller: "Admin", + Operations: []string{"All"}, + Level: "Assignment", + TargetObjects: nil, + InheritableSettings: nil, + EnforceSettings: nil, + }, + } + *output.Rules = append(*output.Rules, enablementRule) + + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyResourceSchemaAssignmentEligibleToRoleManagementPolicyProperties(input RoleManagementPolicyResourceSchemaAssignmentEligible, output *rolemanagementpolicies.RoleManagementPolicyProperties) error { + maximumDuration := "" + if input.ExpireAfterDays > 0 { + maximumDuration = fmt.Sprintf("P%dD", input.ExpireAfterDays) + } else if input.ExpireAfterHours > 0 { + maximumDuration = fmt.Sprintf("PT%dH", input.ExpireAfterHours) + } + expirationRule := ExpirationRule{ + Id: "Expiration_Admin_Eligibility", + RuleType: "RoleManagementPolicyExpirationRule", + MaximumDuration: maximumDuration, + IsExpirationRequired: !input.AllowPermanent, + Target: &Target{ + Caller: "Admin", + Operations: []string{"All"}, + Level: "Eligibility", + TargetObjects: nil, + InheritableSettings: nil, + EnforceSettings: nil, + }, + } + *output.Rules = append(*output.Rules, expirationRule) + + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyResourceSchemaNotificationsToRoleManagementPolicyProperties(input RoleManagementPolicyResourceSchemaNotifications, output *rolemanagementpolicies.RoleManagementPolicyProperties) error { + if len(input.MembersAssignedEligible) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaNotificationsEligibleToRoleManagementPolicyProperties(input.MembersAssignedEligible[0], "Eligibility", output); err != nil { + return err + } + } + if len(input.MembersAssignedActive) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaNotificationsEligibleToRoleManagementPolicyProperties(input.MembersAssignedActive[0], "Assignment", output); err != nil { + return err + } + } + if len(input.EligibleMemberActivate) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaNotificationsEligibleMemberActivateToRoleManagementPolicyProperties(input.EligibleMemberActivate[0], output); err != nil { + return err + } + } + + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyResourceSchemaNotificationsEligibleToRoleManagementPolicyProperties(input RoleManagementPolicyResourceSchemaNotificationsEligible, level string, output *rolemanagementpolicies.RoleManagementPolicyProperties) error { + if len(input.RoleAssignmentAlert) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaNotificationToRoleManagementPolicyProperties(input.RoleAssignmentAlert[0], "Admin", "Admin", level, output); err != nil { + return err + } + } + if len(input.AssignedUser) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaNotificationToRoleManagementPolicyProperties(input.AssignedUser[0], "Requestor", "Admin", level, output); err != nil { + return err + } + } + if len(input.RequestForExtensionOrApproval) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaNotificationToRoleManagementPolicyProperties(input.RequestForExtensionOrApproval[0], "Approver", "Admin", level, output); err != nil { + return err + } + } + + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyResourceSchemaNotificationsEligibleMemberActivateToRoleManagementPolicyProperties(input RoleManagementPolicyResourceSchemaNotificationsActivate, output *rolemanagementpolicies.RoleManagementPolicyProperties) error { + if len(input.RoleAssignmentAlert) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaNotificationToRoleManagementPolicyProperties(input.RoleAssignmentAlert[0], "Admin", "EndUser", "Assignment", output); err != nil { + return err + } + } + if len(input.AssignedUser) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaNotificationToRoleManagementPolicyProperties(input.AssignedUser[0], "Requestor", "EndUser", "Assignment", output); err != nil { + return err + } + } + if len(input.RequestForExtensionOrApproval) == 1 { + if err := r.mapRoleManagementPolicyResourceSchemaNotificationWithoutRecipientsToRoleManagementPolicyProperties(input.RequestForExtensionOrApproval[0], "Approver", "EndUser", "Assignment", output); err != nil { + return err + } + } + + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyResourceSchemaNotificationToRoleManagementPolicyProperties(input RoleManagementPolicyResourceSchemaNotification, recipientType string, caller string, level string, output *rolemanagementpolicies.RoleManagementPolicyProperties) error { + id := fmt.Sprintf("Notification_%s_%s_%s", recipientType, caller, level) + notificationLevel := "All" + if input.CriticalEmailsOnly { + notificationLevel = "Critical" + } + + notificationRule := NotificationRule{ + Id: id, + RuleType: "RoleManagementPolicyNotificationRule", + NotificationRecipients: input.AdditionalRecipients, + RecipientType: recipientType, + NotificationLevel: notificationLevel, + NotificationType: "Email", + IsDefaultRecipientsEnabled: input.DefaultRecipients, + Target: &Target{ + Caller: caller, + Operations: []string{"All"}, + Level: level, + TargetObjects: nil, + InheritableSettings: nil, + EnforceSettings: nil, + }, + } + *output.Rules = append(*output.Rules, notificationRule) + + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyResourceSchemaNotificationWithoutRecipientsToRoleManagementPolicyProperties(input RoleManagementPolicyResourceSchemaNotificationWithoutRecipients, recipientType string, caller string, level string, output *rolemanagementpolicies.RoleManagementPolicyProperties) error { + id := fmt.Sprintf("Notification_%s_%s_%s", recipientType, caller, level) + notificationLevel := "All" + if input.CriticalEmailsOnly { + notificationLevel = "Critical" + } + + notificationRule := NotificationRule{ + Id: id, + RuleType: "RoleManagementPolicyNotificationRule", + RecipientType: recipientType, + NotificationLevel: notificationLevel, + IsDefaultRecipientsEnabled: input.DefaultRecipients, + NotificationType: "Email", + Target: &Target{ + Caller: caller, + Operations: []string{"All"}, + Level: level, + TargetObjects: nil, + InheritableSettings: nil, + EnforceSettings: nil, + }, + } + *output.Rules = append(*output.Rules, notificationRule) + + return nil +} + +// functions to convert data from azure structs to terraform structs + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyToRoleManagementPolicyResourceSchema(input rolemanagementpolicies.RoleManagementPolicy, output *RoleManagementPolicyResourceSchema, config *RoleManagementPolicyResourceSchema) error { + if input.Properties == nil { + input.Properties = &rolemanagementpolicies.RoleManagementPolicyProperties{} + } + if err := r.mapRoleManagementPolicyPropertiesToRoleManagementPolicyResourceSchema(input.Properties, output, config); err != nil { + return err + } + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyPropertiesToRoleManagementPolicyResourceSchema(input *rolemanagementpolicies.RoleManagementPolicyProperties, output *RoleManagementPolicyResourceSchema, config *RoleManagementPolicyResourceSchema) error { + if config.Activation != nil && len(config.Activation) == 1 { + tmpActivation := &RoleManagementPolicyResourceSchemaActivation{} + if err := r.mapRoleManagementPolicyPropertiesToRoleManagementPolicyResourceSchemaActivation(input, tmpActivation, &config.Activation[0]); err != nil { + return err + } else { + output.Activation = make([]RoleManagementPolicyResourceSchemaActivation, 0) + output.Activation = append(output.Activation, *tmpActivation) + } + } + + if config.Assignment != nil && len(config.Assignment) == 1 { + tmpAssignment := &RoleManagementPolicyResourceSchemaAssignment{} + if err := r.mapRoleManagementPolicyPropertiesToRoleManagementPolicyResourceSchemaAssignment(input, tmpAssignment); err != nil { + return err + } else { + output.Assignment = make([]RoleManagementPolicyResourceSchemaAssignment, 0) + output.Assignment = append(output.Assignment, *tmpAssignment) + } + } + + if config.Notifications != nil && len(config.Notifications) == 1 { + tmpNotifications := &RoleManagementPolicyResourceSchemaNotifications{} + if err := r.mapRoleManagementPolicyPropertiesToRoleManagementPolicyResourceSchemaNotifications(input, tmpNotifications, &config.Notifications[0]); err != nil { + return err + } else { + output.Notifications = make([]RoleManagementPolicyResourceSchemaNotifications, 0) + output.Notifications = append(output.Notifications, *tmpNotifications) + } + } + + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyPropertiesToRoleManagementPolicyResourceSchemaActivation(input *rolemanagementpolicies.RoleManagementPolicyProperties, output *RoleManagementPolicyResourceSchemaActivation, config *RoleManagementPolicyResourceSchemaActivation) error { + if input.Rules != nil { + for _, r := range *input.Rules { + rule := r.(rolemanagementpolicies.RawRoleManagementPolicyRuleImpl) + switch rule.Values["id"].(string) { + case "Expiration_EndUser_Assignment": + if config.MaximumDurationHours == 0 { + continue + } + + maximumDurationRaw := rule.Values["maximumDuration"].(string) + re := regexp.MustCompile(`\d+`) + maxDuration, err := strconv.Atoi(re.FindString(maximumDurationRaw)) + if err != nil { + return err + } + output.MaximumDurationHours = maxDuration + + case "Enablement_EndUser_Assignment": + enabledRules := rule.Values["enabledRules"].([]interface{}) + for _, r := range enabledRules { + switch r { + case "Justification": + output.RequireJustification = true + + case "MultiFactorAuthentication": + output.RequireMultiFactorAuthentication = true + + case "Ticketing": + output.RequireTicketInformation = true + } + } + case "Approval_EndUser_Assignment": + if config.Approvers == nil || len(config.Approvers) == 0 { + continue + } + + output.Approvers = make([]RoleManagementPolicyResourceSchemaApprovers, 1) + approvers := &RoleManagementPolicyResourceSchemaApprovers{} + approvers.Groups = make([]RoleManagementPolicyResourceSchemaApproversApprover, 0) + approvers.Users = make([]RoleManagementPolicyResourceSchemaApproversApprover, 0) + + setting := rule.Values["setting"].(map[string]interface{}) + approvalStages := setting["approvalStages"].([]interface{}) + if len(approvalStages) == 1 { + approvalStage := approvalStages[0].(map[string]interface{}) + if approvalStage["primaryApprovers"] != nil { + for _, approver := range approvalStage["primaryApprovers"].([]interface{}) { + approverMap := approver.(map[string]interface{}) + switch approverMap["userType"] { + case "User": + approvers.Users = append(approvers.Users, RoleManagementPolicyResourceSchemaApproversApprover{ + Id: approverMap["id"].(string), + Name: approverMap["description"].(string), + }) + case "Group": + approvers.Groups = append(approvers.Groups, RoleManagementPolicyResourceSchemaApproversApprover{ + Id: approverMap["id"].(string), + Name: approverMap["description"].(string), + }) + } + } + } + } + output.Approvers[0] = *approvers + } + } + } + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyPropertiesToRoleManagementPolicyResourceSchemaAssignment(input *rolemanagementpolicies.RoleManagementPolicyProperties, output *RoleManagementPolicyResourceSchemaAssignment) error { + tmpActive := &RoleManagementPolicyResourceSchemaAssignmentActive{} + tmpEligible := &RoleManagementPolicyResourceSchemaAssignmentEligible{} + + if input.Rules != nil { + for _, r := range *input.Rules { + rule := r.(rolemanagementpolicies.RawRoleManagementPolicyRuleImpl) + switch rule.Values["id"].(string) { + case "Expiration_Admin_Eligibility": + maximumDurationRaw := rule.Values["maximumDuration"].(string) + reHours := regexp.MustCompile(`PT(\d+)H`) + hours := reHours.FindStringSubmatch(maximumDurationRaw) + if len(hours) == 2 { + maxDurationHours, err := strconv.Atoi(hours[1]) + if err != nil { + return err + } + tmpEligible.ExpireAfterHours = maxDurationHours + } + reDays := regexp.MustCompile(`P(\d+)D`) + days := reDays.FindStringSubmatch(maximumDurationRaw) + if len(days) == 2 { + maxDurationDays, err := strconv.Atoi(days[1]) + if err != nil { + return err + } + tmpEligible.ExpireAfterDays = maxDurationDays + } + + tmpEligible.AllowPermanent = !rule.Values["isExpirationRequired"].(bool) + + case "Expiration_Admin_Assignment": + maximumDurationRaw := rule.Values["maximumDuration"].(string) + reHours := regexp.MustCompile(`PT(\d+)H`) + hours := reHours.FindStringSubmatch(maximumDurationRaw) + if len(hours) == 2 { + maxDurationHours, err := strconv.Atoi(hours[1]) + if err != nil { + return err + } + tmpActive.ExpireAfterHours = maxDurationHours + } + reDays := regexp.MustCompile(`P(\d+)D`) + days := reDays.FindStringSubmatch(maximumDurationRaw) + if len(days) == 2 { + maxDurationDays, err := strconv.Atoi(days[1]) + if err != nil { + return err + } + tmpActive.ExpireAfterDays = maxDurationDays + } + + tmpActive.AllowPermanent = !rule.Values["isExpirationRequired"].(bool) + + case "Enablement_Admin_Assignment": + enabledRules := rule.Values["enabledRules"].([]interface{}) + for _, r := range enabledRules { + switch r { + case "Justification": + tmpActive.RequireJustification = true + + case "MultiFactorAuthentication": + tmpActive.RequireMultiFactorAuthentication = true + } + } + + } + } + } + + output.Active = make([]RoleManagementPolicyResourceSchemaAssignmentActive, 0) + output.Active = append(output.Active, *tmpActive) + + output.Eligible = make([]RoleManagementPolicyResourceSchemaAssignmentEligible, 0) + output.Eligible = append(output.Eligible, *tmpEligible) + + return nil +} + +func (r RoleManagementPolicyResource) mapRoleManagementPolicyPropertiesToRoleManagementPolicyResourceSchemaNotifications(input *rolemanagementpolicies.RoleManagementPolicyProperties, output *RoleManagementPolicyResourceSchemaNotifications, config *RoleManagementPolicyResourceSchemaNotifications) error { + var tmpMembersAssignedEligible *RoleManagementPolicyResourceSchemaNotificationsEligible + var tmpMembersAssignedActive *RoleManagementPolicyResourceSchemaNotificationsEligible + var tmpEligibleMemberActivate *RoleManagementPolicyResourceSchemaNotificationsActivate + + if config.MembersAssignedEligible != nil && len(config.MembersAssignedEligible) == 1 { + tmpMembersAssignedEligible = &RoleManagementPolicyResourceSchemaNotificationsEligible{} + } + if config.MembersAssignedActive != nil && len(config.MembersAssignedActive) == 1 { + tmpMembersAssignedActive = &RoleManagementPolicyResourceSchemaNotificationsEligible{} + } + if config.EligibleMemberActivate != nil && len(config.EligibleMemberActivate) == 1 { + tmpEligibleMemberActivate = &RoleManagementPolicyResourceSchemaNotificationsActivate{} + } + + if input.Rules != nil { + for _, r := range *input.Rules { + rule := r.(rolemanagementpolicies.RawRoleManagementPolicyRuleImpl) + + if rule.Values["ruleType"].(string) != "RoleManagementPolicyNotificationRule" { + continue + } + + notificationLevel := rule.Values["notificationLevel"].(string) + criticalEmailsOnly := false + if notificationLevel == "Critical" { + criticalEmailsOnly = true + } + + notificationRecipients := rule.Values["notificationRecipients"] + additionalRecipients := make([]string, 0) + if notificationRecipients != nil { + for _, rec := range notificationRecipients.([]interface{}) { + additionalRecipients = append(additionalRecipients, rec.(string)) + } + } + + switch rule.Values["id"].(string) { + + case "Notification_Admin_Admin_Eligibility": + if config.MembersAssignedEligible != nil && len(config.MembersAssignedEligible) == 1 && config.MembersAssignedEligible[0].RoleAssignmentAlert != nil && len(config.MembersAssignedEligible[0].RoleAssignmentAlert) == 1 { + tmpMembersAssignedEligible.RoleAssignmentAlert = make([]RoleManagementPolicyResourceSchemaNotification, 1) + tmpMembersAssignedEligible.RoleAssignmentAlert[0].AdditionalRecipients = additionalRecipients + tmpMembersAssignedEligible.RoleAssignmentAlert[0].CriticalEmailsOnly = criticalEmailsOnly + tmpMembersAssignedEligible.RoleAssignmentAlert[0].DefaultRecipients = rule.Values["isDefaultRecipientsEnabled"].(bool) + } + + case "Notification_Requestor_Admin_Eligibility": + if config.MembersAssignedEligible != nil && len(config.MembersAssignedEligible) == 1 && config.MembersAssignedEligible[0].AssignedUser != nil && len(config.MembersAssignedEligible[0].AssignedUser) == 1 { + tmpMembersAssignedEligible.AssignedUser = make([]RoleManagementPolicyResourceSchemaNotification, 1) + tmpMembersAssignedEligible.AssignedUser[0].AdditionalRecipients = additionalRecipients + tmpMembersAssignedEligible.AssignedUser[0].CriticalEmailsOnly = criticalEmailsOnly + tmpMembersAssignedEligible.AssignedUser[0].DefaultRecipients = rule.Values["isDefaultRecipientsEnabled"].(bool) + } + + case "Notification_Approver_Admin_Eligibility": + if config.MembersAssignedEligible != nil && len(config.MembersAssignedEligible) == 1 && config.MembersAssignedEligible[0].RequestForExtensionOrApproval != nil && len(config.MembersAssignedEligible[0].RequestForExtensionOrApproval) == 1 { + tmpMembersAssignedEligible.RequestForExtensionOrApproval = make([]RoleManagementPolicyResourceSchemaNotification, 1) + tmpMembersAssignedEligible.RequestForExtensionOrApproval[0].AdditionalRecipients = additionalRecipients + tmpMembersAssignedEligible.RequestForExtensionOrApproval[0].CriticalEmailsOnly = criticalEmailsOnly + tmpMembersAssignedEligible.RequestForExtensionOrApproval[0].DefaultRecipients = rule.Values["isDefaultRecipientsEnabled"].(bool) + } + + case "Notification_Admin_Admin_Assignment": + if config.MembersAssignedActive != nil && len(config.MembersAssignedActive) == 1 && config.MembersAssignedActive[0].RoleAssignmentAlert != nil && len(config.MembersAssignedActive[0].RoleAssignmentAlert) == 1 { + tmpMembersAssignedActive.RoleAssignmentAlert = make([]RoleManagementPolicyResourceSchemaNotification, 1) + tmpMembersAssignedActive.RoleAssignmentAlert[0].AdditionalRecipients = additionalRecipients + tmpMembersAssignedActive.RoleAssignmentAlert[0].CriticalEmailsOnly = criticalEmailsOnly + tmpMembersAssignedActive.RoleAssignmentAlert[0].DefaultRecipients = rule.Values["isDefaultRecipientsEnabled"].(bool) + } + + case "Notification_Requestor_Admin_Assignment": + if config.MembersAssignedActive != nil && len(config.MembersAssignedActive) == 1 && config.MembersAssignedActive[0].AssignedUser != nil && len(config.MembersAssignedActive[0].AssignedUser) == 1 { + tmpMembersAssignedActive.AssignedUser = make([]RoleManagementPolicyResourceSchemaNotification, 1) + tmpMembersAssignedActive.AssignedUser[0].AdditionalRecipients = additionalRecipients + tmpMembersAssignedActive.AssignedUser[0].CriticalEmailsOnly = criticalEmailsOnly + tmpMembersAssignedActive.AssignedUser[0].DefaultRecipients = rule.Values["isDefaultRecipientsEnabled"].(bool) + } + + case "Notification_Approver_Admin_Assignment": + if config.MembersAssignedActive != nil && len(config.MembersAssignedActive) == 1 && config.MembersAssignedActive[0].RequestForExtensionOrApproval != nil && len(config.MembersAssignedActive[0].RequestForExtensionOrApproval) == 1 { + tmpMembersAssignedActive.RequestForExtensionOrApproval = make([]RoleManagementPolicyResourceSchemaNotification, 1) + tmpMembersAssignedActive.RequestForExtensionOrApproval[0].AdditionalRecipients = additionalRecipients + tmpMembersAssignedActive.RequestForExtensionOrApproval[0].CriticalEmailsOnly = criticalEmailsOnly + tmpMembersAssignedActive.RequestForExtensionOrApproval[0].DefaultRecipients = rule.Values["isDefaultRecipientsEnabled"].(bool) + } + + case "Notification_Admin_EndUser_Assignment": + if config.EligibleMemberActivate != nil && len(config.EligibleMemberActivate) == 1 && config.EligibleMemberActivate[0].RoleAssignmentAlert != nil && len(config.EligibleMemberActivate[0].RoleAssignmentAlert) == 1 { + tmpEligibleMemberActivate.RoleAssignmentAlert = make([]RoleManagementPolicyResourceSchemaNotification, 1) + tmpEligibleMemberActivate.RoleAssignmentAlert[0].AdditionalRecipients = additionalRecipients + tmpEligibleMemberActivate.RoleAssignmentAlert[0].CriticalEmailsOnly = criticalEmailsOnly + tmpEligibleMemberActivate.RoleAssignmentAlert[0].DefaultRecipients = rule.Values["isDefaultRecipientsEnabled"].(bool) + } + + case "Notification_Requestor_EndUser_Assignment": + if config.EligibleMemberActivate != nil && len(config.EligibleMemberActivate) == 1 && config.EligibleMemberActivate[0].AssignedUser != nil && len(config.EligibleMemberActivate[0].AssignedUser) == 1 { + tmpEligibleMemberActivate.AssignedUser = make([]RoleManagementPolicyResourceSchemaNotification, 1) + tmpEligibleMemberActivate.AssignedUser[0].AdditionalRecipients = additionalRecipients + tmpEligibleMemberActivate.AssignedUser[0].CriticalEmailsOnly = criticalEmailsOnly + tmpEligibleMemberActivate.AssignedUser[0].DefaultRecipients = rule.Values["isDefaultRecipientsEnabled"].(bool) + } + + case "Notification_Approver_EndUser_Assignment": + if config.EligibleMemberActivate != nil && len(config.EligibleMemberActivate) == 1 && config.EligibleMemberActivate[0].RequestForExtensionOrApproval != nil && len(config.EligibleMemberActivate[0].RequestForExtensionOrApproval) == 1 { + tmpEligibleMemberActivate.RequestForExtensionOrApproval = make([]RoleManagementPolicyResourceSchemaNotificationWithoutRecipients, 1) + tmpEligibleMemberActivate.RequestForExtensionOrApproval[0].CriticalEmailsOnly = criticalEmailsOnly + tmpEligibleMemberActivate.RequestForExtensionOrApproval[0].DefaultRecipients = rule.Values["isDefaultRecipientsEnabled"].(bool) + } + + } + + } + } + + if tmpMembersAssignedEligible != nil { + output.MembersAssignedEligible = make([]RoleManagementPolicyResourceSchemaNotificationsEligible, 0) + output.MembersAssignedEligible = append(output.MembersAssignedEligible, *tmpMembersAssignedEligible) + } + if tmpMembersAssignedActive != nil { + output.MembersAssignedActive = make([]RoleManagementPolicyResourceSchemaNotificationsEligible, 0) + output.MembersAssignedActive = append(output.MembersAssignedActive, *tmpMembersAssignedActive) + } + if tmpEligibleMemberActivate != nil { + output.EligibleMemberActivate = make([]RoleManagementPolicyResourceSchemaNotificationsActivate, 0) + output.EligibleMemberActivate = append(output.EligibleMemberActivate, *tmpEligibleMemberActivate) + } + return nil +} + +type RoleManagementPolicyResourceSchema struct { + RoleDefinitionID string `tfschema:"role_definition_id"` + Scope string `tfschema:"scope"` + Activation []RoleManagementPolicyResourceSchemaActivation `tfschema:"activation"` + Assignment []RoleManagementPolicyResourceSchemaAssignment `tfschema:"assignment"` + Notifications []RoleManagementPolicyResourceSchemaNotifications `tfschema:"notifications"` +} + +type RoleManagementPolicyResourceSchemaActivation struct { + MaximumDurationHours int `tfschema:"maximum_duration_hours"` + RequireMultiFactorAuthentication bool `tfschema:"require_multi_factor_authentication"` + RequireJustification bool `tfschema:"require_justification"` + RequireTicketInformation bool `tfschema:"require_ticket_information"` + Approvers []RoleManagementPolicyResourceSchemaApprovers `tfschema:"approvers"` +} + +type RoleManagementPolicyResourceSchemaApprovers struct { + Groups []RoleManagementPolicyResourceSchemaApproversApprover `tfschema:"group"` + Users []RoleManagementPolicyResourceSchemaApproversApprover `tfschema:"user"` +} + +type RoleManagementPolicyResourceSchemaApproversApprover struct { + Id string `tfschema:"id"` + Name string `tfschema:"name"` +} + +type RoleManagementPolicyResourceSchemaAssignment struct { + Active []RoleManagementPolicyResourceSchemaAssignmentActive `tfschema:"active"` + Eligible []RoleManagementPolicyResourceSchemaAssignmentEligible `tfschema:"eligible"` +} + +type RoleManagementPolicyResourceSchemaAssignmentActive struct { + AllowPermanent bool `tfschema:"allow_permanent"` + ExpireAfterDays int `tfschema:"expire_after_days"` + ExpireAfterHours int `tfschema:"expire_after_hours"` + RequireMultiFactorAuthentication bool `tfschema:"require_multi_factor_authentication"` + RequireJustification bool `tfschema:"require_justification"` +} + +type RoleManagementPolicyResourceSchemaAssignmentEligible struct { + AllowPermanent bool `tfschema:"allow_permanent"` + ExpireAfterDays int `tfschema:"expire_after_days"` + ExpireAfterHours int `tfschema:"expire_after_hours"` +} + +type RoleManagementPolicyResourceSchemaNotifications struct { + MembersAssignedEligible []RoleManagementPolicyResourceSchemaNotificationsEligible `tfschema:"member_assigned_eligible"` + MembersAssignedActive []RoleManagementPolicyResourceSchemaNotificationsEligible `tfschema:"member_assigned_active"` + EligibleMemberActivate []RoleManagementPolicyResourceSchemaNotificationsActivate `tfschema:"eligible_member_activate"` +} + +type RoleManagementPolicyResourceSchemaNotificationsEligible struct { + RoleAssignmentAlert []RoleManagementPolicyResourceSchemaNotification `tfschema:"role_assignment_alert"` + AssignedUser []RoleManagementPolicyResourceSchemaNotification `tfschema:"assigned_user"` + RequestForExtensionOrApproval []RoleManagementPolicyResourceSchemaNotification `tfschema:"request_for_extension_or_approval"` +} + +type RoleManagementPolicyResourceSchemaNotificationsActivate struct { + RoleAssignmentAlert []RoleManagementPolicyResourceSchemaNotification `tfschema:"role_assignment_alert"` + AssignedUser []RoleManagementPolicyResourceSchemaNotification `tfschema:"assigned_user"` + RequestForExtensionOrApproval []RoleManagementPolicyResourceSchemaNotificationWithoutRecipients `tfschema:"request_for_extension_or_approval"` +} + +type RoleManagementPolicyResourceSchemaNotification struct { + AdditionalRecipients []string `tfschema:"additional_recipients"` + CriticalEmailsOnly bool `tfschema:"critical_emails_only"` + DefaultRecipients bool `tfschema:"default_recipients"` +} + +type RoleManagementPolicyResourceSchemaNotificationWithoutRecipients struct { + CriticalEmailsOnly bool `tfschema:"critical_emails_only"` + DefaultRecipients bool `tfschema:"default_recipients"` +} + +type ApprovalRule struct { + Id string `json:"id"` + RuleType string `json:"ruleType"` + Target *Target `json:"target"` + + Setting *Settings `json:"setting"` +} + +type ExpirationRule struct { + Id string `json:"id"` + RuleType string `json:"ruleType"` + Target *Target `json:"target"` + + IsExpirationRequired bool `json:"isExpirationRequired"` + MaximumDuration string `json:"maximumDuration"` +} + +type EnablementRule struct { + Id string `json:"id"` + RuleType string `json:"ruleType"` + Target *Target `json:"target"` + + EnabledRules []string `json:"enabledRules"` +} + +type NotificationRule struct { + Id string `json:"id"` + RuleType string `json:"ruleType"` + Target *Target `json:"target"` + + NotificationType string `json:"notificationType"` + RecipientType string `json:"recipientType"` + IsDefaultRecipientsEnabled bool `json:"isDefaultRecipientsEnabled"` + NotificationLevel string `json:"notificationLevel"` + NotificationRecipients []string `json:"notificationRecipients"` +} + +type Target struct { + Caller string `json:"caller"` + Operations []string `json:"operations"` + Level string `json:"level"` + TargetObjects interface{} `json:"targetObjects"` + InheritableSettings interface{} `json:"inheritableSettings"` + EnforceSettings interface{} `json:"enforceSettings"` +} + +type Settings struct { + ApprovalMode string `json:"approvalMode"` + IsApprovalRequired bool `json:"isApprovalRequired"` + IsApprovalRequiredForExtension bool `json:"isApprovalRequiredForExtension"` + IsRequestorJustificationRequired bool `json:"isRequestorJustificationRequired"` + ApprovalStages []ApprovalStages `json:"approvalStages"` +} + +type ApprovalStages struct { + ApprovalStageTimeOutInDays int `json:"approvalStageTimeOutInDays"` + EscalationTimeInMinutes int `json:"escalationTimeInMinutes"` + IsApproverJustificationRequired bool `json:"isApproverJustificationRequired"` + IsEscalationEnabled bool `json:"isEscalationEnabled"` + PrimaryApprovers *[]PrimaryApprovers `json:"primaryApprovers"` +} + +type PrimaryApprovers struct { + Id string `json:"id"` + Description string `json:"description"` + IsBackup bool `json:"isBackup"` + UserType string `json:"userType"` +} diff --git a/internal/services/authorization/role_management_policy_test.go b/internal/services/authorization/role_management_policy_test.go new file mode 100644 index 000000000000..519560330b4e --- /dev/null +++ b/internal/services/authorization/role_management_policy_test.go @@ -0,0 +1,877 @@ +package authorization_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/authorization/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type RoleManagementPolicyResource struct{} + +func TestAccRoleManagementPolicy_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_role_management_policy", "test") + r := RoleManagementPolicyResource{} + + data.ResourceTestSkipCheckDestroyed(t, []acceptance.TestStep{ + { + Config: r.basic(), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + check.That(data.ResourceName).Key("role_definition_id").Exists(), + check.That(data.ResourceName).Key("activation.0.maximum_duration_hours").HasValue("12"), + ), + }, + }) +} + +func TestAccRoleManagementPolicy_partial(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_role_management_policy", "test") + r := RoleManagementPolicyResource{} + ri := acceptance.RandTimeInt() + rPassword := fmt.Sprintf("%s%s", "p@$$Wd", acceptance.RandString(6)) + + data.ResourceTestSkipCheckDestroyed(t, []acceptance.TestStep{ + { + Config: r.partial1(ri), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + check.That(data.ResourceName).Key("role_definition_id").Exists(), + + check.That(data.ResourceName).Key("activation.0.require_multi_factor_authentication").HasValue("true"), + + check.That(data.ResourceName).Key("assignment.0.eligible.0.expire_after_hours").HasValue("6"), + check.That(data.ResourceName).Key("assignment.0.active.0.expire_after_hours").HasValue("5"), + + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.role_assignment_alert.0.default_recipients").HasValue("false"), + + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.additional_recipients.#").HasValue("1"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.critical_emails_only").HasValue("false"), + + check.That(data.ResourceName).Key("activation.0.approvers.0.group.#").HasValue("1"), + check.That(data.ResourceName).Key("activation.0.approvers.0.user.#").HasValue("0"), + ), + }, + { + Config: r.partial2(ri, rPassword), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + check.That(data.ResourceName).Key("role_definition_id").Exists(), + + check.That(data.ResourceName).Key("activation.0.require_justification").HasValue("true"), + check.That(data.ResourceName).Key("activation.0.require_multi_factor_authentication").HasValue("true"), + + check.That(data.ResourceName).Key("assignment.0.eligible.0.expire_after_days").HasValue("7"), + check.That(data.ResourceName).Key("assignment.0.active.0.expire_after_days").HasValue("4"), + check.That(data.ResourceName).Key("assignment.0.active.0.require_justification").HasValue("true"), + check.That(data.ResourceName).Key("assignment.0.active.0.require_multi_factor_authentication").HasValue("true"), + + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.role_assignment_alert.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.role_assignment_alert.0.critical_emails_only").HasValue("false"), + + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.additional_recipients.#").HasValue("1"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.critical_emails_only").HasValue("false"), + + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.role_assignment_alert.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.role_assignment_alert.0.additional_recipients.#").HasValue("1"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.role_assignment_alert.0.critical_emails_only").HasValue("false"), + + check.That(data.ResourceName).Key("activation.0.approvers.0.group.#").HasValue("0"), + check.That(data.ResourceName).Key("activation.0.approvers.0.user.#").HasValue("1"), + ), + }, + }) +} + +func TestAccRoleManagementPolicy_noExpiry(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_role_management_policy", "test") + r := RoleManagementPolicyResource{} + + data.ResourceTestSkipCheckDestroyed(t, []acceptance.TestStep{ + { + Config: r.noExpiry(), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + check.That(data.ResourceName).Key("role_definition_id").Exists(), + check.That(data.ResourceName).Key("assignment.0.eligible.0.allow_permanent").HasValue("true"), + check.That(data.ResourceName).Key("assignment.0.active.0.allow_permanent").HasValue("true"), + ), + }, + }) +} + +func TestAccRoleManagementPolicy_managementGroup(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_role_management_policy", "test") + r := RoleManagementPolicyResource{} + + data.ResourceTestSkipCheckDestroyed(t, []acceptance.TestStep{ + { + Config: r.managementGroup(), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + check.That(data.ResourceName).Key("role_definition_id").Exists(), + check.That(data.ResourceName).Key("activation.0.maximum_duration_hours").HasValue("12"), + ), + }, + }) +} + +func TestAccRoleManagementPolicy_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_role_management_policy", "test") + r := RoleManagementPolicyResource{} + + data.ResourceTestSkipCheckDestroyed(t, []acceptance.TestStep{ + { + Config: r.basic(), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + check.That(data.ResourceName).Key("role_definition_id").Exists(), + check.That(data.ResourceName).Key("activation.0.maximum_duration_hours").HasValue("12"), + ), + }, + { + Config: r.complete(), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + check.That(data.ResourceName).Key("role_definition_id").Exists(), + + check.That(data.ResourceName).Key("activation.0.maximum_duration_hours").HasValue("4"), + check.That(data.ResourceName).Key("activation.0.require_multi_factor_authentication").HasValue("true"), + check.That(data.ResourceName).Key("activation.0.require_justification").HasValue("true"), + check.That(data.ResourceName).Key("activation.0.require_ticket_information").HasValue("true"), + check.That(data.ResourceName).Key("activation.0.require_ticket_information").HasValue("true"), + check.That(data.ResourceName).Key("activation.0.approvers.0.group.#").HasValue("2"), + check.That(data.ResourceName).Key("activation.0.approvers.0.user.#").HasValue("2"), + + check.That(data.ResourceName).Key("assignment.0.eligible.0.allow_permanent").HasValue("true"), + check.That(data.ResourceName).Key("assignment.0.active.0.allow_permanent").HasValue("true"), + check.That(data.ResourceName).Key("assignment.0.active.0.require_multi_factor_authentication").HasValue("true"), + check.That(data.ResourceName).Key("assignment.0.active.0.require_justification").HasValue("true"), + + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.role_assignment_alert.0.default_recipients").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.role_assignment_alert.0.additional_recipients.#").HasValue("1"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.role_assignment_alert.0.critical_emails_only").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.assigned_user.0.default_recipients").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.assigned_user.0.additional_recipients.#").HasValue("1"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.assigned_user.0.critical_emails_only").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.request_for_extension_or_approval.0.default_recipients").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.request_for_extension_or_approval.0.additional_recipients.#").HasValue("1"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.request_for_extension_or_approval.0.critical_emails_only").HasValue("true"), + + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.default_recipients").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.additional_recipients.#").HasValue("1"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.critical_emails_only").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.assigned_user.0.default_recipients").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.assigned_user.0.additional_recipients.#").HasValue("1"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.assigned_user.0.critical_emails_only").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.request_for_extension_or_approval.0.default_recipients").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.request_for_extension_or_approval.0.additional_recipients.#").HasValue("1"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.request_for_extension_or_approval.0.critical_emails_only").HasValue("true"), + + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.role_assignment_alert.0.default_recipients").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.role_assignment_alert.0.additional_recipients.#").HasValue("1"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.role_assignment_alert.0.critical_emails_only").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.assigned_user.0.default_recipients").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.assigned_user.0.additional_recipients.#").HasValue("1"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.assigned_user.0.critical_emails_only").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.request_for_extension_or_approval.0.default_recipients").HasValue("true"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.request_for_extension_or_approval.0.critical_emails_only").HasValue("true"), + ), + }, + { + Config: r.basic(), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + check.That(data.ResourceName).Key("role_definition_id").Exists(), + check.That(data.ResourceName).Key("activation.0.maximum_duration_hours").HasValue("12"), + check.That(data.ResourceName).Key("activation.0.approvers.0.group.#").HasValue("0"), + check.That(data.ResourceName).Key("activation.0.approvers.0.user.#").HasValue("0"), + ), + }, + }) +} + +func TestAccRoleManagementPolicy_allOff(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_role_management_policy", "test") + r := RoleManagementPolicyResource{} + + data.ResourceTestSkipCheckDestroyed(t, []acceptance.TestStep{ + { + Config: r.allOff(), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + check.That(data.ResourceName).Key("role_definition_id").Exists(), + + check.That(data.ResourceName).Key("activation.0.maximum_duration_hours").HasValue("3"), + check.That(data.ResourceName).Key("activation.0.require_multi_factor_authentication").HasValue("false"), + check.That(data.ResourceName).Key("activation.0.require_justification").HasValue("false"), + check.That(data.ResourceName).Key("activation.0.require_ticket_information").HasValue("false"), + check.That(data.ResourceName).Key("activation.0.approvers.0.group.#").HasValue("0"), + check.That(data.ResourceName).Key("activation.0.approvers.0.user.#").HasValue("0"), + + check.That(data.ResourceName).Key("assignment.0.eligible.0.expire_after_hours").HasValue("3"), + check.That(data.ResourceName).Key("assignment.0.active.0.expire_after_days").HasValue("15"), + check.That(data.ResourceName).Key("assignment.0.active.0.require_multi_factor_authentication").HasValue("false"), + check.That(data.ResourceName).Key("assignment.0.active.0.require_justification").HasValue("false"), + + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.role_assignment_alert.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.role_assignment_alert.0.additional_recipients.#").HasValue("0"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.role_assignment_alert.0.critical_emails_only").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.assigned_user.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.assigned_user.0.additional_recipients.#").HasValue("0"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.assigned_user.0.critical_emails_only").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.request_for_extension_or_approval.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.request_for_extension_or_approval.0.additional_recipients.#").HasValue("0"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_eligible.0.request_for_extension_or_approval.0.critical_emails_only").HasValue("false"), + + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.additional_recipients.#").HasValue("0"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.role_assignment_alert.0.critical_emails_only").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.assigned_user.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.assigned_user.0.additional_recipients.#").HasValue("0"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.assigned_user.0.critical_emails_only").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.request_for_extension_or_approval.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.request_for_extension_or_approval.0.additional_recipients.#").HasValue("0"), + check.That(data.ResourceName).Key("notifications.0.member_assigned_active.0.request_for_extension_or_approval.0.critical_emails_only").HasValue("false"), + + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.role_assignment_alert.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.role_assignment_alert.0.additional_recipients.#").HasValue("0"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.role_assignment_alert.0.critical_emails_only").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.assigned_user.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.assigned_user.0.additional_recipients.#").HasValue("0"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.assigned_user.0.critical_emails_only").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.request_for_extension_or_approval.0.default_recipients").HasValue("false"), + check.That(data.ResourceName).Key("notifications.0.eligible_member_activate.0.request_for_extension_or_approval.0.critical_emails_only").HasValue("false"), + ), + }, + }) +} + +func TestAccRoleManagementPolicy_resourceGroup(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_role_management_policy", "test") + r := RoleManagementPolicyResource{} + ri := acceptance.RandTimeInt() + + data.ResourceTestSkipCheckDestroyed(t, []acceptance.TestStep{ + { + Config: r.resourceGroup(data, ri), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + check.That(data.ResourceName).Key("role_definition_id").Exists(), + ), + }, + }) +} + +func TestAccRoleManagementPolicy_resource(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_role_management_policy", "test") + r := RoleManagementPolicyResource{} + ri := acceptance.RandTimeInt() + + data.ResourceTestSkipCheckDestroyed(t, []acceptance.TestStep{ + { + Config: r.resource(data, ri), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("scope").Exists(), + check.That(data.ResourceName).Key("role_definition_id").Exists(), + ), + }, + }) +} + +func (r RoleManagementPolicyResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := parse.RoleManagementPolicyId(state.ID) + + if err != nil { + return nil, err + } + + resp, err := client.Authorization.RoleManagementPoliciesClient.Get(ctx, id.ScopedRoleManagementPolicyId()) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return nil, nil + } + + return nil, fmt.Errorf("loading Role Management Policy %q: %+v", id, err) + } + + return utils.Bool(true), nil +} + +func (RoleManagementPolicyResource) basic() string { + return ` +provider "azurerm" { + features {} +} + +data "azurerm_subscription" "primary" {} + +data "azurerm_role_definition" "test" { + name = "Monitoring Reader" +} + +resource "azurerm_role_management_policy" "test" { + scope = data.azurerm_subscription.primary.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + + activation { + maximum_duration_hours = 12 + } +}` + +} + +func (RoleManagementPolicyResource) partial1(id int) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_subscription" "primary" {} + +data "azurerm_role_definition" "test" { + name = "Backup Reader" +} + +resource "azuread_group" "test1" { + display_name = "acctest-group-%[1]d1" + security_enabled = true +} + +resource "azurerm_role_management_policy" "test" { + scope = data.azurerm_subscription.primary.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + + activation { + require_multi_factor_authentication = true + + approvers { + group { + name = azuread_group.test1.display_name + id = azuread_group.test1.id + } + } + } + + assignment { + eligible { + expire_after_hours = 6 + } + active { + expire_after_hours = 5 + require_multi_factor_authentication = true + } + } + + notifications { + member_assigned_eligible { + role_assignment_alert { + default_recipients = false + } + } + + member_assigned_active { + role_assignment_alert { + default_recipients = false + additional_recipients = ["role_assignment_alert@member_assigned_active.com"] + critical_emails_only = false + } + } + } +}`, id) + +} + +func (RoleManagementPolicyResource) partial2(id int, password string) string { + return ` +provider "azurerm" { + features {} +} + +data "azurerm_subscription" "primary" {} + +data "azurerm_role_definition" "test" { + name = "Backup Reader" +} + +# There is a timing issue where the PIM API cannot find new users created for 5 to 10 seconds +data "azuread_users" "users" { + return_all = true +} + +resource "azurerm_role_management_policy" "test" { + scope = data.azurerm_subscription.primary.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + + activation { + require_justification = true + + approvers { + user { + name = data.azuread_users.users.users[0].display_name + id = data.azuread_users.users.users[0].object_id + } + } + } + + assignment { + eligible { + expire_after_days = 7 + } + active { + expire_after_days = 4 + require_justification = true + } + } + + notifications { + member_assigned_eligible { + role_assignment_alert { + critical_emails_only = false + } + } + + eligible_member_activate { + role_assignment_alert { + default_recipients = false + additional_recipients = ["role_assignment_alert@eligible_member_activate.com"] + critical_emails_only = false + } + } + } +}` + +} + +func (RoleManagementPolicyResource) managementGroup() string { + return ` +provider "azurerm" { + features {} +} + +data "azurerm_subscription" "primary" {} + +data "azurerm_role_definition" "test" { + name = "Monitoring Reader" +} + +resource "azurerm_management_group" "test" { +} + +resource "azurerm_role_management_policy" "test" { + scope = azurerm_management_group.test.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + + activation { + maximum_duration_hours = 12 + } +}` + +} + +func (RoleManagementPolicyResource) complete() string { + return ` +provider "azurerm" { + features {} +} + +data "azurerm_subscription" "primary" {} + +data "azurerm_role_definition" "test" { + name = "Monitoring Reader" +} + +data "azuread_users" "users" { + return_all = true +} + +data "azuread_groups" "all" { + return_all = true +} + +resource "azurerm_role_management_policy" "test" { + scope = data.azurerm_subscription.primary.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + + activation { + maximum_duration_hours = 4 + + require_multi_factor_authentication = true + require_justification = true + require_ticket_information = true + + approvers { + group { + name = data.azuread_groups.all.display_names[0] + id = data.azuread_groups.all.object_ids[0] + } + group { + name = data.azuread_groups.all.display_names[1] + id = data.azuread_groups.all.object_ids[1] + } + user { + name = data.azuread_users.users.users[0].display_name + id = data.azuread_users.users.users[0].object_id + } + user { + name = data.azuread_users.users.users[1].display_name + id = data.azuread_users.users.users[1].object_id + } + } + } + + assignment { + eligible { + allow_permanent = true + } + + active { + allow_permanent = true + require_multi_factor_authentication = true + require_justification = true + } + } + + notifications { + member_assigned_eligible { + role_assignment_alert { + default_recipients = true + additional_recipients = ["role_assignment_alert@member_assigned_eligible.com"] + critical_emails_only = true + } + assigned_user { + default_recipients = true + additional_recipients = ["assigned_user@member_assigned_eligible.com"] + critical_emails_only = true + } + request_for_extension_or_approval { + default_recipients = true + additional_recipients = ["request_for_extension_or_approval@member_assigned_eligible.com"] + critical_emails_only = true + } + } + member_assigned_active { + role_assignment_alert { + default_recipients = true + additional_recipients = ["role_assignment_alert@member_assigned_active.com"] + critical_emails_only = true + } + assigned_user { + default_recipients = true + additional_recipients = ["assigned_user@member_assigned_active.com"] + critical_emails_only = true + } + request_for_extension_or_approval { + default_recipients = true + additional_recipients = ["request_for_extension_or_approval@member_assigned_active.com"] + critical_emails_only = true + } + } + eligible_member_activate { + role_assignment_alert { + default_recipients = true + additional_recipients = ["role_assignment_alert@eligible_member_activate.com"] + critical_emails_only = true + } + assigned_user { + default_recipients = true + additional_recipients = ["assigned_user@eligible_member_activate.com"] + critical_emails_only = true + } + request_for_extension_or_approval { + default_recipients = true + critical_emails_only = true + } + } + } +} +` +} + +func (RoleManagementPolicyResource) noExpiry() string { + return ` +provider "azurerm" { + features {} +} + +data "azurerm_subscription" "primary" {} + +data "azurerm_role_definition" "test" { + name = "CDN Profile Reader" +} + +resource "azurerm_role_management_policy" "test" { + scope = data.azurerm_subscription.primary.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + + assignment { + eligible { + allow_permanent = true + } + active { + allow_permanent = true + } + } +}` +} + +func (RoleManagementPolicyResource) allOff() string { + return ` +provider "azurerm" { + features {} +} + +data "azurerm_subscription" "primary" {} + +data "azurerm_role_definition" "test" { + name = "Reader" +} + +resource "azurerm_role_management_policy" "test" { + scope = data.azurerm_subscription.primary.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + + activation { + maximum_duration_hours = 3 + + require_multi_factor_authentication = false + require_justification = false + require_ticket_information = false + } + + assignment { + eligible { + expire_after_hours = 3 + } + + active { + expire_after_days = 15 + require_multi_factor_authentication = false + require_justification = false + } + } + + notifications { + member_assigned_eligible { + role_assignment_alert { + default_recipients = false + additional_recipients = [] + critical_emails_only = false + } + assigned_user { + default_recipients = false + additional_recipients = [] + critical_emails_only = false + } + request_for_extension_or_approval { + default_recipients = false + additional_recipients = [] + critical_emails_only = false + } + } + member_assigned_active { + role_assignment_alert { + default_recipients = false + additional_recipients = [] + critical_emails_only = false + } + assigned_user { + default_recipients = false + additional_recipients = [] + critical_emails_only = false + } + request_for_extension_or_approval { + default_recipients = false + additional_recipients = [] + critical_emails_only = false + } + } + eligible_member_activate { + role_assignment_alert { + default_recipients = false + additional_recipients = [] + critical_emails_only = false + } + assigned_user { + default_recipients = false + additional_recipients = [] + critical_emails_only = false + } + request_for_extension_or_approval { + default_recipients = false + critical_emails_only = false + } + } + } +}` +} + +func (RoleManagementPolicyResource) resourceGroup(data acceptance.TestData, id int) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_subscription" "primary" {} + +data "azurerm_role_definition" "test" { + name = "Monitoring Reader" +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_role_management_policy" "test" { + scope = azurerm_resource_group.test.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + + activation { + maximum_duration_hours = 8 + + require_multi_factor_authentication = true + require_justification = true + require_ticket_information = true + } + + assignment { + eligible { + allow_permanent = true + } + + active { + allow_permanent = true + require_multi_factor_authentication = true + require_justification = true + } + } + + notifications { + member_assigned_eligible { + role_assignment_alert { + default_recipients = true + additional_recipients = ["role_assignment_alert@member_assigned_eligible.com"] + critical_emails_only = true + } + assigned_user { + default_recipients = true + additional_recipients = ["assigned_user@member_assigned_eligible.com"] + critical_emails_only = true + } + request_for_extension_or_approval { + default_recipients = true + additional_recipients = ["request_for_extension_or_approval@member_assigned_eligible.com"] + critical_emails_only = true + } + } + member_assigned_active { + role_assignment_alert { + default_recipients = true + additional_recipients = ["role_assignment_alert@member_assigned_active.com"] + critical_emails_only = true + } + assigned_user { + default_recipients = true + additional_recipients = ["assigned_user@member_assigned_active.com"] + critical_emails_only = true + } + request_for_extension_or_approval { + default_recipients = true + additional_recipients = ["request_for_extension_or_approval@member_assigned_active.com"] + critical_emails_only = true + } + } + eligible_member_activate { + role_assignment_alert { + default_recipients = true + additional_recipients = ["role_assignment_alert@eligible_member_activate.com"] + critical_emails_only = true + } + assigned_user { + default_recipients = true + additional_recipients = ["assigned_user@eligible_member_activate.com"] + critical_emails_only = true + } + request_for_extension_or_approval { + default_recipients = true + critical_emails_only = true + } + } + } +} + + +`, id, data.Locations.Primary) +} + +func (RoleManagementPolicyResource) resource(data acceptance.TestData, id int) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_subscription" "primary" {} + +data "azurerm_role_definition" "test" { + name = "Monitoring Reader" +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_virtual_network" "test" { + name = "amtestVNET1-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + address_space = ["10.0.0.0/16"] +} + +resource "azurerm_role_management_policy" "test" { + scope = azurerm_virtual_network.test.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + + activation { + maximum_duration_hours = 16 + + require_multi_factor_authentication = false + require_justification = false + require_ticket_information = false + } + + assignment { + eligible { + allow_permanent = true + } + + active { + allow_permanent = true + require_multi_factor_authentication = false + require_justification = false + } + } +} +`, id, data.Locations.Primary) +} diff --git a/internal/services/authorization/validate/role_management_policy.go b/internal/services/authorization/validate/role_management_policy.go new file mode 100644 index 000000000000..2bfd4a13e548 --- /dev/null +++ b/internal/services/authorization/validate/role_management_policy.go @@ -0,0 +1,37 @@ +package validate + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/authorization/parse" +) + +func ValidateRoleManagementPolicyId(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + ids := strings.Split(v, "|") + if len(ids) != 2 { + errors = append(errors, fmt.Errorf("expected %q to be in format roleManagementPolicyId|roleDefinitionId", v)) + return + } + + _, err := rolemanagementpolicies.ParseScopedRoleManagementPolicyID(ids[0]) + if err != nil { + errors = append(errors, fmt.Errorf("expected %s to be in format roleManagementPolicyId, %+v", ids[0], err)) + return + } + + _, err = parse.RoleDefinitionId(ids[1]) + if err != nil { + errors = append(errors, fmt.Errorf("expected %s to be in format roleManagementPolicyId, %+v", ids[1], err)) + return + } + + return +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/README.md b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/README.md new file mode 100644 index 000000000000..bac83c3fe3f3 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/README.md @@ -0,0 +1,90 @@ + +## `github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies` Documentation + +The `rolemanagementpolicies` SDK allows for interaction with the Azure Resource Manager Service `authorization` (API Version `2020-10-01`). + +This readme covers example usages, but further information on [using this SDK can be found in the project root](https://github.com/hashicorp/go-azure-sdk/tree/main/docs). + +### Import Path + +```go +import "github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies" +``` + + +### Client Initialization + +```go +client := rolemanagementpolicies.NewRoleManagementPoliciesClientWithBaseURI("https://management.azure.com") +client.Client.Authorizer = authorizer +``` + + +### Example Usage: `RoleManagementPoliciesClient.Delete` + +```go +ctx := context.TODO() +id := rolemanagementpolicies.NewScopedRoleManagementPolicyID("/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/some-resource-group", "roleManagementPolicyValue") + +read, err := client.Delete(ctx, id) +if err != nil { + // handle the error +} +if model := read.Model; model != nil { + // do something with the model/response object +} +``` + + +### Example Usage: `RoleManagementPoliciesClient.Get` + +```go +ctx := context.TODO() +id := rolemanagementpolicies.NewScopedRoleManagementPolicyID("/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/some-resource-group", "roleManagementPolicyValue") + +read, err := client.Get(ctx, id) +if err != nil { + // handle the error +} +if model := read.Model; model != nil { + // do something with the model/response object +} +``` + + +### Example Usage: `RoleManagementPoliciesClient.ListForScope` + +```go +ctx := context.TODO() +id := rolemanagementpolicies.NewScopeID("/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/some-resource-group") + +// alternatively `client.ListForScope(ctx, id, rolemanagementpolicies.DefaultListForScopeOperationOptions())` can be used to do batched pagination +items, err := client.ListForScopeComplete(ctx, id, rolemanagementpolicies.DefaultListForScopeOperationOptions()) +if err != nil { + // handle the error +} +for _, item := range items { + // do something +} +``` + + +### Example Usage: `RoleManagementPoliciesClient.Update` + +```go +ctx := context.TODO() +id := rolemanagementpolicies.NewScopedRoleManagementPolicyID("/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/some-resource-group", "roleManagementPolicyValue") + +payload := rolemanagementpolicies.RoleManagementPolicy{ + // ... +} + + +read, err := client.Update(ctx, id, payload) +if err != nil { + // handle the error +} +if model := read.Model; model != nil { + // do something with the model/response object +} +``` diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/client.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/client.go new file mode 100644 index 000000000000..89e8d75169ce --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/client.go @@ -0,0 +1,26 @@ +package rolemanagementpolicies + +import ( + "fmt" + + "github.com/hashicorp/go-azure-sdk/sdk/client/resourcemanager" + sdkEnv "github.com/hashicorp/go-azure-sdk/sdk/environments" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type RoleManagementPoliciesClient struct { + Client *resourcemanager.Client +} + +func NewRoleManagementPoliciesClientWithBaseURI(sdkApi sdkEnv.Api) (*RoleManagementPoliciesClient, error) { + client, err := resourcemanager.NewResourceManagerClient(sdkApi, "rolemanagementpolicies", defaultApiVersion) + if err != nil { + return nil, fmt.Errorf("instantiating RoleManagementPoliciesClient: %+v", err) + } + + return &RoleManagementPoliciesClient{ + Client: client, + }, nil +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/constants.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/constants.go new file mode 100644 index 000000000000..34d30a7f0494 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/constants.go @@ -0,0 +1,60 @@ +package rolemanagementpolicies + +import ( + "encoding/json" + "fmt" + "strings" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type RoleManagementPolicyRuleType string + +const ( + RoleManagementPolicyRuleTypeRoleManagementPolicyApprovalRule RoleManagementPolicyRuleType = "RoleManagementPolicyApprovalRule" + RoleManagementPolicyRuleTypeRoleManagementPolicyAuthenticationContextRule RoleManagementPolicyRuleType = "RoleManagementPolicyAuthenticationContextRule" + RoleManagementPolicyRuleTypeRoleManagementPolicyEnablementRule RoleManagementPolicyRuleType = "RoleManagementPolicyEnablementRule" + RoleManagementPolicyRuleTypeRoleManagementPolicyExpirationRule RoleManagementPolicyRuleType = "RoleManagementPolicyExpirationRule" + RoleManagementPolicyRuleTypeRoleManagementPolicyNotificationRule RoleManagementPolicyRuleType = "RoleManagementPolicyNotificationRule" +) + +func PossibleValuesForRoleManagementPolicyRuleType() []string { + return []string{ + string(RoleManagementPolicyRuleTypeRoleManagementPolicyApprovalRule), + string(RoleManagementPolicyRuleTypeRoleManagementPolicyAuthenticationContextRule), + string(RoleManagementPolicyRuleTypeRoleManagementPolicyEnablementRule), + string(RoleManagementPolicyRuleTypeRoleManagementPolicyExpirationRule), + string(RoleManagementPolicyRuleTypeRoleManagementPolicyNotificationRule), + } +} + +func (s *RoleManagementPolicyRuleType) UnmarshalJSON(bytes []byte) error { + var decoded string + if err := json.Unmarshal(bytes, &decoded); err != nil { + return fmt.Errorf("unmarshaling: %+v", err) + } + out, err := parseRoleManagementPolicyRuleType(decoded) + if err != nil { + return fmt.Errorf("parsing %q: %+v", decoded, err) + } + *s = *out + return nil +} + +func parseRoleManagementPolicyRuleType(input string) (*RoleManagementPolicyRuleType, error) { + vals := map[string]RoleManagementPolicyRuleType{ + "rolemanagementpolicyapprovalrule": RoleManagementPolicyRuleTypeRoleManagementPolicyApprovalRule, + "rolemanagementpolicyauthenticationcontextrule": RoleManagementPolicyRuleTypeRoleManagementPolicyAuthenticationContextRule, + "rolemanagementpolicyenablementrule": RoleManagementPolicyRuleTypeRoleManagementPolicyEnablementRule, + "rolemanagementpolicyexpirationrule": RoleManagementPolicyRuleTypeRoleManagementPolicyExpirationRule, + "rolemanagementpolicynotificationrule": RoleManagementPolicyRuleTypeRoleManagementPolicyNotificationRule, + } + if v, ok := vals[strings.ToLower(input)]; ok { + return &v, nil + } + + // otherwise presume it's an undefined value and best-effort it + out := RoleManagementPolicyRuleType(input) + return &out, nil +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/id_scopedrolemanagementpolicy.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/id_scopedrolemanagementpolicy.go new file mode 100644 index 000000000000..545ad0e8818b --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/id_scopedrolemanagementpolicy.go @@ -0,0 +1,113 @@ +package rolemanagementpolicies + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +var _ resourceids.ResourceId = ScopedRoleManagementPolicyId{} + +// ScopedRoleManagementPolicyId is a struct representing the Resource ID for a Scoped Role Management Policy +type ScopedRoleManagementPolicyId struct { + Scope string + RoleManagementPolicyName string +} + +// NewScopedRoleManagementPolicyID returns a new ScopedRoleManagementPolicyId struct +func NewScopedRoleManagementPolicyID(scope string, roleManagementPolicyName string) ScopedRoleManagementPolicyId { + return ScopedRoleManagementPolicyId{ + Scope: scope, + RoleManagementPolicyName: roleManagementPolicyName, + } +} + +// ParseScopedRoleManagementPolicyID parses 'input' into a ScopedRoleManagementPolicyId +func ParseScopedRoleManagementPolicyID(input string) (*ScopedRoleManagementPolicyId, error) { + parser := resourceids.NewParserFromResourceIdType(ScopedRoleManagementPolicyId{}) + parsed, err := parser.Parse(input, false) + if err != nil { + return nil, fmt.Errorf("parsing %q: %+v", input, err) + } + + var ok bool + id := ScopedRoleManagementPolicyId{} + + if id.Scope, ok = parsed.Parsed["scope"]; !ok { + return nil, resourceids.NewSegmentNotSpecifiedError(id, "scope", *parsed) + } + + if id.RoleManagementPolicyName, ok = parsed.Parsed["roleManagementPolicyName"]; !ok { + return nil, resourceids.NewSegmentNotSpecifiedError(id, "roleManagementPolicyName", *parsed) + } + + return &id, nil +} + +// ParseScopedRoleManagementPolicyIDInsensitively parses 'input' case-insensitively into a ScopedRoleManagementPolicyId +// note: this method should only be used for API response data and not user input +func ParseScopedRoleManagementPolicyIDInsensitively(input string) (*ScopedRoleManagementPolicyId, error) { + parser := resourceids.NewParserFromResourceIdType(ScopedRoleManagementPolicyId{}) + parsed, err := parser.Parse(input, true) + if err != nil { + return nil, fmt.Errorf("parsing %q: %+v", input, err) + } + + var ok bool + id := ScopedRoleManagementPolicyId{} + + if id.Scope, ok = parsed.Parsed["scope"]; !ok { + return nil, resourceids.NewSegmentNotSpecifiedError(id, "scope", *parsed) + } + + if id.RoleManagementPolicyName, ok = parsed.Parsed["roleManagementPolicyName"]; !ok { + return nil, resourceids.NewSegmentNotSpecifiedError(id, "roleManagementPolicyName", *parsed) + } + + return &id, nil +} + +// ValidateScopedRoleManagementPolicyID checks that 'input' can be parsed as a Scoped Role Management Policy ID +func ValidateScopedRoleManagementPolicyID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := ParseScopedRoleManagementPolicyID(v); err != nil { + errors = append(errors, err) + } + + return +} + +// ID returns the formatted Scoped Role Management Policy ID +func (id ScopedRoleManagementPolicyId) ID() string { + fmtString := "/%s/providers/Microsoft.Authorization/roleManagementPolicies/%s" + return fmt.Sprintf(fmtString, strings.TrimPrefix(id.Scope, "/"), id.RoleManagementPolicyName) +} + +// Segments returns a slice of Resource ID Segments which comprise this Scoped Role Management Policy ID +func (id ScopedRoleManagementPolicyId) Segments() []resourceids.Segment { + return []resourceids.Segment{ + resourceids.ScopeSegment("scope", "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/some-resource-group"), + resourceids.StaticSegment("staticProviders", "providers", "providers"), + resourceids.ResourceProviderSegment("staticMicrosoftAuthorization", "Microsoft.Authorization", "Microsoft.Authorization"), + resourceids.StaticSegment("staticRoleManagementPolicies", "roleManagementPolicies", "roleManagementPolicies"), + resourceids.UserSpecifiedSegment("roleManagementPolicyName", "roleManagementPolicyValue"), + } +} + +// String returns a human-readable description of this Scoped Role Management Policy ID +func (id ScopedRoleManagementPolicyId) String() string { + components := []string{ + fmt.Sprintf("Scope: %q", id.Scope), + fmt.Sprintf("Role Management Policy Name: %q", id.RoleManagementPolicyName), + } + return fmt.Sprintf("Scoped Role Management Policy (%s)", strings.Join(components, "\n")) +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_delete.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_delete.go new file mode 100644 index 000000000000..568436b022d2 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_delete.go @@ -0,0 +1,47 @@ +package rolemanagementpolicies + +import ( + "context" + "net/http" + + "github.com/hashicorp/go-azure-sdk/sdk/client" + "github.com/hashicorp/go-azure-sdk/sdk/odata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type DeleteOperationResponse struct { + HttpResponse *http.Response + OData *odata.OData +} + +// Delete ... +func (c RoleManagementPoliciesClient) Delete(ctx context.Context, id ScopedRoleManagementPolicyId) (result DeleteOperationResponse, err error) { + opts := client.RequestOptions{ + ContentType: "application/json; charset=utf-8", + ExpectedStatusCodes: []int{ + http.StatusNoContent, + http.StatusOK, + }, + HttpMethod: http.MethodDelete, + Path: id.ID(), + } + + req, err := c.Client.NewRequest(ctx, opts) + if err != nil { + return + } + + var resp *client.Response + resp, err = req.Execute(ctx) + if resp != nil { + result.OData = resp.OData + result.HttpResponse = resp.Response + } + if err != nil { + return + } + + return +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_get.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_get.go new file mode 100644 index 000000000000..b38b04f63e6a --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_get.go @@ -0,0 +1,51 @@ +package rolemanagementpolicies + +import ( + "context" + "net/http" + + "github.com/hashicorp/go-azure-sdk/sdk/client" + "github.com/hashicorp/go-azure-sdk/sdk/odata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type GetOperationResponse struct { + HttpResponse *http.Response + OData *odata.OData + Model *RoleManagementPolicy +} + +// Get ... +func (c RoleManagementPoliciesClient) Get(ctx context.Context, id ScopedRoleManagementPolicyId) (result GetOperationResponse, err error) { + opts := client.RequestOptions{ + ContentType: "application/json; charset=utf-8", + ExpectedStatusCodes: []int{ + http.StatusOK, + }, + HttpMethod: http.MethodGet, + Path: id.ID(), + } + + req, err := c.Client.NewRequest(ctx, opts) + if err != nil { + return + } + + var resp *client.Response + resp, err = req.Execute(ctx) + if resp != nil { + result.OData = resp.OData + result.HttpResponse = resp.Response + } + if err != nil { + return + } + + if err = resp.Unmarshal(&result.Model); err != nil { + return + } + + return +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_listforscope.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_listforscope.go new file mode 100644 index 000000000000..aa93ddfe786a --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_listforscope.go @@ -0,0 +1,118 @@ +package rolemanagementpolicies + +import ( + "context" + "fmt" + "net/http" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-sdk/sdk/client" + "github.com/hashicorp/go-azure-sdk/sdk/odata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type ListForScopeOperationResponse struct { + HttpResponse *http.Response + OData *odata.OData + Model *[]RoleManagementPolicy +} + +type ListForScopeCompleteResult struct { + Items []RoleManagementPolicy +} + +type ListForScopeOperationOptions struct { + Filter *string +} + +func DefaultListForScopeOperationOptions() ListForScopeOperationOptions { + return ListForScopeOperationOptions{} +} + +func (o ListForScopeOperationOptions) ToHeaders() *client.Headers { + out := client.Headers{} + + return &out +} + +func (o ListForScopeOperationOptions) ToOData() *odata.Query { + out := odata.Query{} + return &out +} + +func (o ListForScopeOperationOptions) ToQuery() *client.QueryParams { + out := client.QueryParams{} + if o.Filter != nil { + out.Append("$filter", fmt.Sprintf("%v", *o.Filter)) + } + return &out +} + +// ListForScope ... +func (c RoleManagementPoliciesClient) ListForScope(ctx context.Context, id commonids.ScopeId, options ListForScopeOperationOptions) (result ListForScopeOperationResponse, err error) { + opts := client.RequestOptions{ + ContentType: "application/json; charset=utf-8", + ExpectedStatusCodes: []int{ + http.StatusOK, + }, + HttpMethod: http.MethodGet, + Path: fmt.Sprintf("%s/providers/Microsoft.Authorization/roleManagementPolicies", id.ID()), + OptionsObject: options, + } + + req, err := c.Client.NewRequest(ctx, opts) + if err != nil { + return + } + + var resp *client.Response + resp, err = req.ExecutePaged(ctx) + if resp != nil { + result.OData = resp.OData + result.HttpResponse = resp.Response + } + if err != nil { + return + } + + var values struct { + Values *[]RoleManagementPolicy `json:"value"` + } + if err = resp.Unmarshal(&values); err != nil { + return + } + + result.Model = values.Values + + return +} + +// ListForScopeComplete retrieves all the results into a single object +func (c RoleManagementPoliciesClient) ListForScopeComplete(ctx context.Context, id commonids.ScopeId, options ListForScopeOperationOptions) (ListForScopeCompleteResult, error) { + return c.ListForScopeCompleteMatchingPredicate(ctx, id, options, RoleManagementPolicyOperationPredicate{}) +} + +// ListForScopeCompleteMatchingPredicate retrieves all the results and then applies the predicate +func (c RoleManagementPoliciesClient) ListForScopeCompleteMatchingPredicate(ctx context.Context, id commonids.ScopeId, options ListForScopeOperationOptions, predicate RoleManagementPolicyOperationPredicate) (result ListForScopeCompleteResult, err error) { + items := make([]RoleManagementPolicy, 0) + + resp, err := c.ListForScope(ctx, id, options) + if err != nil { + err = fmt.Errorf("loading results: %+v", err) + return + } + if resp.Model != nil { + for _, v := range *resp.Model { + if predicate.Matches(v) { + items = append(items, v) + } + } + } + + result = ListForScopeCompleteResult{ + Items: items, + } + return +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_update.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_update.go new file mode 100644 index 000000000000..04cb1db8cb11 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/method_update.go @@ -0,0 +1,55 @@ +package rolemanagementpolicies + +import ( + "context" + "net/http" + + "github.com/hashicorp/go-azure-sdk/sdk/client" + "github.com/hashicorp/go-azure-sdk/sdk/odata" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type UpdateOperationResponse struct { + HttpResponse *http.Response + OData *odata.OData + Model *RoleManagementPolicy +} + +// Update ... +func (c RoleManagementPoliciesClient) Update(ctx context.Context, id ScopedRoleManagementPolicyId, input RoleManagementPolicy) (result UpdateOperationResponse, err error) { + opts := client.RequestOptions{ + ContentType: "application/json; charset=utf-8", + ExpectedStatusCodes: []int{ + http.StatusOK, + }, + HttpMethod: http.MethodPatch, + Path: id.ID(), + } + + req, err := c.Client.NewRequest(ctx, opts) + if err != nil { + return + } + + if err = req.Marshal(input); err != nil { + return + } + + var resp *client.Response + resp, err = req.Execute(ctx) + if resp != nil { + result.OData = resp.OData + result.HttpResponse = resp.Response + } + if err != nil { + return + } + + if err = resp.Unmarshal(&result.Model); err != nil { + return + } + + return +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_policyproperties.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_policyproperties.go new file mode 100644 index 000000000000..af2bc58ecd1d --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_policyproperties.go @@ -0,0 +1,8 @@ +package rolemanagementpolicies + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type PolicyProperties struct { + Scope *PolicyPropertiesScope `json:"scope,omitempty"` +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_policypropertiesscope.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_policypropertiesscope.go new file mode 100644 index 000000000000..5a70ff199bd6 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_policypropertiesscope.go @@ -0,0 +1,10 @@ +package rolemanagementpolicies + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type PolicyPropertiesScope struct { + DisplayName *string `json:"displayName,omitempty"` + Id *string `json:"id,omitempty"` + Type *string `json:"type,omitempty"` +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_principal.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_principal.go new file mode 100644 index 000000000000..ad3771f02ce0 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_principal.go @@ -0,0 +1,11 @@ +package rolemanagementpolicies + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type Principal struct { + DisplayName *string `json:"displayName,omitempty"` + Email *string `json:"email,omitempty"` + Id *string `json:"id,omitempty"` + Type *string `json:"type,omitempty"` +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicy.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicy.go new file mode 100644 index 000000000000..9c5cc478fd16 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicy.go @@ -0,0 +1,11 @@ +package rolemanagementpolicies + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type RoleManagementPolicy struct { + Id *string `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Properties *RoleManagementPolicyProperties `json:"properties,omitempty"` + Type *string `json:"type,omitempty"` +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicyproperties.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicyproperties.go new file mode 100644 index 000000000000..310d9b0cf682 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicyproperties.go @@ -0,0 +1,94 @@ +package rolemanagementpolicies + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/dates" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type RoleManagementPolicyProperties struct { + Description *string `json:"description,omitempty"` + DisplayName *string `json:"displayName,omitempty"` + EffectiveRules *[]RoleManagementPolicyRule `json:"effectiveRules,omitempty"` + IsOrganizationDefault *bool `json:"isOrganizationDefault,omitempty"` + LastModifiedBy *Principal `json:"lastModifiedBy,omitempty"` + LastModifiedDateTime *string `json:"lastModifiedDateTime,omitempty"` + PolicyProperties *PolicyProperties `json:"policyProperties,omitempty"` + Rules *[]RoleManagementPolicyRule `json:"rules,omitempty"` + Scope *string `json:"scope,omitempty"` +} + +func (o *RoleManagementPolicyProperties) GetLastModifiedDateTimeAsTime() (*time.Time, error) { + if o.LastModifiedDateTime == nil { + return nil, nil + } + return dates.ParseAsFormat(o.LastModifiedDateTime, "2006-01-02T15:04:05Z07:00") +} + +func (o *RoleManagementPolicyProperties) SetLastModifiedDateTimeAsTime(input time.Time) { + formatted := input.Format("2006-01-02T15:04:05Z07:00") + o.LastModifiedDateTime = &formatted +} + +var _ json.Unmarshaler = &RoleManagementPolicyProperties{} + +func (s *RoleManagementPolicyProperties) UnmarshalJSON(bytes []byte) error { + type alias RoleManagementPolicyProperties + var decoded alias + if err := json.Unmarshal(bytes, &decoded); err != nil { + return fmt.Errorf("unmarshaling into RoleManagementPolicyProperties: %+v", err) + } + + s.Description = decoded.Description + s.DisplayName = decoded.DisplayName + s.IsOrganizationDefault = decoded.IsOrganizationDefault + s.LastModifiedBy = decoded.LastModifiedBy + s.LastModifiedDateTime = decoded.LastModifiedDateTime + s.PolicyProperties = decoded.PolicyProperties + s.Scope = decoded.Scope + + var temp map[string]json.RawMessage + if err := json.Unmarshal(bytes, &temp); err != nil { + return fmt.Errorf("unmarshaling RoleManagementPolicyProperties into map[string]json.RawMessage: %+v", err) + } + + if v, ok := temp["effectiveRules"]; ok { + var listTemp []json.RawMessage + if err := json.Unmarshal(v, &listTemp); err != nil { + return fmt.Errorf("unmarshaling EffectiveRules into list []json.RawMessage: %+v", err) + } + + output := make([]RoleManagementPolicyRule, 0) + for i, val := range listTemp { + impl, err := unmarshalRoleManagementPolicyRuleImplementation(val) + if err != nil { + return fmt.Errorf("unmarshaling index %d field 'EffectiveRules' for 'RoleManagementPolicyProperties': %+v", i, err) + } + output = append(output, impl) + } + s.EffectiveRules = &output + } + + if v, ok := temp["rules"]; ok { + var listTemp []json.RawMessage + if err := json.Unmarshal(v, &listTemp); err != nil { + return fmt.Errorf("unmarshaling Rules into list []json.RawMessage: %+v", err) + } + + output := make([]RoleManagementPolicyRule, 0) + for i, val := range listTemp { + impl, err := unmarshalRoleManagementPolicyRuleImplementation(val) + if err != nil { + return fmt.Errorf("unmarshaling index %d field 'Rules' for 'RoleManagementPolicyProperties': %+v", i, err) + } + output = append(output, impl) + } + s.Rules = &output + } + return nil +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicyrule.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicyrule.go new file mode 100644 index 000000000000..4b68b9249791 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicyrule.go @@ -0,0 +1,44 @@ +package rolemanagementpolicies + +import ( + "encoding/json" + "fmt" +) + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type RoleManagementPolicyRule interface { +} + +// RawModeOfTransitImpl is returned when the Discriminated Value +// doesn't match any of the defined types +// NOTE: this should only be used when a type isn't defined for this type of Object (as a workaround) +// and is used only for Deserialization (e.g. this cannot be used as a Request Payload). +type RawRoleManagementPolicyRuleImpl struct { + Type string + Values map[string]interface{} +} + +func unmarshalRoleManagementPolicyRuleImplementation(input []byte) (RoleManagementPolicyRule, error) { + if input == nil { + return nil, nil + } + + var temp map[string]interface{} + if err := json.Unmarshal(input, &temp); err != nil { + return nil, fmt.Errorf("unmarshaling RoleManagementPolicyRule into map[string]interface: %+v", err) + } + + value, ok := temp["ruleType"].(string) + if !ok { + return nil, nil + } + + out := RawRoleManagementPolicyRuleImpl{ + Type: value, + Values: temp, + } + return out, nil + +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicyruletarget.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicyruletarget.go new file mode 100644 index 000000000000..b93dd22a7fe3 --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/model_rolemanagementpolicyruletarget.go @@ -0,0 +1,13 @@ +package rolemanagementpolicies + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type RoleManagementPolicyRuleTarget struct { + Caller *string `json:"caller,omitempty"` + EnforcedSettings *[]string `json:"enforcedSettings,omitempty"` + InheritableSettings *[]string `json:"inheritableSettings,omitempty"` + Level *string `json:"level,omitempty"` + Operations *[]string `json:"operations,omitempty"` + TargetObjects *[]string `json:"targetObjects,omitempty"` +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/predicates.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/predicates.go new file mode 100644 index 000000000000..7957ae7375fa --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/predicates.go @@ -0,0 +1,27 @@ +package rolemanagementpolicies + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +type RoleManagementPolicyOperationPredicate struct { + Id *string + Name *string + Type *string +} + +func (p RoleManagementPolicyOperationPredicate) Matches(input RoleManagementPolicy) bool { + + if p.Id != nil && (input.Id == nil || *p.Id != *input.Id) { + return false + } + + if p.Name != nil && (input.Name == nil || *p.Name != *input.Name) { + return false + } + + if p.Type != nil && (input.Type == nil || *p.Type != *input.Type) { + return false + } + + return true +} diff --git a/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/version.go b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/version.go new file mode 100644 index 000000000000..cbd840f2fced --- /dev/null +++ b/vendor/github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies/version.go @@ -0,0 +1,12 @@ +package rolemanagementpolicies + +import "fmt" + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See NOTICE.txt in the project root for license information. + +const defaultApiVersion = "2020-10-01" + +func userAgent() string { + return fmt.Sprintf("hashicorp/go-azure-sdk/rolemanagementpolicies/%s", defaultApiVersion) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 596706960dff..502f679015af 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -224,6 +224,7 @@ github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/role github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/roleassignmentschedulerequests github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/roleeligibilityscheduleinstances github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/roleeligibilityschedulerequests +github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2020-10-01/rolemanagementpolicies github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2022-04-01/roleassignments github.com/hashicorp/go-azure-sdk/resource-manager/authorization/2022-04-01/roledefinitions github.com/hashicorp/go-azure-sdk/resource-manager/automation/2015-10-31/webhook diff --git a/website/docs/r/role_management_policy.html.markdown b/website/docs/r/role_management_policy.html.markdown new file mode 100644 index 000000000000..f2fdf593df36 --- /dev/null +++ b/website/docs/r/role_management_policy.html.markdown @@ -0,0 +1,211 @@ +--- +subcategory: "Authorization" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_role_management_policy" +description: |- + Manages a Role Management Policy. +--- + +# azurerm_role_management_policy + +Manages a Role Management Policy. + +## Example Usage + +```hcl +data "azurerm_subscription" "primary" {} + +data "azurerm_role_definition" "test" { + name = "Monitoring Reader" +} + +resource "azurerm_role_management_policy" "test" { + scope = data.azurerm_subscription.primary.id + role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_role_definition.test.id}" + + activation { + maximum_duration_hours = 12 + } +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `role_definition_id` - (Required) The ID of the role definition id. + +* `scope` - (Required) The scope. + +--- + +* `activation` - (Optional) A `activation` block as defined below. + +* `assignment` - (Optional) A `assignment` block as defined below. + +* `notifications` - (Optional) A `notifications` block as defined below. + +--- + +A `activation` block supports the following: + +* `approvers` - (Optional) A `approvers` block as defined below. + +* `maximum_duration_hours` - (Optional) The maximum duration in hours for an activation.. + +* `require_justification` - (Optional) Is Justification required for an activation?. + +* `require_multi_factor_authentication` - (Optional) Is Multi Factor Authentication required for an activation? + +* `require_ticket_information` - (Optional) Is Ticket Information required for an activation?. + +--- + +A `active` block supports the following: + +* `allow_permanent` - (Optional) Allow permanent active assignment. Conflicts with `assignment.0.active.0.expire_after_days`,`assignment.0.active.0.expire_after_hours` + +* `expire_after_days` - (Optional) The number of days after an active assignments is expired. Conflicts with `assignment.0.active.0.allow_permanent`,`assignment.0.active.0.expire_after_hours` + +* `expire_after_hours` - (Optional) The number of hours after an active assignments is expired. Conflicts with `assignment.0.active.0.allow_permanent`,`assignment.0.active.0.expire_after_days` + +* `require_justification` - (Optional) Is Justification required for an active assignment? + +* `require_multi_factor_authentication` - (Optional) Is Multi Factor Authentication required for an active assignment? + +--- + +A `approvers` block supports the following: + +* `group` - (Optional) One or more `group` blocks as defined below. + +* `user` - (Optional) One or more `user` blocks as defined below. + +--- + +A `assigned_user` block supports the following: + +* `additional_recipients` - (Optional) List of additional recipients to email notifications. + +* `critical_emails_only` - (Optional) Will critical emails only be sent? + +* `default_recipients` - (Optional) Will notifications be sent to the default recipients? + +--- + +A `assignment` block supports the following: + +* `active` - (Optional) A `active` block as defined above. + +* `eligible` - (Optional) A `eligible` block as defined below. + +--- + +A `eligible` block supports the following: + +* `allow_permanent` - (Optional) Allow permanent eligible assignment. Conflicts with `assignment.0.eligible.0.expire_after_hours`,`assignment.0.eligible.0.expire_after_days` + +* `expire_after_days` - (Optional) The number of days after an eligible assignments is expired. Conflicts with `assignment.0.eligible.0.allow_permanent`,`assignment.0.eligible.0.expire_after_hours` + +* `expire_after_hours` - (Optional) The number of hours after an eligible assignments is expired. Conflicts with `assignment.0.eligible.0.allow_permanent`,`assignment.0.eligible.0.expire_after_days` + +--- + +A `eligible_member_activate` block supports the following: + +* `assigned_user` - (Optional) A `assigned_user` block as defined above. + +* `request_for_extension_or_approval` - (Optional) A `request_for_extension_or_approval` block as defined below. + +* `role_assignment_alert` - (Optional) A `role_assignment_alert` block as defined below. + +--- + +A `group` block supports the following: + +* `id` - (Required) The object id of a group. + +* `name` - (Required) The name of the group. + +--- + +A `member_assigned_active` block supports the following: + +* `assigned_user` - (Optional) A `assigned_user` block as defined above. + +* `request_for_extension_or_approval` - (Optional) A `request_for_extension_or_approval` block as defined below. + +* `role_assignment_alert` - (Optional) A `role_assignment_alert` block as defined below. + +--- + +A `member_assigned_eligible` block supports the following: + +* `assigned_user` - (Optional) A `assigned_user` block as defined above. + +* `request_for_extension_or_approval` - (Optional) A `request_for_extension_or_approval` block as defined below. + +* `role_assignment_alert` - (Optional) A `role_assignment_alert` block as defined below. + +--- + +A `notifications` block supports the following: + +* `eligible_member_activate` - (Optional) A `eligible_member_activate` block as defined above. + +* `member_assigned_active` - (Optional) A `member_assigned_active` block as defined above. + +* `member_assigned_eligible` - (Optional) A `member_assigned_eligible` block as defined above. + +--- + +A `request_for_extension_or_approval` block supports the following: + +* `additional_recipients` - (Optional) List of additional recipients to email notifications. + +* `critical_emails_only` - (Optional) Will critical emails only be sent? + +* `default_recipients` - (Optional) Will notifications be sent to the default recipients? + +--- + +A `role_assignment_alert` block supports the following: + +* `additional_recipients` - (Optional) List of additional recipients to email notifications. + +* `critical_emails_only` - (Optional) Will critical emails only be sent? + +* `default_recipients` - (Optional) Will notifications be sent to the default recipients? + +--- + +A `user` block supports the following: + +* `id` - (Required) The object id of a user. + +* `name` - (Required) The name of the user. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Role Management Policy. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Role Management Policy. +* `read` - (Defaults to 5 minutes) Used when retrieving the Role Management Policy. +* `update` - (Defaults to 30 minutes) Used when updating the Role Management Policy. +* `delete` - (Defaults to 30 minutes) Used when deleting the Role Management Policy. + +## Import + +Role Management Policies can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_role_management_policy.example /subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleManagementPolicies/00000000-0000-0000-0000-000000000000|/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleDefinitions/00000000-0000-0000-0000-000000000000 +``` + +-> **NOTE:** This ID is specific to Terraform - and is of the format `{roleManagementPolicyId}|{roleDefinitionId}`.