diff --git a/.gitignore b/.gitignore
index a248d4ca..8d8384b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,4 +29,8 @@
# Ignored vscode files
.vscode/
-.idea/
\ No newline at end of file
+.idea/
+
+# Claude Code
+.claude/
+CLAUDE.md
\ No newline at end of file
diff --git a/examples/gcp-with-psc-exfiltration-protection/README.md b/examples/gcp-with-psc-exfiltration-protection/README.md
index 64d676a9..61faa19c 100644
--- a/examples/gcp-with-psc-exfiltration-protection/README.md
+++ b/examples/gcp-with-psc-exfiltration-protection/README.md
@@ -38,8 +38,9 @@ Most values are related to resources managed by Databricks. The required values
| Name | Version |
|------|---------|
-| [databricks](#requirement\_databricks) | >=1.81.1 |
-| [google](#requirement\_google) | 6.17.0 |
+| [terraform](#requirement\_terraform) | >= 1.9.0 |
+| [databricks](#requirement\_databricks) | >=1.85.0 |
+| [google](#requirement\_google) | ~> 6.45 |
## Providers
@@ -63,17 +64,17 @@ No resources.
| [catalog\_name](#input\_catalog\_name) | Name to assign to default catalog | `string` | n/a | yes |
| [databricks\_account\_id](#input\_databricks\_account\_id) | Databricks Account ID | `string` | n/a | yes |
| [google\_region](#input\_google\_region) | Google Cloud region where the resources will be created | `string` | n/a | yes |
-| [hive\_metastore\_ip](#input\_hive\_metastore\_ip) | Value of regional default Hive Metastore IP | `string` | n/a | yes |
+| [hive\_metastore\_ip](#input\_hive\_metastore\_ip) | IP address of the regional default Hive Metastore | `string` | n/a | yes |
| [hub\_vpc\_cidr](#input\_hub\_vpc\_cidr) | CIDR for Hub VPC | `string` | n/a | yes |
| [hub\_vpc\_google\_project](#input\_hub\_vpc\_google\_project) | Google Cloud project ID related to Hub VPC | `string` | n/a | yes |
| [is\_spoke\_vpc\_shared](#input\_is\_spoke\_vpc\_shared) | Whether the Spoke VPC is a Shared or a dedicated VPC | `bool` | n/a | yes |
| [metastore\_name](#input\_metastore\_name) | Name to assign to regional metastore | `string` | n/a | yes |
-| [prefix](#input\_prefix) | Prefix to use in generated resources name | `string` | n/a | yes |
-| [psc\_subnet\_cidr](#input\_psc\_subnet\_cidr) | CIDR for Spoke VPC | `string` | n/a | yes |
+| [prefix](#input\_prefix) | Prefix to use in generated resource names | `string` | n/a | yes |
+| [psc\_subnet\_cidr](#input\_psc\_subnet\_cidr) | CIDR for PSC subnet within the Spoke VPC | `string` | n/a | yes |
| [spoke\_vpc\_cidr](#input\_spoke\_vpc\_cidr) | CIDR for Spoke VPC | `string` | n/a | yes |
| [spoke\_vpc\_google\_project](#input\_spoke\_vpc\_google\_project) | Google Cloud project ID related to Spoke VPC | `string` | n/a | yes |
-| [workspace\_google\_project](#input\_workspace\_google\_project) | Google Cloud project ID related to Databricks workspace | `string` | n/a | yes |
| [tags](#input\_tags) | Map of tags to add to all resources | `map(string)` | `{}` | no |
+| [workspace\_google\_project](#input\_workspace\_google\_project) | Google Cloud project ID related to Databricks workspace | `string` | n/a | yes |
## Outputs
diff --git a/examples/gcp-with-psc-exfiltration-protection/terraform.tf b/examples/gcp-with-psc-exfiltration-protection/terraform.tf
index 791cc0c9..5bc9f86c 100644
--- a/examples/gcp-with-psc-exfiltration-protection/terraform.tf
+++ b/examples/gcp-with-psc-exfiltration-protection/terraform.tf
@@ -1,12 +1,14 @@
terraform {
+ required_version = ">= 1.9.0"
+
required_providers {
databricks = {
source = "databricks/databricks"
- version = ">=1.81.1"
+ version = ">=1.85.0"
}
google = {
source = "hashicorp/google"
- version = "6.17.0"
+ version = "~> 6.45"
}
random = {
source = "hashicorp/random"
diff --git a/examples/gcp-with-psc-exfiltration-protection/variables.tf b/examples/gcp-with-psc-exfiltration-protection/variables.tf
index 15365ccf..cbafd823 100644
--- a/examples/gcp-with-psc-exfiltration-protection/variables.tf
+++ b/examples/gcp-with-psc-exfiltration-protection/variables.tf
@@ -1,13 +1,33 @@
+# Account
variable "databricks_account_id" {
type = string
description = "Databricks Account ID"
+
+ validation {
+ condition = can(regex("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", lower(var.databricks_account_id)))
+ error_message = "databricks_account_id must be a valid UUID (e.g., 12345678-1234-1234-1234-123456789012)."
+ }
}
+# Region
variable "google_region" {
type = string
description = "Google Cloud region where the resources will be created"
+
+ validation {
+ condition = contains([
+ "asia-northeast1", "asia-south1", "asia-southeast1",
+ "australia-southeast1",
+ "europe-west1", "europe-west2", "europe-west3",
+ "northamerica-northeast1",
+ "southamerica-east1",
+ "us-central1", "us-east1", "us-east4", "us-west1", "us-west4"
+ ], var.google_region)
+ error_message = "google_region must be a GCP region that supports Databricks PSC endpoints."
+ }
}
+# Projects
variable "workspace_google_project" {
type = string
description = "Google Cloud project ID related to Databricks workspace"
@@ -23,45 +43,73 @@ variable "hub_vpc_google_project" {
description = "Google Cloud project ID related to Hub VPC"
}
+# Network
variable "is_spoke_vpc_shared" {
type = bool
description = "Whether the Spoke VPC is a Shared or a dedicated VPC"
}
-variable "prefix" {
+variable "hub_vpc_cidr" {
type = string
- description = "Prefix to use in generated resources name"
+ description = "CIDR for Hub VPC"
+
+ validation {
+ condition = can(cidrhost(var.hub_vpc_cidr, 0))
+ error_message = "hub_vpc_cidr must be a valid CIDR block (e.g., 10.0.0.0/24)."
+ }
}
-# For the value of the regional Hive Metastore IP, refer to the Databricks documentation
-# Here - https://docs.gcp.databricks.com/en/resources/ip-domain-region.html#addresses-for-default-metastore
-variable "hive_metastore_ip" {
+variable "spoke_vpc_cidr" {
type = string
- description = "Value of regional default Hive Metastore IP"
+ description = "CIDR for Spoke VPC"
+
+ validation {
+ condition = can(cidrhost(var.spoke_vpc_cidr, 0))
+ error_message = "spoke_vpc_cidr must be a valid CIDR block (e.g., 10.1.0.0/24)."
+ }
}
-variable "hub_vpc_cidr" {
+variable "psc_subnet_cidr" {
type = string
- description = "CIDR for Hub VPC"
+ description = "CIDR for PSC subnet within the Spoke VPC"
+
+ validation {
+ condition = can(cidrhost(var.psc_subnet_cidr, 0))
+ error_message = "psc_subnet_cidr must be a valid CIDR block (e.g., 10.1.1.0/24)."
+ }
}
-variable "spoke_vpc_cidr" {
+# Naming
+variable "prefix" {
type = string
- description = "CIDR for Spoke VPC"
+ description = "Prefix to use in generated resource names"
+
+ validation {
+ condition = can(regex("^[a-z][a-z0-9-]{1,20}$", var.prefix))
+ error_message = "prefix must start with a lowercase letter, contain only lowercase letters, numbers, and hyphens, and be 2-21 characters long."
+ }
}
-variable "psc_subnet_cidr" {
+# For the value of the regional Hive Metastore IP, refer to the Databricks documentation
+# Here - https://docs.gcp.databricks.com/en/resources/ip-domain-region.html#addresses-for-default-metastore
+variable "hive_metastore_ip" {
type = string
- description = "CIDR for Spoke VPC"
+ description = "IP address of the regional default Hive Metastore"
+
+ validation {
+ condition = can(cidrhost("${var.hive_metastore_ip}/32", 0))
+ error_message = "hive_metastore_ip must be a valid IPv4 address."
+ }
}
+# Tags
variable "tags" {
type = map(string)
description = "Map of tags to add to all resources"
-
- default = {}
+ default = {}
}
+# Unity Catalog
variable "metastore_name" {
type = string
description = "Name to assign to regional metastore"
@@ -70,4 +118,4 @@ variable "metastore_name" {
variable "catalog_name" {
type = string
description = "Name to assign to default catalog"
-}
\ No newline at end of file
+}
diff --git a/modules/gcp-with-psc-exfiltration-protection/README.md b/modules/gcp-with-psc-exfiltration-protection/README.md
index 6f9650de..0d2cfc8b 100644
--- a/modules/gcp-with-psc-exfiltration-protection/README.md
+++ b/modules/gcp-with-psc-exfiltration-protection/README.md
@@ -45,7 +45,9 @@ With this deployment, traffic from user client to webapp (notebook UI), backend
## Requirements
-No requirements.
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | >= 1.9.0 |
## Providers
@@ -119,12 +121,12 @@ No modules.
|------|-------------|------|---------|:--------:|
| [databricks\_account\_id](#input\_databricks\_account\_id) | Databricks Account ID | `string` | n/a | yes |
| [google\_region](#input\_google\_region) | Google Cloud region where the resources will be created | `string` | n/a | yes |
-| [hive\_metastore\_ip](#input\_hive\_metastore\_ip) | Value of regional default Hive Metastore IP | `string` | n/a | yes |
+| [hive\_metastore\_ip](#input\_hive\_metastore\_ip) | IP address of the regional default Hive Metastore | `string` | n/a | yes |
| [hub\_vpc\_cidr](#input\_hub\_vpc\_cidr) | CIDR for Hub VPC | `string` | n/a | yes |
| [hub\_vpc\_google\_project](#input\_hub\_vpc\_google\_project) | Google Cloud project ID related to Hub VPC | `string` | n/a | yes |
| [is\_spoke\_vpc\_shared](#input\_is\_spoke\_vpc\_shared) | Whether the Spoke VPC is a Shared or a dedicated VPC | `bool` | n/a | yes |
-| [prefix](#input\_prefix) | Prefix to use in generated resources name | `string` | n/a | yes |
-| [psc\_subnet\_cidr](#input\_psc\_subnet\_cidr) | CIDR for Spoke VPC | `string` | n/a | yes |
+| [prefix](#input\_prefix) | Prefix to use in generated resource names | `string` | n/a | yes |
+| [psc\_subnet\_cidr](#input\_psc\_subnet\_cidr) | CIDR for PSC subnet within the Spoke VPC | `string` | n/a | yes |
| [spoke\_vpc\_cidr](#input\_spoke\_vpc\_cidr) | CIDR for Spoke VPC | `string` | n/a | yes |
| [spoke\_vpc\_google\_project](#input\_spoke\_vpc\_google\_project) | Google Cloud project ID related to Spoke VPC | `string` | n/a | yes |
| [tags](#input\_tags) | Map of tags to add to all resources | `map(string)` | n/a | yes |
@@ -134,6 +136,14 @@ No modules.
| Name | Description |
|------|-------------|
+| [backend\_psc\_endpoint\_ip](#output\_backend\_psc\_endpoint\_ip) | The IP address of the backend (SCC) PSC endpoint |
+| [hub\_frontend\_psc\_endpoint\_ip](#output\_hub\_frontend\_psc\_endpoint\_ip) | The IP address of the workspace frontend PSC endpoint in the Hub VPC |
+| [hub\_vpc\_id](#output\_hub\_vpc\_id) | The ID of the Hub VPC network |
+| [network\_id](#output\_network\_id) | The Databricks MWS network configuration ID |
+| [psc\_subnetwork\_id](#output\_psc\_subnetwork\_id) | The ID of the PSC subnet within the Spoke VPC |
+| [spoke\_frontend\_psc\_endpoint\_ip](#output\_spoke\_frontend\_psc\_endpoint\_ip) | The IP address of the workspace frontend PSC endpoint in the Spoke VPC |
+| [spoke\_subnetwork\_id](#output\_spoke\_subnetwork\_id) | The ID of the primary Spoke subnet |
+| [spoke\_vpc\_id](#output\_spoke\_vpc\_id) | The ID of the Spoke VPC network |
| [workspace\_id](#output\_workspace\_id) | The Databricks workspace ID |
| [workspace\_url](#output\_workspace\_url) | The workspace URL which is of the format '{workspaceId}.{random}.gcp.databricks.com' |
-
\ No newline at end of file
+
diff --git a/modules/gcp-with-psc-exfiltration-protection/outputs.tf b/modules/gcp-with-psc-exfiltration-protection/outputs.tf
index 27983846..7d504577 100644
--- a/modules/gcp-with-psc-exfiltration-protection/outputs.tf
+++ b/modules/gcp-with-psc-exfiltration-protection/outputs.tf
@@ -1,10 +1,52 @@
-
+# Workspace
output "workspace_url" {
- value = databricks_mws_workspaces.databricks_workspace.workspace_url
description = "The workspace URL which is of the format '{workspaceId}.{random}.gcp.databricks.com'"
+ value = databricks_mws_workspaces.databricks_workspace.workspace_url
}
output "workspace_id" {
description = "The Databricks workspace ID"
value = databricks_mws_workspaces.databricks_workspace.workspace_id
-}
\ No newline at end of file
+}
+
+# Network
+output "spoke_vpc_id" {
+ description = "The ID of the Spoke VPC network"
+ value = google_compute_network.spoke_vpc.id
+}
+
+output "hub_vpc_id" {
+ description = "The ID of the Hub VPC network"
+ value = google_compute_network.hub_vpc.id
+}
+
+output "spoke_subnetwork_id" {
+ description = "The ID of the primary Spoke subnet"
+ value = google_compute_subnetwork.spoke_subnetwork.id
+}
+
+output "psc_subnetwork_id" {
+ description = "The ID of the PSC subnet within the Spoke VPC"
+ value = google_compute_subnetwork.psc_subnetwork.id
+}
+
+output "network_id" {
+ description = "The Databricks MWS network configuration ID"
+ value = databricks_mws_networks.databricks_network.network_id
+}
+
+# PSC Endpoints
+output "backend_psc_endpoint_ip" {
+ description = "The IP address of the backend (SCC) PSC endpoint"
+ value = google_compute_address.backend_pe_ip_address.address
+}
+
+output "spoke_frontend_psc_endpoint_ip" {
+ description = "The IP address of the workspace frontend PSC endpoint in the Spoke VPC"
+ value = google_compute_address.spoke_frontend_pe_ip_address.address
+}
+
+output "hub_frontend_psc_endpoint_ip" {
+ description = "The IP address of the workspace frontend PSC endpoint in the Hub VPC"
+ value = google_compute_address.hub_frontend_pe_ip_address.address
+}
diff --git a/modules/gcp-with-psc-exfiltration-protection/terraform.tf b/modules/gcp-with-psc-exfiltration-protection/terraform.tf
index 688f0fbd..6d4a5f43 100644
--- a/modules/gcp-with-psc-exfiltration-protection/terraform.tf
+++ b/modules/gcp-with-psc-exfiltration-protection/terraform.tf
@@ -1,4 +1,6 @@
terraform {
+ required_version = ">= 1.9.0"
+
required_providers {
databricks = {
source = "databricks/databricks"
diff --git a/modules/gcp-with-psc-exfiltration-protection/variables.tf b/modules/gcp-with-psc-exfiltration-protection/variables.tf
index cd96e520..dd68b757 100644
--- a/modules/gcp-with-psc-exfiltration-protection/variables.tf
+++ b/modules/gcp-with-psc-exfiltration-protection/variables.tf
@@ -1,13 +1,33 @@
+# Account
variable "databricks_account_id" {
type = string
description = "Databricks Account ID"
+
+ validation {
+ condition = can(regex("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", lower(var.databricks_account_id)))
+ error_message = "databricks_account_id must be a valid UUID (e.g., 12345678-1234-1234-1234-123456789012)."
+ }
}
+# Region
variable "google_region" {
type = string
description = "Google Cloud region where the resources will be created"
+
+ validation {
+ condition = contains([
+ "asia-northeast1", "asia-south1", "asia-southeast1",
+ "australia-southeast1",
+ "europe-west1", "europe-west2", "europe-west3",
+ "northamerica-northeast1",
+ "southamerica-east1",
+ "us-central1", "us-east1", "us-east4", "us-west1", "us-west4"
+ ], var.google_region)
+ error_message = "google_region must be a GCP region that supports Databricks PSC endpoints."
+ }
}
+# Projects
variable "workspace_google_project" {
type = string
description = "Google Cloud project ID related to Databricks workspace"
@@ -23,40 +43,67 @@ variable "hub_vpc_google_project" {
description = "Google Cloud project ID related to Hub VPC"
}
+# Network
variable "is_spoke_vpc_shared" {
type = bool
description = "Whether the Spoke VPC is a Shared or a dedicated VPC"
}
-variable "prefix" {
+variable "hub_vpc_cidr" {
type = string
- description = "Prefix to use in generated resources name"
+ description = "CIDR for Hub VPC"
+
+ validation {
+ condition = can(cidrhost(var.hub_vpc_cidr, 0))
+ error_message = "hub_vpc_cidr must be a valid CIDR block (e.g., 10.0.0.0/24)."
+ }
}
-# For the value of the regional Hive Metastore IP, refer to the Databricks documentation
-# Here - https://docs.gcp.databricks.com/en/resources/ip-domain-region.html#addresses-for-default-metastore
-variable "hive_metastore_ip" {
+variable "spoke_vpc_cidr" {
type = string
- description = "Value of regional default Hive Metastore IP"
+ description = "CIDR for Spoke VPC"
+
+ validation {
+ condition = can(cidrhost(var.spoke_vpc_cidr, 0))
+ error_message = "spoke_vpc_cidr must be a valid CIDR block (e.g., 10.1.0.0/24)."
+ }
}
-variable "hub_vpc_cidr" {
+variable "psc_subnet_cidr" {
type = string
- description = "CIDR for Hub VPC"
+ description = "CIDR for PSC subnet within the Spoke VPC"
+
+ validation {
+ condition = can(cidrhost(var.psc_subnet_cidr, 0))
+ error_message = "psc_subnet_cidr must be a valid CIDR block (e.g., 10.1.1.0/24)."
+ }
}
-variable "spoke_vpc_cidr" {
+# Naming
+variable "prefix" {
type = string
- description = "CIDR for Spoke VPC"
+ description = "Prefix to use in generated resource names"
+
+ validation {
+ condition = can(regex("^[a-z][a-z0-9-]{1,20}$", var.prefix))
+ error_message = "prefix must start with a lowercase letter, contain only lowercase letters, numbers, and hyphens, and be 2-21 characters long."
+ }
}
-variable "psc_subnet_cidr" {
+# For the value of the regional Hive Metastore IP, refer to the Databricks documentation
+# Here - https://docs.gcp.databricks.com/en/resources/ip-domain-region.html#addresses-for-default-metastore
+variable "hive_metastore_ip" {
type = string
- description = "CIDR for Spoke VPC"
+ description = "IP address of the regional default Hive Metastore"
+
+ validation {
+ condition = can(cidrhost("${var.hive_metastore_ip}/32", 0))
+ error_message = "hive_metastore_ip must be a valid IPv4 address."
+ }
}
+# Tags
variable "tags" {
- description = "Map of tags to add to all resources"
type = map(string)
+ description = "Map of tags to add to all resources"
}
-