Manage GCP Workload Identity Pool IAM Members

The gcp:iam/workloadIdentityPoolIamMember:WorkloadIdentityPoolIamMember resource, part of the Pulumi GCP provider, grants IAM roles to individual members on workload identity pools without affecting other role assignments. This guide focuses on three capabilities: non-authoritative member grants, time-limited access with IAM Conditions, and authoritative role bindings.

Workload identity pools must exist before you can grant access to them. The examples are intentionally small. Combine them with your own pool configuration and federated identity setup.

Grant a single member access to a pool

Most access control starts by granting individual users or service accounts specific permissions without disrupting existing grants.

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

const member = new gcp.iam.WorkloadIdentityPoolIamMember("member", {
    project: example.project,
    workloadIdentityPoolId: example.workloadIdentityPoolId,
    role: "roles/iam.workloadIdentityPoolViewer",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.iam.WorkloadIdentityPoolIamMember("member",
    project=example["project"],
    workload_identity_pool_id=example["workloadIdentityPoolId"],
    role="roles/iam.workloadIdentityPoolViewer",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := iam.NewWorkloadIdentityPoolIamMember(ctx, "member", &iam.WorkloadIdentityPoolIamMemberArgs{
			Project:                pulumi.Any(example.Project),
			WorkloadIdentityPoolId: pulumi.Any(example.WorkloadIdentityPoolId),
			Role:                   pulumi.String("roles/iam.workloadIdentityPoolViewer"),
			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.Iam.WorkloadIdentityPoolIamMember("member", new()
    {
        Project = example.Project,
        WorkloadIdentityPoolId = example.WorkloadIdentityPoolId,
        Role = "roles/iam.workloadIdentityPoolViewer",
        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.iam.WorkloadIdentityPoolIamMember;
import com.pulumi.gcp.iam.WorkloadIdentityPoolIamMemberArgs;
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 WorkloadIdentityPoolIamMember("member", WorkloadIdentityPoolIamMemberArgs.builder()
            .project(example.project())
            .workloadIdentityPoolId(example.workloadIdentityPoolId())
            .role("roles/iam.workloadIdentityPoolViewer")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:iam:WorkloadIdentityPoolIamMember
    properties:
      project: ${example.project}
      workloadIdentityPoolId: ${example.workloadIdentityPoolId}
      role: roles/iam.workloadIdentityPoolViewer
      member: user:jane@example.com

The WorkloadIdentityPoolIamMember resource adds one member to a role non-authoritatively. The member property accepts user emails, service accounts, groups, or federated identities. Other members with the same role remain unchanged.

Add time-limited access with IAM Conditions

Temporary access grants expire automatically when conditions evaluate to false, eliminating manual cleanup.

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

const member = new gcp.iam.WorkloadIdentityPoolIamMember("member", {
    project: example.project,
    workloadIdentityPoolId: example.workloadIdentityPoolId,
    role: "roles/iam.workloadIdentityPoolViewer",
    member: "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

member = gcp.iam.WorkloadIdentityPoolIamMember("member",
    project=example["project"],
    workload_identity_pool_id=example["workloadIdentityPoolId"],
    role="roles/iam.workloadIdentityPoolViewer",
    member="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/iam"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := iam.NewWorkloadIdentityPoolIamMember(ctx, "member", &iam.WorkloadIdentityPoolIamMemberArgs{
			Project:                pulumi.Any(example.Project),
			WorkloadIdentityPoolId: pulumi.Any(example.WorkloadIdentityPoolId),
			Role:                   pulumi.String("roles/iam.workloadIdentityPoolViewer"),
			Member:                 pulumi.String("user:jane@example.com"),
			Condition: &iam.WorkloadIdentityPoolIamMemberConditionArgs{
				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 member = new Gcp.Iam.WorkloadIdentityPoolIamMember("member", new()
    {
        Project = example.Project,
        WorkloadIdentityPoolId = example.WorkloadIdentityPoolId,
        Role = "roles/iam.workloadIdentityPoolViewer",
        Member = "user:jane@example.com",
        Condition = new Gcp.Iam.Inputs.WorkloadIdentityPoolIamMemberConditionArgs
        {
            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.iam.WorkloadIdentityPoolIamMember;
import com.pulumi.gcp.iam.WorkloadIdentityPoolIamMemberArgs;
import com.pulumi.gcp.iam.inputs.WorkloadIdentityPoolIamMemberConditionArgs;
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 WorkloadIdentityPoolIamMember("member", WorkloadIdentityPoolIamMemberArgs.builder()
            .project(example.project())
            .workloadIdentityPoolId(example.workloadIdentityPoolId())
            .role("roles/iam.workloadIdentityPoolViewer")
            .member("user:jane@example.com")
            .condition(WorkloadIdentityPoolIamMemberConditionArgs.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:
  member:
    type: gcp:iam:WorkloadIdentityPoolIamMember
    properties:
      project: ${example.project}
      workloadIdentityPoolId: ${example.workloadIdentityPoolId}
      role: roles/iam.workloadIdentityPoolViewer
      member: 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 defines when access is valid. The expression property uses CEL syntax to compare request.time against a timestamp. The title and description properties document the condition’s purpose. When the timestamp passes, IAM automatically revokes access.

Manage all members for a role with binding

When you need to control the complete member list for a role, bindings provide authoritative management.

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

const binding = new gcp.iam.WorkloadIdentityPoolIamBinding("binding", {
    project: example.project,
    workloadIdentityPoolId: example.workloadIdentityPoolId,
    role: "roles/iam.workloadIdentityPoolViewer",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.iam.WorkloadIdentityPoolIamBinding("binding",
    project=example["project"],
    workload_identity_pool_id=example["workloadIdentityPoolId"],
    role="roles/iam.workloadIdentityPoolViewer",
    members=["user:jane@example.com"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := iam.NewWorkloadIdentityPoolIamBinding(ctx, "binding", &iam.WorkloadIdentityPoolIamBindingArgs{
			Project:                pulumi.Any(example.Project),
			WorkloadIdentityPoolId: pulumi.Any(example.WorkloadIdentityPoolId),
			Role:                   pulumi.String("roles/iam.workloadIdentityPoolViewer"),
			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.Iam.WorkloadIdentityPoolIamBinding("binding", new()
    {
        Project = example.Project,
        WorkloadIdentityPoolId = example.WorkloadIdentityPoolId,
        Role = "roles/iam.workloadIdentityPoolViewer",
        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.iam.WorkloadIdentityPoolIamBinding;
import com.pulumi.gcp.iam.WorkloadIdentityPoolIamBindingArgs;
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 WorkloadIdentityPoolIamBinding("binding", WorkloadIdentityPoolIamBindingArgs.builder()
            .project(example.project())
            .workloadIdentityPoolId(example.workloadIdentityPoolId())
            .role("roles/iam.workloadIdentityPoolViewer")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:iam:WorkloadIdentityPoolIamBinding
    properties:
      project: ${example.project}
      workloadIdentityPoolId: ${example.workloadIdentityPoolId}
      role: roles/iam.workloadIdentityPoolViewer
      members:
        - user:jane@example.com

The WorkloadIdentityPoolIamBinding resource replaces all members for a role. The members property accepts a list of identities. Any members not in this list lose access to the role. Use this when you need to enforce an exact membership roster.

Beyond these examples

These snippets focus on specific IAM access control features: member-level and binding-level access control, and IAM Conditions for time-based expiration. They’re intentionally minimal rather than complete identity federation setups.

The examples reference pre-existing infrastructure such as workload identity pools and GCP projects with IAM enabled. They focus on granting access rather than provisioning pools or configuring federation.

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

  • Policy-level management (WorkloadIdentityPoolIamPolicy)
  • Federated identity configuration and attribute mapping
  • Service account impersonation setup
  • Workforce vs workload pool distinctions

These omissions are intentional: the goal is to illustrate how each access control mechanism is wired, not provide drop-in identity federation modules. See the Workload Identity Pool IAM Member resource reference for all available configuration options.

Let's manage GCP Workload Identity Pool IAM Members

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Resource Conflicts & Compatibility
Can I use multiple IAM resources together on the same workload identity pool?
You must choose one approach. WorkloadIdentityPoolIamPolicy cannot be used with WorkloadIdentityPoolIamBinding or WorkloadIdentityPoolIamMember as they will conflict. However, you can use WorkloadIdentityPoolIamBinding and WorkloadIdentityPoolIamMember together if they manage different roles.
What's the difference between IamPolicy, IamBinding, and IamMember?
WorkloadIdentityPoolIamPolicy is authoritative and replaces the entire IAM policy. WorkloadIdentityPoolIamBinding is authoritative for a specific role, preserving other roles. WorkloadIdentityPoolIamMember is non-authoritative and adds a single member without affecting other members for that role.
IAM Roles & Permissions
How do I specify custom roles?
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 grant multiple roles to the same member?
Yes, create separate WorkloadIdentityPoolIamMember resources for each role. Each resource grants one role to one member.
Member Identities
What identity formats can I use for the member property?

Multiple formats are supported:

  • allUsers or allAuthenticatedUsers for broad access
  • user:{email}, serviceAccount:{email}, or group:{email} for specific identities
  • domain:{domain} for all users in a G Suite domain
  • projectOwner:{projectid}, projectEditor:{projectid}, or projectViewer:{projectid} for project roles
  • Federated identities like principal://iam.googleapis.com/locations/global/workforcePools/example-contractors/subject/joe@example.com
IAM Conditions
How do I add time-based or conditional access restrictions?
Use the condition property with title, description, and expression. For example, to expire access at a specific time: expression: "request.time < timestamp(\"2020-01-01T00:00:00Z\")".
What are the limitations of IAM Conditions?
IAM Conditions have known limitations that may affect functionality. Review the limitations before using conditions, as certain expressions or scenarios may not be supported.
Resource Management
What properties can't be changed after creation?
All properties are immutable: member, role, workloadIdentityPoolId, project, and condition. To change any of these, you must delete and recreate the resource.
How do I import existing IAM member bindings?
Use space-delimited identifiers: the resource path, role, and member identity. For example: pulumi import gcp:iam/workloadIdentityPoolIamMember:WorkloadIdentityPoolIamMember editor "projects/{{project}}/locations/global/workloadIdentityPools/{{pool_id}} roles/iam.workloadIdentityPoolViewer user:jane@example.com".

Using a different cloud?

Explore security guides for other cloud providers: