Manage GCP Bigtable Table IAM Access

The gcp:bigtable/tableIamMember:TableIamMember resource, part of the Pulumi GCP provider, grants IAM permissions on Bigtable tables by adding individual members to roles without affecting other members. This guide focuses on three capabilities: adding single members to roles, replacing all members for a role, and setting complete IAM policies.

GCP provides three related resources for managing table IAM: TableIamMember (non-authoritative, adds one member), TableIamBinding (authoritative for a role, replaces all members), and TableIamPolicy (authoritative, replaces entire policy). TableIamPolicy cannot be used with the other two resources, as they will conflict. The examples are intentionally small. Combine them with your own Bigtable infrastructure and identity management.

Grant a single user access to a table

Most access control starts by granting individual users or service accounts specific permissions without affecting other members’ access.

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

const editor = new gcp.bigtable.TableIamMember("editor", {
    table: "your-bigtable-table",
    instanceName: "your-bigtable-instance",
    role: "roles/bigtable.user",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

editor = gcp.bigtable.TableIamMember("editor",
    table="your-bigtable-table",
    instance_name="your-bigtable-instance",
    role="roles/bigtable.user",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := bigtable.NewTableIamMember(ctx, "editor", &bigtable.TableIamMemberArgs{
			Table:        pulumi.String("your-bigtable-table"),
			InstanceName: pulumi.String("your-bigtable-instance"),
			Role:         pulumi.String("roles/bigtable.user"),
			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 editor = new Gcp.BigTable.TableIamMember("editor", new()
    {
        Table = "your-bigtable-table",
        InstanceName = "your-bigtable-instance",
        Role = "roles/bigtable.user",
        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.bigtable.TableIamMember;
import com.pulumi.gcp.bigtable.TableIamMemberArgs;
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 editor = new TableIamMember("editor", TableIamMemberArgs.builder()
            .table("your-bigtable-table")
            .instanceName("your-bigtable-instance")
            .role("roles/bigtable.user")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  editor:
    type: gcp:bigtable:TableIamMember
    properties:
      table: your-bigtable-table
      instanceName: your-bigtable-instance
      role: roles/bigtable.user
      member: user:jane@example.com

TableIamMember adds one member to a role non-authoritatively. The member property specifies the identity (user, serviceAccount, group, or domain), and the role property defines the permission level. Other members with the same role remain unchanged. This resource is safe to use alongside other TableIamMember resources for the same table, even for the same role.

Define all members for a role at once

When you need to control exactly who has a specific role, TableIamBinding replaces the entire member list for that role while preserving other roles.

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

const editor = new gcp.bigtable.TableIamBinding("editor", {
    table: "your-bigtable-table",
    instanceName: "your-bigtable-instance",
    role: "roles/bigtable.user",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

editor = gcp.bigtable.TableIamBinding("editor",
    table="your-bigtable-table",
    instance_name="your-bigtable-instance",
    role="roles/bigtable.user",
    members=["user:jane@example.com"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := bigtable.NewTableIamBinding(ctx, "editor", &bigtable.TableIamBindingArgs{
			Table:        pulumi.String("your-bigtable-table"),
			InstanceName: pulumi.String("your-bigtable-instance"),
			Role:         pulumi.String("roles/bigtable.user"),
			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 editor = new Gcp.BigTable.TableIamBinding("editor", new()
    {
        Table = "your-bigtable-table",
        InstanceName = "your-bigtable-instance",
        Role = "roles/bigtable.user",
        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.bigtable.TableIamBinding;
import com.pulumi.gcp.bigtable.TableIamBindingArgs;
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 editor = new TableIamBinding("editor", TableIamBindingArgs.builder()
            .table("your-bigtable-table")
            .instanceName("your-bigtable-instance")
            .role("roles/bigtable.user")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  editor:
    type: gcp:bigtable:TableIamBinding
    properties:
      table: your-bigtable-table
      instanceName: your-bigtable-instance
      role: roles/bigtable.user
      members:
        - user:jane@example.com

TableIamBinding is authoritative for a single role. The members property lists all identities that should have the role; any existing members not in this list are removed. Other roles on the table remain unchanged. You can use multiple TableIamBinding resources on the same table as long as they manage different roles.

Replace the entire IAM policy for a table

TableIamPolicy sets the complete IAM policy, replacing any existing bindings. This approach works when you need full control over all roles and members.

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

const admin = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/bigtable.user",
        members: ["user:jane@example.com"],
    }],
});
const editor = new gcp.bigtable.TableIamPolicy("editor", {
    project: "your-project",
    instanceName: "your-bigtable-instance",
    table: "your-bigtable-table",
    policyData: admin.then(admin => admin.policyData),
});
import pulumi
import pulumi_gcp as gcp

admin = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/bigtable.user",
    "members": ["user:jane@example.com"],
}])
editor = gcp.bigtable.TableIamPolicy("editor",
    project="your-project",
    instance_name="your-bigtable-instance",
    table="your-bigtable-table",
    policy_data=admin.policy_data)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/bigtable"
	"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/bigtable.user",
					Members: []string{
						"user:jane@example.com",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = bigtable.NewTableIamPolicy(ctx, "editor", &bigtable.TableIamPolicyArgs{
			Project:      pulumi.String("your-project"),
			InstanceName: pulumi.String("your-bigtable-instance"),
			Table:        pulumi.String("your-bigtable-table"),
			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/bigtable.user",
                Members = new[]
                {
                    "user:jane@example.com",
                },
            },
        },
    });

    var editor = new Gcp.BigTable.TableIamPolicy("editor", new()
    {
        Project = "your-project",
        InstanceName = "your-bigtable-instance",
        Table = "your-bigtable-table",
        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.bigtable.TableIamPolicy;
import com.pulumi.gcp.bigtable.TableIamPolicyArgs;
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/bigtable.user")
                .members("user:jane@example.com")
                .build())
            .build());

        var editor = new TableIamPolicy("editor", TableIamPolicyArgs.builder()
            .project("your-project")
            .instanceName("your-bigtable-instance")
            .table("your-bigtable-table")
            .policyData(admin.policyData())
            .build());

    }
}
resources:
  editor:
    type: gcp:bigtable:TableIamPolicy
    properties:
      project: your-project
      instanceName: your-bigtable-instance
      table: your-bigtable-table
      policyData: ${admin.policyData}
variables:
  admin:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/bigtable.user
            members:
              - user:jane@example.com

TableIamPolicy is fully authoritative. The policyData property comes from getIAMPolicy, which defines all role bindings. Any existing policy is replaced entirely. This resource cannot coexist with TableIamBinding or TableIamMember on the same table, as they will conflict over policy ownership.

Beyond these examples

These snippets focus on specific IAM management approaches: incremental member grants, role-level member replacement, and complete policy replacement. They’re intentionally minimal rather than full access control configurations.

The examples reference pre-existing infrastructure such as Bigtable tables and instances, and GCP projects. They focus on granting access rather than provisioning the underlying resources.

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

  • Conditional IAM bindings (condition property)
  • Custom role definitions
  • Service account creation
  • Cross-project or organization-level policies

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

Let's manage GCP Bigtable Table IAM Access

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 Bigtable IAM resource should I use?
Choose based on your needs: gcp.bigtable.TableIamPolicy for complete policy control (replaces entire policy), gcp.bigtable.TableIamBinding for managing all members of a specific role (authoritative per role), or gcp.bigtable.TableIamMember for adding individual members without affecting others (non-authoritative).
Which IAM resources can I use together?
gcp.bigtable.TableIamPolicy cannot be used with gcp.bigtable.TableIamBinding or gcp.bigtable.TableIamMember, as they will conflict. However, gcp.bigtable.TableIamBinding and gcp.bigtable.TableIamMember can be used together only if they don’t grant privileges to the same role.
What happens if I use TableIamPolicy with other IAM resources?
They will conflict over policy management. gcp.bigtable.TableIamPolicy is authoritative and replaces the entire policy, while gcp.bigtable.TableIamBinding and gcp.bigtable.TableIamMember make incremental changes.
Can I accidentally remove table ownership with TableIamPolicy?
Yes, gcp.bigtable.TableIamPolicy replaces the entire IAM policy. Ensure all necessary permissions, including ownership, are included in your policy configuration.
IAM Configuration
What member identity formats are supported?

You can use:

  • allUsers - anyone on the internet
  • allAuthenticatedUsers - anyone with a Google account
  • user:{emailid} - specific Google account (e.g., alice@gmail.com)
  • serviceAccount:{emailid} - service account
  • group:{emailid} - Google group
  • domain:{domain} - all users of a G Suite domain
What's the format for custom roles?
Custom roles must follow 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 gcp.bigtable.TableIamMember with member set to user:{emailid} and specify the role, table, and instanceName.
Resource Properties & Immutability
What properties are immutable after creation?
All key properties are immutable: member, role, table, instanceName, and project. Changes to these require resource replacement.
Can I use TableIamBinding for multiple roles?
Yes, but only one gcp.bigtable.TableIamBinding resource can be used per role. Use separate binding resources for different roles.

Using a different cloud?

Explore security guides for other cloud providers: