Skip to content

Commit

Permalink
Add Identity Governance roles and assignments
Browse files Browse the repository at this point in the history
  • Loading branch information
alexwilcox9 committed Feb 23, 2023
1 parent dbad923 commit 34dc70f
Show file tree
Hide file tree
Showing 8 changed files with 482 additions and 14 deletions.
49 changes: 49 additions & 0 deletions docs/data-sources/access_package_catalog_role.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
subcategory: "Identity Governance"
---

# Data Source: azuread_access_package_catalog_role

Gets information about an access package catalog role.

## API Permissions

The following API permissions are required in order to use this data source.

When authenticated with a service principal, this data source requires one of the following application roles: `EntitlementManagement.Read.All` or `Directory.Read.All`

When authenticated with a user principal, this data source does not require any additional roles.

## Example Usage (by Group Display Name)

*Look up by display name*
```terraform
data "azuread_access_package_catalog_role" "example" {
display_name = "Catalog owner"
}
```

*Look up by object ID*
```terraform
data "azuread_access_package_catalog_role" "example" {
object_id = "ae79f266-94d4-4dab-b730-feca7e132178"
}
```

## Argument Reference

The following arguments are supported:

* `display_name` - (Optional) Specifies the display name of the role.
* `object_id` - (Optional) Specifies the object ID of the role.

~> One of `display_name` or `object_id` must be specified.

## Attributes Reference

The following attributes are exported:

* `description` - The description of the role.
* `display_name` - The display name of the role.
* `object_id` - The object ID of the role.
* `template_id` - The object ID of the role.
61 changes: 61 additions & 0 deletions docs/resources/access_package_catalog_role_assignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
subcategory: "Identity Governance"
---

# Resource: azuread_access_package_catalog_role_assignment

Manages a single catalog role assignment within Azure Active Directory.

## API Permissions

The following API permissions are required in order to use this resource.

When authenticated with a service principal, this resource requires one of the following application roles: `EntitlementManagement.ReadWrite.All` or `Directory.ReadWrite.All`

When authenticated with a user principal, this resource requires one of the following directory roles: `Identity Governance administrator` or `Global Administrator`

## Example Usage

```terraform
data "azuread_user" "example" {
user_principal_name = "jdoe@hashicorp.com"
}
resource "azuread_access_package_catalog_role" "example" {
display_name = "Catalog owner"
}
resource "azuread_access_package_catalog" "example" {
display_name = "example-access-package-catalog"
description = "Example access package catalog"
}
resource "azuread_access_package_catalog_role_assignment" "example" {
role_id = azuread_access_package_catalog_role.example.object_id
principal_object_id = data.azuread_user.example.object_id
catalog_id = azuread_access_package_catalog.example.id
}
```


## Argument Reference

The following arguments are supported:

* `catalog_id` - (Required) The ID of the Catalog this role assignment will be scoped to. Changing this forces a new resource to be created.
* `principal_object_id` - (Required) The object ID of the principal for you want to create a role assignment. Supported object types are Users, Groups or Service Principals. Changing this forces a new resource to be created.
* `role_id` - (Required) The object ID of the catalog role you want to assign. Changing this forces a new resource to be created.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:

*No additional attributes are exported*

## Import

Catalog role assignments can be imported using the ID of the assignment, e.g.

```shell
terraform import azuread_access_package_catalog_role_assignment.test 00000000-0000-0000-0000-000000000000
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package identitygovernance

import (
"context"
"errors"
"fmt"
"log"
"net/http"
"strings"
"time"

"github.com/hashicorp/go-uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-azuread/internal/clients"
"github.com/hashicorp/terraform-provider-azuread/internal/tf"
"github.com/hashicorp/terraform-provider-azuread/internal/utils"
"github.com/hashicorp/terraform-provider-azuread/internal/validate"
"github.com/manicminer/hamilton/msgraph"
"github.com/manicminer/hamilton/odata"
)

func accessPackageCatalogRoleAssignmentResource() *schema.Resource {
return &schema.Resource{
CreateContext: accessPackageCatalogRoleAssignmentResourceCreate,
ReadContext: accessPackageCatalogRoleAssignmentResourceRead,
DeleteContext: accessPackageCatalogRoleRoleAssignmentResourceDelete,

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(5 * time.Minute),
Read: schema.DefaultTimeout(5 * time.Minute),
Update: schema.DefaultTimeout(5 * time.Minute),
Delete: schema.DefaultTimeout(5 * time.Minute),
},

Importer: tf.ValidateResourceIDPriorToImport(func(id string) error {
if _, err := uuid.ParseUUID(id); err != nil {
return fmt.Errorf("specified ID (%q) is not valid: %s", id, err)
}
return nil
}),

Schema: map[string]*schema.Schema{
"role_id": {
Description: "The object ID of the catalog role for this assignment",
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateDiagFunc: validate.UUID,
},

"principal_object_id": {
Description: "The object ID of the member principal",
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateDiagFunc: validate.UUID,
},

"catalog_id": {
Description: "The unique ID of the access package catalog.",
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateDiagFunc: validate.UUID,
},
},
}
}

func accessPackageCatalogRoleAssignmentResourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*clients.Client).IdentityGovernance.AccessPackageCatalogRoleAssignmentsClient

catalogId := d.Get("catalog_id").(string)
principalId := d.Get("principal_object_id").(string)
roleId := d.Get("role_id").(string)

properties := msgraph.UnifiedRoleAssignment{
DirectoryScopeId: utils.String("/"),
PrincipalId: utils.String(principalId),
RoleDefinitionId: utils.String(roleId),
AppScopeId: utils.String("/AccessPackageCatalog/" + catalogId),
}

assignment, status, err := client.Create(ctx, properties)
if err != nil {
return tf.ErrorDiagF(err, "Assigning catalog role %q to directory principal %q on catalog %q, received %d with error: %+v", roleId, principalId, catalogId, status, err)
}
if assignment == nil || assignment.ID() == nil {
return tf.ErrorDiagF(errors.New("returned role assignment ID was nil"), "API Error")
}

d.SetId(*assignment.ID())
return accessPackageCatalogRoleAssignmentResourceRead(ctx, d, meta)
}

func accessPackageCatalogRoleAssignmentResourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*clients.Client).IdentityGovernance.AccessPackageCatalogRoleAssignmentsClient

id := d.Id()
assignment, status, err := client.Get(ctx, id, odata.Query{})
if err != nil {
if status == http.StatusNotFound {
log.Printf("[DEBUG] Assignment with ID %q was not found - removing from state", id)
d.SetId("")
return nil
}
return tf.ErrorDiagF(err, "Retrieving role assignment %q", id)
}

catalogId := strings.TrimPrefix(*assignment.AppScopeId, "/AccessPackageCatalog/")

tf.Set(d, "catalog_id", utils.String(catalogId))
tf.Set(d, "principal_object_id", assignment.PrincipalId)
tf.Set(d, "role_id", assignment.RoleDefinitionId)

return nil
}

func accessPackageCatalogRoleRoleAssignmentResourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*clients.Client).IdentityGovernance.AccessPackageCatalogRoleAssignmentsClient

if _, err := client.Delete(ctx, d.Id()); err != nil {
return tf.ErrorDiagF(err, "Deleting role assignment %q: %+v", d.Id(), err)
}
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package identitygovernance_test

import (
"context"
"fmt"
"net/http"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/hashicorp/terraform-provider-azuread/internal/acceptance"
"github.com/hashicorp/terraform-provider-azuread/internal/acceptance/check"
"github.com/hashicorp/terraform-provider-azuread/internal/clients"
"github.com/hashicorp/terraform-provider-azuread/internal/utils"
"github.com/manicminer/hamilton/odata"
)

type AccessPackageCatalogRoleAssignmentResource struct{}

func TestAccAccessPackageCatalogRoleAssignmentResource_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "azuread_access_package_catalog_role_assignment", "test")
r := AccessPackageCatalogRoleAssignmentResource{}

data.DataSourceTest(t, []resource.TestStep{
{
Config: r.basic(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("catalog_id").IsUuid(),
check.That(data.ResourceName).Key("principal_object_id").IsUuid(),
check.That(data.ResourceName).Key("role_id").Exists(),
),
},
})
}

func (r AccessPackageCatalogRoleAssignmentResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) {
client := clients.IdentityGovernance.AccessPackageCatalogRoleAssignmentsClient
client.BaseClient.DisableRetries = true

if _, status, err := client.Get(ctx, state.ID, odata.Query{}); err != nil {
if status == http.StatusNotFound {
return utils.Bool(false), nil
}
return nil, fmt.Errorf("failed to retrieve directory role assignment %q: %+v", state.ID, err)
}

return utils.Bool(true), nil
}

func (AccessPackageCatalogRoleAssignmentResource) basic(data acceptance.TestData) string {
return fmt.Sprintf(`
%[1]s
data "azuread_access_package_catalog_role" "test" {
display_name = "Catalog owner"
}
data "azuread_domains" "test" {
only_initial = true
}
resource "azuread_user" "test" {
user_principal_name = "acctestUser'%[2]d@${data.azuread_domains.test.domains.0.domain_name}"
display_name = "acctestUser-%[2]d"
password = "%[3]s"
}
resource "azuread_access_package_catalog_role_assignment" "test" {
role_id = data.azuread_access_package_catalog_role.test.object_id
catalog_id = azuread_access_package_catalog.test.id
principal_object_id = azuread_user.test.object_id
}
`, AccessPackageCatalogResource{}.basic(data), data.RandomInteger, data.RandomPassword)
}
Loading

0 comments on commit 34dc70f

Please sign in to comment.