The gcp:spanner/databaseIAMBinding:DatabaseIAMBinding resource, part of the Pulumi GCP provider, manages all members who have a specific IAM role on a Spanner database. When you apply a binding, it replaces any existing members for that role. This guide focuses on two capabilities: granting roles to multiple members and applying conditional access with CEL expressions.
DatabaseIAMBinding is one of three IAM resources for Spanner databases. It’s authoritative for a single role but preserves other roles on the database. DatabaseIAMBinding can coexist with DatabaseIAMMember resources as long as they manage different roles. The examples are intentionally small. Combine them with your own Spanner infrastructure and identity management.
Grant a role to multiple members at once
When multiple users or service accounts need the same database permissions, DatabaseIAMBinding manages them as a group.
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
The role property specifies which IAM role to grant. The members array lists all identities that should have this role; any existing members not in this list are removed. The instance and database properties identify which Spanner database to configure. This binding is authoritative for the specified role: it replaces all existing members.
Apply conditional access based on resource attributes
For fine-grained control, IAM Conditions restrict permissions to specific database roles or resources.
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")))
The condition block adds a CEL expression that evaluates at request time. The expression checks resource type and name, granting access only when the condition matches. The title and description document the condition’s purpose. Here, the binding grants roles/compute.networkUser only for operations on the database role named “myrole”.
Beyond these examples
These snippets focus on specific DatabaseIAMBinding features: role-based member management and conditional access with CEL expressions. They’re intentionally minimal rather than complete access control configurations.
The examples reference pre-existing infrastructure such as Spanner instances and databases, and database roles for conditional access. They focus on configuring IAM bindings rather than provisioning the underlying Spanner resources.
To keep things focused, common IAM patterns are omitted, including:
- Full policy replacement (DatabaseIAMPolicy)
- Single-member grants (DatabaseIAMMember)
- Multiple conditions per role
- Custom role definitions
These omissions are intentional: the goal is to illustrate how DatabaseIAMBinding wires access control, not provide drop-in security 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 replaces the entire IAM policy (authoritative), gcp.spanner.DatabaseIAMBinding manages all members for a specific role (authoritative per role), and gcp.spanner.DatabaseIAMMember adds individual members to a role (non-authoritative). Use DatabaseIAMBinding or DatabaseIAMMember for most cases to avoid accidentally removing existing permissions.gcp.spanner.DatabaseIAMPolicy cannot be used with gcp.spanner.DatabaseIAMBinding or gcp.spanner.DatabaseIAMMember because they will conflict over policy management. Choose one approach for your database.Configuration & Usage
allUsers (anyone on the internet), allAuthenticatedUsers (anyone with a Google account), user:{email} (specific Google account), serviceAccount:{email} (service account), group:{email} (Google group), or domain:{domain} (G Suite domain).[projects|organizations]/{parent-name}/roles/{role-name}, for example projects/my-project/roles/my-custom-role.condition block with title, description, and expression fields. For example, to grant access to a specific database role: expression: "(resource.type == \"spanner.googleapis.com/DatabaseRole\" && (resource.name.endsWith(\"/myrole\")))".gcp.spanner.DatabaseIAMBinding can be used per role. If you need to manage members individually, use gcp.spanner.DatabaseIAMMember instead.Common Pitfalls
gcp.spanner.DatabaseIAMPolicy replaces the entire IAM policy, removing any default permissions not explicitly included in your configuration. Always include all necessary permissions, or use gcp.spanner.DatabaseIAMBinding or gcp.spanner.DatabaseIAMMember instead.database, instance, project, role, and condition properties are immutable. To change these, you must delete and recreate the resource.