Manage IAM Permissions for GCP AI Notebooks

The gcp:notebooks/instanceIamMember:InstanceIamMember resource, part of the Pulumi GCP provider, manages IAM permissions for Cloud AI Notebooks instances by adding individual members to roles without affecting other role assignments. This guide focuses on three capabilities: adding single users to instance roles, granting roles to multiple users, and replacing entire IAM policies.

The Pulumi GCP provider offers three related IAM resources for notebook instances: InstanceIamMember (non-authoritative, adds one member), InstanceIamBinding (authoritative for a role, manages all members), and InstanceIamPolicy (authoritative for the entire policy). InstanceIamPolicy cannot be used with the other two resources, as they will conflict over policy state. The examples are intentionally small. Combine them with your own notebook instances and organizational access patterns.

Grant a single user access to a notebook instance

When individual data scientists need access to a specific notebook, you can grant permissions without affecting other users.

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

const member = new gcp.notebooks.InstanceIamMember("member", {
    project: instance.project,
    location: instance.location,
    instanceName: instance.name,
    role: "roles/viewer",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.notebooks.InstanceIamMember("member",
    project=instance["project"],
    location=instance["location"],
    instance_name=instance["name"],
    role="roles/viewer",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := notebooks.NewInstanceIamMember(ctx, "member", &notebooks.InstanceIamMemberArgs{
			Project:      pulumi.Any(instance.Project),
			Location:     pulumi.Any(instance.Location),
			InstanceName: pulumi.Any(instance.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.Notebooks.InstanceIamMember("member", new()
    {
        Project = instance.Project,
        Location = instance.Location,
        InstanceName = instance.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.notebooks.InstanceIamMember;
import com.pulumi.gcp.notebooks.InstanceIamMemberArgs;
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 InstanceIamMember("member", InstanceIamMemberArgs.builder()
            .project(instance.project())
            .location(instance.location())
            .instanceName(instance.name())
            .role("roles/viewer")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:notebooks:InstanceIamMember
    properties:
      project: ${instance.project}
      location: ${instance.location}
      instanceName: ${instance.name}
      role: roles/viewer
      member: user:jane@example.com

The member property specifies the identity receiving access, using formats like “user:jane@example.com” for Google accounts or “serviceAccount:…” for service accounts. The role property defines the permission level (e.g., “roles/viewer” for read-only access). This resource is non-authoritative: it adds the member to the role without removing other members who already have that role.

Grant multiple users the same role

Teams often need to give several users identical permissions, such as granting viewer access to all data scientists in a research group.

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

const binding = new gcp.notebooks.InstanceIamBinding("binding", {
    project: instance.project,
    location: instance.location,
    instanceName: instance.name,
    role: "roles/viewer",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.notebooks.InstanceIamBinding("binding",
    project=instance["project"],
    location=instance["location"],
    instance_name=instance["name"],
    role="roles/viewer",
    members=["user:jane@example.com"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := notebooks.NewInstanceIamBinding(ctx, "binding", &notebooks.InstanceIamBindingArgs{
			Project:      pulumi.Any(instance.Project),
			Location:     pulumi.Any(instance.Location),
			InstanceName: pulumi.Any(instance.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.Notebooks.InstanceIamBinding("binding", new()
    {
        Project = instance.Project,
        Location = instance.Location,
        InstanceName = instance.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.notebooks.InstanceIamBinding;
import com.pulumi.gcp.notebooks.InstanceIamBindingArgs;
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 InstanceIamBinding("binding", InstanceIamBindingArgs.builder()
            .project(instance.project())
            .location(instance.location())
            .instanceName(instance.name())
            .role("roles/viewer")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:notebooks:InstanceIamBinding
    properties:
      project: ${instance.project}
      location: ${instance.location}
      instanceName: ${instance.name}
      role: roles/viewer
      members:
        - user:jane@example.com

The InstanceIamBinding resource uses a members array instead of a single member property, allowing you to assign the same role to multiple identities at once. This resource is authoritative for the specified role: it replaces all existing members for that role with the list you provide. Other roles on the instance remain unchanged.

Replace all instance permissions with a policy document

Organizations with centralized access control sometimes need to enforce a complete IAM policy that replaces any existing permissions.

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.notebooks.InstanceIamPolicy("policy", {
    project: instance.project,
    location: instance.location,
    instanceName: instance.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.notebooks.InstanceIamPolicy("policy",
    project=instance["project"],
    location=instance["location"],
    instance_name=instance["name"],
    policy_data=admin.policy_data)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/notebooks"
	"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 = notebooks.NewInstanceIamPolicy(ctx, "policy", &notebooks.InstanceIamPolicyArgs{
			Project:      pulumi.Any(instance.Project),
			Location:     pulumi.Any(instance.Location),
			InstanceName: pulumi.Any(instance.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.Notebooks.InstanceIamPolicy("policy", new()
    {
        Project = instance.Project,
        Location = instance.Location,
        InstanceName = instance.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.notebooks.InstanceIamPolicy;
import com.pulumi.gcp.notebooks.InstanceIamPolicyArgs;
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 InstanceIamPolicy("policy", InstanceIamPolicyArgs.builder()
            .project(instance.project())
            .location(instance.location())
            .instanceName(instance.name())
            .policyData(admin.policyData())
            .build());

    }
}
resources:
  policy:
    type: gcp:notebooks:InstanceIamPolicy
    properties:
      project: ${instance.project}
      location: ${instance.location}
      instanceName: ${instance.name}
      policyData: ${admin.policyData}
variables:
  admin:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/viewer
            members:
              - user:jane@example.com

The InstanceIamPolicy resource takes a policyData property containing a complete IAM policy document, typically retrieved from getIAMPolicy. This resource is fully authoritative: it replaces the entire IAM policy on the instance. Use this pattern carefully, as it will remove any permissions not included in the policy document. InstanceIamPolicy cannot coexist with InstanceIamBinding or InstanceIamMember resources on the same instance.

Beyond these examples

These snippets focus on specific IAM management features: single-member and multi-member role grants, and authoritative policy replacement. They’re intentionally minimal rather than full access control systems.

The examples reference pre-existing infrastructure such as Cloud AI Notebooks instances and a GCP project with appropriate IAM permissions. They focus on configuring access rather than provisioning the notebook instances themselves.

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

  • Conditional IAM bindings (condition property)
  • Custom role definitions and formatting
  • Service account and federated identity principals
  • Policy conflict resolution between resource types

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

Let's manage IAM Permissions for GCP AI Notebooks

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
What's the difference between InstanceIamPolicy, InstanceIamBinding, and InstanceIamMember?
InstanceIamPolicy is fully authoritative and replaces the entire IAM policy. InstanceIamBinding is authoritative for a specific role, preserving other roles. InstanceIamMember is non-authoritative, adding a single member to a role while preserving other members.
Can I use InstanceIamPolicy together with InstanceIamBinding or InstanceIamMember?
No, InstanceIamPolicy cannot be used with InstanceIamBinding or InstanceIamMember because they will conflict over the policy configuration.
Can I use InstanceIamBinding and InstanceIamMember together?
Yes, but only if they don’t grant privileges to the same role. Using both for the same role will cause conflicts.
IAM Configuration
What member identity formats are supported?
Supported formats include allUsers, allAuthenticatedUsers, user:{email}, serviceAccount:{email}, group:{email}, domain:{domain}, projectOwner:projectid, projectEditor:projectid, projectViewer:projectid, and federated identities (e.g., principal://iam.googleapis.com/...).
How do I specify a custom IAM role?
Custom roles must use the format [projects|organizations]/{parent-name}/roles/{role-name}. For example, projects/my-project/roles/my-custom-role.
What happens if I don't specify location or project?
If not specified, location and project are parsed from the parent resource identifier. If still unavailable, they’re taken from the provider configuration.
Resource Properties
Can I change the role or member after creating the resource?
No, all input properties (instanceName, location, member, project, role, condition) are immutable and cannot be changed after creation.
How do I import an existing IAM member resource?
Use space-delimited identifiers: the resource path, role, and member identity. For example: pulumi import gcp:notebooks/instanceIamMember:InstanceIamMember editor "projects/{{project}}/locations/{{location}}/instances/{{instance_name}} roles/viewer user:jane@example.com".

Using a different cloud?

Explore iam guides for other cloud providers: