Manage GCP Backend Service IAM Permissions

The gcp:compute/backendServiceIamMember:BackendServiceIamMember resource, part of the Pulumi GCP provider, grants IAM roles to individual members on backend services without affecting other members who already have access. This resource is non-authoritative, meaning it adds one member to a role while preserving existing role assignments. This guide focuses on two capabilities: single-member role grants and time-based access conditions.

This resource is one of three IAM resources for backend services. BackendServiceIamPolicy replaces the entire policy (authoritative), BackendServiceIamBinding manages all members for a role (authoritative for that role), and BackendServiceIamMember adds individual members (non-authoritative). The examples reference existing backend services and projects. Combine them with your own backend service infrastructure.

Grant a role to a single member

When you need to give one user or service account access without changing who else has that role, use BackendServiceIamMember.

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

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

member = gcp.compute.BackendServiceIamMember("member",
    project=default["project"],
    name=default["name"],
    role="roles/compute.admin",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewBackendServiceIamMember(ctx, "member", &compute.BackendServiceIamMemberArgs{
			Project: pulumi.Any(_default.Project),
			Name:    pulumi.Any(_default.Name),
			Role:    pulumi.String("roles/compute.admin"),
			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.Compute.BackendServiceIamMember("member", new()
    {
        Project = @default.Project,
        Name = @default.Name,
        Role = "roles/compute.admin",
        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.compute.BackendServiceIamMember;
import com.pulumi.gcp.compute.BackendServiceIamMemberArgs;
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 BackendServiceIamMember("member", BackendServiceIamMemberArgs.builder()
            .project(default_.project())
            .name(default_.name())
            .role("roles/compute.admin")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:compute:BackendServiceIamMember
    properties:
      project: ${default.project}
      name: ${default.name}
      role: roles/compute.admin
      member: user:jane@example.com

The member property identifies who receives access using formats like “user:jane@example.com” or “serviceAccount:app@project.iam.gserviceaccount.com”. The role property specifies the permission level (e.g., “roles/compute.admin”). The name property references the backend service, and project identifies the GCP project. This resource adds the member to the role without removing other members who already have it.

Grant time-limited access with IAM Conditions

For contractors, auditors, or temporary projects, IAM Conditions let you attach expiration dates to role grants.

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

const member = new gcp.compute.BackendServiceIamMember("member", {
    project: _default.project,
    name: _default.name,
    role: "roles/compute.admin",
    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.compute.BackendServiceIamMember("member",
    project=default["project"],
    name=default["name"],
    role="roles/compute.admin",
    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/compute"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewBackendServiceIamMember(ctx, "member", &compute.BackendServiceIamMemberArgs{
			Project: pulumi.Any(_default.Project),
			Name:    pulumi.Any(_default.Name),
			Role:    pulumi.String("roles/compute.admin"),
			Member:  pulumi.String("user:jane@example.com"),
			Condition: &compute.BackendServiceIamMemberConditionArgs{
				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.Compute.BackendServiceIamMember("member", new()
    {
        Project = @default.Project,
        Name = @default.Name,
        Role = "roles/compute.admin",
        Member = "user:jane@example.com",
        Condition = new Gcp.Compute.Inputs.BackendServiceIamMemberConditionArgs
        {
            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.compute.BackendServiceIamMember;
import com.pulumi.gcp.compute.BackendServiceIamMemberArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceIamMemberConditionArgs;
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 BackendServiceIamMember("member", BackendServiceIamMemberArgs.builder()
            .project(default_.project())
            .name(default_.name())
            .role("roles/compute.admin")
            .member("user:jane@example.com")
            .condition(BackendServiceIamMemberConditionArgs.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:compute:BackendServiceIamMember
    properties:
      project: ${default.project}
      name: ${default.name}
      role: roles/compute.admin
      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 adds constraints to the role grant. The expression property uses CEL (Common Expression Language) to define when access is valid; here, it expires at midnight on 2020-01-01. The title property names the condition for identification, and description explains its purpose. IAM evaluates the condition on every request; once the timestamp passes, the member loses access automatically.

Beyond these examples

These snippets focus on specific member-level features: single-member role grants and time-based access conditions. They’re intentionally minimal rather than full IAM configurations.

The examples reference pre-existing infrastructure such as backend services and GCP projects. They focus on granting access to individual members rather than managing complete IAM policies.

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

  • Multi-member role bindings (use BackendServiceIamBinding)
  • Full policy replacement (use BackendServiceIamPolicy)
  • Complex condition expressions (location, resource attributes)
  • Custom role definitions

These omissions are intentional: the goal is to illustrate how member-level access grants are wired, not provide drop-in IAM modules. See the BackendServiceIamMember resource reference for all available configuration options.

Let's manage GCP Backend Service IAM Permissions

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 IamPolicy, IamBinding, and IamMember resources?
BackendServiceIamPolicy is fully authoritative and replaces the entire IAM policy. BackendServiceIamBinding is authoritative for a specific role, managing all members for that role while preserving other roles. BackendServiceIamMember is non-authoritative, adding individual members without affecting other members or roles.
Can I mix different IAM resource types for the same backend service?
BackendServiceIamPolicy cannot be used with BackendServiceIamBinding or BackendServiceIamMember as they will conflict. However, BackendServiceIamBinding and BackendServiceIamMember can be used together if they manage different roles.
When should I use IamMember instead of IamBinding?
Use BackendServiceIamMember when you want to add individual members non-authoritatively without affecting other members for the same role. Use BackendServiceIamBinding when you want to manage all members for a specific role authoritatively.
IAM Configuration
What member identity formats are supported?
Supported formats include allUsers, allAuthenticatedUsers, user:{email}, serviceAccount:{email}, group:{email}, domain:{domain}, projectOwner:{projectid}, projectEditor:{projectid}, projectViewer:{projectid}, and federated identities using principal:// URIs.
How do I specify a custom IAM role?
Custom roles must use the format [projects|organizations]/{parent-name}/roles/{role-name}. For example, projects/my-project/roles/my-custom-role.
How do I add time-based or conditional access restrictions?
Use the condition property with title, description, and expression fields. For example, set expression to request.time < timestamp("2020-01-01T00:00:00Z") for time-based expiration.
What are the limitations of IAM Conditions?
IAM Conditions are supported but have known limitations. Review the GCP documentation on IAM Conditions limitations before implementing conditional access.
Resource Properties & Constraints
What properties can't be changed after creation?
All properties are immutable: member, role, name, project, and condition. Any changes require recreating the resource.
What happens if I don't specify a project?
The project will be parsed from the parent resource identifier. If no project is found there, the provider’s default project is used.

Using a different cloud?

Explore security guides for other cloud providers: