The gcp:projects/iAMBinding:IAMBinding resource, part of the Pulumi GCP provider, grants a GCP IAM role to a list of members with authoritative control over that specific role. This guide focuses on two capabilities: granting roles to multiple members and adding time-based conditional access.
IAMBinding is authoritative for a given role, replacing any existing members for that role while preserving other roles in the project. This differs from IAMMember (additive, non-authoritative) and IAMPolicy (replaces entire policy). The examples are intentionally small. Combine them with your own project structure and access requirements.
Grant a role to multiple members at once
Teams managing project access often grant the same role to multiple users, service accounts, or groups simultaneously.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const project = new gcp.projects.IAMBinding("project", {
project: "your-project-id",
role: "roles/editor",
members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp
project = gcp.projects.IAMBinding("project",
project="your-project-id",
role="roles/editor",
members=["user:jane@example.com"])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := projects.NewIAMBinding(ctx, "project", &projects.IAMBindingArgs{
Project: pulumi.String("your-project-id"),
Role: pulumi.String("roles/editor"),
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 project = new Gcp.Projects.IAMBinding("project", new()
{
Project = "your-project-id",
Role = "roles/editor",
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.projects.IAMBinding;
import com.pulumi.gcp.projects.IAMBindingArgs;
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 project = new IAMBinding("project", IAMBindingArgs.builder()
.project("your-project-id")
.role("roles/editor")
.members("user:jane@example.com")
.build());
}
}
resources:
project:
type: gcp:projects:IAMBinding
properties:
project: your-project-id
role: roles/editor
members:
- user:jane@example.com
The members array lists all identities that receive the specified role. Each entry uses a prefix (user:, serviceAccount:, group:, or domain:) followed by the identifier. IAMBinding is authoritative: it replaces any existing members for this role, so include everyone who needs access.
Add time-based access with IAM Conditions
Temporary access grants require expiration logic to automatically revoke permissions after a deadline.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const project = new gcp.projects.IAMBinding("project", {
project: "your-project-id",
role: "roles/container.admin",
members: ["user:jane@example.com"],
condition: {
title: "expires_after_2019_12_31",
description: "Expiring at midnight of 2019-12-31",
expression: "request.time < timestamp(\"2020-01-01T00:00:00Z\")",
},
});
import pulumi
import pulumi_gcp as gcp
project = gcp.projects.IAMBinding("project",
project="your-project-id",
role="roles/container.admin",
members=["user:jane@example.com"],
condition={
"title": "expires_after_2019_12_31",
"description": "Expiring at midnight of 2019-12-31",
"expression": "request.time < timestamp(\"2020-01-01T00:00:00Z\")",
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := projects.NewIAMBinding(ctx, "project", &projects.IAMBindingArgs{
Project: pulumi.String("your-project-id"),
Role: pulumi.String("roles/container.admin"),
Members: pulumi.StringArray{
pulumi.String("user:jane@example.com"),
},
Condition: &projects.IAMBindingConditionArgs{
Title: pulumi.String("expires_after_2019_12_31"),
Description: pulumi.String("Expiring at midnight of 2019-12-31"),
Expression: pulumi.String("request.time < timestamp(\"2020-01-01T00:00:00Z\")"),
},
})
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 project = new Gcp.Projects.IAMBinding("project", new()
{
Project = "your-project-id",
Role = "roles/container.admin",
Members = new[]
{
"user:jane@example.com",
},
Condition = new Gcp.Projects.Inputs.IAMBindingConditionArgs
{
Title = "expires_after_2019_12_31",
Description = "Expiring at midnight of 2019-12-31",
Expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.projects.IAMBinding;
import com.pulumi.gcp.projects.IAMBindingArgs;
import com.pulumi.gcp.projects.inputs.IAMBindingConditionArgs;
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 project = new IAMBinding("project", IAMBindingArgs.builder()
.project("your-project-id")
.role("roles/container.admin")
.members("user:jane@example.com")
.condition(IAMBindingConditionArgs.builder()
.title("expires_after_2019_12_31")
.description("Expiring at midnight of 2019-12-31")
.expression("request.time < timestamp(\"2020-01-01T00:00:00Z\")")
.build())
.build());
}
}
resources:
project:
type: gcp:projects:IAMBinding
properties:
project: your-project-id
role: roles/container.admin
members:
- user:jane@example.com
condition:
title: expires_after_2019_12_31
description: Expiring at midnight of 2019-12-31
expression: request.time < timestamp("2020-01-01T00:00:00Z")
The condition block attaches constraints to the role binding. The expression property uses Common Expression Language (CEL) to define when access is valid. Here, request.time < timestamp(“2020-01-01T00:00:00Z”) grants access until midnight on December 31, 2019. The title must be unique within the project and role combination.
Beyond these examples
These snippets focus on specific IAMBinding features: authoritative role binding and time-based conditional access. They’re intentionally minimal rather than full access control systems.
The examples reference pre-existing infrastructure such as a GCP project with valid project ID. They focus on configuring role bindings rather than provisioning projects or defining custom roles.
To keep things focused, common IAM patterns are omitted, including:
- Non-authoritative member grants (use IAMMember for additive access)
- Full policy replacement (use IAMPolicy for complete policy control)
- Audit logging configuration (use IAMAuditConfig)
- Custom role definitions and formats
These omissions are intentional: the goal is to illustrate how IAMBinding wires role grants, not provide drop-in access control modules. See the IAMBinding resource reference for all available configuration options.
Let's configure GCP Project IAM Bindings
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Resource Selection & Conflicts
gcp.projects.IAMPolicy is authoritative and replaces the entire IAM policy. gcp.projects.IAMBinding is authoritative for a specific role, preserving other roles. gcp.projects.IAMMember is non-authoritative, adding a single member to a role while preserving other members.gcp.projects.IAMPolicy cannot be used with gcp.projects.IAMBinding, gcp.projects.IAMMember, or gcp.projects.IAMAuditConfig as they will conflict. However, gcp.projects.IAMBinding can be used with gcp.projects.IAMMember only if they grant privileges to different roles.gcp.projects.IAMPolicy removes access from anyone without organization-level access. It’s not recommended for your provider project. Import the policy before applying changes, and only use with fully managed projects.Configuration & Constraints
[projects|organizations]/{parent-name}/roles/{role-name}. For example: projects/my-project/roles/my-custom-role.user:{emailid} for Google accounts, serviceAccount:{emailid} for service accounts, group:{emailid} for Google groups, and domain:{domain} for G Suite domains.gcp.projects.IAMBinding uses members (plural array) to grant a role to multiple identities, while gcp.projects.IAMMember uses member (singular) to grant a role to one identity.Immutability & Updates
project, role, and condition properties are immutable. Changing any of these requires recreating the resource.gcp.projects.IAMBinding can be used per role. Multiple bindings for the same role will conflict.Import & Migration
[projects/my-project|organizations/my-org]/roles/my-custom-role.terraform import google_project_iam_binding.my_project "{{your-project-id}} roles/{{role_id}} condition-title".