Skip to content

microsoftexpert/tf-mod-gcp-redis-instance

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

☁️ Google Cloud Memorystore for Redis Instance Terraform Module

Provisions a single Memorystore for Redis instance (google_redis_instance) β€” Google's fully managed Redis service β€” targeting hashicorp/google ~> 7.0 on Terraform >= 1.12.0.

Terraform Provider Module Version Module Type Resource Count Posture


🧩 Overview

  • 🧠 Manages one Memorystore for Redis instance β€” the GCP console/product name for google_redis_instance β€” a fully managed, in-memory key-value store.
  • πŸ” Requires OSS Redis AUTH and server-authenticated TLS in transit by default, both overriding the provider's own insecure defaults.
  • 🌐 Requires an explicit, caller-supplied VPC network (authorized_network) β€” never falls back to a project's default network.
  • πŸ’Ύ Supports RDB persistence, a weekly maintenance window, and CMEK (customer_managed_key) β€” every configurable concern lives on the one keystone resource; there is no child collection.
  • 🧯 Deletion-protected by default (deletion_protection = true).

πŸ’‘ Why it matters: An unauthenticated, unencrypted Redis endpoint reachable from a broader network than intended is a direct path to a live cache holding session tokens, rate-limit counters, or partially-denormalized application state. This module makes the caller opt out of AUTH and TLS explicitly rather than opt in β€” and makes them provision a real network before this module will even plan.


❀️ Support this project

If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:

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!


πŸ—ΊοΈ Where this fits

flowchart LR
 VPC["tf-mod-gcp-vpc-network\n(google_compute_network)"]:::keystone
 KMS["tf-mod-gcp-kms-keyring\n(google_kms_crypto_key)"]:::neutral
 REDIS["tf-mod-gcp-redis-instance\n(google_redis_instance)"]:::this

 VPC -->|"id to authorized_network (required)"| REDIS
 KMS -->|"crypto_key_ids[key] to customer_managed_key (optional CMEK)"| REDIS

 classDef this fill:#4285F4,color:#ffffff,stroke:#333333
 classDef keystone fill:#174EA6,color:#ffffff,stroke:#333333
 classDef neutral fill:#E8EAED,color:#202124,stroke:#999999
Loading

No module in the current Google Cloud catalog is a known downstream consumer of this module's outputs yet β€” stated explicitly rather than inventing a fictional consumer. Validated via the Mermaid Chart MCP before embedding.


🧬 What this builds

flowchart LR
 subgraph Inputs["Inputs"]
 I1["name, memory_size_gb,\ntier, authorized_network"]
 I2["auth_enabled,\ntransit_encryption_mode"]
 I3["persistence_config,\nmaintenance_policy"]
 I4["customer_managed_key,\nlabels, timeouts"]
 end

 THIS["google_redis_instance.this"]:::this

 subgraph Outputs["Outputs"]
 O1["id, host, port"]
 O2["current_location_id,\npersistence_iam_identity"]
 O3["read_endpoint,\nread_endpoint_port (STANDARD_HA only)"]
 O4["auth_string (sensitive,\nconditional)"]
 end

 I1 --> THIS
 I2 --> THIS
 I3 --> THIS
 I4 --> THIS

 THIS --> O1
 THIS --> O2
 THIS --> O3
 THIS --> O4

 classDef this fill:#4285F4,color:#ffffff,stroke:#333333
Loading

Resource inventory: one keystone resource, google_redis_instance.this. No for_each-managed children β€” this is a standalone module (see SCOPE.md).


βœ… Provider / Versions

Terraform >= 1.12.0
hashicorp/google ~> 7.0 (resolved to 7.39.0 at authoring time)
Provider block None β€” the caller configures google (ADC, WIF, or a service account key per our authentication model)

Schema notes that bite:

  • No self_link attribute exists on this resource at all β€” confirmed absent from both the live Attributes Reference and the schema-JSON attribute dump. id is this module's sole identity output; do not expect a self_link row anywhere in Outputs.
  • tier, authorized_network, connect_mode, and location_id carry no schema-level force_new flag, verified via terraform providers schema -json β€” and this absence was cross-checked against other resources in the same schema dump (including google_compute_network.name, documented elsewhere in this library as force-new) to confirm the schema-JSON output simply does not surface ForceNew/RequiresReplace information reliably for this provider version, rather than concluding these fields are actually mutable. Treat all four as operationally immutable per known Memorystore product behavior β€” terraform plan will not show a replace action for a change to any of them, but the API is expected to reject the update attempt at apply. See Architecture Notes.
  • alternative_location_id, replica_count, read_replicas_mode, read_endpoint, and read_endpoint_port are all Standard-tier concepts. BASIC tier's only valid replica_count is 0; the read-only endpoint does not exist outside STANDARD_HA with read_replicas_mode = "READ_REPLICAS_ENABLED". See Outputs and Design Principles for the conditionality.
  • CMEK uses customer_managed_key, not kms_key_name β€” the argument name Cloud SQL and Filestore use for the equivalent field. Passing the wrong argument name from muscle memory fails at plan (unknown argument), not silently.
  • auth_string is only populated when auth_enabled = true.

πŸ”‘ Required IAM Roles

  • roles/redis.admin on the target project β€” least-privilege role for creating, updating, and deleting Memorystore for Redis instances.

☁️ GCP Prerequisites

  • redis.googleapis.com (Memorystore for Redis API) enabled on the target project β€” via tf-mod-gcp-project-services, applied before this module.
  • The target authorized_network must already exist (e.g. via tf-mod-gcp-vpc-network) β€” this module attaches to it by id; it does not create the VPC network.
  • If connect_mode = "PRIVATE_SERVICE_ACCESS", a google_service_networking_connection must already be established on that network, with an explicit depends_on in the consuming composition (Terraform does not auto-interpolate this dependency).
  • If customer_managed_key is set, the Cloud KMS key ring/crypto key must already exist in a location compatible with this instance's region (via tf-mod-gcp-kms-keyring), and IAM propagation (up to ~60 seconds) should be allowed to settle if composed in the same apply.

πŸ“ Module Structure

tf-mod-gcp-redis-instance/
β”œβ”€β”€ providers.tf # required_providers + required_version β€” no provider {} block
β”œβ”€β”€ variables.tf # google_redis_instance.this schema β€” secure-default overrides, tier-conditional validation
β”œβ”€β”€ main.tf # google_redis_instance.this β€” the sole keystone resource
β”œβ”€β”€ outputs.tf # id, host, port first β€” no self_link (none exists)
β”œβ”€β”€ README.md # this file
β”œβ”€β”€ SCOPE.md # lightweight standalone scope
└── examples/
 └── basic/ # smallest real call (requires a real authorized_network)

βš™οΈ Quick Start

module "redis" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name           = "app-session-cache"
  memory_size_gb = 1

  # Required β€” no default. Use tf-mod-gcp-vpc-network's `id` output in a real
  # composition; a literal value is shown here only for a self-contained example.
  authorized_network = "projects/casey-prod-networking/global/networks/app-vpc"
}

The caller configures the google provider (ADC, WIF, or a service account key per our authentication model) β€” this module never declares project/region/zone/credentials. authorized_network has no default; the smallest real call still requires a real network reference, not a fictional zero-argument call.


πŸ”Œ Cross-Module Contract

Consumes

Input Type Source module
authorized_network string (.id form) tf-mod-gcp-vpc-network (id output)
customer_managed_key string, optional (.id form) tf-mod-gcp-kms-keyring (crypto_key_ids map output)

Emits

Output Description
id Instance resource id (no self_link exists)
host Primary Redis endpoint hostname/IP
port Primary Redis endpoint port
current_location_id Current serving zone
persistence_iam_identity IAM identity for import/export
read_endpoint Read-only endpoint β€” STANDARD_HA + read replicas only
read_endpoint_port Read-only endpoint port β€” STANDARD_HA + read replicas only
auth_string AUTH string β€” sensitive, populated only when auth_enabled = true

πŸ“š Example Library

1 Β· Minimal BASIC tier instance
module "redis_basic" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name               = "basic-cache"
  memory_size_gb     = 1
  authorized_network = module.vpc.id
}

ℹ️ tier defaults to "BASIC" (a standalone instance, the provider's own default) β€” auth_enabled and transit_encryption_mode still default to their secure values regardless of tier.

2 Β· STANDARD_HA with alternative_location_id
module "redis_ha" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name                    = "ha-cache"
  memory_size_gb          = 5
  tier                    = "STANDARD_HA"
  location_id             = "us-central1-a"
  alternative_location_id = "us-central1-f"
  authorized_network      = module.vpc.id
}

πŸ’‘ alternative_location_id must be a different zone from location_id β€” protects against a single-zone failure by provisioning primary/replica across two zones.

3 Β· AUTH enabled (default β€” no action needed)
module "redis_auth_default" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name               = "auth-default-cache"
  memory_size_gb     = 1
  authorized_network = module.vpc.id
  # auth_enabled defaults to true β€” nothing else to set.
}

output "redis_auth_string" {
  value     = module.redis_auth_default.auth_string
  sensitive = true
}
4 Β· AUTH explicitly disabled
module "redis_no_auth" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name               = "scratch-cache"
  memory_size_gb     = 1
  authorized_network = module.vpc.id
  auth_enabled       = false
}

⚠️ Only disable AUTH for an instance reachable exclusively from an already-trusted, fully private network (e.g. a short-lived scratch cache). auth_string will be null for this instance.

5 Β· Transit encryption enabled (default β€” no action needed)
module "redis_tls_default" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name               = "tls-default-cache"
  memory_size_gb     = 1
  authorized_network = module.vpc.id
  # transit_encryption_mode defaults to "SERVER_AUTHENTICATION" β€” nothing else to set.
}
6 Β· Transit encryption explicitly disabled
module "redis_no_tls" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name                    = "legacy-client-cache"
  memory_size_gb          = 1
  authorized_network      = module.vpc.id
  transit_encryption_mode = "DISABLED"
}

⚠️ Only disable transit encryption for a legacy client that cannot negotiate TLS on a fully trusted private network β€” traffic between clients and this instance is unencrypted otherwise.

7 Β· CMEK via customer_managed_key
module "redis_cmek" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name                 = "cmek-cache"
  memory_size_gb       = 1
  authorized_network   = module.vpc.id
  customer_managed_key = module.kms.crypto_key_ids["redis-cmek-key"]
}

πŸ”’ customer_managed_key β€” not kms_key_name β€” is this resource's CMEK argument. Never default this to a specific key; the caller always supplies it explicitly.

8 Β· Persistence via persistence_config with an RDB snapshot schedule
module "redis_persistent" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name               = "persistent-cache"
  memory_size_gb     = 2
  tier               = "STANDARD_HA"
  authorized_network = module.vpc.id

  persistence_config = {
    persistence_mode    = "RDB"
    rdb_snapshot_period = "TWELVE_HOURS"
  }
}
9 Β· maintenance_policy with a weekly_maintenance_window
module "redis_maintenance" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name               = "maintained-cache"
  memory_size_gb     = 1
  authorized_network = module.vpc.id

  maintenance_policy = {
    description = "Weekly low-traffic maintenance window"
    weekly_maintenance_window = {
      day = "TUESDAY"
      start_time = {
        hours   = 3
        minutes = 30
      }
    }
  }
}
10 Β· Read replicas via replica_count + read_replicas_mode on STANDARD_HA
module "redis_read_replicas" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name               = "read-scaled-cache"
  memory_size_gb     = 5
  tier               = "STANDARD_HA"
  authorized_network = module.vpc.id
  replica_count      = 3
  read_replicas_mode = "READ_REPLICAS_ENABLED"
}

output "redis_read_endpoint" {
  value = module.redis_read_replicas.read_endpoint
}

ℹ️ read_endpoint/read_endpoint_port are only populated for this exact combination (STANDARD_HA + READ_REPLICAS_ENABLED) β€” null on every other tier/mode combination this module allows.

11 Β· Private service access connect_mode
resource "google_compute_global_address" "redis_psa_range" {
  name          = "redis-psa-range"
  purpose       = "VPC_PEERING"
  address_type  = "INTERNAL"
  prefix_length = 16
  network       = module.vpc.id
}

resource "google_service_networking_connection" "redis_psa" {
  network                 = module.vpc.id
  service                 = "servicenetworking.googleapis.com"
  reserved_peering_ranges = [google_compute_global_address.redis_psa_range.name]
}

module "redis_psa" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name               = "psa-cache"
  memory_size_gb     = 1
  tier               = "STANDARD_HA"
  authorized_network = module.vpc.id
  connect_mode       = "PRIVATE_SERVICE_ACCESS"

  depends_on = [google_service_networking_connection.redis_psa]
}

⚠️ The explicit depends_on on the private services access peering is mandatory β€” Terraform does not auto-interpolate this dependency (see SCOPE.md).

12 Β· Custom labels
module "redis_labeled" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name               = "labeled-cache"
  memory_size_gb     = 1
  authorized_network = module.vpc.id

  labels = {
    environment = "prod"
    team        = "platform"
    cost_center = "casey-infra"
  }
}
13 Β· Custom timeouts
module "redis_custom_timeouts" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name               = "slow-provision-cache"
  memory_size_gb     = 10
  authorized_network = module.vpc.id

  timeouts = {
    create = "40m"
    update = "40m"
    delete = "40m"
  }
}
14 Β· Reserved IP range and Redis config overrides
module "redis_custom_network" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name               = "tuned-cache"
  memory_size_gb     = 4
  authorized_network = module.vpc.id
  reserved_ip_range  = "10.100.0.0/29"

  redis_configs = {
    "maxmemory-policy" = "allkeys-lru"
  }
}
15 Β· πŸ—οΈ End-to-end composition
module "vpc" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-vpc-network.git?ref=v1.0.0"

  network_name = "app-vpc"

  subnetworks = {
    "app-subnet-use1" = {
      ip_cidr_range = "10.0.1.0/24"
      region        = "us-east1"
    }
  }
}

module "kms" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-kms-keyring.git?ref=v1.0.0"

  key_ring_name = "app-keyring"
  location      = "us-east1"

  crypto_keys = {
    "redis-cmek-key" = {}
  }
}

module "redis" {
  source = "git::https://github.com/microsoftexpert/tf-mod-gcp-redis-instance.git?ref=v1.0.0"

  name           = "app-session-cache"
  memory_size_gb = 5
  tier           = "STANDARD_HA"

  authorized_network   = module.vpc.id
  customer_managed_key = module.kms.crypto_key_ids["redis-cmek-key"]

  location_id             = "us-east1-b"
  alternative_location_id = "us-east1-c"

  replica_count      = 2
  read_replicas_mode = "READ_REPLICAS_ENABLED"

  persistence_config = {
    persistence_mode    = "RDB"
    rdb_snapshot_period = "SIX_HOURS"
  }

  maintenance_policy = {
    weekly_maintenance_window = {
      day        = "SUNDAY"
      start_time = { hours = 4 }
    }
  }

  labels = {
    environment = "prod"
    team        = "platform"
  }
}

output "redis_host" {
  value = module.redis.host
}

output "redis_port" {
  value = module.redis.port
}

output "redis_read_endpoint" {
  value = module.redis.read_endpoint
}

πŸ’‘ Wires tf-mod-gcp-vpc-network's id output into authorized_network and tf-mod-gcp-kms-keyring's crypto_key_ids map into customer_managed_key β€” the two real cross-module contracts this module currently has.


πŸ“₯ Inputs

Required: name, memory_size_gb, authorized_network (no default β€” see Design Principles).

Grouped summary: identity (name, memory_size_gb, display_name), topology (tier, authorized_network, connect_mode, location_id, alternative_location_id, redis_version, redis_configs, reserved_ip_range, secondary_ip_range), security (auth_enabled, transit_encryption_mode, customer_managed_key), scaling (replica_count, read_replicas_mode), operations (persistence_config, maintenance_policy, maintenance_version, deletion_protection, deletion_policy), universal tail (labels, timeouts).

Full object schemas
variable "name" {
  type = string
}

variable "memory_size_gb" {
  type = number
}

variable "tier" {
  type    = string
  default = "BASIC" # "BASIC" | "STANDARD_HA"
}

variable "authorized_network" {
  type = string # required β€” no default
}

variable "connect_mode" {
  type    = string
  default = "DIRECT_PEERING" # "DIRECT_PEERING" | "PRIVATE_SERVICE_ACCESS"
}

variable "location_id" {
  type    = string
  default = null
}

variable "alternative_location_id" {
  type    = string
  default = null
}

variable "redis_version" {
  type    = string
  default = null
}

variable "display_name" {
  type    = string
  default = null
}

variable "redis_configs" {
  type    = map(string)
  default = {}
}

variable "reserved_ip_range" {
  type    = string
  default = null
}

variable "secondary_ip_range" {
  type    = string
  default = null
}

variable "auth_enabled" {
  type    = bool
  default = true # secure-default override β€” provider default is false
}

variable "transit_encryption_mode" {
  type    = string
  default = "SERVER_AUTHENTICATION" # secure-default override β€” provider default is "DISABLED"
}

variable "replica_count" {
  type    = number
  default = null # API applies a tier-/mode-dependent default
}

variable "read_replicas_mode" {
  type    = string
  default = null # "READ_REPLICAS_DISABLED" | "READ_REPLICAS_ENABLED"
}

variable "maintenance_version" {
  type    = string
  default = null
}

variable "customer_managed_key" {
  type    = string
  default = null # never defaulted to a specific key
}

variable "deletion_protection" {
  type    = bool
  default = true
}

variable "deletion_policy" {
  type    = string
  default = "DELETE" # "DELETE" | "ABANDON" | "PREVENT"
}

variable "persistence_config" {
  type = object({
    persistence_mode        = string # required within the object once set
    rdb_snapshot_period     = optional(string)
    rdb_snapshot_start_time = optional(string)
  })
  default = null
}

variable "maintenance_policy" {
  type = object({
    description = optional(string)
    weekly_maintenance_window = optional(object({
      day = string
      start_time = object({
        hours   = optional(number, 0)
        minutes = optional(number, 0)
        seconds = optional(number, 0)
        nanos   = optional(number, 0)
      })
    }))
  })
  default = null
}

variable "labels" {
  type    = map(string)
  default = {}
}

variable "timeouts" {
  type = object({
    create = optional(string)
    update = optional(string)
    delete = optional(string)
  })
  default = null
}

🧾 Outputs

Output Description Notes
id Instance resource id No self_link exists on this resource
host Primary Redis endpoint hostname/IP Always populated
port Primary Redis endpoint port Always populated
current_location_id Current serving zone Always populated
persistence_iam_identity IAM identity for import/export Always populated
read_endpoint Read-only endpoint host Conditional β€” STANDARD_HA + READ_REPLICAS_ENABLED only, else null
read_endpoint_port Read-only endpoint port Conditional β€” same gate as read_endpoint
auth_string AUTH string Sensitive; populated only when auth_enabled = true, else null
name Instance name Always populated
create_time Creation timestamp Always populated
effective_reserved_ip_range Actual reserved CIDR range Always populated
nodes Per-node {id, zone} list Always populated
server_ca_certs Server CA certificate chain Always populated
maintenance_schedule Upcoming maintenance schedule Always populated
terraform_labels Labels from Terraform config + provider defaults Always populated
effective_labels All labels present on the resource in GCP Always populated

🧠 Architecture Notes

  • No self_link. This resource exposes only id as an identity form β€” do not write composing code that expects a self_link output from this module.
  • Tier-conditional outputs. read_endpoint/read_endpoint_port are null unless tier = "STANDARD_HA" and read_replicas_mode = "READ_REPLICAS_ENABLED". auth_string is null unless auth_enabled = true. Downstream consumers must handle the null case rather than assuming these are always populated.
  • ForceNew fields β€” verified, not assumed. terraform providers schema -json against the resolved hashicorp/google ~> 7.0 (7.39.0) install shows no force_new: true anywhere in google_redis_instance's schema β€” including on tier, authorized_network, connect_mode, and location_id. This was cross-checked against google_compute_network and google_compute_instance in the same schema dump to confirm it is a provider-wide limitation of the schema-JSON output for this provider version (many resources are implemented via the modern plugin-framework path, whose RequiresReplace plan modifiers are not serialized into the classic force_new boolean), not evidence these fields are safely mutable. Per known Memorystore product behavior, tier, authorized_network, connect_mode, and location_id are operationally immutable β€” terraform plan will show an in-place update, not a replace, for a change to any of them, and the API is expected to reject that update at apply. Treat any such change as a deliberate new-instance migration, not a routine apply.
  • persistence_config.persistence_mode is modeled as required-within-the-object even though the live schema marks the underlying attribute Optional+Computed β€” the provider's own prose marks it "(Required)" within the block, and this module's typing catches an incomplete persistence_config at plan time rather than letting it reach the API.
  • IAM propagation delay. If this module's IAM role grant (roles/redis.admin) and instance creation are composed in the same apply, allow for GCP IAM's ~60-second propagation delay.

🧱 Design Principles

Concern Secure default Opt-out (explicit)
OSS Redis AUTH auth_enabled = true (provider default is false) Caller sets auth_enabled = false
Transit encryption transit_encryption_mode = "SERVER_AUTHENTICATION" (provider default is "DISABLED") Caller sets transit_encryption_mode = "DISABLED"
Network attachment authorized_network is required, no default β€” never falls back to the project's default VPC N/A β€” caller must always supply a real network
Deletion protection deletion_protection = true Caller sets deletion_protection = false (two-step apply required β€” see Troubleshooting)
CMEK customer_managed_key accepted as optional input, never defaulted to a specific key Caller supplies a key from tf-mod-gcp-kms-keyring
Service tier tier = "BASIC" (provider default β€” not treated as a security control; see variables.tf) Caller sets tier = "STANDARD_HA" for HA

πŸš€ Runbook

cd tf-mod-gcp-redis-instance
terraform init -backend=false
terraform validate
terraform fmt -check

Pin ?ref=v1.0.0 in every source reference β€” never a branch. This library is plan-only; a human applies from CI with valid ADC/WIF credentials.


πŸ§ͺ Testing

terraform validate/fmt -check confirm internal type/reference consistency and canonical formatting only β€” they cannot catch GCP API-level rejections (quota, org policy, IAM propagation, or the operationally-immutable-but-not-schema-ForceNew fields noted in Architecture Notes). A real terraform plan/apply against a live project with valid credentials and an already-existing authorized_network is the only way to confirm this module's behavior end-to-end β€” that step belongs to the consuming pipeline, not this module's own offline validation.


πŸ’¬ Example Output

$ terraform output

id = "projects/casey-prod/locations/us-east1/instances/app-session-cache"
host = "10.36.112.3"
port = 6379
current_location_id = "us-east1-b"

auth_string and persistence_iam_identity are omitted from this sample β€” the former is sensitive = true and never appropriate to show even redacted in documentation; the latter is elided here for the same reason this library avoids showing real service-account-shaped strings in sample output.


πŸ” Troubleshooting

Symptom Cause Fix
Clients suddenly fail to connect after an apply auth_enabled was toggled true after clients were already configured without an AUTH password Update every connecting client's configuration with the new auth_string output before or in the same change window as the apply β€” do not toggle auth_enabled without a coordinated client rollout
apply fails with a permission or quota error on the tenant network Memorystore creates a tenant network per authorized_network; that tenant network is not deleted when the user-created network is deleted, and repeated create/destroy cycles against many networks can exhaust a tenant-network quota Reuse a stable authorized_network across environments rather than creating a new one per short-lived instance; request a quota increase if the pattern is intentional
destroy fails with a deletion-protection error deletion_protection = true (this module's default) Apply once with deletion_protection = false, then run the destroy β€” a two-step operation, not a single apply
Changing tier/authorized_network/connect_mode/location_id fails at apply with no prior plan warning These fields carry no schema-level ForceNew flag (see Architecture Notes), so plan shows an update, not a replace, and the API rejects the update itself Provision a new instance with the desired value instead of editing the field on an existing one
read_endpoint/read_endpoint_port are empty Instance is not STANDARD_HA with read_replicas_mode = "READ_REPLICAS_ENABLED" Set both tier = "STANDARD_HA" and read_replicas_mode = "READ_REPLICAS_ENABLED" if a read-only endpoint is required
Plan fails with an authorized_network validation-adjacent type error before any API call authorized_network was left unset This is intentional β€” supply a real network id (e.g. tf-mod-gcp-vpc-network's id output); this module has no default network fallback by design

πŸ”— Related Docs

Packages

 
 
 

Contributors

Languages