Manage GCP Dataplex Datascan IAM Bindings

The gcp:dataplex/datascanIamBinding:DatascanIamBinding resource, part of the Pulumi GCP provider, manages IAM access control for Dataplex Datascan resources by granting roles to members. This guide focuses on three capabilities: granting roles to multiple members with DatascanIamBinding, adding individual members incrementally with DatascanIamMember, and replacing entire policies with DatascanIamPolicy.

These resources reference existing Dataplex Datascan resources. DatascanIamPolicy cannot be used with DatascanIamBinding or DatascanIamMember (they conflict). DatascanIamBinding and DatascanIamMember can coexist only if they manage different roles. The examples are intentionally small. Combine them with your own datascan resources and identity management strategy.

Grant a role to multiple members at once

When multiple users, service accounts, or groups need the same level of access, you can grant a role to all of them with a single resource.

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

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

binding = gcp.dataplex.DatascanIamBinding("binding",
    project=basic_profile["project"],
    location=basic_profile["location"],
    data_scan_id=basic_profile["dataScanId"],
    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.NewDatascanIamBinding(ctx, "binding", &dataplex.DatascanIamBindingArgs{
			Project:    pulumi.Any(basicProfile.Project),
			Location:   pulumi.Any(basicProfile.Location),
			DataScanId: pulumi.Any(basicProfile.DataScanId),
			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.DatascanIamBinding("binding", new()
    {
        Project = basicProfile.Project,
        Location = basicProfile.Location,
        DataScanId = basicProfile.DataScanId,
        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.DatascanIamBinding;
import com.pulumi.gcp.dataplex.DatascanIamBindingArgs;
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 DatascanIamBinding("binding", DatascanIamBindingArgs.builder()
            .project(basicProfile.project())
            .location(basicProfile.location())
            .dataScanId(basicProfile.dataScanId())
            .role("roles/viewer")
            .members("user:jane@example.com")
            .build());

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

The members array lists all identities that receive the specified role. DatascanIamBinding is authoritative for this role: it replaces any existing members for roles/viewer but preserves other roles on the datascan. The dataScanId, location, and project properties identify which datascan to configure.

Add a single member to a role incrementally

As access needs evolve, you can add individual members to roles without affecting existing grants.

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

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

member = gcp.dataplex.DatascanIamMember("member",
    project=basic_profile["project"],
    location=basic_profile["location"],
    data_scan_id=basic_profile["dataScanId"],
    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.NewDatascanIamMember(ctx, "member", &dataplex.DatascanIamMemberArgs{
			Project:    pulumi.Any(basicProfile.Project),
			Location:   pulumi.Any(basicProfile.Location),
			DataScanId: pulumi.Any(basicProfile.DataScanId),
			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.DatascanIamMember("member", new()
    {
        Project = basicProfile.Project,
        Location = basicProfile.Location,
        DataScanId = basicProfile.DataScanId,
        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.DatascanIamMember;
import com.pulumi.gcp.dataplex.DatascanIamMemberArgs;
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 DatascanIamMember("member", DatascanIamMemberArgs.builder()
            .project(basicProfile.project())
            .location(basicProfile.location())
            .dataScanId(basicProfile.dataScanId())
            .role("roles/viewer")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:dataplex:DatascanIamMember
    properties:
      project: ${basicProfile.project}
      location: ${basicProfile.location}
      dataScanId: ${basicProfile.dataScanId}
      role: roles/viewer
      member: user:jane@example.com

The member property specifies one identity to add to the role. DatascanIamMember is non-authoritative: it adds this member to roles/viewer without removing other members already assigned to that role. This approach works well when access grants happen at different times or are managed by different teams.

Replace the entire IAM policy from a data source

Organizations with centralized IAM policies can define bindings once and apply them to multiple datascans.

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.DatascanIamPolicy("policy", {
    project: basicProfile.project,
    location: basicProfile.location,
    dataScanId: basicProfile.dataScanId,
    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.DatascanIamPolicy("policy",
    project=basic_profile["project"],
    location=basic_profile["location"],
    data_scan_id=basic_profile["dataScanId"],
    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.NewDatascanIamPolicy(ctx, "policy", &dataplex.DatascanIamPolicyArgs{
			Project:    pulumi.Any(basicProfile.Project),
			Location:   pulumi.Any(basicProfile.Location),
			DataScanId: pulumi.Any(basicProfile.DataScanId),
			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.DatascanIamPolicy("policy", new()
    {
        Project = basicProfile.Project,
        Location = basicProfile.Location,
        DataScanId = basicProfile.DataScanId,
        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.DatascanIamPolicy;
import com.pulumi.gcp.dataplex.DatascanIamPolicyArgs;
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 DatascanIamPolicy("policy", DatascanIamPolicyArgs.builder()
            .project(basicProfile.project())
            .location(basicProfile.location())
            .dataScanId(basicProfile.dataScanId())
            .policyData(admin.policyData())
            .build());

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

The policyData property accepts a complete IAM policy from the organizations.getIAMPolicy data source. DatascanIamPolicy is authoritative: it replaces the entire IAM policy on the datascan, removing any bindings not included in the policy data. This approach centralizes access control but requires careful coordination to avoid accidentally removing necessary grants.

Beyond these examples

These snippets focus on specific IAM management features: role-based access control with binding and member resources, and policy replacement from centralized sources. They’re intentionally minimal rather than complete access control solutions.

The examples reference pre-existing infrastructure such as Dataplex Datascan resources (by dataScanId) and GCP project and location configuration. They focus on configuring IAM access rather than provisioning the datascans themselves.

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

  • Conditional IAM bindings (condition property)
  • Custom role definitions and formatting
  • Conflict resolution between Policy, Binding, and Member resources
  • Federated identity and workload identity pool configuration

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 Datascan IAM Binding resource reference for all available configuration options.

Let's manage GCP Dataplex Datascan IAM Bindings

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
Can I use DatascanIamPolicy with DatascanIamBinding or DatascanIamMember?
No, DatascanIamPolicy cannot be used with DatascanIamBinding or DatascanIamMember as they will conflict over policy management. Choose one approach: use Policy for full control, or use Binding/Member for granular management.
Can I use DatascanIamBinding and DatascanIamMember together?
Yes, but only if they don’t grant privileges to the same role. Each role must be managed by only one resource type to avoid conflicts.
What's the difference between DatascanIamPolicy, DatascanIamBinding, and DatascanIamMember?

Three levels of control:

  1. DatascanIamPolicy - Authoritative, replaces the entire IAM policy
  2. DatascanIamBinding - Authoritative for a specific role, preserves other roles
  3. DatascanIamMember - Non-authoritative, adds individual members while preserving existing members
Configuration & Identity Formats
What member identity formats are supported?

Supported formats include:

  • allUsers or allAuthenticatedUsers for public/authenticated access
  • user:{email}, serviceAccount:{email}, group:{email} for specific identities
  • domain:{domain} for G Suite domains
  • projectOwner/Editor/Viewer:{projectid} for project-level roles
  • Federated identities using principal:// format
How do I use custom IAM roles?
Custom roles must use the format [projects|organizations]/{parent-name}/roles/{role-name}. For example, projects/my-project/roles/my-custom-role.
How do I grant a role to a single user?
Use DatascanIamMember with the member property set to user:{email}, such as user:jane@example.com.
Immutability & Import
What properties can't be changed after creation?
The following properties are immutable: dataScanId, location, project, role, and condition. Changing these requires recreating the resource.
What import formats are supported?
Four formats are supported: projects/{{project}}/locations/{{location}}/dataScans/{{data_scan_id}}, {{project}}/{{location}}/{{data_scan_id}}, {{location}}/{{data_scan_id}}, or just {{data_scan_id}}. Missing values are taken from the provider configuration.

Using a different cloud?

Explore security guides for other cloud providers: