Manage GCP Cloud Tasks Queue IAM Policies

The gcp:cloudtasks/queueIamPolicy:QueueIamPolicy resource, part of the Pulumi GCP provider, manages IAM permissions for Cloud Tasks queues by replacing the entire policy. This guide focuses on three approaches: single-member grants (QueueIamMember), role-level member lists (QueueIamBinding), and full policy replacement (QueueIamPolicy).

These three resources reference existing Cloud Tasks queues and have strict conflict rules: QueueIamPolicy cannot be used with QueueIamBinding or QueueIamMember, as they will conflict over policy ownership. QueueIamBinding and QueueIamMember can coexist only if they manage different roles. The examples are intentionally small. Combine them with your own queue infrastructure and choose the approach that matches your access control needs.

Grant a role to a single member

When adding access for one user or service account, QueueIamMember lets you grant a role without affecting other members who already have that role or other roles on the queue.

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

const member = new gcp.cloudtasks.QueueIamMember("member", {
    project: _default.project,
    location: _default.location,
    name: _default.name,
    role: "roles/viewer",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.cloudtasks.QueueIamMember("member",
    project=default["project"],
    location=default["location"],
    name=default["name"],
    role="roles/viewer",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := cloudtasks.NewQueueIamMember(ctx, "member", &cloudtasks.QueueIamMemberArgs{
			Project:  pulumi.Any(_default.Project),
			Location: pulumi.Any(_default.Location),
			Name:     pulumi.Any(_default.Name),
			Role:     pulumi.String("roles/viewer"),
			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.CloudTasks.QueueIamMember("member", new()
    {
        Project = @default.Project,
        Location = @default.Location,
        Name = @default.Name,
        Role = "roles/viewer",
        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.cloudtasks.QueueIamMember;
import com.pulumi.gcp.cloudtasks.QueueIamMemberArgs;
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 QueueIamMember("member", QueueIamMemberArgs.builder()
            .project(default_.project())
            .location(default_.location())
            .name(default_.name())
            .role("roles/viewer")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:cloudtasks:QueueIamMember
    properties:
      project: ${default.project}
      location: ${default.location}
      name: ${default.name}
      role: roles/viewer
      member: user:jane@example.com

The member property specifies a single identity in IAM format (e.g., “user:jane@example.com”, “serviceAccount:app@project.iam.gserviceaccount.com”). This resource is non-authoritative: it adds one member to a role without removing existing members. Use this when you need to incrementally grant access without coordinating with other team members managing the same queue.

Grant a role to multiple members at once

When you need to grant the same role to several users or service accounts, QueueIamBinding manages the complete member list for that role.

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

const binding = new gcp.cloudtasks.QueueIamBinding("binding", {
    project: _default.project,
    location: _default.location,
    name: _default.name,
    role: "roles/viewer",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.cloudtasks.QueueIamBinding("binding",
    project=default["project"],
    location=default["location"],
    name=default["name"],
    role="roles/viewer",
    members=["user:jane@example.com"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := cloudtasks.NewQueueIamBinding(ctx, "binding", &cloudtasks.QueueIamBindingArgs{
			Project:  pulumi.Any(_default.Project),
			Location: pulumi.Any(_default.Location),
			Name:     pulumi.Any(_default.Name),
			Role:     pulumi.String("roles/viewer"),
			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.CloudTasks.QueueIamBinding("binding", new()
    {
        Project = @default.Project,
        Location = @default.Location,
        Name = @default.Name,
        Role = "roles/viewer",
        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.cloudtasks.QueueIamBinding;
import com.pulumi.gcp.cloudtasks.QueueIamBindingArgs;
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 QueueIamBinding("binding", QueueIamBindingArgs.builder()
            .project(default_.project())
            .location(default_.location())
            .name(default_.name())
            .role("roles/viewer")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:cloudtasks:QueueIamBinding
    properties:
      project: ${default.project}
      location: ${default.location}
      name: ${default.name}
      role: roles/viewer
      members:
        - user:jane@example.com

The members property takes an array of identities. This resource is authoritative for the specified role: it replaces all members for that role with your list. Other roles on the queue remain unchanged. Use this when you want to control exactly who has a specific role, such as managing all viewers or all task enqueuers.

Replace the entire IAM policy for a queue

When you need complete control over all permissions on a queue, QueueIamPolicy replaces the entire IAM policy with your specified bindings.

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

const admin = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/viewer",
        members: ["user:jane@example.com"],
    }],
});
const policy = new gcp.cloudtasks.QueueIamPolicy("policy", {
    project: _default.project,
    location: _default.location,
    name: _default.name,
    policyData: admin.then(admin => admin.policyData),
});
import pulumi
import pulumi_gcp as gcp

admin = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/viewer",
    "members": ["user:jane@example.com"],
}])
policy = gcp.cloudtasks.QueueIamPolicy("policy",
    project=default["project"],
    location=default["location"],
    name=default["name"],
    policy_data=admin.policy_data)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudtasks"
	"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/viewer",
					Members: []string{
						"user:jane@example.com",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		_, err = cloudtasks.NewQueueIamPolicy(ctx, "policy", &cloudtasks.QueueIamPolicyArgs{
			Project:    pulumi.Any(_default.Project),
			Location:   pulumi.Any(_default.Location),
			Name:       pulumi.Any(_default.Name),
			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/viewer",
                Members = new[]
                {
                    "user:jane@example.com",
                },
            },
        },
    });

    var policy = new Gcp.CloudTasks.QueueIamPolicy("policy", new()
    {
        Project = @default.Project,
        Location = @default.Location,
        Name = @default.Name,
        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.cloudtasks.QueueIamPolicy;
import com.pulumi.gcp.cloudtasks.QueueIamPolicyArgs;
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/viewer")
                .members("user:jane@example.com")
                .build())
            .build());

        var policy = new QueueIamPolicy("policy", QueueIamPolicyArgs.builder()
            .project(default_.project())
            .location(default_.location())
            .name(default_.name())
            .policyData(admin.policyData())
            .build());

    }
}
resources:
  policy:
    type: gcp:cloudtasks:QueueIamPolicy
    properties:
      project: ${default.project}
      location: ${default.location}
      name: ${default.name}
      policyData: ${admin.policyData}
variables:
  admin:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/viewer
            members:
              - user:jane@example.com

The policyData property comes from the getIAMPolicy data source, which constructs a complete policy document from bindings. Each binding specifies a role and its members. This resource is fully authoritative: it replaces the entire policy, removing any roles or members not in your configuration. Use this when you want to define all queue permissions in one place, but be aware it cannot coexist with QueueIamBinding or QueueIamMember resources on the same queue.

Beyond these examples

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

The examples reference pre-existing infrastructure such as Cloud Tasks queues (referenced but not created). They focus on IAM policy configuration rather than queue provisioning.

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

  • Conditional IAM bindings (condition blocks)
  • Audit logging configuration (auditConfigs)
  • Custom role definitions
  • Cross-project or organization-level policies

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 Cloud Tasks Queue IAM Policy resource reference for all available configuration options.

Let's manage GCP Cloud Tasks Queue 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 & Conflicts
What's the difference between QueueIamPolicy, QueueIamBinding, and QueueIamMember?
QueueIamPolicy is authoritative and replaces the entire IAM policy. QueueIamBinding is authoritative for a specific role, preserving other roles in the policy. QueueIamMember is non-authoritative, adding a single member while preserving other members for that role.
Can I use QueueIamPolicy with QueueIamBinding or QueueIamMember?
No, QueueIamPolicy cannot be used with QueueIamBinding or QueueIamMember because they will conflict over the policy. However, you can use QueueIamBinding and QueueIamMember together as long as they don’t grant privileges to the same role.
Configuration & Setup
How do I configure QueueIamPolicy?
Set the policyData property using the output from the gcp.organizations.getIAMPolicy data source, which generates the policy data with bindings for roles and members.
Import & Custom Roles
What format do custom roles need when importing IAM resources?
Custom roles must use the full name format: [projects/my-project|organizations/my-org]/roles/my-custom-role.

Using a different cloud?

Explore security guides for other cloud providers: