Manage GCP Compute Instance IAM Access

The gcp:compute/instanceIAMMember:InstanceIAMMember resource, part of the Pulumi GCP provider, grants IAM permissions on Compute Engine instances by adding individual members to roles. This guide focuses on three capabilities: single-member role grants, time-limited access with IAM Conditions, and multi-member role bindings.

Three related resources manage instance IAM: InstanceIAMPolicy (authoritative, replaces entire policy), InstanceIAMBinding (authoritative for one role), and InstanceIAMMember (non-authoritative, adds one member). InstanceIAMPolicy cannot be used with the other two; they conflict. The examples are intentionally small. Combine them with your own instance references and identity management.

Grant a single user access to an instance

Most IAM configurations add individual users to specific roles without affecting other permissions.

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

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

member = gcp.compute.InstanceIAMMember("member",
    project=default["project"],
    zone=default["zone"],
    instance_name=default["name"],
    role="roles/compute.osLogin",
    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.NewInstanceIAMMember(ctx, "member", &compute.InstanceIAMMemberArgs{
			Project:      pulumi.Any(_default.Project),
			Zone:         pulumi.Any(_default.Zone),
			InstanceName: pulumi.Any(_default.Name),
			Role:         pulumi.String("roles/compute.osLogin"),
			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.InstanceIAMMember("member", new()
    {
        Project = @default.Project,
        Zone = @default.Zone,
        InstanceName = @default.Name,
        Role = "roles/compute.osLogin",
        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.InstanceIAMMember;
import com.pulumi.gcp.compute.InstanceIAMMemberArgs;
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 InstanceIAMMember("member", InstanceIAMMemberArgs.builder()
            .project(default_.project())
            .zone(default_.zone())
            .instanceName(default_.name())
            .role("roles/compute.osLogin")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:compute:InstanceIAMMember
    properties:
      project: ${default.project}
      zone: ${default.zone}
      instanceName: ${default.name}
      role: roles/compute.osLogin
      member: user:jane@example.com

The member property identifies who receives access, using formats like “user:jane@example.com” for Google accounts or “serviceAccount:app@project.iam.gserviceaccount.com” for service accounts. The role property specifies the permission set, such as “roles/compute.osLogin” for SSH access. InstanceIAMMember is non-authoritative: it adds this one member to this one role, preserving other members and other roles on the instance.

Add time-limited access with IAM Conditions

Temporary access expires automatically when you attach time constraints to role bindings.

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

const member = new gcp.compute.InstanceIAMMember("member", {
    project: _default.project,
    zone: _default.zone,
    instanceName: _default.name,
    role: "roles/compute.osLogin",
    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.InstanceIAMMember("member",
    project=default["project"],
    zone=default["zone"],
    instance_name=default["name"],
    role="roles/compute.osLogin",
    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.NewInstanceIAMMember(ctx, "member", &compute.InstanceIAMMemberArgs{
			Project:      pulumi.Any(_default.Project),
			Zone:         pulumi.Any(_default.Zone),
			InstanceName: pulumi.Any(_default.Name),
			Role:         pulumi.String("roles/compute.osLogin"),
			Member:       pulumi.String("user:jane@example.com"),
			Condition: &compute.InstanceIAMMemberConditionArgs{
				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.InstanceIAMMember("member", new()
    {
        Project = @default.Project,
        Zone = @default.Zone,
        InstanceName = @default.Name,
        Role = "roles/compute.osLogin",
        Member = "user:jane@example.com",
        Condition = new Gcp.Compute.Inputs.InstanceIAMMemberConditionArgs
        {
            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.InstanceIAMMember;
import com.pulumi.gcp.compute.InstanceIAMMemberArgs;
import com.pulumi.gcp.compute.inputs.InstanceIAMMemberConditionArgs;
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 InstanceIAMMember("member", InstanceIAMMemberArgs.builder()
            .project(default_.project())
            .zone(default_.zone())
            .instanceName(default_.name())
            .role("roles/compute.osLogin")
            .member("user:jane@example.com")
            .condition(InstanceIAMMemberConditionArgs.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:InstanceIAMMember
    properties:
      project: ${default.project}
      zone: ${default.zone}
      instanceName: ${default.name}
      role: roles/compute.osLogin
      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 logic to the role binding. The expression property uses Common Expression Language (CEL) to define when the binding applies; here, “request.time < timestamp(…)” expires access at midnight on 2020-01-01. The title and description properties document the condition’s purpose. IAM Conditions have known limitations; review Google Cloud’s documentation before using them in production.

Grant a role to multiple members at once

When several identities need identical permissions, InstanceIAMBinding manages all members for one role together.

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

const binding = new gcp.compute.InstanceIAMBinding("binding", {
    project: _default.project,
    zone: _default.zone,
    instanceName: _default.name,
    role: "roles/compute.osLogin",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

binding = gcp.compute.InstanceIAMBinding("binding",
    project=default["project"],
    zone=default["zone"],
    instance_name=default["name"],
    role="roles/compute.osLogin",
    members=["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.NewInstanceIAMBinding(ctx, "binding", &compute.InstanceIAMBindingArgs{
			Project:      pulumi.Any(_default.Project),
			Zone:         pulumi.Any(_default.Zone),
			InstanceName: pulumi.Any(_default.Name),
			Role:         pulumi.String("roles/compute.osLogin"),
			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.Compute.InstanceIAMBinding("binding", new()
    {
        Project = @default.Project,
        Zone = @default.Zone,
        InstanceName = @default.Name,
        Role = "roles/compute.osLogin",
        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.compute.InstanceIAMBinding;
import com.pulumi.gcp.compute.InstanceIAMBindingArgs;
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 InstanceIAMBinding("binding", InstanceIAMBindingArgs.builder()
            .project(default_.project())
            .zone(default_.zone())
            .instanceName(default_.name())
            .role("roles/compute.osLogin")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  binding:
    type: gcp:compute:InstanceIAMBinding
    properties:
      project: ${default.project}
      zone: ${default.zone}
      instanceName: ${default.name}
      role: roles/compute.osLogin
      members:
        - user:jane@example.com

The members property lists all identities that should have this role. InstanceIAMBinding is authoritative for its role: it replaces any existing member list for “roles/compute.osLogin” on this instance. Use InstanceIAMMember instead if you need to add members without affecting others, or if multiple Pulumi stacks manage the same role.

Beyond these examples

These snippets focus on specific IAM management patterns: single-member grants, multi-member role bindings, and time-based access with IAM Conditions. They’re intentionally minimal rather than full access control configurations.

The examples reference pre-existing infrastructure such as Compute Engine instances and a Google Cloud project with configured zone. They focus on granting permissions rather than provisioning instances or defining custom roles.

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

  • Full policy replacement (InstanceIAMPolicy resource)
  • Custom role definitions and formatting
  • Service account and group identity patterns
  • Federated identity and workload identity pool configuration

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 Compute Instance IAM Member resource reference for all available configuration options.

Let's manage GCP Compute Instance IAM Access

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 InstanceIAMPolicy, InstanceIAMBinding, and InstanceIAMMember?
InstanceIAMPolicy is authoritative and replaces the entire IAM policy. InstanceIAMBinding is authoritative for a specific role, preserving other roles in the policy. InstanceIAMMember is non-authoritative and adds a single member to a role while preserving other members for that role.
Can I use InstanceIAMPolicy together with InstanceIAMBinding or InstanceIAMMember?
No, InstanceIAMPolicy cannot be used with InstanceIAMBinding or InstanceIAMMember because they will conflict over the policy configuration.
Can I use InstanceIAMBinding and InstanceIAMMember together?
Yes, but only if they don’t grant privileges to the same role. Each role must be managed by only one resource type.
Configuration & Identity Formats
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 like principal://iam.googleapis.com/....
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.
What properties can I change after creating an InstanceIAMMember?
None. All properties (instanceName, member, role, project, zone, and condition) are immutable and require resource replacement if changed.
Advanced Features
Can I use IAM Conditions with instance IAM resources?
Yes, IAM Conditions are supported by adding a condition block with title, description, and expression fields. However, IAM Conditions have known limitations that you should review before use.

Using a different cloud?

Explore security guides for other cloud providers: