Manage GCP Cloud Storage Managed Folder IAM Access

The gcp:storage/managedFolderIamMember:ManagedFolderIamMember resource, part of the Pulumi GCP provider, grants IAM roles to individual members on Cloud Storage managed folders. This guide focuses on two capabilities: non-authoritative member grants and time-based IAM Conditions.

This resource references existing managed folders and adds members to roles without replacing other assignments. It’s one of three IAM resources for managed folders; ManagedFolderIamPolicy and ManagedFolderIamBinding provide authoritative control. The examples are intentionally small. Combine them with your own bucket and folder infrastructure.

Grant a role to a single member

When you need to give one user or service account access to a managed folder, this resource adds that member without affecting existing permissions.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const member = new gcp.storage.ManagedFolderIamMember("member", {
    bucket: folder.bucket,
    managedFolder: folder.name,
    role: "roles/storage.admin",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

member = gcp.storage.ManagedFolderIamMember("member",
    bucket=folder["bucket"],
    managed_folder=folder["name"],
    role="roles/storage.admin",
    member="user:jane@example.com")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/storage"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := storage.NewManagedFolderIamMember(ctx, "member", &storage.ManagedFolderIamMemberArgs{
			Bucket:        pulumi.Any(folder.Bucket),
			ManagedFolder: pulumi.Any(folder.Name),
			Role:          pulumi.String("roles/storage.admin"),
			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.Storage.ManagedFolderIamMember("member", new()
    {
        Bucket = folder.Bucket,
        ManagedFolder = folder.Name,
        Role = "roles/storage.admin",
        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.storage.ManagedFolderIamMember;
import com.pulumi.gcp.storage.ManagedFolderIamMemberArgs;
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 ManagedFolderIamMember("member", ManagedFolderIamMemberArgs.builder()
            .bucket(folder.bucket())
            .managedFolder(folder.name())
            .role("roles/storage.admin")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  member:
    type: gcp:storage:ManagedFolderIamMember
    properties:
      bucket: ${folder.bucket}
      managedFolder: ${folder.name}
      role: roles/storage.admin
      member: user:jane@example.com

The member property identifies who receives access using formats like “user:jane@example.com” or “serviceAccount:app@project.iam.gserviceaccount.com”. The role property specifies the permission level. Because this resource is non-authoritative, other members with the same role remain unchanged.

Add time-limited access with IAM Conditions

IAM Conditions grant temporary access that expires automatically, useful for contractors or time-bound projects.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const member = new gcp.storage.ManagedFolderIamMember("member", {
    bucket: folder.bucket,
    managedFolder: folder.name,
    role: "roles/storage.admin",
    member: "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

member = gcp.storage.ManagedFolderIamMember("member",
    bucket=folder["bucket"],
    managed_folder=folder["name"],
    role="roles/storage.admin",
    member="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/storage"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := storage.NewManagedFolderIamMember(ctx, "member", &storage.ManagedFolderIamMemberArgs{
			Bucket:        pulumi.Any(folder.Bucket),
			ManagedFolder: pulumi.Any(folder.Name),
			Role:          pulumi.String("roles/storage.admin"),
			Member:        pulumi.String("user:jane@example.com"),
			Condition: &storage.ManagedFolderIamMemberConditionArgs{
				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 member = new Gcp.Storage.ManagedFolderIamMember("member", new()
    {
        Bucket = folder.Bucket,
        ManagedFolder = folder.Name,
        Role = "roles/storage.admin",
        Member = "user:jane@example.com",
        Condition = new Gcp.Storage.Inputs.ManagedFolderIamMemberConditionArgs
        {
            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.storage.ManagedFolderIamMember;
import com.pulumi.gcp.storage.ManagedFolderIamMemberArgs;
import com.pulumi.gcp.storage.inputs.ManagedFolderIamMemberConditionArgs;
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 ManagedFolderIamMember("member", ManagedFolderIamMemberArgs.builder()
            .bucket(folder.bucket())
            .managedFolder(folder.name())
            .role("roles/storage.admin")
            .member("user:jane@example.com")
            .condition(ManagedFolderIamMemberConditionArgs.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:
  member:
    type: gcp:storage:ManagedFolderIamMember
    properties:
      bucket: ${folder.bucket}
      managedFolder: ${folder.name}
      role: roles/storage.admin
      member: 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")

The condition block adds time-based restrictions to the role grant. The expression property uses CEL (Common Expression Language) to define when access is valid; here, it expires at midnight on 2020-01-01. The title and description help identify the condition’s purpose in audit logs.

Beyond these examples

These snippets focus on specific member-level features: single-member IAM grants and time-based access conditions. They’re intentionally minimal rather than full access control configurations.

The examples reference pre-existing infrastructure such as Cloud Storage buckets with managed folders. They focus on granting access to individual members rather than managing complete IAM policies.

To keep things focused, common IAM patterns are omitted, including:

  • Policy and Binding resources (authoritative alternatives)
  • Multiple members or roles in one resource
  • Complex condition expressions (location, resource attributes)
  • Custom role definitions

These omissions are intentional: the goal is to illustrate how member grants are wired, not provide drop-in access control modules. See the ManagedFolderIamMember resource reference for all available configuration options.

Let's manage GCP Cloud Storage Managed Folder IAM Access

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Resource Selection & Conflicts
Can I use ManagedFolderIamPolicy with ManagedFolderIamBinding or ManagedFolderIamMember?
No, ManagedFolderIamPolicy cannot be used with ManagedFolderIamBinding or ManagedFolderIamMember as they will conflict over the policy configuration.
Can I use ManagedFolderIamBinding and ManagedFolderIamMember together?
Yes, but only if they don’t grant privileges to the same role. Each role must be managed by only one resource type.
Which IAM resource should I use for my managed folder?
Choose based on your needs: ManagedFolderIamPolicy for complete policy control (replaces entire policy), ManagedFolderIamBinding for managing all members of a specific role (authoritative per role), or ManagedFolderIamMember for adding individual members without affecting others (non-authoritative).
What's the difference between authoritative and non-authoritative IAM resources?
Authoritative resources (ManagedFolderIamPolicy and ManagedFolderIamBinding) replace existing configuration, while non-authoritative (ManagedFolderIamMember) adds to existing configuration without removing other members.
Configuration & Identity Formats
What member identity formats are supported?
Supported formats include user:{email}, serviceAccount:{email}, group:{email}, domain:{domain}, allUsers, allAuthenticatedUsers, projectOwner:{projectid}, projectEditor:{projectid}, and projectViewer:{projectid}.
How do I specify a custom IAM role?
Use the full role name format: [projects|organizations]/{parent-name}/roles/{role-name}. For example, projects/my-project/roles/my-custom-role.
What properties can't be changed after creation?
All input properties are immutable: bucket, managedFolder, member, role, and condition. Changes require resource replacement.
Advanced Features & Limitations
Can I use IAM Conditions with managed folder IAM resources?
Yes, IAM Conditions are supported through the condition property, but they have known limitations. Set title, description, and expression fields to define time-based or attribute-based access controls.

Using a different cloud?

Explore security guides for other cloud providers: