Creates a single Vertex AI managed Dataset (
google_vertex_ai_dataset) — a collection of DataItems and Annotations used as training/evaluation data for a custom ML model or AutoML pipeline. Targetshashicorp/google ~> 7.0, Terraform>= 1.12.0. First module in this catalog'sdata-ml(Vertex AI) domain.
- 🧠 Creates one
google_vertex_ai_dataset— a managed container for DataItems and Annotations whosemetadata_schema_uridetermines the dataset's TYPE (image/text/tabular/video classification, object detection, and so on). - 🔑 True standalone module — a Dataset's entity-level DataItems/Annotations are managed inside the
Vertex AI API/console itself, never as Terraform resources, so there is no
for_each-managed child collection here. - 🔒 Optional customer-managed encryption (CMEK) via
encryption_spec.kms_key_name, sourced from aterraform-google-kms-keyringcrypto keyid— never defaulted to a specific key. - 🛡️
deletion_policydefaults to"PREVENT"— a documented extension to this module suite's secure-by-default table (see 🧱 Design Principles). - 🌎
regionis optional (Vertex AI region availability is narrower than general Compute Engine — see ✅ Provider/Versions). - 🚫 No
self_link— this resource exports onlyidandname, and the two are the same value (see 🧾 Outputs and 🧠 Architecture Notes).
💡 Why it matters: a Dataset is the first artifact in every Vertex AI training workflow — getting its type (
metadata_schema_uri) and its encryption posture right at creation time matters disproportionately, because neither is a practical in-place change once real DataItems exist.
If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:
- ⭐ Star this repository to help others discover this Terraform module.
- 🤝 Connect with me on LinkedIn: linkedin.com/in/microsoftexpert
- ☕ Buy me a coffee: buymeacoffee.com/microsoftexpert
Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!
flowchart LR
classDef thisModule fill:#174EA6,stroke:#174EA6,color:#ffffff,stroke-width:2px;
classDef neutral fill:#F1F3F4,stroke:#9AA0A6,color:#202124,stroke-width:1px;
subgraph dataml["data-ml domain (new)"]
VDS["terraform-google-vertex-ai-dataset"]:::thisModule
end
subgraph security["Security domain"]
KMS["terraform-google-kms-keyring"]:::neutral
end
subgraph storage["Storage domain"]
BKT["terraform-google-storage-bucket"]:::neutral
end
subgraph networking["Networking domain"]
VPC["terraform-google-vpc-network"]:::neutral
end
subgraph compute["Compute domain"]
GKE["terraform-google-gke-cluster"]:::neutral
end
subgraph data["Data domain"]
BQ["terraform-google-bigquery-dataset"]:::neutral
end
subgraph iamdom["IAM domain"]
SA["terraform-google-service-account"]:::neutral
end
subgraph observability["Observability domain"]
LS["terraform-google-log-sink"]:::neutral
end
KMS -. "optional CMEK: crypto_key_ids feeds encryption_spec.kms_key_name".-> VDS
BKT -. "optional: custom metadata_schema_uri GCS object".-> VDS
This module founds the data-ml domain — there is no existing keystone/target sibling in this
domain yet (terraform-google-vertex-ai-featurestore and terraform-google-vertex-ai-endpoint are authored
alongside it in this same batch), so this module's own node is colored #174EA6 rather than the
usual #4285F4 "this module" / #174EA6 "keystone sibling" pairing — there is no sibling to
receive that second color yet. Both inbound edges are optional: terraform-google-kms-keyring only
matters when a caller opts into CMEK; terraform-google-storage-bucket only matters when a caller
publishes a genuinely custom metadata_schema_uri (most callers reference one of Google's own
published schema catalog entries instead — see Example Library). No outbound consumer edge is shown
from this module's outputs, since none exists in this library yet.
flowchart TD
classDef thisModule fill:#174EA6,stroke:#174EA6,color:#ffffff,stroke-width:2px;
classDef neutral fill:#F1F3F4,stroke:#9AA0A6,color:#202124,stroke-width:1px;
IN["Inputs: display_name, metadata_schema_uri,<br/>region, encryption_spec,<br/>deletion_policy, labels, timeouts"]:::neutral
DS["google_vertex_ai_dataset.this"]:::thisModule
OUT["Outputs: id, name, display_name,<br/>create_time, update_time"]:::neutral
IN -- "var.*" --> DS
DS -- "id, name, display_name, create_time, update_time" --> OUT
Resource inventory: google_vertex_ai_dataset.this — exactly one resource, always created. No
other resources, no for_each-managed children.
| Requirement | Value |
|---|---|
| Terraform | >= 1.12.0 |
hashicorp/google provider |
~> 7.0 |
| Provider block | None — the caller configures google (project, region/zone, auth) |
Schema notes that bite (verified against hashicorp/google v7.39.0 via the live provider schema,
providerDocID 12684204, cross-checked against
terraform providers schema -json):
- No
self_linkon this resource at all. The Attributes Reference lists onlyid,name,create_time,update_time,terraform_labels,effective_labels.idhas the format{{name}}—idandnameare the same value for this resource. metadata_schema_uriis effectively force-new, but neither available source can confirm a ForceNew flag. The live docs do not mark it "Immutable" (unusual for a force-new field in this provider), andterraform providers schema -jsondoes not expose a ForceNew indicator for any attribute of any resource in this provider at all (confirmed by inspecting the full schema export — zeroforce_newoccurrences anywhere in the file). Operationally, changing a Dataset's type post-creation is not a supported Vertex AI API operation — Terraform may show an in-place "update" atplantime that the API then rejects atapplytime. See Troubleshooting.encryption_spec's doc text is a copy-paste artifact: "kms_key_name- (Optional) Required." The block itself is optional;kms_key_nameis required once the block is used. Modeled here as a required string inside theencryption_specobject type.regionhas no companionlocationfield on this resource (unlikegoogle_vertex_ai_endpoint) —regionis the only placement argument, and it is optional + computed (the provider/API resolves a value if omitted).- Vertex AI region availability is narrower than general Compute Engine. Do not assume every
Compute Engine region supports every Vertex AI feature — check
https://cloud.google.com/vertex-ai/docs/general/locations before setting
region. deletion_policy(DELETE/ABANDON/PREVENT) defaults to"DELETE"in the provider — this module overrides that default to"PREVENT"(see 🧱 Design Principles).- All three
create/update/deletetimeouts are supported, each defaulting to 20 minutes in the provider. - No
importsupport — the provider docs state this resource does not supportterraform import.
roles/aiplatform.useron the target project — create/manage Datasets and most other Vertex AI resources. Default, least-privilege role for the applying principal.roles/aiplatform.adminonly if the same applying principal must also set IAM policy directly on Vertex AI resources — do not default to admin.
aiplatform.googleapis.comenabled on the target project (viaterraform-google-project-services, applied before this module per the house authoring order).cloudkms.googleapis.comadditionally required only whenvar.encryption_specis set.- Vertex AI region availability is narrower than general Compute Engine — verify the target
regionagainst https://cloud.google.com/vertex-ai/docs/general/locations before applying. - If
encryption_spec.kms_key_nameis set, the Vertex AI service agent (service-<PROJECT_NUMBER>@gcp-sa-aiplatform.iam.gserviceaccount.com) must independently holdroles/cloudkms.cryptoKeyEncrypterDecrypteron the referenced key — this module does not, and cannot, grant that binding itself.
terraform-google-vertex-ai-dataset/
├── providers.tf # required_providers (hashicorp/google ~> 7.0) + required_version — no provider {} block
├── variables.tf # display_name, metadata_schema_uri, region, encryption_spec, deletion_policy, labels, timeouts
├── main.tf # google_vertex_ai_dataset.this — single keystone, no for_each children
├── outputs.tf # id, name, display_name, create_time, update_time — no self_link
├── README.md # this file
├── SCOPE.md # lightweight cross-module contract
└── examples/ # runnable example matching the Quick Start below
module "image_training_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "image-classification-training"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"
region = "us-central1"
}The caller's root module configures the google provider (project, region/zone, and authentication
via ADC, Workload Identity Federation, or a service account key supplied out-of-band) — this module
accepts none of those as variables (region here is this resource's own optional per-dataset
argument, not a provider-level override).
Consumes
| Input | Type | Source module |
|---|---|---|
encryption_spec.kms_key_name (optional) |
string |
terraform-google-kms-keyring — crypto key id output; key region must match this module's var.region |
Emits
| Output | Description | Consumed by |
|---|---|---|
id |
Format {{name}} — same value as name (no self_link on this resource) |
unknown/none yet — first module in this domain |
name |
Fully-qualified resource name, format projects/{project}/locations/{region}/datasets/{dataset_id} |
unknown/none yet |
display_name |
The Dataset's user-defined display name | unknown/none yet |
create_time |
RFC3339 creation timestamp | unknown/none yet |
update_time |
RFC3339 last-update timestamp | unknown/none yet |
1 · Minimal image-classification dataset
module "image_training_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "image-classification-training"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"
region = "us-central1"
}💡 The smallest real call: two required arguments plus
region.deletion_policydefaults to"PREVENT"and Google-managed encryption applies sinceencryption_specis omitted.
2 · Tabular dataset
module "customer_churn_tabular_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "customer-churn-tabular"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/tabular_1.0.0.yaml"
region = "us-central1"
}ℹ️
metadata_schema_uriis what makes this a tabular dataset rather than an image dataset — everything else about the call is identical in shape to Example 1.
3 · Text classification dataset
module "support_ticket_text_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "support-ticket-classification"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/text_1.0.0.yaml"
region = "us-central1"
}4 · Video action recognition dataset
module "field_inspection_video_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "field-inspection-action-recognition"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/video_action_recognition_1.0.0.yaml"
region = "us-central1"
}5 · Object detection dataset
module "equipment_defect_detection_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "equipment-defect-object-detection"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/image_object_detection_1.0.0.yaml"
region = "us-central1"
}6 · CMEK-encrypted dataset
module "cmek_training_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "prod-cmek-training-dataset"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"
region = "us-central1"
encryption_spec = {
kms_key_name = module.kms_keyring.crypto_key_ids["vertex-ai-encryption-key"]
}
}🔒 Requires an out-of-band
google_kms_crypto_key_iam_membergrant ofroles/cloudkms.cryptoKeyEncrypterDecrypterto the Vertex AI service agent on the referenced crypto key before thisapply— this module cannot grant that binding itself. The key's region must matchregionabove. See the mandatory end-to-end composition (Example 15) for the full wiring.
7 · Custom metadata_schema_uri (caller-published schema)
module "custom_schema_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "custom-anomaly-schema-dataset"
metadata_schema_uri = "gs://${module.custom_schema_bucket.name}/schemas/custom_anomaly_1.0.0.yaml"
region = "us-central1"
}ℹ️ Only reference
terraform-google-storage-buckethere when publishing a genuinely custom schema YAML — most callers instead point at one of Google's own published catalog entries undergs://google-cloud-aiplatform/schema/dataset/metadata/(Examples 1-5). This is not a normal live Terraform reference (the bucket'snameoutput only supplies the GCS path string; the schema object itself is uploaded out of band, e.g. viagoogle_storage_bucket_objector a CI step).
8 · deletion_policy = "DELETE" (explicit opt-out)
module "scratch_test_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "scratch-integration-test-dataset"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"
region = "us-central1"
deletion_policy = "DELETE"
}
⚠️ deletion_policy = "PREVENT"is the secure default (this module's own extension to this module suite's secure-by-default table). Reserve"DELETE"for genuinely disposable datasets — integration test fixtures, scratch environments — never for a dataset backing a production model.
9 · deletion_policy = "ABANDON"
module "externally_managed_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "handed-off-to-ml-team-dataset"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/tabular_1.0.0.yaml"
region = "us-central1"
deletion_policy = "ABANDON"
}ℹ️
"ABANDON"drops the resource from Terraform state without touching it in the API — rarely appropriate. Use it only when ownership of an existing Dataset is being deliberately handed off to a different management path (e.g. the ML team manages it directly viagcloud/console going forward), and document why in the calling composition.
10 · Custom labels
module "labeled_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "labeled-training-dataset"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"
region = "us-central1"
labels = {
environment = "prod"
domain = "data-ml"
owner = "ml-platform-team"
}
}ℹ️
labelsis non-authoritative per the provider — this module only manages the labels present in this map (see the resource's owneffective_labels/terraform_labelscomputed attributes for the full merged view; not exposed as a module output in v1.0.0).
11 · Custom timeouts
module "slow_region_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "slow-provisioning-region-dataset"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/video_classification_1.0.0.yaml"
region = "asia-southeast1"
timeouts = {
create = "30m"
delete = "30m"
}
}ℹ️ All three (
create/update/delete) default to 20 minutes in the provider; override individually as needed rather than supplying all three every time.
12 · Explicit region omission (provider/API-resolved)
module "default_region_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "default-region-training-dataset"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"
}
⚠️ Omittingregionlets the provider/API resolve a value (typically the provider block's configured region, where one is set). This module recommends supplyingregionexplicitly in production compositions for predictability, given Vertex AI's narrower region coverage.
13 · Multiple datasets via root-module for_each
locals {
training_datasets = {
"image-classification-v1" = "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"
"tabular-churn-v1" = "gs://google-cloud-aiplatform/schema/dataset/metadata/tabular_1.0.0.yaml"
}
}
module "training_datasets" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
for_each = local.training_datasets
display_name = each.key
metadata_schema_uri = each.value
region = "us-central1"
}ℹ️ This module itself has no internal
for_each(it is a true standalone — see SCOPE.md Design intent). A caller needing several Datasets wraps the module call in afor_eachat the composition level, as shown here.
14 · Consuming id directly in a resource-scoped IAM binding
module "shared_reference_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "cross-team-reference-dataset"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"
region = "us-central1"
}
resource "google_vertex_ai_dataset_iam_member" "ml_team_user" {
dataset = module.shared_reference_dataset.id
role = "roles/aiplatform.user"
member = "group:ml-platform-team@financialpartners.com"
}💡 No dedicated Vertex AI Dataset IAM aggregation module exists yet in this catalog — consuming
iddirectly in an inline, additive_iam_memberresource (never an authoritative_iam_policy) is a fully valid pattern consistent with this module suite's IAM conventions.
15 · 🏗️ End-to-end composition
module "project_services" {
source = "git::https://github.com/microsoftexpert/terraform-google-project-services.git?ref=v1.0.0"
# Enables aiplatform.googleapis.com and cloudkms.googleapis.com for this composition.
}
module "kms_keyring" {
source = "git::https://github.com/microsoftexpert/terraform-google-kms-keyring.git?ref=v1.0.0"
key_ring_name = "casey-prod-vertex-ai-keyring"
location = "us-central1"
crypto_keys = {
"vertex-ai-encryption-key" = {
purpose = "ENCRYPT_DECRYPT"
}
}
depends_on = [module.project_services]
}
data "google_project" "current" {}
resource "google_kms_crypto_key_iam_member" "vertex_ai_encrypter" {
crypto_key_id = module.kms_keyring.crypto_key_ids["vertex-ai-encryption-key"]
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
member = "serviceAccount:service-${data.google_project.current.number}@gcp-sa-aiplatform.iam.gserviceaccount.com"
}
module "image_training_dataset" {
source = "git::https://github.com/microsoftexpert/terraform-google-vertex-ai-dataset.git?ref=v1.0.0"
display_name = "prod-image-classification-training"
metadata_schema_uri = "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"
region = "us-central1"
encryption_spec = {
kms_key_name = module.kms_keyring.crypto_key_ids["vertex-ai-encryption-key"]
}
labels = {
environment = "prod"
domain = "data-ml"
}
depends_on = [google_kms_crypto_key_iam_member.vertex_ai_encrypter]
}💡 This wires
terraform-google-project-services→terraform-google-kms-keyring→ (an inline, additivegoogle_kms_crypto_key_iam_membergrant) →terraform-google-vertex-ai-datasetin dependency order: APIs enabled, then the CMEK key ring/key created, then the Vertex AI service agent grantedroles/cloudkms.cryptoKeyEncrypterDecrypteron that key, then the Dataset created withencryption_specreferencing it, matching the key's region to the Dataset'sregion.
⚠️ The explicitdepends_onon the IAM grant is deliberate and necessary — no attribute ofgoogle_kms_crypto_key_iam_memberotherwise flows intoimage_training_dataset, so an implicit reference cannot express this ordering; without it, a freshapplycan race the IAM grant against the Dataset's CMEK-encrypted creation and fail with a transient permission-denied error (IAM propagation can take up to ~60 seconds). See Troubleshooting.
| Variable | Type | Required | Default | Notes |
|---|---|---|---|---|
display_name |
string |
Yes | — | 1-128 characters |
metadata_schema_uri |
string |
Yes | — | gs:// URI; effectively force-new (see Architecture Notes) |
region |
string |
No | null (provider/API-resolved) |
Narrower Vertex AI region availability than Compute Engine |
encryption_spec |
object({ kms_key_name }) |
No | null |
kms_key_name required once the block is used; region must match region |
deletion_policy |
string |
No | "PREVENT" |
One of DELETE/ABANDON/PREVENT |
labels |
map(string) |
No | {} |
GCP label format enforced; ≤ 64 entries; non-authoritative |
timeouts |
object({ create, update, delete }) |
No | null |
All three supported (20 min default each) |
Full variable schemas
variable "display_name" {
type = string
# 1-128 chars enforced via validation {}
}
variable "metadata_schema_uri" {
type = string
# gs:// prefix enforced via validation {}
}
variable "region" {
type = string
default = null
}
variable "encryption_spec" {
type = object({
kms_key_name = string
})
default = null
}
variable "deletion_policy" {
type = string
default = "PREVENT"
# One of DELETE/ABANDON/PREVENT enforced via validation {}
}
variable "labels" {
type = map(string)
default = {}
# GCP label key/value format + <= 64 entries enforced via validation {}
}
variable "timeouts" {
type = object({
create = optional(string)
update = optional(string)
delete = optional(string)
})
default = null
}| Output | Description |
|---|---|
id |
Format {{name}} — primary output; same value as name (no distinct self_link on this resource) |
name |
Fully-qualified resource name, format projects/{project}/locations/{region}/datasets/{dataset_id} |
display_name |
The Dataset's user-defined display name |
create_time |
RFC3339 UTC "Zulu" creation timestamp |
update_time |
RFC3339 UTC "Zulu" last-update timestamp |
ℹ️ This resource has no
self_link.idandnameare numerically identical — both are still emitted, in that order, per this module suite's outputs-ordering convention, not because they carry different values.
metadata_schema_uridetermines the Dataset's TYPE and is effectively force-new, even though neither the live provider docs norterraform providers schema -jsonmark it ForceNew (the schema-JSON format does not expose a ForceNew indicator for any attribute on any resource in this provider at all — confirmed by inspecting the full export). Changing a Dataset's type post-creation is not a supported Vertex AI API operation; Terraform may show an in-place "update" atplantime that the API then rejects atapplytime. See Troubleshooting.idandnameare the same value for this resource.idhas the format{{name}}. Both are emitted per house convention (id first, then name), not because they differ — see Outputs.encryption_spec.kms_key_name's Cloud KMS key must be in the same region as this Dataset'sregion. The provider enforces this atapplytime only; it cannot be checked atplantime since both values are plain strings to the type system. See Troubleshooting.regionis a genuine per-resource argument, not an invented provider override. This resource has nolocationfield (unlikegoogle_vertex_ai_endpoint);regionis the only placement argument the provider itself defines ongoogle_vertex_ai_dataset. This module suite's convention against inventingproject/region/zonemodule variables refers to modules manufacturing an override pattern the resource schema does not define — that is not the case here.- No
projectvariable. Per this module suite's authentication-model convention,projectis a provider/caller concern; this module does not expose the resource's own optionalprojectoverride as a variable, matching the house pattern used across this library's other standalone modules. labelsis non-authoritative. This module only manages the labels present in its configuration; the resource's owneffective_labels/terraform_labelscomputed attributes carry the full merged view, not exposed as an output in v1.0.0.- A false lead avoided: an early lookup for this resource surfaced a
dataset_id(Required) argument. That argument does not exist ongoogle_vertex_ai_dataset— both the live provider schema and the schema-JSON ground truth confirm the real argument list is exactlydisplay_name/metadata_schema_uri/labels/encryption_spec/region/project/deletion_policy. Thedataset_idhit was noise, most likely fromgoogle_bigquery_dataset(which does take a requireddataset_id), surfaced by the shared word "dataset."
| Concern | Secure default | Opt-out (explicit) |
|---|---|---|
deletion_policy |
"PREVENT" — this module's own documented extension to this module suite's secure-by-default table. The suite's existing "Deletion protection" row assumes a boolean deletion_protection argument, which this resource does not have; this module (and, consistently, terraform-google-vertex-ai-featurestore, terraform-google-vertex-ai-endpoint, and terraform-google-dataflow-job in this same authoring batch) adds the analogous row for the deletion_policy enum. The provider's own default is "DELETE" — this module locks it down further. |
Caller sets deletion_policy = "DELETE" explicitly |
CMEK (encryption_spec) |
Accepted as an optional kms_key_name variable; never defaulted to a specific key |
Caller supplies encryption_spec.kms_key_name from terraform-google-kms-keyring |
region |
No hardcoded region allow-list (per house convention — a validation list would go stale as Google adds Vertex AI region coverage) | Caller checks https://cloud.google.com/vertex-ai/docs/general/locations and supplies an explicit region |
| IAM grants on the Dataset | Not managed by this module at all — grant access via a resource-scoped google_vertex_ai_dataset_iam_member, never an authoritative _iam_policy |
N/A — authoritative IAM policy is intentionally excluded from this library |
| Secret/key material | This module creates no key material — encryption_spec.kms_key_name is always a reference to a key created elsewhere |
N/A |
cd terraform-google-vertex-ai-dataset
terraform init -backend=false
terraform validate
terraform fmt -checkPin the module source to ?ref=v1.0.0 — never a branch. This library is plan-only from an
authoring session; a human applies from CI with valid Workload Identity Federation or ADC
credentials.
terraform validate confirms internal type/reference consistency — including the closed
deletion_policy enum and the gs://-prefix format check on metadata_schema_uri. terraform fmt -check confirms canonical formatting. Neither can catch GCP API-level rejections: a
metadata_schema_uri that is a syntactically valid gs:// string but not an actual, readable
Vertex AI schema file will pass validate cleanly and fail only at apply time; likewise, a target
region that Vertex AI does not support in a particular sub-feature, or an encryption_spec.kms_key_name
in a different region than the Dataset, both pass plan and fail only at apply. Only a real
terraform plan/apply against a live project, with valid credentials, exercises those paths — and
that step belongs to the consuming CI pipeline, not this authoring session.
$ terraform output
id = "projects/casey-prod-ml/locations/us-central1/datasets/1234567890123456789"
name = "projects/casey-prod-ml/locations/us-central1/datasets/1234567890123456789"
display_name = "prod-image-classification-training"
create_time = "2026-07-12T14:03:22.123456Z"
update_time = "2026-07-12T14:03:22.123456Z"
| Symptom | Cause | Fix |
|---|---|---|
plan succeeds but apply fails because metadata_schema_uri isn't a real Vertex AI schema file |
The value is a syntactically valid gs:// URI, but the object either does not exist or is not a valid OpenAPI 3.0.2 Dataset metadata schema — validate/plan cannot check GCS object contents |
Confirm the URI against Google's published catalog (gs://google-cloud-aiplatform/schema/dataset/metadata/) or verify a custom schema object's contents before applying |
apply fails because encryption_spec.kms_key_name's key is in a different region than the Dataset |
The provider enforces key/dataset region matching only at apply time |
Set encryption_spec.kms_key_name to a key whose region matches var.region exactly |
apply fails with a CMEK encrypt/decrypt permission-denied error |
The Vertex AI service agent has not been granted roles/cloudkms.cryptoKeyEncrypterDecrypter on the referenced crypto key, or the grant has not yet propagated |
Grant the role via an out-of-band google_kms_crypto_key_iam_member before this module's apply; allow up to ~60 seconds for propagation if granted in the same apply |
A change to metadata_schema_uri shows as an in-place update in plan but fails at apply |
Terraform's schema does not mark this argument ForceNew, but the Vertex AI API does not support changing a Dataset's type post-creation | Treat any change to metadata_schema_uri as requiring a new Dataset (new module instance / new display_name), not an in-place edit |
destroy fails or is refused |
deletion_policy = "PREVENT" (the default) |
Set deletion_policy = "DELETE" explicitly and re-apply before the subsequent destroy |
plan fails a variable "deletion_policy" validation error |
Value supplied is not one of DELETE/ABANDON/PREVENT |
Use exactly one of the three legal values |
apply fails or is rejected for an unsupported region |
The chosen region does not (yet) support the Vertex AI Dataset feature in question | Check https://cloud.google.com/vertex-ai/docs/general/locations for current Vertex AI region coverage before applying |
google_vertex_ai_datasetprovider resource reference- Vertex AI locations
- Vertex AI Dataset schema catalog (
gs://google-cloud-aiplatform/schema/dataset/metadata/) terraform-google-kms-keyring(optional CMEK source, crypto keyidoutput)terraform-google-storage-bucket(optional custom schema YAML source)terraform-google-project-services(must enableaiplatform.googleapis.combefore this module applies)terraform-google-vertex-ai-featurestore,terraform-google-vertex-ai-endpoint(sibling modules founding this samedata-mldomain in this authoring batch)- This module's
SCOPE.md