Manage GCP Data Catalog Entry Group IAM Policies

The gcp:datacatalog/entryGroupIamPolicy:EntryGroupIamPolicy resource, part of the Pulumi GCP provider, manages IAM policies for Data Catalog entry groups. This resource is deprecated; Google recommends migrating to gcp.dataplex.EntryGroup for new deployments. This guide focuses on three capabilities: authoritative policy replacement, role-level member binding, and individual member grants.

IAM resources for entry groups come in three variants with different levels of authority. EntryGroupIamPolicy replaces the entire policy, EntryGroupIamBinding manages all members for a specific role, and EntryGroupIamMember adds individual members. The examples are intentionally small. Combine them with your own entry group infrastructure and access requirements.

Replace the entire IAM policy for an entry group

When you need complete control over who can access an entry group, you can set the entire IAM policy at once.

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.datacatalog.EntryGroupIamPolicy("policy", {
    entryGroup: basicEntryGroup.name,
    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.datacatalog.EntryGroupIamPolicy("policy",
    entry_group=basic_entry_group["name"],
    policy_data=admin.policy_data)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/datacatalog"
	"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 = datacatalog.NewEntryGroupIamPolicy(ctx, "policy", &datacatalog.EntryGroupIamPolicyArgs{
			EntryGroup: pulumi.Any(basicEntryGroup.Name),
			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.DataCatalog.EntryGroupIamPolicy("policy", new()
    {
        EntryGroup = basicEntryGroup.Name,
        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.datacatalog.EntryGroupIamPolicy;
import com.pulumi.gcp.datacatalog.EntryGroupIamPolicyArgs;
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 EntryGroupIamPolicy("policy", EntryGroupIamPolicyArgs.builder()
            .entryGroup(basicEntryGroup.name())
            .policyData(admin.policyData())
            .build());

    }
}
resources:
  policy:
    type: gcp:datacatalog:EntryGroupIamPolicy
    properties:
      entryGroup: ${basicEntryGroup.name}
      policyData: ${admin.policyData}
variables:
  admin:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/viewer
            members:
              - user:jane@example.com

The EntryGroupIamPolicy resource is authoritative: it replaces all existing IAM bindings on the entry group. The policyData property accepts output from the getIAMPolicy data source, which defines roles and members in a structured format. This approach gives you full control but requires careful coordination, since it cannot be used alongside EntryGroupIamBinding or EntryGroupIamMember resources.

Grant a role to multiple members at once

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

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

const binding = new gcp.datacatalog.EntryGroupIamBinding("binding", {
    entryGroup: basicEntryGroup.name,
    role: "roles/viewer",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.datacatalog.EntryGroupIamBinding("binding",
    entry_group=basic_entry_group["name"],
    role="roles/viewer",
    members=["user:jane@example.com"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := datacatalog.NewEntryGroupIamBinding(ctx, "binding", &datacatalog.EntryGroupIamBindingArgs{
			EntryGroup: pulumi.Any(basicEntryGroup.Name),
			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.DataCatalog.EntryGroupIamBinding("binding", new()
    {
        EntryGroup = basicEntryGroup.Name,
        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.datacatalog.EntryGroupIamBinding;
import com.pulumi.gcp.datacatalog.EntryGroupIamBindingArgs;
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 EntryGroupIamBinding("binding", EntryGroupIamBindingArgs.builder()
            .entryGroup(basicEntryGroup.name())
            .role("roles/viewer")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:datacatalog:EntryGroupIamBinding
    properties:
      entryGroup: ${basicEntryGroup.name}
      role: roles/viewer
      members:
        - user:jane@example.com

The EntryGroupIamBinding resource is authoritative for a specific role: it replaces all members for that role while preserving other roles on the entry group. The members property accepts a list of identities (users, service accounts, groups). You can use multiple EntryGroupIamBinding resources for different roles, but only one binding per role to avoid conflicts.

Add a single member to a role incrementally

When you need to grant access to one user without affecting existing permissions, you can add individual members.

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

const member = new gcp.datacatalog.EntryGroupIamMember("member", {
    entryGroup: basicEntryGroup.name,
    role: "roles/viewer",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.datacatalog.EntryGroupIamMember("member",
    entry_group=basic_entry_group["name"],
    role="roles/viewer",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := datacatalog.NewEntryGroupIamMember(ctx, "member", &datacatalog.EntryGroupIamMemberArgs{
			EntryGroup: pulumi.Any(basicEntryGroup.Name),
			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.DataCatalog.EntryGroupIamMember("member", new()
    {
        EntryGroup = basicEntryGroup.Name,
        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.datacatalog.EntryGroupIamMember;
import com.pulumi.gcp.datacatalog.EntryGroupIamMemberArgs;
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 EntryGroupIamMember("member", EntryGroupIamMemberArgs.builder()
            .entryGroup(basicEntryGroup.name())
            .role("roles/viewer")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:datacatalog:EntryGroupIamMember
    properties:
      entryGroup: ${basicEntryGroup.name}
      role: roles/viewer
      member: user:jane@example.com

The EntryGroupIamMember resource is non-authoritative: it adds a single member to a role without removing existing members. This is the safest approach when multiple teams manage access independently. You can combine EntryGroupIamMember resources with EntryGroupIamBinding resources as long as they don’t grant the same role.

Beyond these examples

These snippets focus on specific IAM management features: authoritative vs non-authoritative IAM management, and policy-level, role-level, and member-level access control. They’re intentionally minimal rather than full access control configurations.

The examples reference pre-existing infrastructure such as Data Catalog entry groups (referenced by name). They focus on configuring IAM policies rather than provisioning the underlying catalog resources.

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

  • Project and region specification (defaults to provider config)
  • Conditional IAM bindings
  • Custom role definitions
  • Service account creation and management

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

Let's manage GCP Data Catalog Entry Group 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

Migration & Deprecation
Is this resource deprecated?
Yes, the parent resource gcp.datacatalog.EntryGroup is deprecated and will be removed in a future major release. Migrate to gcp.dataplex.EntryGroup instead. See the transition guide at https://cloud.google.com/dataplex/docs/transition-to-dataplex-catalog.
Resource Selection & Conflicts
What's the difference between EntryGroupIamPolicy, EntryGroupIamBinding, and EntryGroupIamMember?

Each resource has different authorization behavior:

  • EntryGroupIamPolicy: Authoritative, replaces the entire IAM policy
  • EntryGroupIamBinding: Authoritative for a specific role, preserves other roles
  • EntryGroupIamMember: Non-authoritative, adds a single member while preserving others
Which IAM resources can I use together?
You cannot use EntryGroupIamPolicy with EntryGroupIamBinding or EntryGroupIamMember (they will conflict). However, you can use EntryGroupIamBinding with EntryGroupIamMember only if they don’t grant the same role.
When should I use EntryGroupIamPolicy vs the other resources?
Use EntryGroupIamPolicy when you want complete control over the entire IAM policy. Use EntryGroupIamBinding or EntryGroupIamMember when you need to manage specific roles or members without affecting other permissions.
Configuration & Defaults
What properties are immutable after creation?
The entryGroup, project, and region properties are immutable and cannot be changed after the resource is created.
How do project and region defaults work?
If not specified, project and region are parsed from the parent resource identifier. If not present there, they default to the provider configuration.
Import & Management
How do I import an existing IAM policy?
Use the format: pulumi import gcp:datacatalog/entryGroupIamPolicy:EntryGroupIamPolicy editor projects/{{project}}/locations/{{region}}/entryGroups/{{entry_group}}

Using a different cloud?

Explore security guides for other cloud providers: