The gcp:spanner/databaseIAMBinding:DatabaseIAMBinding resource, part of the Pulumi GCP provider, manages IAM role bindings for Spanner databases by granting roles to lists of members. This guide focuses on three capabilities: authoritative role binding, conditional access with IAM Conditions, and non-authoritative member grants.
DatabaseIAMBinding is one of three resources for managing Spanner database IAM. It authoritatively controls all members for a specific role, replacing any existing grants for that role while preserving other roles. The examples are intentionally small. Combine them with your own Spanner infrastructure and identity management.
Grant a role to multiple members with DatabaseIAMBinding
Teams managing Spanner access often grant the same role to multiple users or service accounts at once.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const database = new gcp.spanner.DatabaseIAMBinding("database", {
instance: "your-instance-name",
database: "your-database-name",
role: "roles/compute.networkUser",
members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp
database = gcp.spanner.DatabaseIAMBinding("database",
instance="your-instance-name",
database="your-database-name",
role="roles/compute.networkUser",
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.NewDatabaseIAMBinding(ctx, "database", &spanner.DatabaseIAMBindingArgs{
Instance: pulumi.String("your-instance-name"),
Database: pulumi.String("your-database-name"),
Role: pulumi.String("roles/compute.networkUser"),
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 database = new Gcp.Spanner.DatabaseIAMBinding("database", new()
{
Instance = "your-instance-name",
Database = "your-database-name",
Role = "roles/compute.networkUser",
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.DatabaseIAMBinding;
import com.pulumi.gcp.spanner.DatabaseIAMBindingArgs;
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 database = new DatabaseIAMBinding("database", DatabaseIAMBindingArgs.builder()
.instance("your-instance-name")
.database("your-database-name")
.role("roles/compute.networkUser")
.members("user:jane@example.com")
.build());
}
}
resources:
database:
type: gcp:spanner:DatabaseIAMBinding
properties:
instance: your-instance-name
database: your-database-name
role: roles/compute.networkUser
members:
- user:jane@example.com
DatabaseIAMBinding replaces all members for the specified role. The members array accepts user accounts, service accounts, groups, and special identifiers like allUsers. The role property specifies which IAM role to grant; only one DatabaseIAMBinding can exist per role per database.
Apply conditional access with IAM Conditions
Fine-grained access control requires conditions that limit when permissions apply, such as restricting access to specific database roles.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const database = new gcp.spanner.DatabaseIAMBinding("database", {
instance: "your-instance-name",
database: "your-database-name",
role: "roles/compute.networkUser",
members: ["user:jane@example.com"],
condition: {
title: "My Role",
description: "Grant permissions on my_role",
expression: "(resource.type == \"spanner.googleapis.com/DatabaseRole\" && (resource.name.endsWith(\"/myrole\")))",
},
});
import pulumi
import pulumi_gcp as gcp
database = gcp.spanner.DatabaseIAMBinding("database",
instance="your-instance-name",
database="your-database-name",
role="roles/compute.networkUser",
members=["user:jane@example.com"],
condition={
"title": "My Role",
"description": "Grant permissions on my_role",
"expression": "(resource.type == \"spanner.googleapis.com/DatabaseRole\" && (resource.name.endsWith(\"/myrole\")))",
})
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.NewDatabaseIAMBinding(ctx, "database", &spanner.DatabaseIAMBindingArgs{
Instance: pulumi.String("your-instance-name"),
Database: pulumi.String("your-database-name"),
Role: pulumi.String("roles/compute.networkUser"),
Members: pulumi.StringArray{
pulumi.String("user:jane@example.com"),
},
Condition: &spanner.DatabaseIAMBindingConditionArgs{
Title: pulumi.String("My Role"),
Description: pulumi.String("Grant permissions on my_role"),
Expression: pulumi.String("(resource.type == \"spanner.googleapis.com/DatabaseRole\" && (resource.name.endsWith(\"/myrole\")))"),
},
})
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 database = new Gcp.Spanner.DatabaseIAMBinding("database", new()
{
Instance = "your-instance-name",
Database = "your-database-name",
Role = "roles/compute.networkUser",
Members = new[]
{
"user:jane@example.com",
},
Condition = new Gcp.Spanner.Inputs.DatabaseIAMBindingConditionArgs
{
Title = "My Role",
Description = "Grant permissions on my_role",
Expression = "(resource.type == \"spanner.googleapis.com/DatabaseRole\" && (resource.name.endsWith(\"/myrole\")))",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.spanner.DatabaseIAMBinding;
import com.pulumi.gcp.spanner.DatabaseIAMBindingArgs;
import com.pulumi.gcp.spanner.inputs.DatabaseIAMBindingConditionArgs;
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 database = new DatabaseIAMBinding("database", DatabaseIAMBindingArgs.builder()
.instance("your-instance-name")
.database("your-database-name")
.role("roles/compute.networkUser")
.members("user:jane@example.com")
.condition(DatabaseIAMBindingConditionArgs.builder()
.title("My Role")
.description("Grant permissions on my_role")
.expression("(resource.type == \"spanner.googleapis.com/DatabaseRole\" && (resource.name.endsWith(\"/myrole\")))")
.build())
.build());
}
}
resources:
database:
type: gcp:spanner:DatabaseIAMBinding
properties:
instance: your-instance-name
database: your-database-name
role: roles/compute.networkUser
members:
- user:jane@example.com
condition:
title: My Role
description: Grant permissions on my_role
expression: (resource.type == "spanner.googleapis.com/DatabaseRole" && (resource.name.endsWith("/myrole")))
IAM Conditions use CEL expressions to evaluate resource attributes at access time. The condition block requires a title, optional description, and an expression that returns true or false. In this configuration, the expression restricts access to resources ending with “/myrole”, limiting the role grant to specific database roles rather than the entire database.
Add a single member to a role with DatabaseIAMMember
When multiple teams manage access independently, DatabaseIAMMember adds individual members without affecting other grants.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const database = new gcp.spanner.DatabaseIAMMember("database", {
instance: "your-instance-name",
database: "your-database-name",
role: "roles/compute.networkUser",
member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp
database = gcp.spanner.DatabaseIAMMember("database",
instance="your-instance-name",
database="your-database-name",
role="roles/compute.networkUser",
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.NewDatabaseIAMMember(ctx, "database", &spanner.DatabaseIAMMemberArgs{
Instance: pulumi.String("your-instance-name"),
Database: pulumi.String("your-database-name"),
Role: pulumi.String("roles/compute.networkUser"),
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 database = new Gcp.Spanner.DatabaseIAMMember("database", new()
{
Instance = "your-instance-name",
Database = "your-database-name",
Role = "roles/compute.networkUser",
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.DatabaseIAMMember;
import com.pulumi.gcp.spanner.DatabaseIAMMemberArgs;
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 database = new DatabaseIAMMember("database", DatabaseIAMMemberArgs.builder()
.instance("your-instance-name")
.database("your-database-name")
.role("roles/compute.networkUser")
.member("user:jane@example.com")
.build());
}
}
resources:
database:
type: gcp:spanner:DatabaseIAMMember
properties:
instance: your-instance-name
database: your-database-name
role: roles/compute.networkUser
member: user:jane@example.com
Unlike DatabaseIAMBinding, DatabaseIAMMember is non-authoritative: it adds one member to a role without replacing existing members. Use this when different parts of your infrastructure need to grant the same role independently. The member property accepts a single identity in the same formats as the members array.
Beyond these examples
These snippets focus on specific IAM binding features: role binding and member management, conditional access with IAM Conditions, and authoritative vs non-authoritative grants. They’re intentionally minimal rather than full access control configurations.
The examples reference pre-existing infrastructure such as Spanner instances and databases. They focus on configuring IAM bindings rather than provisioning the database infrastructure.
To keep things focused, common IAM patterns are omitted, including:
- Full IAM policy replacement (DatabaseIAMPolicy)
- Project-level configuration (project property)
- Custom role definitions and formats
- Combining Binding and Member resources safely
These omissions are intentional: the goal is to illustrate how each IAM binding feature is wired, not provide drop-in access control modules. See the Spanner DatabaseIAMBinding resource reference for all available configuration options.
Let's configure GCP Spanner Database IAM Permissions
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Resource Selection & Compatibility
gcp.spanner.DatabaseIAMPolicy is fully authoritative and replaces the entire IAM policy. gcp.spanner.DatabaseIAMBinding is authoritative for a specific role but preserves other roles. gcp.spanner.DatabaseIAMMember is non-authoritative and adds individual members without affecting other members for that role.gcp.spanner.DatabaseIAMPolicy cannot be used with gcp.spanner.DatabaseIAMBinding or gcp.spanner.DatabaseIAMMember because they will conflict over policy management. However, DatabaseIAMBinding and DatabaseIAMMember can be used together as long as they don’t grant privileges to the same role.Common Pitfalls & Errors
gcp.spanner.DatabaseIAMPolicy removes any permissions not explicitly included in your configuration, including default permissions. Always include all necessary permissions in your policy to maintain access.Configuration & Syntax
The members array supports six formats:
allUsers(anyone on the internet)allAuthenticatedUsers(anyone with a Google account)user:{emailid}(specific Google account)serviceAccount:{emailid}(service account)group:{emailid}(Google group)domain:{domain}(all users in a G Suite domain)
[projects|organizations]/{parent-name}/roles/{role-name}. Only one gcp.spanner.DatabaseIAMBinding can be used per role.condition property with title, description, and expression fields to apply conditional access policies.Immutability & Updates
database, instance, project, role, and condition properties are all immutable and require resource replacement if changed.