Manage GCP Dataplex AspectType IAM Policies

The gcp:dataplex/aspectTypeIamPolicy:AspectTypeIamPolicy resource, part of the Pulumi GCP provider, manages IAM policies for Dataplex AspectType resources, controlling who can access and modify aspect type definitions. This guide focuses on three capabilities: authoritative policy replacement, role-based member grants, and incremental member additions.

These resources reference an existing AspectType and require the Dataplex API enabled in your project. The examples are intentionally small. Combine them with your own AspectType resources and organizational IAM structure.

Replace the entire IAM policy authoritatively

When you need complete control over AspectType access, replacing the entire IAM policy ensures no unexpected permissions remain.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const admin = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/viewer",
        members: ["user:jane@example.com"],
    }],
});
const policy = new gcp.dataplex.AspectTypeIamPolicy("policy", {
    project: testAspectTypeBasic.project,
    location: testAspectTypeBasic.location,
    aspectTypeId: testAspectTypeBasic.aspectTypeId,
    policyData: admin.then(admin => admin.policyData),
});
import pulumi
import pulumi_gcp as gcp

admin = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/viewer",
    "members": ["user:jane@example.com"],
}])
policy = gcp.dataplex.AspectTypeIamPolicy("policy",
    project=test_aspect_type_basic["project"],
    location=test_aspect_type_basic["location"],
    aspect_type_id=test_aspect_type_basic["aspectTypeId"],
    policy_data=admin.policy_data)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dataplex"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		admin, err := organizations.LookupIAMPolicy(ctx, &organizations.LookupIAMPolicyArgs{
			Bindings: []organizations.GetIAMPolicyBinding{
				{
					Role: "roles/viewer",
					Members: []string{
						"user:jane@example.com",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = dataplex.NewAspectTypeIamPolicy(ctx, "policy", &dataplex.AspectTypeIamPolicyArgs{
			Project:      pulumi.Any(testAspectTypeBasic.Project),
			Location:     pulumi.Any(testAspectTypeBasic.Location),
			AspectTypeId: pulumi.Any(testAspectTypeBasic.AspectTypeId),
			PolicyData:   pulumi.String(admin.PolicyData),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var admin = Gcp.Organizations.GetIAMPolicy.Invoke(new()
    {
        Bindings = new[]
        {
            new Gcp.Organizations.Inputs.GetIAMPolicyBindingInputArgs
            {
                Role = "roles/viewer",
                Members = new[]
                {
                    "user:jane@example.com",
                },
            },
        },
    });

    var policy = new Gcp.DataPlex.AspectTypeIamPolicy("policy", new()
    {
        Project = testAspectTypeBasic.Project,
        Location = testAspectTypeBasic.Location,
        AspectTypeId = testAspectTypeBasic.AspectTypeId,
        PolicyData = admin.Apply(getIAMPolicyResult => getIAMPolicyResult.PolicyData),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetIAMPolicyArgs;
import com.pulumi.gcp.dataplex.AspectTypeIamPolicy;
import com.pulumi.gcp.dataplex.AspectTypeIamPolicyArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var admin = OrganizationsFunctions.getIAMPolicy(GetIAMPolicyArgs.builder()
            .bindings(GetIAMPolicyBindingArgs.builder()
                .role("roles/viewer")
                .members("user:jane@example.com")
                .build())
            .build());

        var policy = new AspectTypeIamPolicy("policy", AspectTypeIamPolicyArgs.builder()
            .project(testAspectTypeBasic.project())
            .location(testAspectTypeBasic.location())
            .aspectTypeId(testAspectTypeBasic.aspectTypeId())
            .policyData(admin.policyData())
            .build());

    }
}
resources:
  policy:
    type: gcp:dataplex:AspectTypeIamPolicy
    properties:
      project: ${testAspectTypeBasic.project}
      location: ${testAspectTypeBasic.location}
      aspectTypeId: ${testAspectTypeBasic.aspectTypeId}
      policyData: ${admin.policyData}
variables:
  admin:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/viewer
            members:
              - user:jane@example.com

AspectTypeIamPolicy sets the complete IAM policy, removing any permissions not explicitly defined. The policyData comes from getIAMPolicy, which constructs a policy document from bindings. This approach is authoritative: it replaces the existing policy entirely. The aspectTypeId, location, and project properties identify which AspectType to manage.

Grant a role to multiple members at once

Teams often grant the same role to several users simultaneously, maintaining consistent permissions for that role.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const binding = new gcp.dataplex.AspectTypeIamBinding("binding", {
    project: testAspectTypeBasic.project,
    location: testAspectTypeBasic.location,
    aspectTypeId: testAspectTypeBasic.aspectTypeId,
    role: "roles/viewer",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.dataplex.AspectTypeIamBinding("binding",
    project=test_aspect_type_basic["project"],
    location=test_aspect_type_basic["location"],
    aspect_type_id=test_aspect_type_basic["aspectTypeId"],
    role="roles/viewer",
    members=["user:jane@example.com"])
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dataplex"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := dataplex.NewAspectTypeIamBinding(ctx, "binding", &dataplex.AspectTypeIamBindingArgs{
			Project:      pulumi.Any(testAspectTypeBasic.Project),
			Location:     pulumi.Any(testAspectTypeBasic.Location),
			AspectTypeId: pulumi.Any(testAspectTypeBasic.AspectTypeId),
			Role:         pulumi.String("roles/viewer"),
			Members: pulumi.StringArray{
				pulumi.String("user:jane@example.com"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var binding = new Gcp.DataPlex.AspectTypeIamBinding("binding", new()
    {
        Project = testAspectTypeBasic.Project,
        Location = testAspectTypeBasic.Location,
        AspectTypeId = testAspectTypeBasic.AspectTypeId,
        Role = "roles/viewer",
        Members = new[]
        {
            "user:jane@example.com",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dataplex.AspectTypeIamBinding;
import com.pulumi.gcp.dataplex.AspectTypeIamBindingArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var binding = new AspectTypeIamBinding("binding", AspectTypeIamBindingArgs.builder()
            .project(testAspectTypeBasic.project())
            .location(testAspectTypeBasic.location())
            .aspectTypeId(testAspectTypeBasic.aspectTypeId())
            .role("roles/viewer")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:dataplex:AspectTypeIamBinding
    properties:
      project: ${testAspectTypeBasic.project}
      location: ${testAspectTypeBasic.location}
      aspectTypeId: ${testAspectTypeBasic.aspectTypeId}
      role: roles/viewer
      members:
        - user:jane@example.com

AspectTypeIamBinding manages all members for a specific role. The members array lists everyone who should have this role. Unlike AspectTypeIamPolicy, this resource is authoritative only for the specified role; other roles on the AspectType remain unchanged. You can use multiple Binding resources for different roles without conflicts.

Add a single member to a role incrementally

When onboarding individual users, adding them one at a time avoids disrupting existing assignments.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const member = new gcp.dataplex.AspectTypeIamMember("member", {
    project: testAspectTypeBasic.project,
    location: testAspectTypeBasic.location,
    aspectTypeId: testAspectTypeBasic.aspectTypeId,
    role: "roles/viewer",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.dataplex.AspectTypeIamMember("member",
    project=test_aspect_type_basic["project"],
    location=test_aspect_type_basic["location"],
    aspect_type_id=test_aspect_type_basic["aspectTypeId"],
    role="roles/viewer",
    member="user:jane@example.com")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dataplex"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := dataplex.NewAspectTypeIamMember(ctx, "member", &dataplex.AspectTypeIamMemberArgs{
			Project:      pulumi.Any(testAspectTypeBasic.Project),
			Location:     pulumi.Any(testAspectTypeBasic.Location),
			AspectTypeId: pulumi.Any(testAspectTypeBasic.AspectTypeId),
			Role:         pulumi.String("roles/viewer"),
			Member:       pulumi.String("user:jane@example.com"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var member = new Gcp.DataPlex.AspectTypeIamMember("member", new()
    {
        Project = testAspectTypeBasic.Project,
        Location = testAspectTypeBasic.Location,
        AspectTypeId = testAspectTypeBasic.AspectTypeId,
        Role = "roles/viewer",
        Member = "user:jane@example.com",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dataplex.AspectTypeIamMember;
import com.pulumi.gcp.dataplex.AspectTypeIamMemberArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var member = new AspectTypeIamMember("member", AspectTypeIamMemberArgs.builder()
            .project(testAspectTypeBasic.project())
            .location(testAspectTypeBasic.location())
            .aspectTypeId(testAspectTypeBasic.aspectTypeId())
            .role("roles/viewer")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:dataplex:AspectTypeIamMember
    properties:
      project: ${testAspectTypeBasic.project}
      location: ${testAspectTypeBasic.location}
      aspectTypeId: ${testAspectTypeBasic.aspectTypeId}
      role: roles/viewer
      member: user:jane@example.com

AspectTypeIamMember grants a role to one member without affecting other members of that role. This is the most granular approach: it’s non-authoritative, meaning it adds to existing permissions rather than replacing them. The member property uses the format “user:email”, “serviceAccount:email”, or “group:email”. You can combine multiple Member resources for the same role, and they won’t conflict with each other.

Beyond these examples

These snippets focus on specific IAM management approaches: authoritative vs incremental IAM management, and role-based and member-based access control. They’re intentionally minimal rather than full access control configurations.

The examples reference pre-existing infrastructure such as Dataplex AspectType resources and a GCP project with Dataplex API enabled. They focus on IAM policy configuration rather than provisioning the AspectTypes themselves.

To keep things focused, common IAM patterns are omitted, including:

  • Conditional IAM bindings (conditions)
  • Custom role definitions
  • Service account impersonation
  • IAM policy etag handling for concurrent updates

These omissions are intentional: the goal is to illustrate how each IAM resource type is wired, not provide drop-in access control modules. See the AspectTypeIamPolicy resource reference for all available configuration options.

Let's manage GCP Dataplex AspectType IAM Policies

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Resource Selection & Conflicts
Which IAM resource should I use for managing AspectType permissions?

You have three options:

  1. AspectTypeIamPolicy - Authoritative, replaces the entire IAM policy
  2. AspectTypeIamBinding - Authoritative for a specific role, preserves other roles
  3. AspectTypeIamMember - Non-authoritative, adds a single member to a role
Can I use AspectTypeIamPolicy with AspectTypeIamBinding or AspectTypeIamMember?
No, AspectTypeIamPolicy cannot be used with AspectTypeIamBinding or AspectTypeIamMember because they will conflict over the policy state.
Can I use AspectTypeIamBinding and AspectTypeIamMember together?
Yes, but only if they manage different roles. Using both for the same role will cause conflicts.
Configuration & Setup
How do I generate the policyData for AspectTypeIamPolicy?
Use the gcp.organizations.getIAMPolicy data source to define your bindings, then pass its policyData output to the AspectTypeIamPolicy resource.
Do I need to specify project and location for IAM resources?
Not necessarily. Both project and location can be parsed from the parent resource identifier or taken from the provider configuration if not explicitly specified.
How do I import IAM resources with custom roles?
Use the full custom role name in the format [projects/my-project|organizations/my-org]/roles/my-custom-role when importing.

Using a different cloud?

Explore security guides for other cloud providers: