Manage GCP Workforce Pool IAM Policies

The gcp:iam/workforcePoolIamPolicy:WorkforcePoolIamPolicy resource, part of the Pulumi GCP provider, manages IAM policies for workforce pools, controlling who can administer and use workforce identity federation. This guide focuses on three approaches: authoritative policy replacement, role-level member binding, and incremental member grants.

GCP provides three related resources for workforce pool IAM management. WorkforcePoolIamPolicy replaces the entire policy authoritatively. WorkforcePoolIamBinding manages all members for a specific role authoritatively. WorkforcePoolIamMember adds individual members non-authoritatively. These resources cannot be mixed arbitrarily: Policy conflicts with Binding and Member; Binding and Member can coexist only if they manage different roles. All examples reference existing workforce pools and require the location property. The examples are intentionally small. Combine them with your own workforce pool infrastructure and organizational IAM strategy.

Replace the entire IAM policy authoritatively

When you need complete control over a workforce pool’s IAM policy, replacing the entire policy ensures no unexpected permissions remain.

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

const admin = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/iam.workforcePoolAdmin",
        members: ["user:jane@example.com"],
    }],
});
const policy = new gcp.iam.WorkforcePoolIamPolicy("policy", {
    location: example.location,
    workforcePoolId: example.workforcePoolId,
    policyData: admin.then(admin => admin.policyData),
});
import pulumi
import pulumi_gcp as gcp

admin = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/iam.workforcePoolAdmin",
    "members": ["user:jane@example.com"],
}])
policy = gcp.iam.WorkforcePoolIamPolicy("policy",
    location=example["location"],
    workforce_pool_id=example["workforcePoolId"],
    policy_data=admin.policy_data)
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		admin, err := organizations.LookupIAMPolicy(ctx, &organizations.LookupIAMPolicyArgs{
			Bindings: []organizations.GetIAMPolicyBinding{
				{
					Role: "roles/iam.workforcePoolAdmin",
					Members: []string{
						"user:jane@example.com",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = iam.NewWorkforcePoolIamPolicy(ctx, "policy", &iam.WorkforcePoolIamPolicyArgs{
			Location:        pulumi.Any(example.Location),
			WorkforcePoolId: pulumi.Any(example.WorkforcePoolId),
			PolicyData:      pulumi.String(admin.PolicyData),
		})
		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 admin = Gcp.Organizations.GetIAMPolicy.Invoke(new()
    {
        Bindings = new[]
        {
            new Gcp.Organizations.Inputs.GetIAMPolicyBindingInputArgs
            {
                Role = "roles/iam.workforcePoolAdmin",
                Members = new[]
                {
                    "user:jane@example.com",
                },
            },
        },
    });

    var policy = new Gcp.Iam.WorkforcePoolIamPolicy("policy", new()
    {
        Location = example.Location,
        WorkforcePoolId = example.WorkforcePoolId,
        PolicyData = admin.Apply(getIAMPolicyResult => getIAMPolicyResult.PolicyData),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetIAMPolicyArgs;
import com.pulumi.gcp.iam.WorkforcePoolIamPolicy;
import com.pulumi.gcp.iam.WorkforcePoolIamPolicyArgs;
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) {
        final var admin = OrganizationsFunctions.getIAMPolicy(GetIAMPolicyArgs.builder()
            .bindings(GetIAMPolicyBindingArgs.builder()
                .role("roles/iam.workforcePoolAdmin")
                .members("user:jane@example.com")
                .build())
            .build());

        var policy = new WorkforcePoolIamPolicy("policy", WorkforcePoolIamPolicyArgs.builder()
            .location(example.location())
            .workforcePoolId(example.workforcePoolId())
            .policyData(admin.policyData())
            .build());

    }
}
resources:
  policy:
    type: gcp:iam:WorkforcePoolIamPolicy
    properties:
      location: ${example.location}
      workforcePoolId: ${example.workforcePoolId}
      policyData: ${admin.policyData}
variables:
  admin:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/iam.workforcePoolAdmin
            members:
              - user:jane@example.com

The WorkforcePoolIamPolicy resource sets the complete IAM policy for the workforce pool. The policyData property accepts output from the getIAMPolicy data source, which constructs the policy document from role-member bindings. This approach is authoritative: it removes any existing bindings not defined in your configuration. Use this when you want full control and can define all necessary permissions in one place.

Grant a role to multiple members at once

Teams often assign the same role to several users simultaneously, maintaining a single authoritative list for that role.

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

const binding = new gcp.iam.WorkforcePoolIamBinding("binding", {
    location: example.location,
    workforcePoolId: example.workforcePoolId,
    role: "roles/iam.workforcePoolAdmin",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.iam.WorkforcePoolIamBinding("binding",
    location=example["location"],
    workforce_pool_id=example["workforcePoolId"],
    role="roles/iam.workforcePoolAdmin",
    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.NewWorkforcePoolIamBinding(ctx, "binding", &iam.WorkforcePoolIamBindingArgs{
			Location:        pulumi.Any(example.Location),
			WorkforcePoolId: pulumi.Any(example.WorkforcePoolId),
			Role:            pulumi.String("roles/iam.workforcePoolAdmin"),
			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.WorkforcePoolIamBinding("binding", new()
    {
        Location = example.Location,
        WorkforcePoolId = example.WorkforcePoolId,
        Role = "roles/iam.workforcePoolAdmin",
        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.WorkforcePoolIamBinding;
import com.pulumi.gcp.iam.WorkforcePoolIamBindingArgs;
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 WorkforcePoolIamBinding("binding", WorkforcePoolIamBindingArgs.builder()
            .location(example.location())
            .workforcePoolId(example.workforcePoolId())
            .role("roles/iam.workforcePoolAdmin")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:iam:WorkforcePoolIamBinding
    properties:
      location: ${example.location}
      workforcePoolId: ${example.workforcePoolId}
      role: roles/iam.workforcePoolAdmin
      members:
        - user:jane@example.com

The WorkforcePoolIamBinding resource manages all members for a specific role. The members property accepts a list of identities (users, service accounts, groups). This resource is authoritative for its role: it replaces any existing members for that role but preserves other roles in the policy. Use this when you want to manage a role’s member list as a single unit while leaving other roles untouched.

Add a single member to a role incrementally

When granting access to individual users without affecting existing role members, non-authoritative member resources let you add permissions incrementally.

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

const member = new gcp.iam.WorkforcePoolIamMember("member", {
    location: example.location,
    workforcePoolId: example.workforcePoolId,
    role: "roles/iam.workforcePoolAdmin",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.iam.WorkforcePoolIamMember("member",
    location=example["location"],
    workforce_pool_id=example["workforcePoolId"],
    role="roles/iam.workforcePoolAdmin",
    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.NewWorkforcePoolIamMember(ctx, "member", &iam.WorkforcePoolIamMemberArgs{
			Location:        pulumi.Any(example.Location),
			WorkforcePoolId: pulumi.Any(example.WorkforcePoolId),
			Role:            pulumi.String("roles/iam.workforcePoolAdmin"),
			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.WorkforcePoolIamMember("member", new()
    {
        Location = example.Location,
        WorkforcePoolId = example.WorkforcePoolId,
        Role = "roles/iam.workforcePoolAdmin",
        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.WorkforcePoolIamMember;
import com.pulumi.gcp.iam.WorkforcePoolIamMemberArgs;
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 WorkforcePoolIamMember("member", WorkforcePoolIamMemberArgs.builder()
            .location(example.location())
            .workforcePoolId(example.workforcePoolId())
            .role("roles/iam.workforcePoolAdmin")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:iam:WorkforcePoolIamMember
    properties:
      location: ${example.location}
      workforcePoolId: ${example.workforcePoolId}
      role: roles/iam.workforcePoolAdmin
      member: user:jane@example.com

The WorkforcePoolIamMember resource grants a role to one member without managing the full member list. The member property accepts a single identity. This resource is non-authoritative: it adds the member to the role without removing other members. Use this when multiple teams or configurations need to grant the same role independently, or when you want to add permissions without coordinating with other configurations.

Beyond these examples

These snippets focus on specific IAM management approaches: authoritative vs non-authoritative management, and policy-level, role-level, and member-level control. They’re intentionally minimal rather than full access control configurations.

The examples reference pre-existing infrastructure such as workforce pools (workforcePoolId references). They focus on IAM policy configuration rather than provisioning the workforce pools themselves.

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

  • Conditional IAM bindings (condition blocks)
  • Custom role definitions and references
  • Multiple role bindings in a single configuration
  • IAM policy retrieval (data source usage)

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 WorkforcePoolIamPolicy resource reference for all available configuration options.

Let's manage GCP Workforce Pool IAM Policies

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 & Compatibility
Which IAM resources can I use together?
gcp.iam.WorkforcePoolIamPolicy cannot be used with gcp.iam.WorkforcePoolIamBinding or gcp.iam.WorkforcePoolIamMember as they will conflict over policy control. However, WorkforcePoolIamBinding and WorkforcePoolIamMember can coexist if they manage different roles.
Which IAM resource should I use for my use case?

Choose based on your needs:

  • WorkforcePoolIamPolicy - Authoritative control of the entire IAM policy (replaces any existing policy)
  • WorkforcePoolIamBinding - Authoritative control of a specific role (preserves other roles, replaces members for that role)
  • WorkforcePoolIamMember - Non-authoritative addition of a single member to a role (preserves existing members)
Configuration & Properties
What properties can't be changed after creation?
Both location and workforcePoolId are immutable and cannot be modified after the resource is created.
How do I generate the policy data for WorkforcePoolIamPolicy?
Use the gcp.organizations.getIAMPolicy data source to generate the policyData, then pass it to the WorkforcePoolIamPolicy resource.
Import & Custom Roles
How do I import an IAM resource with a custom role?
Use the full custom role name in the format [projects/my-project|organizations/my-org]/roles/my-custom-role rather than just the role name.

Using a different cloud?

Explore security guides for other cloud providers: