Skip to content

PostgreSQL read replica fails when var.zone is null due to inconsistent zone fallback usage #761

@yasra002

Description

@yasra002

TL;DR

Bug Description

The PostgreSQL module's read replica configuration has an inconsistency in how it handles zone fallbacks. While local.zone is properly defined with a fallback mechanism, the region and encryption_key_name calculations still reference var.zone directly, which can cause Terraform errors when var.zone is null.

Affected file

https://github.com/terraform-google-modules/terraform-google-sql-db/blob/main/modules/postgresql/read_replica.tf

Root Cause

The code defines local.zone with proper fallback logic:

locals {
  zone = var.zone == null ? data.google_compute_zones.available.names[0] : var.zone
}

Expected behavior

When var.zone is null:

The replica should automatically use the first available zone in the region (as defined in local.zone)
The region calculation should work correctly by extracting the region from the fallback zone
The encryption_key_name logic should properly determine cross-region vs same-region replicas
No Terraform errors should occur during planning or applying

Observed behavior

When var.zone is not specified (null), the following lines fail:

  • Line 36: region = join("-", slice(split("-", lookup(each.value, "zone", var.zone)), 0, 2))
  • Line 39: encryption_key_name = (join("-", slice(split("-", lookup(each.value, "zone", var.zone)), 0, 2))) == var.region ? null : each.value.encryption_key_name

This results in a Terraform error:

╷
│ Error: Invalid function argument
│ 
│   on .terraform/modules/pg.this.cloud_psql/modules/postgresql/read_replica.tf line 40, in resource "google_sql_database_instance" "replicas":
│   40:   encryption_key_name  = (join("-", slice(split("-", lookup(each.value, "zone", var.zone)), 0, 2))) == var.region ? null : each.value.encryption_key_name
│     ├────────────────
│     │ while calling split(separator, str)
│     │ each.value is object with 16 attributes
│     │ var.zone is null
│ 
│ Invalid value for "str" parameter: argument must not be null.
╵

Terraform Configuration

# Reproducible Terraform configuration that demonstrates the issue

terraform {
  required_version = ">= 1.3"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
    google-beta = {
      source  = "hashicorp/google-beta"
      version = "~> 5.0"
    }
  }
}

provider "google" {
  project = "your-project-id"
  region  = "us-central1"
}

provider "google-beta" {
  project = "your-project-id"
  region  = "us-central1"
}

# VPC network for private IP
resource "google_compute_network" "vpc" {
  name                    = "test-vpc"
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "subnet" {
  name          = "test-subnet"
  ip_cidr_range = "10.0.0.0/24"
  region        = "us-central1"
  network       = google_compute_network.vpc.id
}

# Private services access
resource "google_compute_global_address" "private_ip_range" {
  name          = "test-private-ip"
  purpose       = "VPC_PEERING"
  address_type  = "INTERNAL"
  prefix_length = 16
  network       = google_compute_network.vpc.id
}

resource "google_service_networking_connection" "private_vpc_connection" {
  network                 = google_compute_network.vpc.id
  service                 = "servicenetworking.googleapis.com"
  reserved_peering_ranges = [google_compute_global_address.private_ip_range.name]
}

# PostgreSQL module configuration that triggers the bug
module "postgresql" {
  source = "GoogleCloudPlatform/sql-db/google//modules/postgresql"
  version = "~> 21.0"

  name                = "test-postgres"
  database_version    = "POSTGRES_15"
  project_id          = "your-project-id"
  region              = "us-central1"
  
  # Critical: zone is NOT specified (null) - this triggers the bug
  zone = null
  
  tier = "db-f1-micro"
  
  ip_configuration = {
    ipv4_enabled                                  = false
    private_network                               = google_compute_network.vpc.id
    allocated_ip_range                            = google_compute_global_address.private_ip_range.name
    enable_private_path_for_google_cloud_services = true
  }

  # Read replicas configuration - this is where the bug manifests
  read_replicas = [
    {
      name = "replica1"
      # Zone not specified for replica either - relies on fallback
      tier = "db-f1-micro"
      ip_configuration = {
        ipv4_enabled                                  = false
        private_network                               = google_compute_network.vpc.id
        allocated_ip_range                            = google_compute_global_address.private_ip_range.name
        enable_private_path_for_google_cloud_services = true
      }
    },
    {
      name = "replica2" 
      # Cross-region replica to test encryption_key_name logic
      zone = "us-west1-a"
      tier = "db-f1-micro"
      encryption_key_name = "projects/your-project-id/locations/us-west1/keyRings/test-ring/cryptoKeys/test-key"
      ip_configuration = {
        ipv4_enabled                                  = false
        private_network                               = google_compute_network.vpc.id
        allocated_ip_range                            = google_compute_global_address.private_ip_range.name
        enable_private_path_for_google_cloud_services = true
      }
    }
  ]

  depends_on = [google_service_networking_connection.private_vpc_connection]
}

Terraform Version

Terraform v1.12.0
on darwin_arm64
+ provider registry.terraform.io/cyrilgdn/postgresql v1.25.0
+ provider registry.terraform.io/hashicorp/google v6.47.0
+ provider registry.terraform.io/hashicorp/google-beta v6.47.0
+ provider registry.terraform.io/hashicorp/helm v3.0.2
+ provider registry.terraform.io/hashicorp/kubernetes v2.38.0
+ provider registry.terraform.io/hashicorp/null v3.2.4
+ provider registry.terraform.io/hashicorp/random v3.7.2
+ provider registry.terraform.io/hashicorp/time v0.13.1

Terraform Provider Versions

Providers required by configuration:
.
└── module.pg
    └── module.this
        ├── provider[registry.terraform.io/cyrilgdn/postgresql] 1.25.0
        ├── provider[registry.terraform.io/hashicorp/google] >= 6.1.0, < 7.0.0
        ├── provider[registry.terraform.io/hashicorp/google-beta] >= 6.1.0, < 7.0.0
        ├── provider[registry.terraform.io/hashicorp/random]
        ├── module.psc_consumer_replicas
        │   └── module.raw_psc_consumer
        │       └── provider[registry.terraform.io/hashicorp/google]
        ├── module.cloud_psql
        │   ├── provider[registry.terraform.io/hashicorp/google] >= 6.1.0, < 7.0.0
        │   ├── provider[registry.terraform.io/hashicorp/google-beta] >= 6.1.0, < 7.0.0
        │   ├── provider[registry.terraform.io/hashicorp/null] ~> 3.1
        │   └── provider[registry.terraform.io/hashicorp/random] ~> 3.1
        ├── module.cloudsql_autorestore
        │   ├── provider[registry.terraform.io/hashicorp/helm] >= 3.0.2
        │   ├── provider[registry.terraform.io/hashicorp/kubernetes] >= 2.0.0
        │   ├── provider[registry.terraform.io/hashicorp/google]
        │   └── provider[registry.terraform.io/hashicorp/random]
        ├── module.csql_migration
        │   └── provider[registry.terraform.io/hashicorp/google]
        ├── module.database
        │   ├── provider[registry.terraform.io/cyrilgdn/postgresql] 1.25.0
        │   └── provider[registry.terraform.io/hashicorp/google] >= 6.1.0, < 7.0.0
        ├── module.init_passwords
        │   ├── provider[registry.terraform.io/hashicorp/google] >= 6.1.0, < 7.0.0
        │   └── provider[registry.terraform.io/hashicorp/random]
        ├── module.project
        │   ├── provider[registry.terraform.io/hashicorp/google]
        │   ├── provider[registry.terraform.io/hashicorp/time]
        │   ├── provider[registry.terraform.io/hashicorp/random]
        │   ├── module.folder_iam
        │       ├── provider[registry.terraform.io/hashicorp/google] >= 3.53.0, < 7.0.0
        │       └── module.helper
        │   └── module.owner_folder_iam
        │       ├── provider[registry.terraform.io/hashicorp/google] >= 3.53.0, < 7.0.0
        │       └── module.helper
        └── module.psc_consumer
            └── module.raw_psc_consumer
                └── provider[registry.terraform.io/hashicorp/google]

Providers required by state:

    provider[registry.terraform.io/hashicorp/kubernetes]

    provider[registry.terraform.io/hashicorp/google]

    provider[registry.terraform.io/hashicorp/google-beta]

    provider[registry.terraform.io/hashicorp/null]

    provider[registry.terraform.io/hashicorp/random]

    provider[registry.terraform.io/hashicorp/time]

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions