The gcp:secretmanager/secretIamBinding:SecretIamBinding resource, part of the Pulumi GCP provider, manages IAM role bindings for Secret Manager secrets, controlling which identities can access secret data. This guide focuses on three capabilities: authoritative role binding for multiple members, time-based access expiration with IAM Conditions, and non-authoritative member addition.
IAM bindings reference existing Secret Manager secrets and grant access to GCP identities such as users, service accounts, and groups. The examples are intentionally small. Combine them with your own secrets and identity management strategy.
Grant a role to multiple members at once
Teams managing secret access often need to grant the same role to multiple users or service accounts simultaneously.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const binding = new gcp.secretmanager.SecretIamBinding("binding", {
project: secret_basic.project,
secretId: secret_basic.secretId,
role: "roles/secretmanager.secretAccessor",
members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp
binding = gcp.secretmanager.SecretIamBinding("binding",
project=secret_basic["project"],
secret_id=secret_basic["secretId"],
role="roles/secretmanager.secretAccessor",
members=["user:jane@example.com"])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := secretmanager.NewSecretIamBinding(ctx, "binding", &secretmanager.SecretIamBindingArgs{
Project: pulumi.Any(secret_basic.Project),
SecretId: pulumi.Any(secret_basic.SecretId),
Role: pulumi.String("roles/secretmanager.secretAccessor"),
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.SecretManager.SecretIamBinding("binding", new()
{
Project = secret_basic.Project,
SecretId = secret_basic.SecretId,
Role = "roles/secretmanager.secretAccessor",
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.secretmanager.SecretIamBinding;
import com.pulumi.gcp.secretmanager.SecretIamBindingArgs;
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 SecretIamBinding("binding", SecretIamBindingArgs.builder()
.project(secret_basic.project())
.secretId(secret_basic.secretId())
.role("roles/secretmanager.secretAccessor")
.members("user:jane@example.com")
.build());
}
}
resources:
binding:
type: gcp:secretmanager:SecretIamBinding
properties:
project: ${["secret-basic"].project}
secretId: ${["secret-basic"].secretId}
role: roles/secretmanager.secretAccessor
members:
- user:jane@example.com
The SecretIamBinding resource is authoritative for the specified role: it replaces all existing members for that role with the list you provide. The members array accepts various identity formats including user emails, service account emails, groups, and special identifiers like allAuthenticatedUsers. The role property specifies which permission set to grant; roles/secretmanager.secretAccessor allows reading secret values.
Add time-based access expiration with IAM Conditions
Temporary access grants require expiration dates to ensure permissions don’t persist beyond their intended lifetime.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const binding = new gcp.secretmanager.SecretIamBinding("binding", {
project: secret_basic.project,
secretId: secret_basic.secretId,
role: "roles/secretmanager.secretAccessor",
members: ["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
binding = gcp.secretmanager.SecretIamBinding("binding",
project=secret_basic["project"],
secret_id=secret_basic["secretId"],
role="roles/secretmanager.secretAccessor",
members=["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/secretmanager"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := secretmanager.NewSecretIamBinding(ctx, "binding", &secretmanager.SecretIamBindingArgs{
Project: pulumi.Any(secret_basic.Project),
SecretId: pulumi.Any(secret_basic.SecretId),
Role: pulumi.String("roles/secretmanager.secretAccessor"),
Members: pulumi.StringArray{
pulumi.String("user:jane@example.com"),
},
Condition: &secretmanager.SecretIamBindingConditionArgs{
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 binding = new Gcp.SecretManager.SecretIamBinding("binding", new()
{
Project = secret_basic.Project,
SecretId = secret_basic.SecretId,
Role = "roles/secretmanager.secretAccessor",
Members = new[]
{
"user:jane@example.com",
},
Condition = new Gcp.SecretManager.Inputs.SecretIamBindingConditionArgs
{
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.secretmanager.SecretIamBinding;
import com.pulumi.gcp.secretmanager.SecretIamBindingArgs;
import com.pulumi.gcp.secretmanager.inputs.SecretIamBindingConditionArgs;
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 SecretIamBinding("binding", SecretIamBindingArgs.builder()
.project(secret_basic.project())
.secretId(secret_basic.secretId())
.role("roles/secretmanager.secretAccessor")
.members("user:jane@example.com")
.condition(SecretIamBindingConditionArgs.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:
binding:
type: gcp:secretmanager:SecretIamBinding
properties:
project: ${["secret-basic"].project}
secretId: ${["secret-basic"].secretId}
role: roles/secretmanager.secretAccessor
members:
- 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")
IAM Conditions attach constraints to role bindings through CEL (Common Expression Language) expressions. The condition block requires a title for identification and an expression that evaluates to true or false. Here, request.time < timestamp(“2020-01-01T00:00:00Z”) grants access only until the specified date. When the condition evaluates to false, the binding no longer grants access even though it remains in the policy.
Add a single member to an existing role
When you need to grant access to one additional user without affecting other members, SecretIamMember provides non-authoritative updates.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const member = new gcp.secretmanager.SecretIamMember("member", {
project: secret_basic.project,
secretId: secret_basic.secretId,
role: "roles/secretmanager.secretAccessor",
member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp
member = gcp.secretmanager.SecretIamMember("member",
project=secret_basic["project"],
secret_id=secret_basic["secretId"],
role="roles/secretmanager.secretAccessor",
member="user:jane@example.com")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := secretmanager.NewSecretIamMember(ctx, "member", &secretmanager.SecretIamMemberArgs{
Project: pulumi.Any(secret_basic.Project),
SecretId: pulumi.Any(secret_basic.SecretId),
Role: pulumi.String("roles/secretmanager.secretAccessor"),
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.SecretManager.SecretIamMember("member", new()
{
Project = secret_basic.Project,
SecretId = secret_basic.SecretId,
Role = "roles/secretmanager.secretAccessor",
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.secretmanager.SecretIamMember;
import com.pulumi.gcp.secretmanager.SecretIamMemberArgs;
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 SecretIamMember("member", SecretIamMemberArgs.builder()
.project(secret_basic.project())
.secretId(secret_basic.secretId())
.role("roles/secretmanager.secretAccessor")
.member("user:jane@example.com")
.build());
}
}
resources:
member:
type: gcp:secretmanager:SecretIamMember
properties:
project: ${["secret-basic"].project}
secretId: ${["secret-basic"].secretId}
role: roles/secretmanager.secretAccessor
member: user:jane@example.com
Unlike SecretIamBinding, SecretIamMember adds a single member to a role without replacing existing members. The member property uses the same identity format as the members array in bindings. This resource is useful when multiple teams manage access independently; each can add their own members without coordinating changes to a shared binding.
Beyond these examples
These snippets focus on specific IAM binding features: role binding with multiple members, time-based access expiration, and incremental member addition. They’re intentionally minimal rather than full access control policies.
The examples reference pre-existing infrastructure such as Secret Manager secrets and a GCP project with Secret Manager API enabled. They focus on configuring IAM bindings rather than provisioning secrets or managing the broader identity landscape.
To keep things focused, common IAM patterns are omitted, including:
- Full IAM policy replacement (SecretIamPolicy)
- Custom role definitions and formatting
- Complex IAM Condition expressions (resource attributes, request context)
- Federated identity and workload identity pool configuration
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 Secret Manager SecretIamBinding resource reference for all available configuration options.
Let's manage GCP Secret Manager IAM Bindings
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Resource Conflicts & Compatibility
SecretIamPolicy is authoritative for the entire policy (replaces all existing bindings). SecretIamBinding is authoritative for a specific role (preserves other roles). SecretIamMember is non-authoritative (adds a single member to a role, preserves other members).SecretIamPolicy cannot be used with SecretIamBinding or SecretIamMember because they will conflict over the policy configuration.SecretIamBinding is authoritative for a given role, meaning it manages all members for that role. Multiple bindings for the same role would conflict.IAM Configuration & Members
You can use:
allUsersorallAuthenticatedUsers(special identifiers)user:{email},serviceAccount:{email},group:{email}(Google identities)domain:{domain}(G Suite domains)projectOwner/Editor/Viewer:{projectid}(project roles)principal://...(federated identities)
[projects|organizations]/{parent-name}/roles/{role-name}, for example projects/my-project/roles/my-custom-role.IAM Conditions & Time-Based Access
condition property with title, description, and expression fields. For example, set expression to request.time < timestamp("2020-01-01T00:00:00Z") for time-limited access. Note that IAM Conditions have known limitations.Immutability & Lifecycle
role, secretId, project, and condition properties are all immutable and require resource replacement if changed.