Manage GCP Machine Image IAM Permissions

The gcp:compute/machineImageIamMember:MachineImageIamMember resource, part of the Pulumi GCP provider, grants IAM permissions to individual members for machine images. This guide focuses on two capabilities: adding single members to roles and configuring time-limited access with IAM Conditions.

This resource operates non-authoritatively: it adds one member to a role without affecting other members already assigned to that role. It references existing machine images and works alongside MachineImageIamBinding and MachineImageIamPolicy, though you must avoid conflicts by not managing the same role with multiple resource types. The examples are intentionally small. Combine them with your own machine images and IAM strategy.

Grant a role to a single member

When you need to give one person or service account access to a machine image, this resource adds that member without affecting existing permissions.

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

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

member = gcp.compute.MachineImageIamMember("member",
    project=image["project"],
    machine_image=image["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.NewMachineImageIamMember(ctx, "member", &compute.MachineImageIamMemberArgs{
			Project:      pulumi.Any(image.Project),
			MachineImage: pulumi.Any(image.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.MachineImageIamMember("member", new()
    {
        Project = image.Project,
        MachineImage = image.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.MachineImageIamMember;
import com.pulumi.gcp.compute.MachineImageIamMemberArgs;
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 MachineImageIamMember("member", MachineImageIamMemberArgs.builder()
            .project(image.project())
            .machineImage(image.name())
            .role("roles/compute.admin")
            .member("user:jane@example.com")
            .build());

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

The member property identifies who receives access, using formats like “user:jane@example.com” for individual users or “serviceAccount:app@project.iam.gserviceaccount.com” for service accounts. The role property specifies the permission level, such as “roles/compute.admin” for full compute access. The machineImage and project properties identify which machine image in which project receives the permission grant.

Grant time-limited access with IAM Conditions

IAM Conditions let you grant temporary access that expires automatically, useful for contractors or time-bound projects.

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

const member = new gcp.compute.MachineImageIamMember("member", {
    project: image.project,
    machineImage: image.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.MachineImageIamMember("member",
    project=image["project"],
    machine_image=image["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.NewMachineImageIamMember(ctx, "member", &compute.MachineImageIamMemberArgs{
			Project:      pulumi.Any(image.Project),
			MachineImage: pulumi.Any(image.Name),
			Role:         pulumi.String("roles/compute.admin"),
			Member:       pulumi.String("user:jane@example.com"),
			Condition: &compute.MachineImageIamMemberConditionArgs{
				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.MachineImageIamMember("member", new()
    {
        Project = image.Project,
        MachineImage = image.Name,
        Role = "roles/compute.admin",
        Member = "user:jane@example.com",
        Condition = new Gcp.Compute.Inputs.MachineImageIamMemberConditionArgs
        {
            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.MachineImageIamMember;
import com.pulumi.gcp.compute.MachineImageIamMemberArgs;
import com.pulumi.gcp.compute.inputs.MachineImageIamMemberConditionArgs;
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 MachineImageIamMember("member", MachineImageIamMemberArgs.builder()
            .project(image.project())
            .machineImage(image.name())
            .role("roles/compute.admin")
            .member("user:jane@example.com")
            .condition(MachineImageIamMemberConditionArgs.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:MachineImageIamMember
    properties:
      project: ${image.project}
      machineImage: ${image.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 temporal constraints to the permission grant. The expression property uses CEL (Common Expression Language) to define when access is valid; here, “request.time < timestamp(…)” grants access until midnight on December 31, 2019. The title and description properties document the condition’s purpose. When the condition evaluates to false, the member loses access automatically without requiring manual revocation.

Beyond these examples

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

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

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

  • Policy-level management (MachineImageIamPolicy)
  • Role-level binding (MachineImageIamBinding)
  • Multiple members in one resource
  • Custom role definitions

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

Let's manage GCP Machine Image 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
Which IAM resource should I use for Machine Image permissions?
Choose based on your needs: MachineImageIamPolicy for full policy control (replaces entire policy), MachineImageIamBinding for managing all members of a specific role, or MachineImageIamMember for adding individual members non-authoritatively.
Can I use multiple IAM resources together for the same Machine Image?
MachineImageIamPolicy cannot be used with MachineImageIamBinding or MachineImageIamMember as they will conflict. However, MachineImageIamBinding and MachineImageIamMember can be used together only if they don’t grant the same role.
What happens if I use Policy with Binding or Member resources?
They will fight over the policy configuration, causing conflicts and unpredictable behavior. Use Policy alone or use Binding/Member together (for different roles).
IAM Configuration
What member identity formats are supported?
Supports allUsers, allAuthenticatedUsers, user:{email}, serviceAccount:{email}, group:{email}, domain:{domain}, projectOwner/Editor/Viewer:{projectid}, and federated identities (e.g., principal://iam.googleapis.com/...).
How do I specify custom roles?
Custom roles must use the format [projects|organizations]/{parent-name}/roles/{role-name} (e.g., 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 have known limitations that may affect functionality. Review the GCP documentation on IAM Conditions limitations before implementing conditional access.
Resource Behavior
What properties can't be changed after creation?
All core properties are immutable: machineImage, member, role, project, and condition. Changes require resource replacement.

Using a different cloud?

Explore security guides for other cloud providers: