Manage GCP BigQuery Dataset IAM Policies

The gcp:bigquery/datasetIamPolicy:DatasetIamPolicy resource, part of the Pulumi GCP provider, manages IAM permissions for BigQuery datasets using standard GCP IAM roles and bindings. This guide focuses on four capabilities: authoritative policy replacement (DatasetIamPolicy), single-role management (DatasetIamBinding), incremental member grants (DatasetIamMember), and time-based IAM conditions.

These resources reference existing BigQuery datasets and cannot be used with DatasetAccess or the access field on Dataset resources. The examples are intentionally small. Combine them with your own dataset infrastructure and organizational IAM strategy.

Replace the entire IAM policy for a dataset

When you need complete control over who can access a dataset, DatasetIamPolicy replaces the entire IAM policy with your specified bindings.

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

const owner = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/bigquery.dataOwner",
        members: ["user:jane@example.com"],
    }],
});
const datasetDataset = new gcp.bigquery.Dataset("dataset", {datasetId: "example_dataset"});
const dataset = new gcp.bigquery.DatasetIamPolicy("dataset", {
    datasetId: datasetDataset.datasetId,
    policyData: owner.then(owner => owner.policyData),
});
import pulumi
import pulumi_gcp as gcp

owner = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/bigquery.dataOwner",
    "members": ["user:jane@example.com"],
}])
dataset_dataset = gcp.bigquery.Dataset("dataset", dataset_id="example_dataset")
dataset = gcp.bigquery.DatasetIamPolicy("dataset",
    dataset_id=dataset_dataset.dataset_id,
    policy_data=owner.policy_data)
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		owner, err := organizations.LookupIAMPolicy(ctx, &organizations.LookupIAMPolicyArgs{
			Bindings: []organizations.GetIAMPolicyBinding{
				{
					Role: "roles/bigquery.dataOwner",
					Members: []string{
						"user:jane@example.com",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		datasetDataset, err := bigquery.NewDataset(ctx, "dataset", &bigquery.DatasetArgs{
			DatasetId: pulumi.String("example_dataset"),
		})
		if err != nil {
			return err
		}
		_, err = bigquery.NewDatasetIamPolicy(ctx, "dataset", &bigquery.DatasetIamPolicyArgs{
			DatasetId:  datasetDataset.DatasetId,
			PolicyData: pulumi.String(owner.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 owner = Gcp.Organizations.GetIAMPolicy.Invoke(new()
    {
        Bindings = new[]
        {
            new Gcp.Organizations.Inputs.GetIAMPolicyBindingInputArgs
            {
                Role = "roles/bigquery.dataOwner",
                Members = new[]
                {
                    "user:jane@example.com",
                },
            },
        },
    });

    var datasetDataset = new Gcp.BigQuery.Dataset("dataset", new()
    {
        DatasetId = "example_dataset",
    });

    var dataset = new Gcp.BigQuery.DatasetIamPolicy("dataset", new()
    {
        DatasetId = datasetDataset.DatasetId,
        PolicyData = owner.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.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.bigquery.DatasetIamPolicy;
import com.pulumi.gcp.bigquery.DatasetIamPolicyArgs;
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 owner = OrganizationsFunctions.getIAMPolicy(GetIAMPolicyArgs.builder()
            .bindings(GetIAMPolicyBindingArgs.builder()
                .role("roles/bigquery.dataOwner")
                .members("user:jane@example.com")
                .build())
            .build());

        var datasetDataset = new Dataset("datasetDataset", DatasetArgs.builder()
            .datasetId("example_dataset")
            .build());

        var dataset = new DatasetIamPolicy("dataset", DatasetIamPolicyArgs.builder()
            .datasetId(datasetDataset.datasetId())
            .policyData(owner.policyData())
            .build());

    }
}
resources:
  dataset:
    type: gcp:bigquery:DatasetIamPolicy
    properties:
      datasetId: ${datasetDataset.datasetId}
      policyData: ${owner.policyData}
  datasetDataset:
    type: gcp:bigquery:Dataset
    name: dataset
    properties:
      datasetId: example_dataset
variables:
  owner:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/bigquery.dataOwner
            members:
              - user:jane@example.com

DatasetIamPolicy is authoritative: it replaces any existing policy on the dataset. The policyData comes from getIAMPolicy, which constructs the policy document from bindings. Each binding maps a role to a list of members. This approach works when you want to define all permissions in one place, but it will remove any permissions not explicitly listed.

Add time-based expiration to policy bindings

Temporary access grants often require automatic expiration to reduce manual cleanup and security risk.

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

const owner = gcp.organizations.getIAMPolicy({
    bindings: [{
        role: "roles/bigquery.dataOwner",
        members: ["user:jane@example.com"],
        condition: {
            title: "expires_after_2029_12_31",
            description: "Expiring at midnight of 2029-12-31",
            expression: "request.time < timestamp(\"2030-01-01T00:00:00Z\")",
        },
    }],
});
const datasetDataset = new gcp.bigquery.Dataset("dataset", {datasetId: "example_dataset"});
const dataset = new gcp.bigquery.DatasetIamPolicy("dataset", {
    datasetId: datasetDataset.datasetId,
    policyData: owner.then(owner => owner.policyData),
});
import pulumi
import pulumi_gcp as gcp

owner = gcp.organizations.get_iam_policy(bindings=[{
    "role": "roles/bigquery.dataOwner",
    "members": ["user:jane@example.com"],
    "condition": {
        "title": "expires_after_2029_12_31",
        "description": "Expiring at midnight of 2029-12-31",
        "expression": "request.time < timestamp(\"2030-01-01T00:00:00Z\")",
    },
}])
dataset_dataset = gcp.bigquery.Dataset("dataset", dataset_id="example_dataset")
dataset = gcp.bigquery.DatasetIamPolicy("dataset",
    dataset_id=dataset_dataset.dataset_id,
    policy_data=owner.policy_data)
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		owner, err := organizations.LookupIAMPolicy(ctx, &organizations.LookupIAMPolicyArgs{
			Bindings: []organizations.GetIAMPolicyBinding{
				{
					Role: "roles/bigquery.dataOwner",
					Members: []string{
						"user:jane@example.com",
					},
					Condition: {
						Title:       "expires_after_2029_12_31",
						Description: pulumi.StringRef("Expiring at midnight of 2029-12-31"),
						Expression:  "request.time < timestamp(\"2030-01-01T00:00:00Z\")",
					},
				},
			},
		}, nil)
		if err != nil {
			return err
		}
		datasetDataset, err := bigquery.NewDataset(ctx, "dataset", &bigquery.DatasetArgs{
			DatasetId: pulumi.String("example_dataset"),
		})
		if err != nil {
			return err
		}
		_, err = bigquery.NewDatasetIamPolicy(ctx, "dataset", &bigquery.DatasetIamPolicyArgs{
			DatasetId:  datasetDataset.DatasetId,
			PolicyData: pulumi.String(owner.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 owner = Gcp.Organizations.GetIAMPolicy.Invoke(new()
    {
        Bindings = new[]
        {
            new Gcp.Organizations.Inputs.GetIAMPolicyBindingInputArgs
            {
                Role = "roles/bigquery.dataOwner",
                Members = new[]
                {
                    "user:jane@example.com",
                },
                Condition = new Gcp.Organizations.Inputs.GetIAMPolicyBindingConditionInputArgs
                {
                    Title = "expires_after_2029_12_31",
                    Description = "Expiring at midnight of 2029-12-31",
                    Expression = "request.time < timestamp(\"2030-01-01T00:00:00Z\")",
                },
            },
        },
    });

    var datasetDataset = new Gcp.BigQuery.Dataset("dataset", new()
    {
        DatasetId = "example_dataset",
    });

    var dataset = new Gcp.BigQuery.DatasetIamPolicy("dataset", new()
    {
        DatasetId = datasetDataset.DatasetId,
        PolicyData = owner.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.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.bigquery.DatasetIamPolicy;
import com.pulumi.gcp.bigquery.DatasetIamPolicyArgs;
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 owner = OrganizationsFunctions.getIAMPolicy(GetIAMPolicyArgs.builder()
            .bindings(GetIAMPolicyBindingArgs.builder()
                .role("roles/bigquery.dataOwner")
                .members("user:jane@example.com")
                .condition(GetIAMPolicyBindingConditionArgs.builder()
                    .title("expires_after_2029_12_31")
                    .description("Expiring at midnight of 2029-12-31")
                    .expression("request.time < timestamp(\"2030-01-01T00:00:00Z\")")
                    .build())
                .build())
            .build());

        var datasetDataset = new Dataset("datasetDataset", DatasetArgs.builder()
            .datasetId("example_dataset")
            .build());

        var dataset = new DatasetIamPolicy("dataset", DatasetIamPolicyArgs.builder()
            .datasetId(datasetDataset.datasetId())
            .policyData(owner.policyData())
            .build());

    }
}
resources:
  dataset:
    type: gcp:bigquery:DatasetIamPolicy
    properties:
      datasetId: ${datasetDataset.datasetId}
      policyData: ${owner.policyData}
  datasetDataset:
    type: gcp:bigquery:Dataset
    name: dataset
    properties:
      datasetId: example_dataset
variables:
  owner:
    fn::invoke:
      function: gcp:organizations:getIAMPolicy
      arguments:
        bindings:
          - role: roles/bigquery.dataOwner
            members:
              - user:jane@example.com
            condition:
              title: expires_after_2029_12_31
              description: Expiring at midnight of 2029-12-31
              expression: request.time < timestamp("2030-01-01T00:00:00Z")

IAM conditions add temporal or contextual constraints to role bindings. The condition block requires a title, optional description, and an expression using Common Expression Language (CEL). The expression request.time < timestamp("2030-01-01T00:00:00Z") grants access only until the specified date. After that timestamp, the binding becomes inactive automatically.

Grant a role to multiple members at once

When multiple users or service accounts need the same level of access, DatasetIamBinding manages all members for a single role together.

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

const dataset = new gcp.bigquery.Dataset("dataset", {datasetId: "example_dataset"});
const reader = new gcp.bigquery.DatasetIamBinding("reader", {
    datasetId: dataset.datasetId,
    role: "roles/bigquery.dataViewer",
    members: ["user:jane@example.com"],
});
import pulumi
import pulumi_gcp as gcp

dataset = gcp.bigquery.Dataset("dataset", dataset_id="example_dataset")
reader = gcp.bigquery.DatasetIamBinding("reader",
    dataset_id=dataset.dataset_id,
    role="roles/bigquery.dataViewer",
    members=["user:jane@example.com"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		dataset, err := bigquery.NewDataset(ctx, "dataset", &bigquery.DatasetArgs{
			DatasetId: pulumi.String("example_dataset"),
		})
		if err != nil {
			return err
		}
		_, err = bigquery.NewDatasetIamBinding(ctx, "reader", &bigquery.DatasetIamBindingArgs{
			DatasetId: dataset.DatasetId,
			Role:      pulumi.String("roles/bigquery.dataViewer"),
			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 dataset = new Gcp.BigQuery.Dataset("dataset", new()
    {
        DatasetId = "example_dataset",
    });

    var reader = new Gcp.BigQuery.DatasetIamBinding("reader", new()
    {
        DatasetId = dataset.DatasetId,
        Role = "roles/bigquery.dataViewer",
        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.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.bigquery.DatasetIamBinding;
import com.pulumi.gcp.bigquery.DatasetIamBindingArgs;
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 dataset = new Dataset("dataset", DatasetArgs.builder()
            .datasetId("example_dataset")
            .build());

        var reader = new DatasetIamBinding("reader", DatasetIamBindingArgs.builder()
            .datasetId(dataset.datasetId())
            .role("roles/bigquery.dataViewer")
            .members("user:jane@example.com")
            .build());

    }
}
resources:
  reader:
    type: gcp:bigquery:DatasetIamBinding
    properties:
      datasetId: ${dataset.datasetId}
      role: roles/bigquery.dataViewer
      members:
        - user:jane@example.com
  dataset:
    type: gcp:bigquery:Dataset
    properties:
      datasetId: example_dataset

DatasetIamBinding is authoritative for a single role: it sets the complete member list for that role while preserving other roles on the dataset. The members property accepts a list of identities (users, service accounts, groups). This resource works well when you manage access by role rather than by individual member, but it will replace any existing members for that specific role.

Add a single member to a role incrementally

Applications that grant access dynamically often add one member at a time without affecting other role assignments.

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

const dataset = new gcp.bigquery.Dataset("dataset", {datasetId: "example_dataset"});
const editor = new gcp.bigquery.DatasetIamMember("editor", {
    datasetId: dataset.datasetId,
    role: "roles/bigquery.dataEditor",
    member: "user:jane@example.com",
});
import pulumi
import pulumi_gcp as gcp

dataset = gcp.bigquery.Dataset("dataset", dataset_id="example_dataset")
editor = gcp.bigquery.DatasetIamMember("editor",
    dataset_id=dataset.dataset_id,
    role="roles/bigquery.dataEditor",
    member="user:jane@example.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		dataset, err := bigquery.NewDataset(ctx, "dataset", &bigquery.DatasetArgs{
			DatasetId: pulumi.String("example_dataset"),
		})
		if err != nil {
			return err
		}
		_, err = bigquery.NewDatasetIamMember(ctx, "editor", &bigquery.DatasetIamMemberArgs{
			DatasetId: dataset.DatasetId,
			Role:      pulumi.String("roles/bigquery.dataEditor"),
			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 dataset = new Gcp.BigQuery.Dataset("dataset", new()
    {
        DatasetId = "example_dataset",
    });

    var editor = new Gcp.BigQuery.DatasetIamMember("editor", new()
    {
        DatasetId = dataset.DatasetId,
        Role = "roles/bigquery.dataEditor",
        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.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.bigquery.DatasetIamMember;
import com.pulumi.gcp.bigquery.DatasetIamMemberArgs;
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 dataset = new Dataset("dataset", DatasetArgs.builder()
            .datasetId("example_dataset")
            .build());

        var editor = new DatasetIamMember("editor", DatasetIamMemberArgs.builder()
            .datasetId(dataset.datasetId())
            .role("roles/bigquery.dataEditor")
            .member("user:jane@example.com")
            .build());

    }
}
resources:
  editor:
    type: gcp:bigquery:DatasetIamMember
    properties:
      datasetId: ${dataset.datasetId}
      role: roles/bigquery.dataEditor
      member: user:jane@example.com
  dataset:
    type: gcp:bigquery:Dataset
    properties:
      datasetId: example_dataset

DatasetIamMember is non-authoritative: it adds one member to a role without modifying other members or roles. The member property takes a single identity string. This resource is useful for incremental access grants, such as when users request access through an approval workflow. Multiple DatasetIamMember resources can target the same role without conflict.

Beyond these examples

These snippets focus on specific IAM management approaches: authoritative vs non-authoritative IAM management, role-based access control, and time-based IAM conditions. They’re intentionally minimal rather than full access control systems.

The examples reference pre-existing infrastructure such as BigQuery datasets (referenced by datasetId) and GCP project context. They focus on IAM configuration rather than dataset provisioning.

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

  • Authorized views (use DatasetAccess instead)
  • Legacy BigQuery roles (OWNER, WRITER, READER)
  • Combining Policy with Binding/Member resources
  • Multiple conditions per binding

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 BigQuery DatasetIamPolicy resource reference for all available configuration options.

Let's manage GCP BigQuery Dataset IAM Policies

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 & Compatibility
What's the difference between DatasetIamPolicy, DatasetIamBinding, and DatasetIamMember?
DatasetIamPolicy is authoritative and replaces the entire IAM policy. DatasetIamBinding is authoritative for a single role, preserving other roles. DatasetIamMember is non-authoritative and adds individual members without affecting others.
Can I use DatasetIamPolicy with DatasetIamBinding or DatasetIamMember?
No, DatasetIamPolicy cannot be used with DatasetIamBinding or DatasetIamMember because they’ll conflict over the policy. Choose either full policy control (Policy) or granular control (Binding/Member).
Can I use DatasetIamBinding with DatasetIamMember?
Yes, but only if they don’t grant privileges to the same role. If they target the same role, they’ll conflict.
Can I use these IAM resources with DatasetAccess or the access field?
No, IAM resources (DatasetIamPolicy, DatasetIamBinding, DatasetIamMember) cannot be used with gcp.bigquery.DatasetAccess or the access field on gcp.bigquery.Dataset. They’ll conflict over permissions.
Role Configuration
What role names should I use for BigQuery dataset permissions?
Use full role forms: roles/bigquery.dataOwner, roles/bigquery.dataEditor, and roles/bigquery.dataViewer. Legacy role names (OWNER, WRITER, READER) are not supported.
How do I add time-based expiration to IAM permissions?
Use the condition field with title, description, and expression. For example, set expression to request.time < timestamp("2030-01-01T00:00:00Z") for expiration.
Advanced Use Cases
How do I create authorized views for my dataset?
Use gcp.bigquery.DatasetAccess or the access field on gcp.bigquery.Dataset. IAM resources don’t support authorized views.
Why did my authorized view permissions disappear?
Using any IAM resource (DatasetIamPolicy, DatasetIamBinding, DatasetIamMember) removes authorized view permissions. Use gcp.bigquery.DatasetAccess to preserve them.
Configuration Details
What properties are immutable after creation?
datasetId and project cannot be changed after the resource is created.
How do I generate the policyData for DatasetIamPolicy?
Use the gcp.organizations.getIAMPolicy data source to generate policyData with your desired bindings.

Using a different cloud?

Explore security guides for other cloud providers: