Manage GCP Service Directory IAM Bindings

The gcp:servicedirectory/serviceIamBinding:ServiceIamBinding resource, part of the Pulumi GCP provider, manages IAM role bindings for Service Directory services. This guide focuses on two capabilities: granting roles to multiple members and adding individual members to roles.

IAM bindings reference existing Service Directory services. The examples are intentionally small. Combine them with your own Service Directory namespaces and services.

Grant a role to multiple members

Teams managing Service Directory services grant IAM roles to groups of users, service accounts, or other principals.

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

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

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

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := servicedirectory.NewServiceIamBinding(ctx, "binding", &servicedirectory.ServiceIamBindingArgs{
			Name: 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.ServiceDirectory.ServiceIamBinding("binding", new()
    {
        Name = 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.servicedirectory.ServiceIamBinding;
import com.pulumi.gcp.servicedirectory.ServiceIamBindingArgs;
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 ServiceIamBinding("binding", ServiceIamBindingArgs.builder()
            .name(example.name())
            .role("roles/viewer")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:servicedirectory:ServiceIamBinding
    properties:
      name: ${example.name}
      role: roles/viewer
      members:
        - user:jane@example.com

The role property specifies which permission set to grant (e.g., “roles/viewer”). The members array lists all principals who receive that role. ServiceIamBinding is authoritative for the specified role: it replaces any existing member list for that role, but preserves other roles on the service.

Add a single member to a role

When onboarding individual users or service accounts, ServiceIamMember adds one principal without affecting others.

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

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

member = gcp.servicedirectory.ServiceIamMember("member",
    name=example["name"],
    role="roles/viewer",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := servicedirectory.NewServiceIamMember(ctx, "member", &servicedirectory.ServiceIamMemberArgs{
			Name:   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.ServiceDirectory.ServiceIamMember("member", new()
    {
        Name = 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.servicedirectory.ServiceIamMember;
import com.pulumi.gcp.servicedirectory.ServiceIamMemberArgs;
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 ServiceIamMember("member", ServiceIamMemberArgs.builder()
            .name(example.name())
            .role("roles/viewer")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:servicedirectory:ServiceIamMember
    properties:
      name: ${example.name}
      role: roles/viewer
      member: user:jane@example.com

The member property (singular) specifies one principal to grant access. Unlike ServiceIamBinding, ServiceIamMember is non-authoritative: it adds the specified member without removing others already granted the same role. Use ServiceIamMember when you need incremental access grants; use ServiceIamBinding when you want to define the complete member list for a role.

Beyond these examples

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

The examples reference pre-existing infrastructure such as Service Directory services (namespace and service must exist). They focus on configuring IAM bindings rather than provisioning the services themselves.

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

  • Conditional IAM bindings (condition property)
  • Custom role definitions and formatting
  • ServiceIamPolicy for full policy replacement
  • Federated identity and workload identity pool configuration

These omissions are intentional: the goal is to illustrate how IAM bindings are wired, not provide drop-in access control modules. See the Service Directory ServiceIamBinding resource reference for all available configuration options.

Let's manage GCP Service Directory 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
Why are my IAM resources conflicting?
ServiceIamPolicy cannot be used with ServiceIamBinding or ServiceIamMember, as they will fight over the policy. Additionally, ServiceIamBinding and ServiceIamMember conflict if they grant privilege to the same role.
What's the difference between ServiceIamPolicy, ServiceIamBinding, and ServiceIamMember?
ServiceIamPolicy is authoritative and replaces the entire IAM policy. ServiceIamBinding is authoritative for a specific role, preserving other roles in the policy. ServiceIamMember is non-authoritative, adding a single member to a role while preserving other members for that role.
Can I use ServiceIamBinding with ServiceIamMember?
Yes, but only if they don’t grant privilege to the same role. Using both resources for the same role will cause conflicts.
Configuration & Roles
How do I specify a custom role?
Custom roles must use the full path format: [projects|organizations]/{parent-name}/roles/{role-name}. For example, projects/my-project/roles/my-custom-role or organizations/my-org/roles/my-custom-role.
Can I change the role after creating a ServiceIamBinding?
No, the role property is immutable. You must destroy and recreate the resource to change the role.
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
  • principal://... for federated identities (workload/workforce pools)

Using a different cloud?

Explore security guides for other cloud providers: