The gcp:projects/iAMPolicy:IAMPolicy resource family, part of the Pulumi GCP provider, manages IAM access control for GCP projects through four distinct resources. IAMPolicy replaces the entire policy (authoritative), IAMBinding controls all members for a specific role (role-authoritative), IAMMember adds individual members without affecting others (non-authoritative), and IAMAuditConfig enables audit logging. This guide focuses on four capabilities: role-based access with IAMBinding, incremental grants with IAMMember, time-based conditional access, and audit logging.
These resources require an existing GCP project and reference user or service account identities that must already exist. The examples are intentionally small. Combine them with your own project structure and identity management.
Grant a role to multiple members with IAMBinding
When you need to manage all members for a specific role as a single unit, IAMBinding provides authoritative control over that role’s membership list.
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 IAMBinding resource takes complete ownership of the specified role. The members array lists all identities that should have this role; anyone not in the list loses access. This is useful when you want to define the complete membership for a role in one place, but it cannot be mixed with IAMMember resources for the same role.
Add time-based conditions to role bindings
Temporary access grants often require expiration dates to limit privilege duration without manual cleanup.
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")
IAM conditions use Common Expression Language (CEL) to define access constraints. The expression property evaluates at request time; here, request.time < timestamp("2020-01-01T00:00:00Z") automatically revokes access after the specified date. The title and description properties document the condition’s purpose. Note that conditions cannot be used with Basic Roles like Owner.
Add a single member to a role with IAMMember
Applications that grant access incrementally need non-authoritative updates that preserve existing role members.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const project = new gcp.projects.IAMMember("project", {
project: "your-project-id",
role: "roles/editor",
member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp
project = gcp.projects.IAMMember("project",
project="your-project-id",
role="roles/editor",
member="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.NewIAMMember(ctx, "project", &projects.IAMMemberArgs{
Project: pulumi.String("your-project-id"),
Role: pulumi.String("roles/editor"),
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 project = new Gcp.Projects.IAMMember("project", new()
{
Project = "your-project-id",
Role = "roles/editor",
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.projects.IAMMember;
import com.pulumi.gcp.projects.IAMMemberArgs;
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 IAMMember("project", IAMMemberArgs.builder()
.project("your-project-id")
.role("roles/editor")
.member("user:jane@example.com")
.build());
}
}
resources:
project:
type: gcp:projects:IAMMember
properties:
project: your-project-id
role: roles/editor
member: user:jane@example.com
The IAMMember resource adds one identity to a role without affecting other members. Unlike IAMBinding, multiple IAMMember resources can target the same role, making it suitable for incremental grants. The member property uses the format type:identity (e.g., user:, serviceAccount:, group:).
Enable audit logging for project operations
Compliance requirements often mandate logging of administrative actions and data access across all services.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const project = new gcp.projects.IAMAuditConfig("project", {
project: "your-project-id",
service: "allServices",
auditLogConfigs: [
{
logType: "ADMIN_READ",
},
{
logType: "DATA_READ",
exemptedMembers: ["user:joebloggs@example.com"],
},
],
});
import pulumi
import pulumi_gcp as gcp
project = gcp.projects.IAMAuditConfig("project",
project="your-project-id",
service="allServices",
audit_log_configs=[
{
"log_type": "ADMIN_READ",
},
{
"log_type": "DATA_READ",
"exempted_members": ["user:joebloggs@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.NewIAMAuditConfig(ctx, "project", &projects.IAMAuditConfigArgs{
Project: pulumi.String("your-project-id"),
Service: pulumi.String("allServices"),
AuditLogConfigs: projects.IAMAuditConfigAuditLogConfigArray{
&projects.IAMAuditConfigAuditLogConfigArgs{
LogType: pulumi.String("ADMIN_READ"),
},
&projects.IAMAuditConfigAuditLogConfigArgs{
LogType: pulumi.String("DATA_READ"),
ExemptedMembers: pulumi.StringArray{
pulumi.String("user:joebloggs@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.IAMAuditConfig("project", new()
{
Project = "your-project-id",
Service = "allServices",
AuditLogConfigs = new[]
{
new Gcp.Projects.Inputs.IAMAuditConfigAuditLogConfigArgs
{
LogType = "ADMIN_READ",
},
new Gcp.Projects.Inputs.IAMAuditConfigAuditLogConfigArgs
{
LogType = "DATA_READ",
ExemptedMembers = new[]
{
"user:joebloggs@example.com",
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.projects.IAMAuditConfig;
import com.pulumi.gcp.projects.IAMAuditConfigArgs;
import com.pulumi.gcp.projects.inputs.IAMAuditConfigAuditLogConfigArgs;
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 IAMAuditConfig("project", IAMAuditConfigArgs.builder()
.project("your-project-id")
.service("allServices")
.auditLogConfigs(
IAMAuditConfigAuditLogConfigArgs.builder()
.logType("ADMIN_READ")
.build(),
IAMAuditConfigAuditLogConfigArgs.builder()
.logType("DATA_READ")
.exemptedMembers("user:joebloggs@example.com")
.build())
.build());
}
}
resources:
project:
type: gcp:projects:IAMAuditConfig
properties:
project: your-project-id
service: allServices
auditLogConfigs:
- logType: ADMIN_READ
- logType: DATA_READ
exemptedMembers:
- user:joebloggs@example.com
The IAMAuditConfig resource enables Cloud Audit Logs for the specified service. The service property can target specific APIs or use allServices for project-wide logging. Each auditLogConfig entry specifies a logType (ADMIN_READ, DATA_READ, DATA_WRITE) and optional exemptedMembers who bypass logging. This generates logs in Cloud Logging for security analysis and compliance audits.
Beyond these examples
These snippets focus on specific IAM management features: role binding and member management, conditional access with time constraints, and audit logging configuration. They’re intentionally minimal rather than full access control systems.
The examples require pre-existing infrastructure such as a GCP project with project ID, and user accounts or service accounts to grant access to. They focus on configuring IAM policies rather than provisioning the underlying project or identity infrastructure.
To keep things focused, common IAM patterns are omitted, including:
- IAMPolicy resource (authoritative, replaces entire policy)
- Organization-level IAM (focuses on project scope)
- Custom role definitions
- Service account impersonation
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 Projects IAMPolicy resource reference for all available configuration options.
Let's configure GCP Project IAM Policies
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 but preserves other roles. gcp.projects.IAMMember is non-authoritative and preserves other members for the same role. gcp.projects.IAMAuditConfig is authoritative for audit logging configuration for a service.gcp.projects.IAMPolicy cannot be used with gcp.projects.IAMBinding, gcp.projects.IAMMember, or gcp.projects.IAMAuditConfig because they will conflict over the policy configuration.Lockout Prevention & Safety
gcp.projects.IAMPolicy removes access from anyone without organization-level access to the project. It’s not recommended to use gcp.projects.IAMPolicy with your provider project to avoid locking yourself out.gcp.projects.IAMPolicy only with projects fully managed by Pulumi. Avoid using it with your provider project to prevent lockout.IAM Conditions
condition block with title, description, and expression properties. For example, to expire access at a specific time: expression: "request.time < timestamp(\"2020-01-01T00:00:00Z\")".Configuration
gcp.organizations.getIAMPolicy data source to generate the policyData. The policy will be merged with any existing policy on the project.project parameter is required and must be explicitly specified. It’s not inferred from the provider configuration.