The gcp:compute/snapshotIamMember:SnapshotIamMember resource, part of the Pulumi GCP provider, manages IAM permissions for Compute Engine snapshots by adding individual members to roles. This guide focuses on three approaches to IAM management and the differences between authoritative and non-authoritative control.
GCP provides three related resources for snapshot IAM: SnapshotIamPolicy (replaces entire policy), SnapshotIamBinding (manages all members for one role), and SnapshotIamMember (adds one member to one role). The examples are intentionally small. Choose the resource type that matches your permission management strategy.
Replace the entire IAM policy for a snapshot
When you need complete control over snapshot access, you can set the entire IAM policy at once, replacing any existing permissions.
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.compute.SnapshotIamPolicy("policy", {
project: snapshot.project,
name: snapshot.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.compute.SnapshotIamPolicy("policy",
project=snapshot["project"],
name=snapshot["name"],
policy_data=admin.policy_data)
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"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 = compute.NewSnapshotIamPolicy(ctx, "policy", &compute.SnapshotIamPolicyArgs{
Project: pulumi.Any(snapshot.Project),
Name: pulumi.Any(snapshot.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.Compute.SnapshotIamPolicy("policy", new()
{
Project = snapshot.Project,
Name = snapshot.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.compute.SnapshotIamPolicy;
import com.pulumi.gcp.compute.SnapshotIamPolicyArgs;
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 SnapshotIamPolicy("policy", SnapshotIamPolicyArgs.builder()
.project(snapshot.project())
.name(snapshot.name())
.policyData(admin.policyData())
.build());
}
}
resources:
policy:
type: gcp:compute:SnapshotIamPolicy
properties:
project: ${snapshot.project}
name: ${snapshot.name}
policyData: ${admin.policyData}
variables:
admin:
fn::invoke:
function: gcp:organizations:getIAMPolicy
arguments:
bindings:
- role: roles/viewer
members:
- user:jane@example.com
The SnapshotIamPolicy resource is authoritative: it replaces the snapshot’s entire IAM policy with the bindings you define. The getIAMPolicy data source constructs the policy document from role-member pairs. This approach cannot be used alongside SnapshotIamBinding or SnapshotIamMember; they will conflict over policy ownership.
Grant a role to multiple members at once
When multiple users or service accounts need the same access level, you can bind them all to a role in a single resource.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const binding = new gcp.compute.SnapshotIamBinding("binding", {
project: snapshot.project,
name: snapshot.name,
role: "roles/viewer",
members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp
binding = gcp.compute.SnapshotIamBinding("binding",
project=snapshot["project"],
name=snapshot["name"],
role="roles/viewer",
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.NewSnapshotIamBinding(ctx, "binding", &compute.SnapshotIamBindingArgs{
Project: pulumi.Any(snapshot.Project),
Name: pulumi.Any(snapshot.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.Compute.SnapshotIamBinding("binding", new()
{
Project = snapshot.Project,
Name = snapshot.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.compute.SnapshotIamBinding;
import com.pulumi.gcp.compute.SnapshotIamBindingArgs;
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 SnapshotIamBinding("binding", SnapshotIamBindingArgs.builder()
.project(snapshot.project())
.name(snapshot.name())
.role("roles/viewer")
.members("user:jane@example.com")
.build());
}
}
resources:
binding:
type: gcp:compute:SnapshotIamBinding
properties:
project: ${snapshot.project}
name: ${snapshot.name}
role: roles/viewer
members:
- user:jane@example.com
The SnapshotIamBinding resource is authoritative for one role: it sets the complete member list for that role while preserving other roles in the policy. The members property accepts a list of identity strings. You can use multiple SnapshotIamBinding resources for different roles, but only one per role.
Add a single member to a role incrementally
When you need to grant access to one user without affecting existing permissions, you can add individual members to roles.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const member = new gcp.compute.SnapshotIamMember("member", {
project: snapshot.project,
name: snapshot.name,
role: "roles/viewer",
member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp
member = gcp.compute.SnapshotIamMember("member",
project=snapshot["project"],
name=snapshot["name"],
role="roles/viewer",
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.NewSnapshotIamMember(ctx, "member", &compute.SnapshotIamMemberArgs{
Project: pulumi.Any(snapshot.Project),
Name: pulumi.Any(snapshot.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.Compute.SnapshotIamMember("member", new()
{
Project = snapshot.Project,
Name = snapshot.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.compute.SnapshotIamMember;
import com.pulumi.gcp.compute.SnapshotIamMemberArgs;
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 SnapshotIamMember("member", SnapshotIamMemberArgs.builder()
.project(snapshot.project())
.name(snapshot.name())
.role("roles/viewer")
.member("user:jane@example.com")
.build());
}
}
resources:
member:
type: gcp:compute:SnapshotIamMember
properties:
project: ${snapshot.project}
name: ${snapshot.name}
role: roles/viewer
member: user:jane@example.com
The SnapshotIamMember resource is non-authoritative: it adds one member to one role without removing other members. The member property accepts a single identity string. You can use multiple SnapshotIamMember resources for the same role; they combine additively. This resource can coexist with SnapshotIamBinding as long as they don’t manage the same role.
Beyond these examples
These snippets focus on specific IAM management features: authoritative vs non-authoritative IAM 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 Compute Engine snapshots and IAM principals (users, service accounts, groups). They focus on permission grants rather than creating the underlying resources.
To keep things focused, common IAM patterns are omitted, including:
- Conditional IAM bindings (condition property)
- Custom role definitions
- Cross-project snapshot sharing
- Federated identity 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 SnapshotIamMember resource reference for all available configuration options.
Let's manage GCP Compute Snapshot IAM Access
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Resource Selection & Conflicts
gcp.compute.SnapshotIamPolicy cannot be used with gcp.compute.SnapshotIamBinding or gcp.compute.SnapshotIamMember because they will conflict over the policy. Use SnapshotIamPolicy alone for authoritative management, or use SnapshotIamBinding and SnapshotIamMember together for non-authoritative management.SnapshotIamPolicy is authoritative and replaces the entire IAM policy. SnapshotIamBinding is authoritative for a specific role and grants it to a list of members. SnapshotIamMember is non-authoritative and adds a single member to a role while preserving other members.IAM Configuration
allUsers, allAuthenticatedUsers, user:{email}, serviceAccount:{email}, group:{email}, domain:{domain}, projectOwner/Editor/Viewer:{projectid}, or federated identities like principal://iam.googleapis.com/....[projects|organizations]/{parent-name}/roles/{role-name}. For example, projects/my-project/roles/my-custom-role.Resource Properties
member, role, name, and project properties are all immutable and cannot be changed after the resource is created.project, it will be parsed from the parent snapshot identifier. If that’s not available, the provider’s default project is used.