From acb8692f0a1bc9dbfaf440fda5b6b11ff97eacbd Mon Sep 17 00:00:00 2001 From: Antoine Meausoone <592978+Ameausoone@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:48:03 +0100 Subject: [PATCH] feat(backup): add GKE backup configuration variables Introduce new variables for GKE backup configuration, including `backup_cron_schedule`, `backup_rpo_target_in_minutes`, `backup_config`, and `backup_retain_days`. These new settings enable backup schedule definition, RPO configuration, volume data and secrets backup options, and backup retention period definition. --- README.md | 4 ++ autogen/main/backup.tf.tmpl | 36 ++++++++++++++++++ autogen/main/variables.tf.tmpl | 38 +++++++++++++++++++ backup.tf | 37 ++++++++++++++++++ .../beta-autopilot-private-cluster/README.md | 4 ++ .../beta-autopilot-private-cluster/backup.tf | 37 ++++++++++++++++++ .../variables.tf | 38 +++++++++++++++++++ .../beta-autopilot-public-cluster/README.md | 4 ++ .../beta-autopilot-public-cluster/backup.tf | 37 ++++++++++++++++++ .../variables.tf | 38 +++++++++++++++++++ .../README.md | 4 ++ .../backup.tf | 37 ++++++++++++++++++ .../variables.tf | 38 +++++++++++++++++++ modules/beta-private-cluster/README.md | 4 ++ modules/beta-private-cluster/backup.tf | 37 ++++++++++++++++++ modules/beta-private-cluster/variables.tf | 38 +++++++++++++++++++ .../README.md | 4 ++ .../backup.tf | 37 ++++++++++++++++++ .../variables.tf | 38 +++++++++++++++++++ modules/beta-public-cluster/README.md | 4 ++ modules/beta-public-cluster/backup.tf | 37 ++++++++++++++++++ modules/beta-public-cluster/variables.tf | 38 +++++++++++++++++++ .../private-cluster-update-variant/README.md | 4 ++ .../private-cluster-update-variant/backup.tf | 37 ++++++++++++++++++ .../variables.tf | 38 +++++++++++++++++++ modules/private-cluster/README.md | 4 ++ modules/private-cluster/backup.tf | 37 ++++++++++++++++++ modules/private-cluster/variables.tf | 38 +++++++++++++++++++ variables.tf | 38 +++++++++++++++++++ 29 files changed, 785 insertions(+) create mode 100644 autogen/main/backup.tf.tmpl create mode 100644 backup.tf create mode 100644 modules/beta-autopilot-private-cluster/backup.tf create mode 100644 modules/beta-autopilot-public-cluster/backup.tf create mode 100644 modules/beta-private-cluster-update-variant/backup.tf create mode 100644 modules/beta-private-cluster/backup.tf create mode 100644 modules/beta-public-cluster-update-variant/backup.tf create mode 100644 modules/beta-public-cluster/backup.tf create mode 100644 modules/private-cluster-update-variant/backup.tf create mode 100644 modules/private-cluster/backup.tf diff --git a/README.md b/README.md index 22c14254be..870bbd4a59 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,10 @@ Then perform the following commands on the root folder: | additional\_ip\_range\_pods | List of _names_ of the additional secondary subnet ip ranges to use for pods | `list(string)` | `[]` | no | | additive\_vpc\_scope\_dns\_domain | This will enable Cloud DNS additive VPC scope. Must provide a domain name that is unique within the VPC. For this to work cluster\_dns = `CLOUD_DNS` and cluster\_dns\_scope = `CLUSTER_SCOPE` must both be set as well. | `string` | `""` | no | | authenticator\_security\_group | The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format gke-security-groups@yourdomain.com | `string` | `null` | no | +| backup\_config | Defines the backup configuration settings, including volume data and secrets backup options. |
object({
include_volume_data = optional(bool)
include_secrets = optional(bool)
}) | {
"include_secrets": true,
"include_volume_data": true
} | no |
+| backup\_cron\_schedule | Defines the GKE backup schedule. Mutually exclusive with backup\_rpo\_target\_in\_minutes; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `string` | `null` | no |
+| backup\_retain\_days | The number of days to retain backups. Must be between 1 and 35. Defaults to 7. | `number` | `7` | no |
+| backup\_rpo\_target\_in\_minutes | Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup\_cron\_schedule; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `number` | `null` | no |
| boot\_disk\_kms\_key | The Customer Managed Encryption Key used to encrypt the boot disk attached to each node in the node pool, if not overridden in `node_pools`. This should be of the form projects/[KEY\_PROJECT\_ID]/locations/[LOCATION]/keyRings/[RING\_NAME]/cryptoKeys/[KEY\_NAME]. For more information about protecting resources with Cloud KMS Keys please see: https://cloud.google.com/compute/docs/disks/customer-managed-encryption | `string` | `null` | no |
| cluster\_autoscaling | Cluster autoscaling configuration. See [more details](https://cloud.google.com/kubernetes-engine/docs/reference/rest/v1beta1/projects.locations.clusters#clusterautoscaling) | object({
enabled = bool
autoscaling_profile = string
min_cpu_cores = number
max_cpu_cores = number
min_memory_gb = number
max_memory_gb = number
gpu_resources = list(object({ resource_type = string, minimum = number, maximum = number }))
auto_repair = bool
auto_upgrade = bool
disk_size = optional(number)
disk_type = optional(string)
image_type = optional(string)
strategy = optional(string)
max_surge = optional(number)
max_unavailable = optional(number)
node_pool_soak_duration = optional(string)
batch_soak_duration = optional(string)
batch_percentage = optional(number)
batch_node_count = optional(number)
enable_secure_boot = optional(bool, false)
enable_integrity_monitoring = optional(bool, true)
}) | {
"auto_repair": true,
"auto_upgrade": true,
"autoscaling_profile": "BALANCED",
"disk_size": 100,
"disk_type": "pd-standard",
"enable_integrity_monitoring": true,
"enable_secure_boot": false,
"enabled": false,
"gpu_resources": [],
"image_type": "COS_CONTAINERD",
"max_cpu_cores": 0,
"max_memory_gb": 0,
"min_cpu_cores": 0,
"min_memory_gb": 0
} | no |
| cluster\_dns\_domain | The suffix used for all cluster service records. | `string` | `""` | no |
diff --git a/autogen/main/backup.tf.tmpl b/autogen/main/backup.tf.tmpl
new file mode 100644
index 0000000000..7aee37c68a
--- /dev/null
+++ b/autogen/main/backup.tf.tmpl
@@ -0,0 +1,36 @@
+resource "google_gke_backup_backup_plan" "backup" {
+ count = (var.backup_cron_schedule != null || var.backup_rpo_target_in_minutes != null) && var.gke_backup_agent_config ? 1 : 0
+
+ name = "${google_container_cluster.primary.name}-backup-plan"
+ cluster = google_container_cluster.primary.id
+
+ # Location (fallback to region or derived from zones)
+ location = try(var.region, substr(var.zones[0], 0, length(var.zones[0]) - 2))
+
+ backup_config {
+ include_volume_data = try(var.backup_config.include_volume_data, true)
+ include_secrets = try(var.backup_config.include_secrets, true)
+ all_namespaces = true
+ }
+
+ dynamic "backup_schedule" {
+ for_each = var.backup_cron_schedule != null ? [var.backup_cron_schedule] : []
+ content {
+ cron_schedule = backup_schedule.value
+ }
+ }
+
+ dynamic "backup_schedule" {
+ # If both backup_schedule and rpo_config are specified, backup_schedule have the precedence
+ for_each = var.backup_rpo_target_in_minutes != null && var.backup_cron_schedule ==null ? [var.backup_rpo_target_in_minutes] : []
+ content {
+ rpo_config {
+ target_rpo_minutes = backup_schedule.value
+ }
+ }
+ }
+
+ retention_policy {
+ backup_retain_days = var.backup_retain_days
+ }
+}
\ No newline at end of file
diff --git a/autogen/main/variables.tf.tmpl b/autogen/main/variables.tf.tmpl
index c7f85ea6a0..b73ac69f86 100644
--- a/autogen/main/variables.tf.tmpl
+++ b/autogen/main/variables.tf.tmpl
@@ -822,6 +822,44 @@ variable "gke_backup_agent_config" {
default = false
}
+variable "backup_cron_schedule" {
+ description = "Defines the GKE backup schedule. Mutually exclusive with backup_rpo_target_in_minutes; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = string
+ default = null
+}
+
+variable "backup_rpo_target_in_minutes" {
+ description = "Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup_cron_schedule; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = number
+ default = null
+ validation {
+ condition = var.backup_rpo_target_in_minutes == null || try(var.backup_rpo_target_in_minutes >= 60 && var.backup_rpo_target_in_minutes <= 86400, false)
+ error_message = "backup_rpo_target_in_minutes must be between 60 and 86400."
+ }
+}
+
+variable "backup_config" {
+ description = "Defines the backup configuration settings, including volume data and secrets backup options."
+ type = object({
+ include_volume_data = optional(bool)
+ include_secrets = optional(bool)
+ })
+ default = {
+ include_volume_data = true
+ include_secrets = true
+ }
+}
+
+variable "backup_retain_days" {
+ description = "The number of days to retain backups. Must be between 1 and 35. Defaults to 7."
+ type = number
+ default = 7
+ validation {
+ condition = var.backup_retain_days >= 1 && var.backup_retain_days <= 35
+ error_message = "backup_retain_days must be between 1 and 35."
+ }
+}
+
variable "stateful_ha" {
type = bool
description = "Whether the Stateful HA Addon is enabled for this cluster."
diff --git a/backup.tf b/backup.tf
new file mode 100644
index 0000000000..f8549a4ff4
--- /dev/null
+++ b/backup.tf
@@ -0,0 +1,37 @@
+resource "google_gke_backup_backup_plan" "backup" {
+ count = (var.backup_cron_schedule != null || var.backup_rpo_target_in_minutes != null) && var.gke_backup_agent_config ? 1 : 0
+
+ # Plan name and cluster identification
+ name = "${google_container_cluster.primary.name}-backup-plan"
+ cluster = google_container_cluster.primary.id
+
+ # Location (fallback to region or derived from zones)
+ location = try(var.region, substr(var.zones[0], 0, length(var.zones[0]) - 2))
+
+ backup_config {
+ include_volume_data = try(var.backup_config.include_volume_data, true)
+ include_secrets = try(var.backup_config.include_secrets, true)
+ all_namespaces = true
+ }
+
+ dynamic "backup_schedule" {
+ for_each = var.backup_cron_schedule != null ? [var.backup_cron_schedule] : []
+ content {
+ cron_schedule = backup_schedule.value
+ }
+ }
+
+ dynamic "backup_schedule" {
+ # If both backup_schedule and rpo_config are specified, backup_schedule have the precedence
+ for_each = var.backup_rpo_target_in_minutes != null && var.backup_cron_schedule == null ? [var.backup_rpo_target_in_minutes] : []
+ content {
+ rpo_config {
+ target_rpo_minutes = backup_schedule.value
+ }
+ }
+ }
+
+ retention_policy {
+ backup_retain_days = var.backup_retain_days
+ }
+}
\ No newline at end of file
diff --git a/modules/beta-autopilot-private-cluster/README.md b/modules/beta-autopilot-private-cluster/README.md
index 75e5b470b6..497554fae0 100644
--- a/modules/beta-autopilot-private-cluster/README.md
+++ b/modules/beta-autopilot-private-cluster/README.md
@@ -77,6 +77,10 @@ Then perform the following commands on the root folder:
| additional\_ip\_range\_pods | List of _names_ of the additional secondary subnet ip ranges to use for pods | `list(string)` | `[]` | no |
| allow\_net\_admin | (Optional) Enable NET\_ADMIN for the cluster. | `bool` | `null` | no |
| authenticator\_security\_group | The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format gke-security-groups@yourdomain.com | `string` | `null` | no |
+| backup\_config | Defines the backup configuration settings, including volume data and secrets backup options. | object({
include_volume_data = optional(bool)
include_secrets = optional(bool)
}) | {
"include_secrets": true,
"include_volume_data": true
} | no |
+| backup\_cron\_schedule | Defines the GKE backup schedule. Mutually exclusive with backup\_rpo\_target\_in\_minutes; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `string` | `null` | no |
+| backup\_retain\_days | The number of days to retain backups. Must be between 1 and 35. Defaults to 7. | `number` | `7` | no |
+| backup\_rpo\_target\_in\_minutes | Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup\_cron\_schedule; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `number` | `null` | no |
| boot\_disk\_kms\_key | The Customer Managed Encryption Key used to encrypt the boot disk attached to each node in the node pool, if not overridden in `node_pools`. This should be of the form projects/[KEY\_PROJECT\_ID]/locations/[LOCATION]/keyRings/[RING\_NAME]/cryptoKeys/[KEY\_NAME]. For more information about protecting resources with Cloud KMS Keys please see: https://cloud.google.com/compute/docs/disks/customer-managed-encryption | `string` | `null` | no |
| cluster\_ipv4\_cidr | The IP address range of the kubernetes pods in this cluster. Default is an automatically assigned CIDR. | `string` | `null` | no |
| cluster\_resource\_labels | The GCE resource labels (a map of key/value pairs) to be applied to the cluster | `map(string)` | `{}` | no |
diff --git a/modules/beta-autopilot-private-cluster/backup.tf b/modules/beta-autopilot-private-cluster/backup.tf
new file mode 100644
index 0000000000..f8549a4ff4
--- /dev/null
+++ b/modules/beta-autopilot-private-cluster/backup.tf
@@ -0,0 +1,37 @@
+resource "google_gke_backup_backup_plan" "backup" {
+ count = (var.backup_cron_schedule != null || var.backup_rpo_target_in_minutes != null) && var.gke_backup_agent_config ? 1 : 0
+
+ # Plan name and cluster identification
+ name = "${google_container_cluster.primary.name}-backup-plan"
+ cluster = google_container_cluster.primary.id
+
+ # Location (fallback to region or derived from zones)
+ location = try(var.region, substr(var.zones[0], 0, length(var.zones[0]) - 2))
+
+ backup_config {
+ include_volume_data = try(var.backup_config.include_volume_data, true)
+ include_secrets = try(var.backup_config.include_secrets, true)
+ all_namespaces = true
+ }
+
+ dynamic "backup_schedule" {
+ for_each = var.backup_cron_schedule != null ? [var.backup_cron_schedule] : []
+ content {
+ cron_schedule = backup_schedule.value
+ }
+ }
+
+ dynamic "backup_schedule" {
+ # If both backup_schedule and rpo_config are specified, backup_schedule have the precedence
+ for_each = var.backup_rpo_target_in_minutes != null && var.backup_cron_schedule == null ? [var.backup_rpo_target_in_minutes] : []
+ content {
+ rpo_config {
+ target_rpo_minutes = backup_schedule.value
+ }
+ }
+ }
+
+ retention_policy {
+ backup_retain_days = var.backup_retain_days
+ }
+}
\ No newline at end of file
diff --git a/modules/beta-autopilot-private-cluster/variables.tf b/modules/beta-autopilot-private-cluster/variables.tf
index 6e71292b88..e1942aa123 100644
--- a/modules/beta-autopilot-private-cluster/variables.tf
+++ b/modules/beta-autopilot-private-cluster/variables.tf
@@ -495,6 +495,44 @@ variable "gke_backup_agent_config" {
default = false
}
+variable "backup_cron_schedule" {
+ description = "Defines the GKE backup schedule. Mutually exclusive with backup_rpo_target_in_minutes; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = string
+ default = null
+}
+
+variable "backup_rpo_target_in_minutes" {
+ description = "Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup_cron_schedule; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = number
+ default = null
+ validation {
+ condition = var.backup_rpo_target_in_minutes == null || try(var.backup_rpo_target_in_minutes >= 60 && var.backup_rpo_target_in_minutes <= 86400, false)
+ error_message = "backup_rpo_target_in_minutes must be between 60 and 86400."
+ }
+}
+
+variable "backup_config" {
+ description = "Defines the backup configuration settings, including volume data and secrets backup options."
+ type = object({
+ include_volume_data = optional(bool)
+ include_secrets = optional(bool)
+ })
+ default = {
+ include_volume_data = true
+ include_secrets = true
+ }
+}
+
+variable "backup_retain_days" {
+ description = "The number of days to retain backups. Must be between 1 and 35. Defaults to 7."
+ type = number
+ default = 7
+ validation {
+ condition = var.backup_retain_days >= 1 && var.backup_retain_days <= 35
+ error_message = "backup_retain_days must be between 1 and 35."
+ }
+}
+
variable "stateful_ha" {
type = bool
description = "Whether the Stateful HA Addon is enabled for this cluster."
diff --git a/modules/beta-autopilot-public-cluster/README.md b/modules/beta-autopilot-public-cluster/README.md
index 9161fac806..ab001e8a18 100644
--- a/modules/beta-autopilot-public-cluster/README.md
+++ b/modules/beta-autopilot-public-cluster/README.md
@@ -72,6 +72,10 @@ Then perform the following commands on the root folder:
| additional\_ip\_range\_pods | List of _names_ of the additional secondary subnet ip ranges to use for pods | `list(string)` | `[]` | no |
| allow\_net\_admin | (Optional) Enable NET\_ADMIN for the cluster. | `bool` | `null` | no |
| authenticator\_security\_group | The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format gke-security-groups@yourdomain.com | `string` | `null` | no |
+| backup\_config | Defines the backup configuration settings, including volume data and secrets backup options. | object({
include_volume_data = optional(bool)
include_secrets = optional(bool)
}) | {
"include_secrets": true,
"include_volume_data": true
} | no |
+| backup\_cron\_schedule | Defines the GKE backup schedule. Mutually exclusive with backup\_rpo\_target\_in\_minutes; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `string` | `null` | no |
+| backup\_retain\_days | The number of days to retain backups. Must be between 1 and 35. Defaults to 7. | `number` | `7` | no |
+| backup\_rpo\_target\_in\_minutes | Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup\_cron\_schedule; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `number` | `null` | no |
| boot\_disk\_kms\_key | The Customer Managed Encryption Key used to encrypt the boot disk attached to each node in the node pool, if not overridden in `node_pools`. This should be of the form projects/[KEY\_PROJECT\_ID]/locations/[LOCATION]/keyRings/[RING\_NAME]/cryptoKeys/[KEY\_NAME]. For more information about protecting resources with Cloud KMS Keys please see: https://cloud.google.com/compute/docs/disks/customer-managed-encryption | `string` | `null` | no |
| cluster\_ipv4\_cidr | The IP address range of the kubernetes pods in this cluster. Default is an automatically assigned CIDR. | `string` | `null` | no |
| cluster\_resource\_labels | The GCE resource labels (a map of key/value pairs) to be applied to the cluster | `map(string)` | `{}` | no |
diff --git a/modules/beta-autopilot-public-cluster/backup.tf b/modules/beta-autopilot-public-cluster/backup.tf
new file mode 100644
index 0000000000..f8549a4ff4
--- /dev/null
+++ b/modules/beta-autopilot-public-cluster/backup.tf
@@ -0,0 +1,37 @@
+resource "google_gke_backup_backup_plan" "backup" {
+ count = (var.backup_cron_schedule != null || var.backup_rpo_target_in_minutes != null) && var.gke_backup_agent_config ? 1 : 0
+
+ # Plan name and cluster identification
+ name = "${google_container_cluster.primary.name}-backup-plan"
+ cluster = google_container_cluster.primary.id
+
+ # Location (fallback to region or derived from zones)
+ location = try(var.region, substr(var.zones[0], 0, length(var.zones[0]) - 2))
+
+ backup_config {
+ include_volume_data = try(var.backup_config.include_volume_data, true)
+ include_secrets = try(var.backup_config.include_secrets, true)
+ all_namespaces = true
+ }
+
+ dynamic "backup_schedule" {
+ for_each = var.backup_cron_schedule != null ? [var.backup_cron_schedule] : []
+ content {
+ cron_schedule = backup_schedule.value
+ }
+ }
+
+ dynamic "backup_schedule" {
+ # If both backup_schedule and rpo_config are specified, backup_schedule have the precedence
+ for_each = var.backup_rpo_target_in_minutes != null && var.backup_cron_schedule == null ? [var.backup_rpo_target_in_minutes] : []
+ content {
+ rpo_config {
+ target_rpo_minutes = backup_schedule.value
+ }
+ }
+ }
+
+ retention_policy {
+ backup_retain_days = var.backup_retain_days
+ }
+}
\ No newline at end of file
diff --git a/modules/beta-autopilot-public-cluster/variables.tf b/modules/beta-autopilot-public-cluster/variables.tf
index 470009e335..adde72bcf0 100644
--- a/modules/beta-autopilot-public-cluster/variables.tf
+++ b/modules/beta-autopilot-public-cluster/variables.tf
@@ -459,6 +459,44 @@ variable "gke_backup_agent_config" {
default = false
}
+variable "backup_cron_schedule" {
+ description = "Defines the GKE backup schedule. Mutually exclusive with backup_rpo_target_in_minutes; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = string
+ default = null
+}
+
+variable "backup_rpo_target_in_minutes" {
+ description = "Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup_cron_schedule; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = number
+ default = null
+ validation {
+ condition = var.backup_rpo_target_in_minutes == null || try(var.backup_rpo_target_in_minutes >= 60 && var.backup_rpo_target_in_minutes <= 86400, false)
+ error_message = "backup_rpo_target_in_minutes must be between 60 and 86400."
+ }
+}
+
+variable "backup_config" {
+ description = "Defines the backup configuration settings, including volume data and secrets backup options."
+ type = object({
+ include_volume_data = optional(bool)
+ include_secrets = optional(bool)
+ })
+ default = {
+ include_volume_data = true
+ include_secrets = true
+ }
+}
+
+variable "backup_retain_days" {
+ description = "The number of days to retain backups. Must be between 1 and 35. Defaults to 7."
+ type = number
+ default = 7
+ validation {
+ condition = var.backup_retain_days >= 1 && var.backup_retain_days <= 35
+ error_message = "backup_retain_days must be between 1 and 35."
+ }
+}
+
variable "stateful_ha" {
type = bool
description = "Whether the Stateful HA Addon is enabled for this cluster."
diff --git a/modules/beta-private-cluster-update-variant/README.md b/modules/beta-private-cluster-update-variant/README.md
index 4c4da6a7e9..8b841307a2 100644
--- a/modules/beta-private-cluster-update-variant/README.md
+++ b/modules/beta-private-cluster-update-variant/README.md
@@ -174,6 +174,10 @@ Then perform the following commands on the root folder:
| additional\_ip\_range\_pods | List of _names_ of the additional secondary subnet ip ranges to use for pods | `list(string)` | `[]` | no |
| additive\_vpc\_scope\_dns\_domain | This will enable Cloud DNS additive VPC scope. Must provide a domain name that is unique within the VPC. For this to work cluster\_dns = `CLOUD_DNS` and cluster\_dns\_scope = `CLUSTER_SCOPE` must both be set as well. | `string` | `""` | no |
| authenticator\_security\_group | The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format gke-security-groups@yourdomain.com | `string` | `null` | no |
+| backup\_config | Defines the backup configuration settings, including volume data and secrets backup options. | object({
include_volume_data = optional(bool)
include_secrets = optional(bool)
}) | {
"include_secrets": true,
"include_volume_data": true
} | no |
+| backup\_cron\_schedule | Defines the GKE backup schedule. Mutually exclusive with backup\_rpo\_target\_in\_minutes; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `string` | `null` | no |
+| backup\_retain\_days | The number of days to retain backups. Must be between 1 and 35. Defaults to 7. | `number` | `7` | no |
+| backup\_rpo\_target\_in\_minutes | Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup\_cron\_schedule; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `number` | `null` | no |
| boot\_disk\_kms\_key | The Customer Managed Encryption Key used to encrypt the boot disk attached to each node in the node pool, if not overridden in `node_pools`. This should be of the form projects/[KEY\_PROJECT\_ID]/locations/[LOCATION]/keyRings/[RING\_NAME]/cryptoKeys/[KEY\_NAME]. For more information about protecting resources with Cloud KMS Keys please see: https://cloud.google.com/compute/docs/disks/customer-managed-encryption | `string` | `null` | no |
| cloudrun | (Beta) Enable CloudRun addon | `bool` | `false` | no |
| cloudrun\_load\_balancer\_type | (Beta) Configure the Cloud Run load balancer type. External by default. Set to `LOAD_BALANCER_TYPE_INTERNAL` to configure as an internal load balancer. | `string` | `""` | no |
diff --git a/modules/beta-private-cluster-update-variant/backup.tf b/modules/beta-private-cluster-update-variant/backup.tf
new file mode 100644
index 0000000000..f8549a4ff4
--- /dev/null
+++ b/modules/beta-private-cluster-update-variant/backup.tf
@@ -0,0 +1,37 @@
+resource "google_gke_backup_backup_plan" "backup" {
+ count = (var.backup_cron_schedule != null || var.backup_rpo_target_in_minutes != null) && var.gke_backup_agent_config ? 1 : 0
+
+ # Plan name and cluster identification
+ name = "${google_container_cluster.primary.name}-backup-plan"
+ cluster = google_container_cluster.primary.id
+
+ # Location (fallback to region or derived from zones)
+ location = try(var.region, substr(var.zones[0], 0, length(var.zones[0]) - 2))
+
+ backup_config {
+ include_volume_data = try(var.backup_config.include_volume_data, true)
+ include_secrets = try(var.backup_config.include_secrets, true)
+ all_namespaces = true
+ }
+
+ dynamic "backup_schedule" {
+ for_each = var.backup_cron_schedule != null ? [var.backup_cron_schedule] : []
+ content {
+ cron_schedule = backup_schedule.value
+ }
+ }
+
+ dynamic "backup_schedule" {
+ # If both backup_schedule and rpo_config are specified, backup_schedule have the precedence
+ for_each = var.backup_rpo_target_in_minutes != null && var.backup_cron_schedule == null ? [var.backup_rpo_target_in_minutes] : []
+ content {
+ rpo_config {
+ target_rpo_minutes = backup_schedule.value
+ }
+ }
+ }
+
+ retention_policy {
+ backup_retain_days = var.backup_retain_days
+ }
+}
\ No newline at end of file
diff --git a/modules/beta-private-cluster-update-variant/variables.tf b/modules/beta-private-cluster-update-variant/variables.tf
index 0dbb0d64ee..1d64c54d04 100644
--- a/modules/beta-private-cluster-update-variant/variables.tf
+++ b/modules/beta-private-cluster-update-variant/variables.tf
@@ -788,6 +788,44 @@ variable "gke_backup_agent_config" {
default = false
}
+variable "backup_cron_schedule" {
+ description = "Defines the GKE backup schedule. Mutually exclusive with backup_rpo_target_in_minutes; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = string
+ default = null
+}
+
+variable "backup_rpo_target_in_minutes" {
+ description = "Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup_cron_schedule; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = number
+ default = null
+ validation {
+ condition = var.backup_rpo_target_in_minutes == null || try(var.backup_rpo_target_in_minutes >= 60 && var.backup_rpo_target_in_minutes <= 86400, false)
+ error_message = "backup_rpo_target_in_minutes must be between 60 and 86400."
+ }
+}
+
+variable "backup_config" {
+ description = "Defines the backup configuration settings, including volume data and secrets backup options."
+ type = object({
+ include_volume_data = optional(bool)
+ include_secrets = optional(bool)
+ })
+ default = {
+ include_volume_data = true
+ include_secrets = true
+ }
+}
+
+variable "backup_retain_days" {
+ description = "The number of days to retain backups. Must be between 1 and 35. Defaults to 7."
+ type = number
+ default = 7
+ validation {
+ condition = var.backup_retain_days >= 1 && var.backup_retain_days <= 35
+ error_message = "backup_retain_days must be between 1 and 35."
+ }
+}
+
variable "stateful_ha" {
type = bool
description = "Whether the Stateful HA Addon is enabled for this cluster."
diff --git a/modules/beta-private-cluster/README.md b/modules/beta-private-cluster/README.md
index b48fd27864..45ce718193 100644
--- a/modules/beta-private-cluster/README.md
+++ b/modules/beta-private-cluster/README.md
@@ -152,6 +152,10 @@ Then perform the following commands on the root folder:
| additional\_ip\_range\_pods | List of _names_ of the additional secondary subnet ip ranges to use for pods | `list(string)` | `[]` | no |
| additive\_vpc\_scope\_dns\_domain | This will enable Cloud DNS additive VPC scope. Must provide a domain name that is unique within the VPC. For this to work cluster\_dns = `CLOUD_DNS` and cluster\_dns\_scope = `CLUSTER_SCOPE` must both be set as well. | `string` | `""` | no |
| authenticator\_security\_group | The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format gke-security-groups@yourdomain.com | `string` | `null` | no |
+| backup\_config | Defines the backup configuration settings, including volume data and secrets backup options. | object({
include_volume_data = optional(bool)
include_secrets = optional(bool)
}) | {
"include_secrets": true,
"include_volume_data": true
} | no |
+| backup\_cron\_schedule | Defines the GKE backup schedule. Mutually exclusive with backup\_rpo\_target\_in\_minutes; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `string` | `null` | no |
+| backup\_retain\_days | The number of days to retain backups. Must be between 1 and 35. Defaults to 7. | `number` | `7` | no |
+| backup\_rpo\_target\_in\_minutes | Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup\_cron\_schedule; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `number` | `null` | no |
| boot\_disk\_kms\_key | The Customer Managed Encryption Key used to encrypt the boot disk attached to each node in the node pool, if not overridden in `node_pools`. This should be of the form projects/[KEY\_PROJECT\_ID]/locations/[LOCATION]/keyRings/[RING\_NAME]/cryptoKeys/[KEY\_NAME]. For more information about protecting resources with Cloud KMS Keys please see: https://cloud.google.com/compute/docs/disks/customer-managed-encryption | `string` | `null` | no |
| cloudrun | (Beta) Enable CloudRun addon | `bool` | `false` | no |
| cloudrun\_load\_balancer\_type | (Beta) Configure the Cloud Run load balancer type. External by default. Set to `LOAD_BALANCER_TYPE_INTERNAL` to configure as an internal load balancer. | `string` | `""` | no |
diff --git a/modules/beta-private-cluster/backup.tf b/modules/beta-private-cluster/backup.tf
new file mode 100644
index 0000000000..f8549a4ff4
--- /dev/null
+++ b/modules/beta-private-cluster/backup.tf
@@ -0,0 +1,37 @@
+resource "google_gke_backup_backup_plan" "backup" {
+ count = (var.backup_cron_schedule != null || var.backup_rpo_target_in_minutes != null) && var.gke_backup_agent_config ? 1 : 0
+
+ # Plan name and cluster identification
+ name = "${google_container_cluster.primary.name}-backup-plan"
+ cluster = google_container_cluster.primary.id
+
+ # Location (fallback to region or derived from zones)
+ location = try(var.region, substr(var.zones[0], 0, length(var.zones[0]) - 2))
+
+ backup_config {
+ include_volume_data = try(var.backup_config.include_volume_data, true)
+ include_secrets = try(var.backup_config.include_secrets, true)
+ all_namespaces = true
+ }
+
+ dynamic "backup_schedule" {
+ for_each = var.backup_cron_schedule != null ? [var.backup_cron_schedule] : []
+ content {
+ cron_schedule = backup_schedule.value
+ }
+ }
+
+ dynamic "backup_schedule" {
+ # If both backup_schedule and rpo_config are specified, backup_schedule have the precedence
+ for_each = var.backup_rpo_target_in_minutes != null && var.backup_cron_schedule == null ? [var.backup_rpo_target_in_minutes] : []
+ content {
+ rpo_config {
+ target_rpo_minutes = backup_schedule.value
+ }
+ }
+ }
+
+ retention_policy {
+ backup_retain_days = var.backup_retain_days
+ }
+}
\ No newline at end of file
diff --git a/modules/beta-private-cluster/variables.tf b/modules/beta-private-cluster/variables.tf
index 0dbb0d64ee..1d64c54d04 100644
--- a/modules/beta-private-cluster/variables.tf
+++ b/modules/beta-private-cluster/variables.tf
@@ -788,6 +788,44 @@ variable "gke_backup_agent_config" {
default = false
}
+variable "backup_cron_schedule" {
+ description = "Defines the GKE backup schedule. Mutually exclusive with backup_rpo_target_in_minutes; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = string
+ default = null
+}
+
+variable "backup_rpo_target_in_minutes" {
+ description = "Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup_cron_schedule; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = number
+ default = null
+ validation {
+ condition = var.backup_rpo_target_in_minutes == null || try(var.backup_rpo_target_in_minutes >= 60 && var.backup_rpo_target_in_minutes <= 86400, false)
+ error_message = "backup_rpo_target_in_minutes must be between 60 and 86400."
+ }
+}
+
+variable "backup_config" {
+ description = "Defines the backup configuration settings, including volume data and secrets backup options."
+ type = object({
+ include_volume_data = optional(bool)
+ include_secrets = optional(bool)
+ })
+ default = {
+ include_volume_data = true
+ include_secrets = true
+ }
+}
+
+variable "backup_retain_days" {
+ description = "The number of days to retain backups. Must be between 1 and 35. Defaults to 7."
+ type = number
+ default = 7
+ validation {
+ condition = var.backup_retain_days >= 1 && var.backup_retain_days <= 35
+ error_message = "backup_retain_days must be between 1 and 35."
+ }
+}
+
variable "stateful_ha" {
type = bool
description = "Whether the Stateful HA Addon is enabled for this cluster."
diff --git a/modules/beta-public-cluster-update-variant/README.md b/modules/beta-public-cluster-update-variant/README.md
index bfb0e162f8..13c1218da2 100644
--- a/modules/beta-public-cluster-update-variant/README.md
+++ b/modules/beta-public-cluster-update-variant/README.md
@@ -169,6 +169,10 @@ Then perform the following commands on the root folder:
| additional\_ip\_range\_pods | List of _names_ of the additional secondary subnet ip ranges to use for pods | `list(string)` | `[]` | no |
| additive\_vpc\_scope\_dns\_domain | This will enable Cloud DNS additive VPC scope. Must provide a domain name that is unique within the VPC. For this to work cluster\_dns = `CLOUD_DNS` and cluster\_dns\_scope = `CLUSTER_SCOPE` must both be set as well. | `string` | `""` | no |
| authenticator\_security\_group | The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format gke-security-groups@yourdomain.com | `string` | `null` | no |
+| backup\_config | Defines the backup configuration settings, including volume data and secrets backup options. | object({
include_volume_data = optional(bool)
include_secrets = optional(bool)
}) | {
"include_secrets": true,
"include_volume_data": true
} | no |
+| backup\_cron\_schedule | Defines the GKE backup schedule. Mutually exclusive with backup\_rpo\_target\_in\_minutes; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `string` | `null` | no |
+| backup\_retain\_days | The number of days to retain backups. Must be between 1 and 35. Defaults to 7. | `number` | `7` | no |
+| backup\_rpo\_target\_in\_minutes | Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup\_cron\_schedule; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `number` | `null` | no |
| boot\_disk\_kms\_key | The Customer Managed Encryption Key used to encrypt the boot disk attached to each node in the node pool, if not overridden in `node_pools`. This should be of the form projects/[KEY\_PROJECT\_ID]/locations/[LOCATION]/keyRings/[RING\_NAME]/cryptoKeys/[KEY\_NAME]. For more information about protecting resources with Cloud KMS Keys please see: https://cloud.google.com/compute/docs/disks/customer-managed-encryption | `string` | `null` | no |
| cloudrun | (Beta) Enable CloudRun addon | `bool` | `false` | no |
| cloudrun\_load\_balancer\_type | (Beta) Configure the Cloud Run load balancer type. External by default. Set to `LOAD_BALANCER_TYPE_INTERNAL` to configure as an internal load balancer. | `string` | `""` | no |
diff --git a/modules/beta-public-cluster-update-variant/backup.tf b/modules/beta-public-cluster-update-variant/backup.tf
new file mode 100644
index 0000000000..f8549a4ff4
--- /dev/null
+++ b/modules/beta-public-cluster-update-variant/backup.tf
@@ -0,0 +1,37 @@
+resource "google_gke_backup_backup_plan" "backup" {
+ count = (var.backup_cron_schedule != null || var.backup_rpo_target_in_minutes != null) && var.gke_backup_agent_config ? 1 : 0
+
+ # Plan name and cluster identification
+ name = "${google_container_cluster.primary.name}-backup-plan"
+ cluster = google_container_cluster.primary.id
+
+ # Location (fallback to region or derived from zones)
+ location = try(var.region, substr(var.zones[0], 0, length(var.zones[0]) - 2))
+
+ backup_config {
+ include_volume_data = try(var.backup_config.include_volume_data, true)
+ include_secrets = try(var.backup_config.include_secrets, true)
+ all_namespaces = true
+ }
+
+ dynamic "backup_schedule" {
+ for_each = var.backup_cron_schedule != null ? [var.backup_cron_schedule] : []
+ content {
+ cron_schedule = backup_schedule.value
+ }
+ }
+
+ dynamic "backup_schedule" {
+ # If both backup_schedule and rpo_config are specified, backup_schedule have the precedence
+ for_each = var.backup_rpo_target_in_minutes != null && var.backup_cron_schedule == null ? [var.backup_rpo_target_in_minutes] : []
+ content {
+ rpo_config {
+ target_rpo_minutes = backup_schedule.value
+ }
+ }
+ }
+
+ retention_policy {
+ backup_retain_days = var.backup_retain_days
+ }
+}
\ No newline at end of file
diff --git a/modules/beta-public-cluster-update-variant/variables.tf b/modules/beta-public-cluster-update-variant/variables.tf
index 972309520d..b1f63c5aa5 100644
--- a/modules/beta-public-cluster-update-variant/variables.tf
+++ b/modules/beta-public-cluster-update-variant/variables.tf
@@ -752,6 +752,44 @@ variable "gke_backup_agent_config" {
default = false
}
+variable "backup_cron_schedule" {
+ description = "Defines the GKE backup schedule. Mutually exclusive with backup_rpo_target_in_minutes; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = string
+ default = null
+}
+
+variable "backup_rpo_target_in_minutes" {
+ description = "Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup_cron_schedule; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = number
+ default = null
+ validation {
+ condition = var.backup_rpo_target_in_minutes == null || try(var.backup_rpo_target_in_minutes >= 60 && var.backup_rpo_target_in_minutes <= 86400, false)
+ error_message = "backup_rpo_target_in_minutes must be between 60 and 86400."
+ }
+}
+
+variable "backup_config" {
+ description = "Defines the backup configuration settings, including volume data and secrets backup options."
+ type = object({
+ include_volume_data = optional(bool)
+ include_secrets = optional(bool)
+ })
+ default = {
+ include_volume_data = true
+ include_secrets = true
+ }
+}
+
+variable "backup_retain_days" {
+ description = "The number of days to retain backups. Must be between 1 and 35. Defaults to 7."
+ type = number
+ default = 7
+ validation {
+ condition = var.backup_retain_days >= 1 && var.backup_retain_days <= 35
+ error_message = "backup_retain_days must be between 1 and 35."
+ }
+}
+
variable "stateful_ha" {
type = bool
description = "Whether the Stateful HA Addon is enabled for this cluster."
diff --git a/modules/beta-public-cluster/README.md b/modules/beta-public-cluster/README.md
index e6e879034f..e7254b14f8 100644
--- a/modules/beta-public-cluster/README.md
+++ b/modules/beta-public-cluster/README.md
@@ -147,6 +147,10 @@ Then perform the following commands on the root folder:
| additional\_ip\_range\_pods | List of _names_ of the additional secondary subnet ip ranges to use for pods | `list(string)` | `[]` | no |
| additive\_vpc\_scope\_dns\_domain | This will enable Cloud DNS additive VPC scope. Must provide a domain name that is unique within the VPC. For this to work cluster\_dns = `CLOUD_DNS` and cluster\_dns\_scope = `CLUSTER_SCOPE` must both be set as well. | `string` | `""` | no |
| authenticator\_security\_group | The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format gke-security-groups@yourdomain.com | `string` | `null` | no |
+| backup\_config | Defines the backup configuration settings, including volume data and secrets backup options. | object({
include_volume_data = optional(bool)
include_secrets = optional(bool)
}) | {
"include_secrets": true,
"include_volume_data": true
} | no |
+| backup\_cron\_schedule | Defines the GKE backup schedule. Mutually exclusive with backup\_rpo\_target\_in\_minutes; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `string` | `null` | no |
+| backup\_retain\_days | The number of days to retain backups. Must be between 1 and 35. Defaults to 7. | `number` | `7` | no |
+| backup\_rpo\_target\_in\_minutes | Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup\_cron\_schedule; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `number` | `null` | no |
| boot\_disk\_kms\_key | The Customer Managed Encryption Key used to encrypt the boot disk attached to each node in the node pool, if not overridden in `node_pools`. This should be of the form projects/[KEY\_PROJECT\_ID]/locations/[LOCATION]/keyRings/[RING\_NAME]/cryptoKeys/[KEY\_NAME]. For more information about protecting resources with Cloud KMS Keys please see: https://cloud.google.com/compute/docs/disks/customer-managed-encryption | `string` | `null` | no |
| cloudrun | (Beta) Enable CloudRun addon | `bool` | `false` | no |
| cloudrun\_load\_balancer\_type | (Beta) Configure the Cloud Run load balancer type. External by default. Set to `LOAD_BALANCER_TYPE_INTERNAL` to configure as an internal load balancer. | `string` | `""` | no |
diff --git a/modules/beta-public-cluster/backup.tf b/modules/beta-public-cluster/backup.tf
new file mode 100644
index 0000000000..f8549a4ff4
--- /dev/null
+++ b/modules/beta-public-cluster/backup.tf
@@ -0,0 +1,37 @@
+resource "google_gke_backup_backup_plan" "backup" {
+ count = (var.backup_cron_schedule != null || var.backup_rpo_target_in_minutes != null) && var.gke_backup_agent_config ? 1 : 0
+
+ # Plan name and cluster identification
+ name = "${google_container_cluster.primary.name}-backup-plan"
+ cluster = google_container_cluster.primary.id
+
+ # Location (fallback to region or derived from zones)
+ location = try(var.region, substr(var.zones[0], 0, length(var.zones[0]) - 2))
+
+ backup_config {
+ include_volume_data = try(var.backup_config.include_volume_data, true)
+ include_secrets = try(var.backup_config.include_secrets, true)
+ all_namespaces = true
+ }
+
+ dynamic "backup_schedule" {
+ for_each = var.backup_cron_schedule != null ? [var.backup_cron_schedule] : []
+ content {
+ cron_schedule = backup_schedule.value
+ }
+ }
+
+ dynamic "backup_schedule" {
+ # If both backup_schedule and rpo_config are specified, backup_schedule have the precedence
+ for_each = var.backup_rpo_target_in_minutes != null && var.backup_cron_schedule == null ? [var.backup_rpo_target_in_minutes] : []
+ content {
+ rpo_config {
+ target_rpo_minutes = backup_schedule.value
+ }
+ }
+ }
+
+ retention_policy {
+ backup_retain_days = var.backup_retain_days
+ }
+}
\ No newline at end of file
diff --git a/modules/beta-public-cluster/variables.tf b/modules/beta-public-cluster/variables.tf
index 972309520d..b1f63c5aa5 100644
--- a/modules/beta-public-cluster/variables.tf
+++ b/modules/beta-public-cluster/variables.tf
@@ -752,6 +752,44 @@ variable "gke_backup_agent_config" {
default = false
}
+variable "backup_cron_schedule" {
+ description = "Defines the GKE backup schedule. Mutually exclusive with backup_rpo_target_in_minutes; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = string
+ default = null
+}
+
+variable "backup_rpo_target_in_minutes" {
+ description = "Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup_cron_schedule; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = number
+ default = null
+ validation {
+ condition = var.backup_rpo_target_in_minutes == null || try(var.backup_rpo_target_in_minutes >= 60 && var.backup_rpo_target_in_minutes <= 86400, false)
+ error_message = "backup_rpo_target_in_minutes must be between 60 and 86400."
+ }
+}
+
+variable "backup_config" {
+ description = "Defines the backup configuration settings, including volume data and secrets backup options."
+ type = object({
+ include_volume_data = optional(bool)
+ include_secrets = optional(bool)
+ })
+ default = {
+ include_volume_data = true
+ include_secrets = true
+ }
+}
+
+variable "backup_retain_days" {
+ description = "The number of days to retain backups. Must be between 1 and 35. Defaults to 7."
+ type = number
+ default = 7
+ validation {
+ condition = var.backup_retain_days >= 1 && var.backup_retain_days <= 35
+ error_message = "backup_retain_days must be between 1 and 35."
+ }
+}
+
variable "stateful_ha" {
type = bool
description = "Whether the Stateful HA Addon is enabled for this cluster."
diff --git a/modules/private-cluster-update-variant/README.md b/modules/private-cluster-update-variant/README.md
index 670b8db6ca..cde8d9fa29 100644
--- a/modules/private-cluster-update-variant/README.md
+++ b/modules/private-cluster-update-variant/README.md
@@ -171,6 +171,10 @@ Then perform the following commands on the root folder:
| additional\_ip\_range\_pods | List of _names_ of the additional secondary subnet ip ranges to use for pods | `list(string)` | `[]` | no |
| additive\_vpc\_scope\_dns\_domain | This will enable Cloud DNS additive VPC scope. Must provide a domain name that is unique within the VPC. For this to work cluster\_dns = `CLOUD_DNS` and cluster\_dns\_scope = `CLUSTER_SCOPE` must both be set as well. | `string` | `""` | no |
| authenticator\_security\_group | The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format gke-security-groups@yourdomain.com | `string` | `null` | no |
+| backup\_config | Defines the backup configuration settings, including volume data and secrets backup options. | object({
include_volume_data = optional(bool)
include_secrets = optional(bool)
}) | {
"include_secrets": true,
"include_volume_data": true
} | no |
+| backup\_cron\_schedule | Defines the GKE backup schedule. Mutually exclusive with backup\_rpo\_target\_in\_minutes; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `string` | `null` | no |
+| backup\_retain\_days | The number of days to retain backups. Must be between 1 and 35. Defaults to 7. | `number` | `7` | no |
+| backup\_rpo\_target\_in\_minutes | Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup\_cron\_schedule; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `number` | `null` | no |
| boot\_disk\_kms\_key | The Customer Managed Encryption Key used to encrypt the boot disk attached to each node in the node pool, if not overridden in `node_pools`. This should be of the form projects/[KEY\_PROJECT\_ID]/locations/[LOCATION]/keyRings/[RING\_NAME]/cryptoKeys/[KEY\_NAME]. For more information about protecting resources with Cloud KMS Keys please see: https://cloud.google.com/compute/docs/disks/customer-managed-encryption | `string` | `null` | no |
| cluster\_autoscaling | Cluster autoscaling configuration. See [more details](https://cloud.google.com/kubernetes-engine/docs/reference/rest/v1beta1/projects.locations.clusters#clusterautoscaling) | object({
enabled = bool
autoscaling_profile = string
min_cpu_cores = number
max_cpu_cores = number
min_memory_gb = number
max_memory_gb = number
gpu_resources = list(object({ resource_type = string, minimum = number, maximum = number }))
auto_repair = bool
auto_upgrade = bool
disk_size = optional(number)
disk_type = optional(string)
image_type = optional(string)
strategy = optional(string)
max_surge = optional(number)
max_unavailable = optional(number)
node_pool_soak_duration = optional(string)
batch_soak_duration = optional(string)
batch_percentage = optional(number)
batch_node_count = optional(number)
enable_secure_boot = optional(bool, false)
enable_integrity_monitoring = optional(bool, true)
}) | {
"auto_repair": true,
"auto_upgrade": true,
"autoscaling_profile": "BALANCED",
"disk_size": 100,
"disk_type": "pd-standard",
"enable_integrity_monitoring": true,
"enable_secure_boot": false,
"enabled": false,
"gpu_resources": [],
"image_type": "COS_CONTAINERD",
"max_cpu_cores": 0,
"max_memory_gb": 0,
"min_cpu_cores": 0,
"min_memory_gb": 0
} | no |
| cluster\_dns\_domain | The suffix used for all cluster service records. | `string` | `""` | no |
diff --git a/modules/private-cluster-update-variant/backup.tf b/modules/private-cluster-update-variant/backup.tf
new file mode 100644
index 0000000000..f8549a4ff4
--- /dev/null
+++ b/modules/private-cluster-update-variant/backup.tf
@@ -0,0 +1,37 @@
+resource "google_gke_backup_backup_plan" "backup" {
+ count = (var.backup_cron_schedule != null || var.backup_rpo_target_in_minutes != null) && var.gke_backup_agent_config ? 1 : 0
+
+ # Plan name and cluster identification
+ name = "${google_container_cluster.primary.name}-backup-plan"
+ cluster = google_container_cluster.primary.id
+
+ # Location (fallback to region or derived from zones)
+ location = try(var.region, substr(var.zones[0], 0, length(var.zones[0]) - 2))
+
+ backup_config {
+ include_volume_data = try(var.backup_config.include_volume_data, true)
+ include_secrets = try(var.backup_config.include_secrets, true)
+ all_namespaces = true
+ }
+
+ dynamic "backup_schedule" {
+ for_each = var.backup_cron_schedule != null ? [var.backup_cron_schedule] : []
+ content {
+ cron_schedule = backup_schedule.value
+ }
+ }
+
+ dynamic "backup_schedule" {
+ # If both backup_schedule and rpo_config are specified, backup_schedule have the precedence
+ for_each = var.backup_rpo_target_in_minutes != null && var.backup_cron_schedule == null ? [var.backup_rpo_target_in_minutes] : []
+ content {
+ rpo_config {
+ target_rpo_minutes = backup_schedule.value
+ }
+ }
+ }
+
+ retention_policy {
+ backup_retain_days = var.backup_retain_days
+ }
+}
\ No newline at end of file
diff --git a/modules/private-cluster-update-variant/variables.tf b/modules/private-cluster-update-variant/variables.tf
index ba5b694e7a..8bca33b7e0 100644
--- a/modules/private-cluster-update-variant/variables.tf
+++ b/modules/private-cluster-update-variant/variables.tf
@@ -770,6 +770,44 @@ variable "gke_backup_agent_config" {
default = false
}
+variable "backup_cron_schedule" {
+ description = "Defines the GKE backup schedule. Mutually exclusive with backup_rpo_target_in_minutes; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = string
+ default = null
+}
+
+variable "backup_rpo_target_in_minutes" {
+ description = "Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup_cron_schedule; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = number
+ default = null
+ validation {
+ condition = var.backup_rpo_target_in_minutes == null || try(var.backup_rpo_target_in_minutes >= 60 && var.backup_rpo_target_in_minutes <= 86400, false)
+ error_message = "backup_rpo_target_in_minutes must be between 60 and 86400."
+ }
+}
+
+variable "backup_config" {
+ description = "Defines the backup configuration settings, including volume data and secrets backup options."
+ type = object({
+ include_volume_data = optional(bool)
+ include_secrets = optional(bool)
+ })
+ default = {
+ include_volume_data = true
+ include_secrets = true
+ }
+}
+
+variable "backup_retain_days" {
+ description = "The number of days to retain backups. Must be between 1 and 35. Defaults to 7."
+ type = number
+ default = 7
+ validation {
+ condition = var.backup_retain_days >= 1 && var.backup_retain_days <= 35
+ error_message = "backup_retain_days must be between 1 and 35."
+ }
+}
+
variable "stateful_ha" {
type = bool
description = "Whether the Stateful HA Addon is enabled for this cluster."
diff --git a/modules/private-cluster/README.md b/modules/private-cluster/README.md
index 1bd34d5563..b3fa5d3f7c 100644
--- a/modules/private-cluster/README.md
+++ b/modules/private-cluster/README.md
@@ -149,6 +149,10 @@ Then perform the following commands on the root folder:
| additional\_ip\_range\_pods | List of _names_ of the additional secondary subnet ip ranges to use for pods | `list(string)` | `[]` | no |
| additive\_vpc\_scope\_dns\_domain | This will enable Cloud DNS additive VPC scope. Must provide a domain name that is unique within the VPC. For this to work cluster\_dns = `CLOUD_DNS` and cluster\_dns\_scope = `CLUSTER_SCOPE` must both be set as well. | `string` | `""` | no |
| authenticator\_security\_group | The name of the RBAC security group for use with Google security groups in Kubernetes RBAC. Group name must be in format gke-security-groups@yourdomain.com | `string` | `null` | no |
+| backup\_config | Defines the backup configuration settings, including volume data and secrets backup options. | object({
include_volume_data = optional(bool)
include_secrets = optional(bool)
}) | {
"include_secrets": true,
"include_volume_data": true
} | no |
+| backup\_cron\_schedule | Defines the GKE backup schedule. Mutually exclusive with backup\_rpo\_target\_in\_minutes; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `string` | `null` | no |
+| backup\_retain\_days | The number of days to retain backups. Must be between 1 and 35. Defaults to 7. | `number` | `7` | no |
+| backup\_rpo\_target\_in\_minutes | Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup\_cron\_schedule; backup\_cron\_schedule takes precedence if both are set. Configure at least one to enable backup. | `number` | `null` | no |
| boot\_disk\_kms\_key | The Customer Managed Encryption Key used to encrypt the boot disk attached to each node in the node pool, if not overridden in `node_pools`. This should be of the form projects/[KEY\_PROJECT\_ID]/locations/[LOCATION]/keyRings/[RING\_NAME]/cryptoKeys/[KEY\_NAME]. For more information about protecting resources with Cloud KMS Keys please see: https://cloud.google.com/compute/docs/disks/customer-managed-encryption | `string` | `null` | no |
| cluster\_autoscaling | Cluster autoscaling configuration. See [more details](https://cloud.google.com/kubernetes-engine/docs/reference/rest/v1beta1/projects.locations.clusters#clusterautoscaling) | object({
enabled = bool
autoscaling_profile = string
min_cpu_cores = number
max_cpu_cores = number
min_memory_gb = number
max_memory_gb = number
gpu_resources = list(object({ resource_type = string, minimum = number, maximum = number }))
auto_repair = bool
auto_upgrade = bool
disk_size = optional(number)
disk_type = optional(string)
image_type = optional(string)
strategy = optional(string)
max_surge = optional(number)
max_unavailable = optional(number)
node_pool_soak_duration = optional(string)
batch_soak_duration = optional(string)
batch_percentage = optional(number)
batch_node_count = optional(number)
enable_secure_boot = optional(bool, false)
enable_integrity_monitoring = optional(bool, true)
}) | {
"auto_repair": true,
"auto_upgrade": true,
"autoscaling_profile": "BALANCED",
"disk_size": 100,
"disk_type": "pd-standard",
"enable_integrity_monitoring": true,
"enable_secure_boot": false,
"enabled": false,
"gpu_resources": [],
"image_type": "COS_CONTAINERD",
"max_cpu_cores": 0,
"max_memory_gb": 0,
"min_cpu_cores": 0,
"min_memory_gb": 0
} | no |
| cluster\_dns\_domain | The suffix used for all cluster service records. | `string` | `""` | no |
diff --git a/modules/private-cluster/backup.tf b/modules/private-cluster/backup.tf
new file mode 100644
index 0000000000..f8549a4ff4
--- /dev/null
+++ b/modules/private-cluster/backup.tf
@@ -0,0 +1,37 @@
+resource "google_gke_backup_backup_plan" "backup" {
+ count = (var.backup_cron_schedule != null || var.backup_rpo_target_in_minutes != null) && var.gke_backup_agent_config ? 1 : 0
+
+ # Plan name and cluster identification
+ name = "${google_container_cluster.primary.name}-backup-plan"
+ cluster = google_container_cluster.primary.id
+
+ # Location (fallback to region or derived from zones)
+ location = try(var.region, substr(var.zones[0], 0, length(var.zones[0]) - 2))
+
+ backup_config {
+ include_volume_data = try(var.backup_config.include_volume_data, true)
+ include_secrets = try(var.backup_config.include_secrets, true)
+ all_namespaces = true
+ }
+
+ dynamic "backup_schedule" {
+ for_each = var.backup_cron_schedule != null ? [var.backup_cron_schedule] : []
+ content {
+ cron_schedule = backup_schedule.value
+ }
+ }
+
+ dynamic "backup_schedule" {
+ # If both backup_schedule and rpo_config are specified, backup_schedule have the precedence
+ for_each = var.backup_rpo_target_in_minutes != null && var.backup_cron_schedule == null ? [var.backup_rpo_target_in_minutes] : []
+ content {
+ rpo_config {
+ target_rpo_minutes = backup_schedule.value
+ }
+ }
+ }
+
+ retention_policy {
+ backup_retain_days = var.backup_retain_days
+ }
+}
\ No newline at end of file
diff --git a/modules/private-cluster/variables.tf b/modules/private-cluster/variables.tf
index ba5b694e7a..8bca33b7e0 100644
--- a/modules/private-cluster/variables.tf
+++ b/modules/private-cluster/variables.tf
@@ -770,6 +770,44 @@ variable "gke_backup_agent_config" {
default = false
}
+variable "backup_cron_schedule" {
+ description = "Defines the GKE backup schedule. Mutually exclusive with backup_rpo_target_in_minutes; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = string
+ default = null
+}
+
+variable "backup_rpo_target_in_minutes" {
+ description = "Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup_cron_schedule; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = number
+ default = null
+ validation {
+ condition = var.backup_rpo_target_in_minutes == null || try(var.backup_rpo_target_in_minutes >= 60 && var.backup_rpo_target_in_minutes <= 86400, false)
+ error_message = "backup_rpo_target_in_minutes must be between 60 and 86400."
+ }
+}
+
+variable "backup_config" {
+ description = "Defines the backup configuration settings, including volume data and secrets backup options."
+ type = object({
+ include_volume_data = optional(bool)
+ include_secrets = optional(bool)
+ })
+ default = {
+ include_volume_data = true
+ include_secrets = true
+ }
+}
+
+variable "backup_retain_days" {
+ description = "The number of days to retain backups. Must be between 1 and 35. Defaults to 7."
+ type = number
+ default = 7
+ validation {
+ condition = var.backup_retain_days >= 1 && var.backup_retain_days <= 35
+ error_message = "backup_retain_days must be between 1 and 35."
+ }
+}
+
variable "stateful_ha" {
type = bool
description = "Whether the Stateful HA Addon is enabled for this cluster."
diff --git a/variables.tf b/variables.tf
index 7bec53d7c0..02b5535d3d 100644
--- a/variables.tf
+++ b/variables.tf
@@ -734,6 +734,44 @@ variable "gke_backup_agent_config" {
default = false
}
+variable "backup_cron_schedule" {
+ description = "Defines the GKE backup schedule. Mutually exclusive with backup_rpo_target_in_minutes; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = string
+ default = null
+}
+
+variable "backup_rpo_target_in_minutes" {
+ description = "Configuration for Recovery Point Objective (RPO), specifying the target RPO in minutes. Must be between 60 and 86400. Mutually exclusive with backup_cron_schedule; backup_cron_schedule takes precedence if both are set. Configure at least one to enable backup."
+ type = number
+ default = null
+ validation {
+ condition = var.backup_rpo_target_in_minutes == null || try(var.backup_rpo_target_in_minutes >= 60 && var.backup_rpo_target_in_minutes <= 86400, false)
+ error_message = "backup_rpo_target_in_minutes must be between 60 and 86400."
+ }
+}
+
+variable "backup_config" {
+ description = "Defines the backup configuration settings, including volume data and secrets backup options."
+ type = object({
+ include_volume_data = optional(bool)
+ include_secrets = optional(bool)
+ })
+ default = {
+ include_volume_data = true
+ include_secrets = true
+ }
+}
+
+variable "backup_retain_days" {
+ description = "The number of days to retain backups. Must be between 1 and 35. Defaults to 7."
+ type = number
+ default = 7
+ validation {
+ condition = var.backup_retain_days >= 1 && var.backup_retain_days <= 35
+ error_message = "backup_retain_days must be between 1 and 35."
+ }
+}
+
variable "stateful_ha" {
type = bool
description = "Whether the Stateful HA Addon is enabled for this cluster."