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 FREEFrequently Asked Questions
Resource Selection & Compatibility
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.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
location and workforcePoolId are immutable and cannot be modified after the resource is created.gcp.organizations.getIAMPolicy data source to generate the policyData, then pass it to the WorkforcePoolIamPolicy resource.Import & Custom Roles
[projects/my-project|organizations/my-org]/roles/my-custom-role rather than just the role name.