Create GCP Healthcare Consent Stores

The gcp:healthcare/consentStore:ConsentStore resource, part of the Pulumi GCP provider, defines a consent store within a healthcare dataset for tracking user consents and associated documentation. This guide focuses on three capabilities: creating consent stores in healthcare datasets, configuring consent expiration policies, and managing IAM access to consent data.

Consent stores belong to healthcare datasets and require IAM configuration for application access. The examples are intentionally small. Combine them with your own dataset infrastructure and access policies.

Healthcare applications that track user consents start by creating a consent store within an existing dataset.

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

const dataset = new gcp.healthcare.Dataset("dataset", {
    location: "us-central1",
    name: "my-dataset",
});
const my_consent = new gcp.healthcare.ConsentStore("my-consent", {
    dataset: dataset.id,
    name: "my-consent-store",
});
import pulumi
import pulumi_gcp as gcp

dataset = gcp.healthcare.Dataset("dataset",
    location="us-central1",
    name="my-dataset")
my_consent = gcp.healthcare.ConsentStore("my-consent",
    dataset=dataset.id,
    name="my-consent-store")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		dataset, err := healthcare.NewDataset(ctx, "dataset", &healthcare.DatasetArgs{
			Location: pulumi.String("us-central1"),
			Name:     pulumi.String("my-dataset"),
		})
		if err != nil {
			return err
		}
		_, err = healthcare.NewConsentStore(ctx, "my-consent", &healthcare.ConsentStoreArgs{
			Dataset: dataset.ID(),
			Name:    pulumi.String("my-consent-store"),
		})
		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.Healthcare.Dataset("dataset", new()
    {
        Location = "us-central1",
        Name = "my-dataset",
    });

    var my_consent = new Gcp.Healthcare.ConsentStore("my-consent", new()
    {
        Dataset = dataset.Id,
        Name = "my-consent-store",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.healthcare.Dataset;
import com.pulumi.gcp.healthcare.DatasetArgs;
import com.pulumi.gcp.healthcare.ConsentStore;
import com.pulumi.gcp.healthcare.ConsentStoreArgs;
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()
            .location("us-central1")
            .name("my-dataset")
            .build());

        var my_consent = new ConsentStore("my-consent", ConsentStoreArgs.builder()
            .dataset(dataset.id())
            .name("my-consent-store")
            .build());

    }
}
resources:
  dataset:
    type: gcp:healthcare:Dataset
    properties:
      location: us-central1
      name: my-dataset
  my-consent:
    type: gcp:healthcare:ConsentStore
    properties:
      dataset: ${dataset.id}
      name: my-consent-store

The dataset property references the parent healthcare dataset using its full resource path. The name property sets the consent store identifier within that dataset. The store provides a namespace for organizing consent records and their documentation.

Organizations with consent lifecycle policies need to control how long consents remain valid and whether updates can create new records automatically.

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

const dataset = new gcp.healthcare.Dataset("dataset", {
    location: "us-central1",
    name: "my-dataset",
});
const my_consent = new gcp.healthcare.ConsentStore("my-consent", {
    dataset: dataset.id,
    name: "my-consent-store",
    enableConsentCreateOnUpdate: true,
    defaultConsentTtl: "90000s",
    labels: {
        label1: "labelvalue1",
    },
});
import pulumi
import pulumi_gcp as gcp

dataset = gcp.healthcare.Dataset("dataset",
    location="us-central1",
    name="my-dataset")
my_consent = gcp.healthcare.ConsentStore("my-consent",
    dataset=dataset.id,
    name="my-consent-store",
    enable_consent_create_on_update=True,
    default_consent_ttl="90000s",
    labels={
        "label1": "labelvalue1",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		dataset, err := healthcare.NewDataset(ctx, "dataset", &healthcare.DatasetArgs{
			Location: pulumi.String("us-central1"),
			Name:     pulumi.String("my-dataset"),
		})
		if err != nil {
			return err
		}
		_, err = healthcare.NewConsentStore(ctx, "my-consent", &healthcare.ConsentStoreArgs{
			Dataset:                     dataset.ID(),
			Name:                        pulumi.String("my-consent-store"),
			EnableConsentCreateOnUpdate: pulumi.Bool(true),
			DefaultConsentTtl:           pulumi.String("90000s"),
			Labels: pulumi.StringMap{
				"label1": pulumi.String("labelvalue1"),
			},
		})
		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.Healthcare.Dataset("dataset", new()
    {
        Location = "us-central1",
        Name = "my-dataset",
    });

    var my_consent = new Gcp.Healthcare.ConsentStore("my-consent", new()
    {
        Dataset = dataset.Id,
        Name = "my-consent-store",
        EnableConsentCreateOnUpdate = true,
        DefaultConsentTtl = "90000s",
        Labels = 
        {
            { "label1", "labelvalue1" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.healthcare.Dataset;
import com.pulumi.gcp.healthcare.DatasetArgs;
import com.pulumi.gcp.healthcare.ConsentStore;
import com.pulumi.gcp.healthcare.ConsentStoreArgs;
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()
            .location("us-central1")
            .name("my-dataset")
            .build());

        var my_consent = new ConsentStore("my-consent", ConsentStoreArgs.builder()
            .dataset(dataset.id())
            .name("my-consent-store")
            .enableConsentCreateOnUpdate(true)
            .defaultConsentTtl("90000s")
            .labels(Map.of("label1", "labelvalue1"))
            .build());

    }
}
resources:
  dataset:
    type: gcp:healthcare:Dataset
    properties:
      location: us-central1
      name: my-dataset
  my-consent:
    type: gcp:healthcare:ConsentStore
    properties:
      dataset: ${dataset.id}
      name: my-consent-store
      enableConsentCreateOnUpdate: true
      defaultConsentTtl: 90000s
      labels:
        label1: labelvalue1

The defaultConsentTtl property sets the expiration time for new consents as a duration string (e.g., “90000s” for 25 hours). The enableConsentCreateOnUpdate property allows consent updates to create records if they don’t exist, simplifying application logic. The labels property adds key-value metadata for organization and filtering.

Applications that read or modify consent records need IAM permissions scoped to specific consent stores.

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

const dataset = new gcp.healthcare.Dataset("dataset", {
    location: "us-central1",
    name: "my-dataset",
});
const my_consent = new gcp.healthcare.ConsentStore("my-consent", {
    dataset: dataset.id,
    name: "my-consent-store",
});
const test_account = new gcp.serviceaccount.Account("test-account", {
    accountId: "my-account",
    displayName: "Test Service Account",
});
const test_iam = new gcp.healthcare.ConsentStoreIamMember("test-iam", {
    dataset: dataset.id,
    consentStoreId: my_consent.name,
    role: "roles/editor",
    member: pulumi.interpolate`serviceAccount:${test_account.email}`,
});
import pulumi
import pulumi_gcp as gcp

dataset = gcp.healthcare.Dataset("dataset",
    location="us-central1",
    name="my-dataset")
my_consent = gcp.healthcare.ConsentStore("my-consent",
    dataset=dataset.id,
    name="my-consent-store")
test_account = gcp.serviceaccount.Account("test-account",
    account_id="my-account",
    display_name="Test Service Account")
test_iam = gcp.healthcare.ConsentStoreIamMember("test-iam",
    dataset=dataset.id,
    consent_store_id=my_consent.name,
    role="roles/editor",
    member=test_account.email.apply(lambda email: f"serviceAccount:{email}"))
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/healthcare"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/serviceaccount"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		dataset, err := healthcare.NewDataset(ctx, "dataset", &healthcare.DatasetArgs{
			Location: pulumi.String("us-central1"),
			Name:     pulumi.String("my-dataset"),
		})
		if err != nil {
			return err
		}
		my_consent, err := healthcare.NewConsentStore(ctx, "my-consent", &healthcare.ConsentStoreArgs{
			Dataset: dataset.ID(),
			Name:    pulumi.String("my-consent-store"),
		})
		if err != nil {
			return err
		}
		test_account, err := serviceaccount.NewAccount(ctx, "test-account", &serviceaccount.AccountArgs{
			AccountId:   pulumi.String("my-account"),
			DisplayName: pulumi.String("Test Service Account"),
		})
		if err != nil {
			return err
		}
		_, err = healthcare.NewConsentStoreIamMember(ctx, "test-iam", &healthcare.ConsentStoreIamMemberArgs{
			Dataset:        dataset.ID(),
			ConsentStoreId: my_consent.Name,
			Role:           pulumi.String("roles/editor"),
			Member: test_account.Email.ApplyT(func(email string) (string, error) {
				return fmt.Sprintf("serviceAccount:%v", email), nil
			}).(pulumi.StringOutput),
		})
		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.Healthcare.Dataset("dataset", new()
    {
        Location = "us-central1",
        Name = "my-dataset",
    });

    var my_consent = new Gcp.Healthcare.ConsentStore("my-consent", new()
    {
        Dataset = dataset.Id,
        Name = "my-consent-store",
    });

    var test_account = new Gcp.ServiceAccount.Account("test-account", new()
    {
        AccountId = "my-account",
        DisplayName = "Test Service Account",
    });

    var test_iam = new Gcp.Healthcare.ConsentStoreIamMember("test-iam", new()
    {
        Dataset = dataset.Id,
        ConsentStoreId = my_consent.Name,
        Role = "roles/editor",
        Member = test_account.Email.Apply(email => $"serviceAccount:{email}"),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.healthcare.Dataset;
import com.pulumi.gcp.healthcare.DatasetArgs;
import com.pulumi.gcp.healthcare.ConsentStore;
import com.pulumi.gcp.healthcare.ConsentStoreArgs;
import com.pulumi.gcp.serviceaccount.Account;
import com.pulumi.gcp.serviceaccount.AccountArgs;
import com.pulumi.gcp.healthcare.ConsentStoreIamMember;
import com.pulumi.gcp.healthcare.ConsentStoreIamMemberArgs;
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()
            .location("us-central1")
            .name("my-dataset")
            .build());

        var my_consent = new ConsentStore("my-consent", ConsentStoreArgs.builder()
            .dataset(dataset.id())
            .name("my-consent-store")
            .build());

        var test_account = new Account("test-account", AccountArgs.builder()
            .accountId("my-account")
            .displayName("Test Service Account")
            .build());

        var test_iam = new ConsentStoreIamMember("test-iam", ConsentStoreIamMemberArgs.builder()
            .dataset(dataset.id())
            .consentStoreId(my_consent.name())
            .role("roles/editor")
            .member(test_account.email().applyValue(_email -> String.format("serviceAccount:%s", _email)))
            .build());

    }
}
resources:
  dataset:
    type: gcp:healthcare:Dataset
    properties:
      location: us-central1
      name: my-dataset
  my-consent:
    type: gcp:healthcare:ConsentStore
    properties:
      dataset: ${dataset.id}
      name: my-consent-store
  test-account:
    type: gcp:serviceaccount:Account
    properties:
      accountId: my-account
      displayName: Test Service Account
  test-iam:
    type: gcp:healthcare:ConsentStoreIamMember
    properties:
      dataset: ${dataset.id}
      consentStoreId: ${["my-consent"].name}
      role: roles/editor
      member: serviceAccount:${["test-account"].email}

The ConsentStoreIamMember resource grants a service account the editor role on the consent store. The member property uses the service account email in the format “serviceAccount:{email}”. This scopes permissions to the consent store rather than the entire dataset.

Beyond these examples

These snippets focus on specific consent store features: consent store creation and naming, consent lifecycle policies, and IAM access control. They’re intentionally minimal rather than full consent management systems.

The examples reference pre-existing infrastructure such as healthcare datasets (the parent resource). They focus on configuring the consent store rather than provisioning the surrounding healthcare infrastructure.

To keep things focused, common consent store patterns are omitted, including:

  • Consent record creation and management (separate API operations)
  • Consent policy evaluation logic
  • Audit logging configuration
  • Integration with FHIR stores or DICOM stores

These omissions are intentional: the goal is to illustrate how each consent store feature is wired, not provide drop-in consent management modules. See the ConsentStore resource reference for all available configuration options.

Let's create GCP Healthcare Consent Stores

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Resource Configuration & Immutability
What properties can't I change after creating a consent store?
The dataset and name properties are immutable. Changing either will force Pulumi to replace the resource.
What format does the dataset property require?
The dataset must be in the format projects/{project}/locations/{location}/datasets/{dataset}.
Consent Lifecycle & TTL
What's the minimum TTL I can set for consents?
The defaultConsentTtl must be at least 24 hours. Specify it as a duration in seconds with an ’s’ suffix, like 90000s.
Does updating the TTL affect existing consents?
No, updating defaultConsentTtl only applies to new consents created after the change. Existing consents keep their original expiration time.
Labels & Metadata
What's the difference between labels and effectiveLabels?
The labels field only manages labels defined in your Pulumi configuration. Use effectiveLabels to see all labels on the resource, including those added by other clients or services.
What are the label naming requirements?
Label keys must be 1-63 characters matching [\p{Ll}\p{Lo}][\p{Ll}\p{Lo}\p{N}_-]{0,62}. Label values are optional, 0-63 characters matching [\p{Ll}\p{Lo}\p{N}_-]{0,63}. Maximum 64 labels per store.
Consent Management
What does enableConsentCreateOnUpdate do?
When enableConsentCreateOnUpdate is true, updating a consent will automatically create it if it doesn’t already exist.

Using a different cloud?

Explore security guides for other cloud providers: