The gcp:spanner/instanceIAMPolicy:InstanceIAMPolicy resource, part of the Pulumi GCP provider, manages IAM policies for Spanner instances with three levels of control. This guide focuses on three capabilities: authoritative policy replacement (InstanceIAMPolicy), role-level member lists (InstanceIAMBinding), and individual member grants (InstanceIAMMember).
These resources reference existing Spanner instances and work with IAM principals such as users, service accounts, and groups. The examples are intentionally small. Combine them with your own instance references and IAM principals. Note that InstanceIAMPolicy cannot be used alongside InstanceIAMBinding or InstanceIAMMember, as they will conflict over policy state.
Replace the entire IAM policy authoritatively
When you need complete control over all IAM bindings, InstanceIAMPolicy replaces the entire policy in one operation, removing any existing bindings not included.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const admin = gcp.organizations.getIAMPolicy({
bindings: [{
role: "roles/editor",
members: ["user:jane@example.com"],
}],
});
const instance = new gcp.spanner.InstanceIAMPolicy("instance", {
instance: "your-instance-name",
policyData: admin.then(admin => admin.policyData),
});
import pulumi
import pulumi_gcp as gcp
admin = gcp.organizations.get_iam_policy(bindings=[{
"role": "roles/editor",
"members": ["user:jane@example.com"],
}])
instance = gcp.spanner.InstanceIAMPolicy("instance",
instance="your-instance-name",
policy_data=admin.policy_data)
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/spanner"
"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/editor",
Members: []string{
"user:jane@example.com",
},
},
},
}, nil)
if err != nil {
return err
}
_, err = spanner.NewInstanceIAMPolicy(ctx, "instance", &spanner.InstanceIAMPolicyArgs{
Instance: pulumi.String("your-instance-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/editor",
Members = new[]
{
"user:jane@example.com",
},
},
},
});
var instance = new Gcp.Spanner.InstanceIAMPolicy("instance", new()
{
Instance = "your-instance-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.spanner.InstanceIAMPolicy;
import com.pulumi.gcp.spanner.InstanceIAMPolicyArgs;
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/editor")
.members("user:jane@example.com")
.build())
.build());
var instance = new InstanceIAMPolicy("instance", InstanceIAMPolicyArgs.builder()
.instance("your-instance-name")
.policyData(admin.policyData())
.build());
}
}
resources:
instance:
type: gcp:spanner:InstanceIAMPolicy
properties:
instance: your-instance-name
policyData: ${admin.policyData}
variables:
admin:
fn::invoke:
function: gcp:organizations:getIAMPolicy
arguments:
bindings:
- role: roles/editor
members:
- user:jane@example.com
The policyData property accepts output from getIAMPolicy, which defines bindings as role-member pairs. InstanceIAMPolicy is authoritative: it removes any permissions not explicitly listed, including default grants. This can lock you out if you omit necessary bindings.
Grant a role to multiple members at once
Teams often assign the same role to several users, such as granting database admin access to an operations team.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const instance = new gcp.spanner.InstanceIAMBinding("instance", {
instance: "your-instance-name",
role: "roles/spanner.databaseAdmin",
members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp
instance = gcp.spanner.InstanceIAMBinding("instance",
instance="your-instance-name",
role="roles/spanner.databaseAdmin",
members=["user:jane@example.com"])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/spanner"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := spanner.NewInstanceIAMBinding(ctx, "instance", &spanner.InstanceIAMBindingArgs{
Instance: pulumi.String("your-instance-name"),
Role: pulumi.String("roles/spanner.databaseAdmin"),
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 instance = new Gcp.Spanner.InstanceIAMBinding("instance", new()
{
Instance = "your-instance-name",
Role = "roles/spanner.databaseAdmin",
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.spanner.InstanceIAMBinding;
import com.pulumi.gcp.spanner.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 instance = new InstanceIAMBinding("instance", InstanceIAMBindingArgs.builder()
.instance("your-instance-name")
.role("roles/spanner.databaseAdmin")
.members("user:jane@example.com")
.build());
}
}
resources:
instance:
type: gcp:spanner:InstanceIAMBinding
properties:
instance: your-instance-name
role: roles/spanner.databaseAdmin
members:
- user:jane@example.com
InstanceIAMBinding is authoritative for a single role. The members array lists all principals who should have this role. Other roles on the instance remain unchanged, but any members not in this list lose the specified role.
Add a single member to a role incrementally
When onboarding individual users, InstanceIAMMember adds one member without affecting others who already have the role.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const instance = new gcp.spanner.InstanceIAMMember("instance", {
instance: "your-instance-name",
role: "roles/spanner.databaseAdmin",
member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp
instance = gcp.spanner.InstanceIAMMember("instance",
instance="your-instance-name",
role="roles/spanner.databaseAdmin",
member="user:jane@example.com")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/spanner"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := spanner.NewInstanceIAMMember(ctx, "instance", &spanner.InstanceIAMMemberArgs{
Instance: pulumi.String("your-instance-name"),
Role: pulumi.String("roles/spanner.databaseAdmin"),
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 instance = new Gcp.Spanner.InstanceIAMMember("instance", new()
{
Instance = "your-instance-name",
Role = "roles/spanner.databaseAdmin",
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.spanner.InstanceIAMMember;
import com.pulumi.gcp.spanner.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 instance = new InstanceIAMMember("instance", InstanceIAMMemberArgs.builder()
.instance("your-instance-name")
.role("roles/spanner.databaseAdmin")
.member("user:jane@example.com")
.build());
}
}
resources:
instance:
type: gcp:spanner:InstanceIAMMember
properties:
instance: your-instance-name
role: roles/spanner.databaseAdmin
member: user:jane@example.com
InstanceIAMMember is non-authoritative: it grants a role to one member without modifying other assignments. You can use multiple InstanceIAMMember resources for the same role, or combine them with InstanceIAMBinding for different roles.
Beyond these examples
These snippets focus on specific IAM management approaches: authoritative vs non-authoritative updates, 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 Spanner instances. They focus on IAM policy configuration rather than provisioning instances or principals.
To keep things focused, common IAM patterns are omitted, including:
- Project specification (project property)
- Conditional IAM bindings
- Service account creation and management
- Custom role definitions
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 Spanner InstanceIAMPolicy resource reference for all available configuration options.
Let's manage GCP Spanner Instance IAM Policies
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
There are three options for managing Spanner instance IAM:
- InstanceIAMPolicy - Authoritative, replaces the entire IAM policy
- InstanceIAMBinding - Authoritative for a specific role, preserves other roles
- InstanceIAMMember - Non-authoritative, adds a single member to a role while preserving other members
gcp.spanner.InstanceIAMPolicy cannot be used with gcp.spanner.InstanceIAMBinding or gcp.spanner.InstanceIAMMember because they will conflict. However, gcp.spanner.InstanceIAMBinding and gcp.spanner.InstanceIAMMember can be used together as long as they don’t grant privileges to the same role.Common Pitfalls
gcp.spanner.InstanceIAMPolicy. It replaces the entire IAM policy, removing any default permissions not explicitly included in your configuration. Make sure to include all necessary permissions you want to preserve.gcp.spanner.InstanceIAMPolicy cannot coexist with gcp.spanner.InstanceIAMBinding or gcp.spanner.InstanceIAMMember as they will fight over the policy. Choose one approach and stick with it.Configuration & Immutability
instance and project are immutable. Changing either requires replacing the resource.[projects/my-project|organizations/my-org]/roles/my-custom-role.