Manage GCP Pub/Sub Schema IAM Bindings

The gcp:pubsub/schemaIamBinding:SchemaIamBinding resource, part of the Pulumi GCP provider, manages IAM role bindings for Pub/Sub schemas by granting a specific role to a list of members. This guide focuses on two capabilities: authoritative role-to-members binding and adding individual members non-authoritatively.

This resource references existing Pub/Sub schemas and requires a GCP project with IAM enabled. The examples are intentionally small. Combine them with your own schema definitions and organizational IAM structure.

Grant a role to multiple members

Teams managing schemas often need to grant the same role to multiple users, service accounts, or groups at once.

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

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

binding = gcp.pubsub.SchemaIamBinding("binding",
    project=example["project"],
    schema=example["name"],
    role="roles/viewer",
    members=["user:jane@example.com"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := pubsub.NewSchemaIamBinding(ctx, "binding", &pubsub.SchemaIamBindingArgs{
			Project: pulumi.Any(example.Project),
			Schema:  pulumi.Any(example.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.PubSub.SchemaIamBinding("binding", new()
    {
        Project = example.Project,
        Schema = example.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.pubsub.SchemaIamBinding;
import com.pulumi.gcp.pubsub.SchemaIamBindingArgs;
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 SchemaIamBinding("binding", SchemaIamBindingArgs.builder()
            .project(example.project())
            .schema(example.name())
            .role("roles/viewer")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:pubsub:SchemaIamBinding
    properties:
      project: ${example.project}
      schema: ${example.name}
      role: roles/viewer
      members:
        - user:jane@example.com

The role property specifies which IAM role to grant (e.g., “roles/viewer”). The members array lists all identities that receive this role. SchemaIamBinding is authoritative for the specified role: it replaces any existing members for that role on the schema. The schema property references the schema by name, and project identifies the GCP project.

Add a single member to a role

When you need to grant access to one additional user without affecting existing members, SchemaIamMember adds that member while preserving other role assignments.

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

const member = new gcp.pubsub.SchemaIamMember("member", {
    project: example.project,
    schema: example.name,
    role: "roles/viewer",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.pubsub.SchemaIamMember("member",
    project=example["project"],
    schema=example["name"],
    role="roles/viewer",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := pubsub.NewSchemaIamMember(ctx, "member", &pubsub.SchemaIamMemberArgs{
			Project: pulumi.Any(example.Project),
			Schema:  pulumi.Any(example.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.PubSub.SchemaIamMember("member", new()
    {
        Project = example.Project,
        Schema = example.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.pubsub.SchemaIamMember;
import com.pulumi.gcp.pubsub.SchemaIamMemberArgs;
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 SchemaIamMember("member", SchemaIamMemberArgs.builder()
            .project(example.project())
            .schema(example.name())
            .role("roles/viewer")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:pubsub:SchemaIamMember
    properties:
      project: ${example.project}
      schema: ${example.name}
      role: roles/viewer
      member: user:jane@example.com

The member property specifies a single identity to add (e.g., “user:jane@example.com”). Unlike SchemaIamBinding, SchemaIamMember is non-authoritative: it adds this member to the role without removing existing members. You can use multiple SchemaIamMember resources for the same role, or combine them with SchemaIamBinding resources for different roles.

Beyond these examples

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

The examples may reference pre-existing infrastructure such as Pub/Sub schemas and a GCP project with IAM enabled. They focus on configuring IAM bindings rather than provisioning schemas or projects.

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

  • Conditional IAM bindings (condition property)
  • Policy-level management (SchemaIamPolicy resource)
  • Custom role definitions
  • Federated identity configuration

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

Let's manage GCP Pub/Sub Schema 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
What's the difference between SchemaIamPolicy, SchemaIamBinding, and SchemaIamMember?
SchemaIamPolicy is authoritative and replaces the entire IAM policy. SchemaIamBinding is authoritative for a specific role, preserving other roles. SchemaIamMember is non-authoritative, adding members to a role without affecting other members.
Can I use SchemaIamPolicy with SchemaIamBinding or SchemaIamMember?
No, SchemaIamPolicy cannot be used with SchemaIamBinding or SchemaIamMember because they will conflict over policy control.
Can I use SchemaIamBinding and SchemaIamMember together?
Yes, but only if they manage different roles. Using both for the same role causes conflicts.
Configuration & Usage
What member identity formats are supported?
Supported formats include allUsers, allAuthenticatedUsers, user:{email}, serviceAccount:{email}, group:{email}, domain:{domain}, projectOwner/Editor/Viewer:{projectid}, and federated identities like principal://iam.googleapis.com/....
How do I specify custom roles?
Custom roles must use the format [projects|organizations]/{parent-name}/roles/{role-name}, for example projects/my-project/roles/my-custom-role.
What properties can't be changed after creation?
The role, schema, project, and condition properties are immutable and cannot be changed after creation.
Can I create multiple SchemaIamBinding resources for the same schema?
Yes, but only one SchemaIamBinding per role. Multiple bindings are allowed if they manage different roles.
Import & Migration
What resource identifier formats can I use for import?
Three formats are supported: projects/{{project}}/schemas/{{name}}, {{project}}/{{name}}, or just {{name}}. Missing variables are taken from the provider configuration.

Using a different cloud?

Explore security guides for other cloud providers: