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 IAM roles and bindings. This guide focuses on four capabilities: authoritative policy replacement (DatasetIamPolicy), single-role management (DatasetIamBinding), individual member grants (DatasetIamMember), and time-based conditional access.

These resources reference existing BigQuery datasets and convert BigQuery’s legacy permission system to standard IAM. They cannot be used with DatasetAccess resources or the access field on Dataset, as they will conflict. For authorized views, use DatasetAccess instead. The examples are intentionally small. Combine them with your own datasets and IAM principals.

Replace the entire IAM policy with DatasetIamPolicy

When you need complete control over dataset access, DatasetIamPolicy replaces the entire IAM policy in one operation. This is useful when migrating from legacy BigQuery permissions to standard IAM roles.

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

The getIAMPolicy data source generates the policy document with role bindings. DatasetIamPolicy applies this policy to the dataset, replacing any existing permissions. The policyData property contains the complete IAM policy; any roles or members not listed are removed.

Add time-based conditions to policy bindings

IAM conditions let you grant temporary access that expires automatically, useful for contractors or time-limited projects.

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")

The condition block adds temporal constraints to role bindings. The expression uses CEL (Common Expression Language) to compare request.time against a timestamp. When the condition evaluates to false, the binding no longer grants access. The title and description help identify the condition’s purpose.

Grant a role to multiple members with DatasetIamBinding

When multiple users need the same level of access, DatasetIamBinding manages all members for a single role without affecting other roles on the dataset.

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 but non-authoritative for the dataset. It sets the complete member list for roles/bigquery.dataViewer, but other roles (like dataOwner or dataEditor) remain unchanged. The members array accepts user, serviceAccount, and group identities.

Add individual members with DatasetIamMember

For incremental permission changes, DatasetIamMember adds one member to one role without disturbing existing members or other roles.

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 at both the role and dataset level. It adds a single member to a role, preserving other members for that role and all other role bindings. Use this when you need to grant access without knowing or affecting the complete member list.

Beyond these examples

These snippets focus on specific IAM management features: authoritative vs non-authoritative IAM management, conditional access with time-based expiration, and role-level and member-level permission grants. They’re intentionally minimal rather than full access control configurations.

The examples reference pre-existing infrastructure such as BigQuery datasets (created separately) and a GCP project with BigQuery API enabled. They focus on IAM binding configuration rather than dataset provisioning.

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

  • Advanced conditions (resource attributes, request context)
  • Service account and group member types
  • Multiple role bindings in a single policy
  • Authorized view permissions (requires DatasetAccess resource)

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 Conflicts & Compatibility
Can I use DatasetIamPolicy with DatasetAccess or the access field on Dataset?
No, these IAM resources cannot be used with gcp.bigquery.DatasetAccess or the access field on gcp.bigquery.Dataset - they will conflict over the policy configuration.
Can I use DatasetIamPolicy together with DatasetIamBinding or DatasetIamMember?
No, gcp.bigquery.DatasetIamPolicy cannot be used with gcp.bigquery.DatasetIamBinding or gcp.bigquery.DatasetIamMember - they will conflict over the policy. Use DatasetIamPolicy alone, or use Binding/Member together without Policy.
Can I use DatasetIamBinding and DatasetIamMember together?
Yes, but only if they don’t grant privileges to the same role. Each role must be managed by only one resource type.
What happens to authorized view permissions when I use these IAM resources?
Using any of these IAM resources will remove authorized view permissions from the dataset. To preserve authorized views, use gcp.bigquery.DatasetAccess instead.
Resource Selection
What's the difference between DatasetIamPolicy, DatasetIamBinding, and DatasetIamMember?
DatasetIamPolicy is authoritative and replaces the entire IAM policy. DatasetIamBinding is authoritative for a specific role but preserves other roles. DatasetIamMember is non-authoritative and adds a single member to a role without affecting other members.
When should I use DatasetAccess instead of these IAM resources?
Use gcp.bigquery.DatasetAccess for advanced use cases like creating authorized views, or when you need to preserve existing authorized view permissions.
Role Configuration
Can I use legacy BigQuery roles like OWNER, WRITER, and READER?
No, legacy roles cannot be used with these IAM resources. Use the full role forms instead: roles/bigquery.dataOwner, roles/bigquery.dataEditor, and roles/bigquery.dataViewer.
IAM Conditions
How do I add time-based or conditional IAM permissions?
Add a condition block with title, description, and expression fields. For example, use request.time < timestamp("2030-01-01T00:00:00Z") to expire permissions at a specific date.

Using a different cloud?

Explore security guides for other cloud providers: