diff --git a/cloud_sql/database_instances.tf b/cloud_sql/database_instances.tf new file mode 100644 index 0000000..fafd374 --- /dev/null +++ b/cloud_sql/database_instances.tf @@ -0,0 +1,89 @@ +# tfsec:ignore:google-sql-no-public-access tfsec:ignore:google-sql-encrypt-in-transit-data tfsec:ignore:google-sql-enable-pg-temp-file-logging tfsec:ignore:google-sql-pg-log-connections tfsec:ignore:google-sql-pg-log-checkpoints tfsec:ignore:google-sql-pg-log-lock-waits tfsec:ignore:google-sql-pg-log-disconnections +resource "google_sql_database_instance" "database" { + provider = google + + project = var.project + region = var.region + + name = var.name + + database_version = var.database_version + + master_instance_name = var.master_instance_name + + settings { + + activation_policy = var.activation_policy + availability_type = var.availability_type + + backup_configuration { + enabled = var.backup_enabled + start_time = var.backup_start_time + location = var.backup_location + binary_log_enabled = var.backup_binary_log_enabled + } + + disk_size = var.disk_size + disk_type = var.disk_type + disk_autoresize = var.disk_autoresize + + location_preference { + zone = "${var.region}-${var.zone}" + secondary_zone = var.secondary_zone != null ? "${var.region}-${var.secondary_zone}" : null + } + + dynamic "maintenance_window" { + for_each = (var.maintenance_window_day != null) || (var.maintenance_window_hour != null) ? [1] : [] + + content { + day = var.maintenance_window_day + hour = var.maintenance_window_hour + } + } + + dynamic "database_flags" { + for_each = var.database_flags + + content { + name = database_flags.value.name + value = database_flags.value.value + } + } + + dynamic "insights_config" { + for_each = var.insights_config != null ? [1] : [] + + content { + query_insights_enabled = var.insights_config.query_insights_enabled + query_string_length = var.insights_config.query_string_length + record_application_tags = var.insights_config.record_application_tags + record_client_address = var.insights_config.record_client_address + query_plans_per_minute = var.insights_config.query_plans_per_minute + } + } + + tier = var.tier + + pricing_plan = "PER_USE" + + user_labels = var.user_labels + + ip_configuration { + + ipv4_enabled = true + private_network = var.private_network + require_ssl = false + + dynamic "authorized_networks" { + for_each = var.authorized_networks + + content { + name = authorized_networks.value.display_name + value = authorized_networks.value.cidr_block + } + } + + } + + } +} diff --git a/cloud_sql/databases.tf b/cloud_sql/databases.tf new file mode 100644 index 0000000..57ba2a1 --- /dev/null +++ b/cloud_sql/databases.tf @@ -0,0 +1,7 @@ +resource "google_sql_database" "databases" { + count = length(var.databases) + + instance = google_sql_database_instance.database.name + + name = var.databases[count.index].name +} diff --git a/cloud_sql/output.tf b/cloud_sql/output.tf new file mode 100644 index 0000000..e42cb7a --- /dev/null +++ b/cloud_sql/output.tf @@ -0,0 +1,27 @@ +output "id" { + value = google_sql_database_instance.database.id +} + +output "name" { + value = google_sql_database_instance.database.name +} + +output "ip_address" { + value = google_sql_database_instance.database.ip_address +} + +output "private_ip_address" { + value = google_sql_database_instance.database.private_ip_address +} + +output "public_ip_address" { + value = google_sql_database_instance.database.public_ip_address +} + +output "databases" { + value = google_sql_database.databases.*.name +} + +output "users" { + value = google_sql_user.users.*.name +} diff --git a/cloud_sql/users.tf b/cloud_sql/users.tf new file mode 100644 index 0000000..bd0a47e --- /dev/null +++ b/cloud_sql/users.tf @@ -0,0 +1,23 @@ +resource "random_password" "users_passwords" { + count = length(var.users) + + length = 64 + + special = true + override_special = "!#$%&*()-_=+[]{}<>:?" +} + +resource "google_sql_user" "users" { + count = length(var.users) + + instance = google_sql_database_instance.database.name + + name = var.users[count.index].name + password = random_password.users_passwords[count.index].result + + lifecycle { + ignore_changes = [ + password + ] + } +} diff --git a/cloud_sql/variables.tf b/cloud_sql/variables.tf new file mode 100644 index 0000000..5487032 --- /dev/null +++ b/cloud_sql/variables.tf @@ -0,0 +1,190 @@ +variable "project" { + type = string + description = "(Optional) The ID of the Project in which the Resource belongs. Defaults to `jobtome-platform`." + + default = "jobtome-platform" +} + +variable "region" { + type = string + description = "(Required) The Region the Instance will sit in." +} + +variable "zone" { + type = string + description = "(Required) The preferred Zone." +} + +variable "secondary_zone" { + type = string + description = "(Optional) The preferred Compute Engine Zone for the Secondary/Failover." + + default = null +} + +variable "name" { + type = string + description = "(Required) The Name of the Instance." +} + +variable "database_version" { + type = string + description = "(Required) The MySQL, PostgreSQL or SQL Server Version to use." +} + +variable "master_instance_name" { + type = string + description = "(Optional) The Name of the existing Instance that will act as the Master in the Replication Setup. NOTE: This requires the Master to have `binary_log_enabled` set, as well as existing Backups." + + default = null +} + +variable "availability_type" { + type = string + description = "(Optional) The Availability Type of the Cloud SQL Instance, High Availability (`REGIONAL`) or Single Zone (`ZONAL`). Defaults to `ZONAL`." + + default = "ZONAL" +} + +variable "activation_policy" { + type = string + description = "(Optional) This specifies when the Instance should be active. Can be either `ALWAYS`, `NEVER` or `ON_DEMAND`. Defaults to `ALWAYS`." + + default = "ALWAYS" +} + +variable "backup_enabled" { + type = bool + description = "(Optional) True if Backup Configuration is enabled." + + default = true +} + +variable "backup_binary_log_enabled" { + type = bool + description = "(Optional) True if Binary Logging is Enabled. Can only be used with MySQL. Defaults to `false`." + + default = false +} + +variable "backup_start_time" { + type = string + description = "(Optional) `HH:MM` Format Time indicating when Backup Configuration Starts. Defaults to `14:00`." + + default = "14:00" +} + +variable "backup_location" { + type = string + description = "(Optional) The Region where the Backup will be stored." + + default = null +} + +variable "disk_autoresize" { + type = bool + description = "(Optional) Enables Auto-Resizing of the Storage Size. Defaults to `true`." + + default = true +} + +variable "disk_size" { + type = number + description = "(Optional) The Size of Data Disk, in GB. Size of a Running Instance cannot be reduced but can be increased. The Minimum Value is 10GB. Defaults to `10`." + + default = 10 +} + +variable "disk_type" { + type = string + description = "(Optional) The Type of Data Disk: `PD_SSD` or `PD_HDD`. Defaults to `PD_SSD`." + + default = "PD_SSD" +} + +variable "maintenance_window_day" { + type = number + description = "(Optional) Declares a One-Hour Maintenance Window when an Instance can automatically restart to apply Updates. Day of Week (`1-7`)." + + default = null +} + +variable "maintenance_window_hour" { + type = number + description = "(Optional) Declares a One-Hour Maintenance Window when an Instance can automatically restart to apply Updates. Hour of Day (`0-23`)." + + default = null +} + +variable "tier" { + type = string + description = "(Required) The Machine Type to use." +} + +variable "authorized_networks" { + type = list(any) + description = "(Optional) Authorized Networks." + + default = [] +} + +variable "database_flags" { + type = list( + object({ + name = string + value = string + }) + ) + description = "(Optional) Database Flags." + + default = [] +} + +variable "user_labels" { + type = map(string) + description = "(Optional) A Set of Key/Value User Label Pairs to assign to the Instance." + + default = {} +} + +variable "private_network" { + type = string + description = "(Optional) The VPC Network from which the Cloud SQL Instance is accessible for Private IP." + + default = null +} + +variable "insights_config" { + type = object({ + query_insights_enabled = bool + query_string_length = number + record_application_tags = bool + record_client_address = bool + query_plans_per_minute = number + }) + description = "(Optional) Query Insights (MySQL, PostgreSQL) Configuration." + + default = null +} + +variable "databases" { + type = list( + object({ + name = string + }) + ) + description = "(Optional) List of SQL Databases inside the Cloud SQL Instance to be created." + + default = [] +} + +variable "users" { + type = list( + object({ + name = string + }) + ) + description = "(Optional) List of SQL Database Users inside the Cloud SQL Instance to be created." + + default = [] +} diff --git a/cloud_sql/versions.tf b/cloud_sql/versions.tf new file mode 100644 index 0000000..b7fdacb --- /dev/null +++ b/cloud_sql/versions.tf @@ -0,0 +1,14 @@ +terraform { + required_version = "~> v1.6.2" + + required_providers { + google = { + source = "hashicorp/google" + version = "~> 5.4.0" + } + google-beta = { + source = "hashicorp/google-beta" + version = "~> 5.4.0" + } + } +}