diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 83267903..823c984b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -332,6 +332,11 @@ updates: schedule: interval: "daily" + - package-ecosystem: "terraform" + directory: "/modules/azure/mysql_flexible_server_public" + schedule: + interval: "daily" + - package-ecosystem: "terraform" directory: "/modules/azure/network_security_group" schedule: @@ -342,6 +347,11 @@ updates: schedule: interval: "daily" + - package-ecosystem: "terraform" + directory: "/modules/azure/postgresql_public" + schedule: + interval: "daily" + - package-ecosystem: "terraform" directory: "/modules/azure/private_dns_zone" schedule: @@ -501,3 +511,28 @@ updates: directory: "/modules/other/password_generator" schedule: interval: "daily" + + - package-ecosystem: "terraform" + directory: "/modules/kubernetes/configmap" + schedule: + interval: "daily" + + - package-ecosystem: "terraform" + directory: "/modules/kubernetes/deployment_with_service" + schedule: + interval: "daily" + + - package-ecosystem: "terraform" + directory: "/modules/kubernetes/ingress" + schedule: + interval: "daily" + + - package-ecosystem: "terraform" + directory: "/modules/kubernetes/secret" + schedule: + interval: "daily" + + - package-ecosystem: "terraform" + directory: "/modules/kubernetes/pvc" + schedule: + interval: "daily" diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index 75261abb..805109b9 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -1,8 +1,9 @@ name: Validate on: - push: + pull_request: branches: - - '**' + - main + - develop jobs: validate-terraform: diff --git a/modules/azure/mysql_flexible_server/variables.tf b/modules/azure/mysql_flexible_server/variables.tf index cbd283e0..cd510d4f 100644 --- a/modules/azure/mysql_flexible_server/variables.tf +++ b/modules/azure/mysql_flexible_server/variables.tf @@ -45,7 +45,7 @@ variable "storage_auto_grow_enabled" { variable "backup_retention_days" { type = number description = "Backup retention days for the mysql server." - default = 7 + default = 30 } variable "geo_redundant_backup_enabled" { @@ -101,4 +101,4 @@ variable "slow_query_log" { variable "private_dns_zone_id" { type = string description = "ID of the private dns zone" -} \ No newline at end of file +} diff --git a/modules/azure/mysql_flexible_server_public/main.tf b/modules/azure/mysql_flexible_server_public/main.tf new file mode 100644 index 00000000..d2fae6c9 --- /dev/null +++ b/modules/azure/mysql_flexible_server_public/main.tf @@ -0,0 +1,117 @@ +terraform { + required_version = "~> 1.3" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.48" + } + } + + backend "azurerm" {} +} + +provider "azurerm" { + features {} +} + +resource "random_password" "mysql_admin_password" { + length = 16 + special = true + override_special = "_%@" + keepers = var.password_keeper +} + +resource "azurerm_mysql_flexible_server" "mysql_flexible_server" { + name = var.server_name + location = var.location + resource_group_name = var.resource_group_name + + administrator_login = var.admin_username + administrator_password = random_password.mysql_admin_password.result + + backup_retention_days = var.backup_retention_days + geo_redundant_backup_enabled = var.geo_redundant_backup_enabled + + sku_name = var.server_sku + version = var.server_version + + storage { + auto_grow_enabled = var.storage_auto_grow_enabled + size_gb = var.server_storage_max + } + + lifecycle { + ignore_changes = [zone] + prevent_destroy = true + } +} + +resource "azurerm_mysql_flexible_database" "mysql_flexible_database" { + name = var.database_name + resource_group_name = var.resource_group_name + server_name = azurerm_mysql_flexible_server.mysql_flexible_server.name + charset = var.database_charset + collation = var.database_collation +} + +resource "azurerm_mysql_flexible_server_configuration" "mysql_flexible_server_configuration" { + name = "slow_query_log" + resource_group_name = var.resource_group_name + server_name = azurerm_mysql_flexible_server.mysql_flexible_server.name + value = var.slow_query_log +} + +data "azurerm_monitor_diagnostic_categories" "diagnostic_categories" { + count = var.log_analytics_workspace_id == null ? 0 : 1 + resource_id = azurerm_mysql_flexible_server.mysql_flexible_server.id +} + +resource "azurerm_monitor_diagnostic_setting" "diagnostic_setting" { + count = var.log_analytics_workspace_id == null ? 0 : 1 + name = "diag-${var.server_name}" + target_resource_id = azurerm_mysql_flexible_server.mysql_flexible_server.id + log_analytics_workspace_id = var.log_analytics_workspace_id + + dynamic "enabled_log" { + for_each = data.azurerm_monitor_diagnostic_categories.diagnostic_categories[0].log_category_types + + content { + category = enabled_log.value + + retention_policy { + enabled = false + } + } + } + + dynamic "metric" { + for_each = data.azurerm_monitor_diagnostic_categories.diagnostic_categories[0].metrics + + content { + category = metric.value + enabled = true + + retention_policy { + enabled = false + } + } + } + + // TODO: not yet implemented by Azure + // log_analytics_destination_type = "Dedicated" + lifecycle { + ignore_changes = [log_analytics_destination_type] + } +} + +resource "azurerm_mysql_flexible_server_firewall_rule" "rule" { + for_each = var.whitelist_ip_addresses + + name = "fw-${var.server_name}-${replace(each.value, ".", "-")}" + resource_group_name = var.resource_group_name + server_name = azurerm_mysql_flexible_server.mysql_flexible_server.name + start_ip_address = each.value + end_ip_address = each.value +} + diff --git a/modules/azure/mysql_flexible_server_public/outputs.tf b/modules/azure/mysql_flexible_server_public/outputs.tf new file mode 100644 index 00000000..0cfdcc19 --- /dev/null +++ b/modules/azure/mysql_flexible_server_public/outputs.tf @@ -0,0 +1,21 @@ +output "id" { + value = azurerm_mysql_flexible_server.mysql_flexible_server.id +} + +output "fqdn" { + value = azurerm_mysql_flexible_server.mysql_flexible_server.fqdn +} + +output "database_name" { + value = azurerm_mysql_flexible_database.mysql_flexible_database.name +} + +output "admin_username" { + value = azurerm_mysql_flexible_server.mysql_flexible_server.administrator_login + sensitive = true +} + +output "admin_password" { + value = azurerm_mysql_flexible_server.mysql_flexible_server.administrator_password + sensitive = true +} diff --git a/modules/azure/mysql_flexible_server_public/variables.tf b/modules/azure/mysql_flexible_server_public/variables.tf new file mode 100644 index 00000000..65ad027c --- /dev/null +++ b/modules/azure/mysql_flexible_server_public/variables.tf @@ -0,0 +1,94 @@ +variable "location" { + type = string + description = "A datacenter location in Azure." +} + +variable "resource_group_name" { + type = string + description = "Name of the resource group." +} + +variable "server_name" { + type = string + description = "Name of the mysql server." +} + +variable "server_sku" { + type = string + description = "Specifies the sku for the mysql server" + default = "GP_Standard_D2ds_v4" +} + +variable "server_storage_max" { + type = number + description = "Max storage allowed in GB for the mysql server." + default = 20 +} + +variable "server_version" { + type = string + description = "Mysql server version." +} + +variable "storage_auto_grow_enabled" { + type = bool + description = "Enables auto-growing of mysql server storage." + default = true +} + +variable "backup_retention_days" { + type = number + description = "Backup retention days for the mysql server." + default = 30 +} + +variable "geo_redundant_backup_enabled" { + type = bool + description = "Enables geo-redundant mysql server backups." + default = true +} + +variable "database_name" { + type = string + description = "Name of the mysql database." +} + +variable "database_charset" { + type = string + description = "Specifies the charset for the mysql database." + default = "utf8mb3" +} + +variable "database_collation" { + type = string + description = "Specifies the collation for the mysql database." + default = "utf8mb3_unicode_ci" +} + +variable "admin_username" { + type = string + description = "The administrator login username for the mysql server." +} + +variable "password_keeper" { + type = map(string) + description = "Random map of strings, when changed the mysql admin password will rotate." +} + +variable "log_analytics_workspace_id" { + type = string + description = "ID of a log analytics workspace (optional)." + default = null +} + +variable "slow_query_log" { + type = string + description = "Slow query log. ON or OFF (default)" + default = "OFF" +} + +variable "whitelist_ip_addresses" { + type = set(string) + description = "List of IP addresses to whitelist." + default = [] +} diff --git a/modules/azure/postgresql_public/main.tf b/modules/azure/postgresql_public/main.tf new file mode 100644 index 00000000..cecb4fd9 --- /dev/null +++ b/modules/azure/postgresql_public/main.tf @@ -0,0 +1,115 @@ +terraform { + required_version = "~> 1.3" + + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.48" + } + } + + backend "azurerm" {} +} + +provider "azurerm" { + features {} +} + +resource "random_password" "postgresql_admin" { + length = 16 + special = false + override_special = "_%@" + keepers = var.password_keeper +} + +resource "azurerm_postgresql_flexible_server" "postgresql_server" { + name = var.name + location = var.location + resource_group_name = var.resource_group_name + + sku_name = var.postgresql_sku_name + + storage_mb = var.postgresql_db_size + backup_retention_days = 30 + + administrator_login = var.admin_username + administrator_password = random_password.postgresql_admin.result + version = var.postgresql_version + zone = "1" + + maintenance_window { + day_of_week = 1 # Monday + start_hour = 2 + start_minute = 0 + } + + lifecycle { + prevent_destroy = true + } +} + +resource "azurerm_postgresql_flexible_server_database" "postgresql_database" { + name = var.postgresql_database_name + server_id = azurerm_postgresql_flexible_server.postgresql_server.id + charset = "UTF8" + collation = var.postgresql_database_collation + + lifecycle { + prevent_destroy = true + } +} + +resource "azurerm_postgresql_flexible_server_configuration" "configuration_query_capture_mode" { + name = "pg_qs.query_capture_mode" + server_id = azurerm_postgresql_flexible_server.postgresql_server.id + value = "TOP" +} + +data "azurerm_monitor_diagnostic_categories" "diagnostic_categories" { + count = var.log_analytics_workspace_id == null ? 0 : 1 + resource_id = azurerm_postgresql_flexible_server.postgresql_server.id +} + +resource "azurerm_monitor_diagnostic_setting" "diagnostic_setting" { + count = var.log_analytics_workspace_id == null ? 0 : 1 + name = "diag-${var.name}" + target_resource_id = azurerm_postgresql_flexible_server.postgresql_server.id + log_analytics_workspace_id = var.log_analytics_workspace_id + + // TODO: not yet implemented by Azure + // log_analytics_destination_type = "Dedicated" + + dynamic "enabled_log" { + for_each = data.azurerm_monitor_diagnostic_categories.diagnostic_categories[0].log_category_types + + content { + category = enabled_log.value + + retention_policy { + enabled = false + } + } + } + + dynamic "metric" { + for_each = data.azurerm_monitor_diagnostic_categories.diagnostic_categories[0].metrics + + content { + category = metric.value + enabled = true + + retention_policy { + enabled = false + } + } + } +} + +resource "azurerm_postgresql_flexible_server_firewall_rule" "rule" { + for_each = var.whitelist_ip_addresses + + name = "fw-${var.name}-${replace(each.value, ".", "-")}" + server_id = azurerm_postgresql_flexible_server.postgresql_server.id + start_ip_address = each.value + end_ip_address = each.value +} diff --git a/modules/azure/postgresql_public/outputs.tf b/modules/azure/postgresql_public/outputs.tf new file mode 100644 index 00000000..d9faa80a --- /dev/null +++ b/modules/azure/postgresql_public/outputs.tf @@ -0,0 +1,16 @@ +output "admin_username" { + value = var.admin_username +} + +output "admin_password" { + value = random_password.postgresql_admin.result + sensitive = true +} + +output "database_name" { + value = azurerm_postgresql_flexible_server_database.postgresql_database.name +} + +output "fqdn" { + value = azurerm_postgresql_flexible_server.postgresql_server.fqdn +} diff --git a/modules/azure/postgresql_public/variables.tf b/modules/azure/postgresql_public/variables.tf new file mode 100644 index 00000000..dd2e13bd --- /dev/null +++ b/modules/azure/postgresql_public/variables.tf @@ -0,0 +1,62 @@ +variable "location" { + type = string + description = "A datacenter location in Azure." +} + +variable "resource_group_name" { + type = string + description = "Name of the resource group." +} + +variable "name" { + type = string + description = "Specifies the name of the PostgreSQL Flexible Server." +} + +variable "postgresql_sku_name" { + type = string + description = "Specifies the SKU Name for this PostgreSQL Server" +} + +variable "postgresql_db_size" { + type = number + description = "Specifies the max storage allowed for this PostgreSQL Server" +} + +variable "postgresql_version" { + type = string + description = "Version of the PostgreSQL database." +} + +variable "postgresql_database_name" { + type = string + description = "Name of the PostgreSQL resource." +} + +variable "postgresql_database_collation" { + type = string + description = "Specifies the Collation for this PostgreSQL Flexible Server" + default = "en_US.utf8" +} + +variable "admin_username" { + type = string + description = "Specifies the Administrator username for this PostgreSQL Flexible Server." +} + +variable "log_analytics_workspace_id" { + type = string + description = "ID of a log analytics workspace (optional)." + default = null +} + +variable "password_keeper" { + type = map(string) + description = "Random map of strings, when changed the postgresql admin password will rotate." +} + +variable "whitelist_ip_addresses" { + type = set(string) + description = "List of IP addresses to whitelist." + default = [] +} diff --git a/modules/kubernetes/configmap/main.tf b/modules/kubernetes/configmap/main.tf new file mode 100644 index 00000000..414908dd --- /dev/null +++ b/modules/kubernetes/configmap/main.tf @@ -0,0 +1,31 @@ +terraform { + required_version = "~> 1.3" + + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.20" + } + } + + backend "azurerm" {} +} + +provider "kubernetes" { + config_path = var.config_path +} + +resource "kubernetes_config_map_v1" "config" { + metadata { + name = var.name + namespace = var.namespace + } + + data = var.data + + lifecycle { + ignore_changes = [ + metadata[0].labels, + ] + } +} diff --git a/modules/kubernetes/configmap/outputs.tf b/modules/kubernetes/configmap/outputs.tf new file mode 100644 index 00000000..a519dd1f --- /dev/null +++ b/modules/kubernetes/configmap/outputs.tf @@ -0,0 +1,3 @@ +output "name" { + value = kubernetes_config_map_v1.config.metadata.0.name +} diff --git a/modules/kubernetes/configmap/variables.tf b/modules/kubernetes/configmap/variables.tf new file mode 100644 index 00000000..c488b69b --- /dev/null +++ b/modules/kubernetes/configmap/variables.tf @@ -0,0 +1,20 @@ +variable "namespace" { + type = string + description = "The namespace to deploy the configmap to" +} + +variable "name" { + type = string + description = "The name of the configmap" +} + +variable "data" { + type = map(string) + description = "The data to store in the configmap" +} + +variable "config_path" { + type = string + description = "The path to the config file" + default = "~/.kube/config" +} diff --git a/modules/kubernetes/deployment_with_service/main.tf b/modules/kubernetes/deployment_with_service/main.tf new file mode 100644 index 00000000..b7707194 --- /dev/null +++ b/modules/kubernetes/deployment_with_service/main.tf @@ -0,0 +1,282 @@ +terraform { + required_version = "~> 1.3" + + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.20" + } + } + + backend "azurerm" {} +} + +provider "kubernetes" { + config_path = var.config_path +} + +resource "kubernetes_deployment_v1" "deployment" { + metadata { + name = var.name + namespace = var.namespace + labels = { + app = var.name + } + } + + spec { + replicas = var.replicas + + selector { + match_labels = { + "io.kompose.service" = var.name + } + } + + template { + metadata { + labels = { + "io.kompose.service" = var.name + } + } + + spec { + container { + image = var.docker_image + image_pull_policy = "Always" + name = var.name + + resources { + limits = { + cpu = var.cpu_limit + memory = var.memory_limit + } + requests = { + cpu = var.cpu_request + memory = var.memory_request + } + } + + dynamic "env_from" { + for_each = var.env_secret_refs + + content { + secret_ref { + name = env_from.value + } + } + } + + dynamic "env" { + for_each = var.env + + content { + name = env.key + value = env.value + } + } + + dynamic "env_from" { + for_each = var.env_configmap_refs + + content { + config_map_ref { + name = env_from.value + } + } + } + + port { + container_port = var.container_port + } + + dynamic "volume_mount" { + for_each = var.volume_mounts + + content { + mount_path = volume_mount.value.mount_path + name = volume_mount.value.claim + sub_path = volume_mount.value.sub_path + } + } + + dynamic "readiness_probe" { + for_each = var.readiness_probe != null ? [1] : [] + + content { + http_get { + path = var.readiness_probe.path + port = var.readiness_probe.port + scheme = "HTTP" + } + + initial_delay_seconds = lookup(var.readiness_probe, "initial_delay_seconds", 10) + period_seconds = lookup(var.readiness_probe, "period_seconds", 5) + failure_threshold = lookup(var.readiness_probe, "failure_threshold", 50) + timeout_seconds = lookup(var.readiness_probe, "timeout_seconds", 5) + } + } + + dynamic "liveness_probe" { + for_each = var.liveness_probe != null ? [1] : [] + + content { + http_get { + path = var.liveness_probe.path + port = var.liveness_probe.port + scheme = "HTTP" + } + + initial_delay_seconds = lookup(var.liveness_probe, "initial_delay_seconds", 5) + period_seconds = lookup(var.liveness_probe, "period_seconds", 25) + failure_threshold = lookup(var.liveness_probe, "failure_threshold", 3) + timeout_seconds = lookup(var.liveness_probe, "timeout_seconds", 5) + } + } + } + + dns_config { + option { + name = "single-request-reopen" + } + } + + dynamic "volume" { + for_each = var.volume_mounts + + content { + name = volume.value.claim + + persistent_volume_claim { + claim_name = volume.value.claim + } + } + } + + restart_policy = "Always" + } + } + } +} + +resource "kubernetes_service_v1" "service" { + metadata { + name = var.name + namespace = var.namespace + } + + spec { + selector = { + "io.kompose.service" = kubernetes_deployment_v1.deployment.metadata[0].name + } + + port { + port = var.target_port + target_port = var.container_port + } + + type = "ClusterIP" + } + + lifecycle { + ignore_changes = [ + metadata[0].labels, + ] + } +} + +resource "kubernetes_manifest" "http-scaler" { + count = var.scaler.type == "http" ? 1 : 0 + + manifest = { + kind = "HTTPScaledObject" + apiVersion = "http.keda.sh/v1alpha1" + metadata = { + name = var.name + namespace = var.namespace + } + spec = { + host = var.scaler.host + scaleTargetRef = { + deployment = var.name + service = var.name + port = var.target_port + } + replicas = { + min = var.scaler.replicas.min + max = var.scaler.replicas.max + } + } + } +} + +# +resource "kubernetes_service_v1" "http-scaler-service-proxy" { + count = var.scaler.type == "http" ? 1 : 0 + + metadata { + name = "${var.name}-keda-bridge" + namespace = var.namespace + } + + spec { + external_name = "keda-add-ons-http-interceptor-proxy.keda.svc.cluster.local" + port { + port = 8080 + } + + type = "ExternalName" + } + + lifecycle { + ignore_changes = [ + metadata[0].labels, + ] + } +} + +resource "kubernetes_horizontal_pod_autoscaler_v2" "resource-scaler" { + count = var.scaler.type == "resource" ? 1 : 0 + + metadata { + name = var.name + namespace = var.namespace + } + + spec { + scale_target_ref { + api_version = "apps/v1" + kind = "Deployment" + name = var.name + } + + min_replicas = var.scaler.replicas.min + max_replicas = var.scaler.replicas.max + + metric { + type = "Resource" + + resource { + name = "cpu" + + target { + type = "Utilization" + average_utilization = lookup(var.scaler.metrics, "cpu", 70) + } + } + } + + metric { + type = "Resource" + + resource { + name = "memory" + + target { + type = "Utilization" + average_utilization = lookup(var.scaler.metrics, "memory", 80) + } + } + } + } +} diff --git a/modules/kubernetes/deployment_with_service/outputs.tf b/modules/kubernetes/deployment_with_service/outputs.tf new file mode 100644 index 00000000..d636c27e --- /dev/null +++ b/modules/kubernetes/deployment_with_service/outputs.tf @@ -0,0 +1,12 @@ + +output "deployment_name" { + value = kubernetes_deployment_v1.deployment.metadata.0.name +} + +output "service_port" { + value = var.scaler.type == "http" ? kubernetes_service_v1.http-scaler-service-proxy.0.spec.0.port.0.port : kubernetes_service_v1.service.spec.0.port.0.port +} + +output "service_name" { + value = var.scaler.type == "http" ? kubernetes_service_v1.http-scaler-service-proxy.0.metadata.0.name : kubernetes_service_v1.service.metadata.0.name +} diff --git a/modules/kubernetes/deployment_with_service/variables.tf b/modules/kubernetes/deployment_with_service/variables.tf new file mode 100644 index 00000000..bbaa0677 --- /dev/null +++ b/modules/kubernetes/deployment_with_service/variables.tf @@ -0,0 +1,126 @@ +variable "name" { + type = string + description = "The name of the application" +} + +variable "namespace" { + type = string + description = "The namespace to deploy the application to" +} + +variable "replicas" { + type = number + description = "The number of replicas to deploy" +} + +variable "docker_image" { + type = string + description = "The docker image to deploy" +} + +variable "cpu_request" { + type = string + description = "The CPU request for the application" +} + +variable "cpu_limit" { + type = string + description = "The CPU limit for the application" +} + +variable "memory_request" { + type = string + description = "The memory request for the application" +} + +variable "memory_limit" { + type = string + description = "The memory limit for the application" +} + +variable "container_port" { + type = number + description = "The port the container listens on" +} + +variable "target_port" { + type = number + description = "The port the service forwards to" +} + +variable "readiness_probe" { + type = object({ + path = string + port = number + initial_delay_seconds = optional(number) + period_seconds = optional(number) + failure_threshold = optional(number) + timeout_seconds = optional(number) + }) + description = "The readiness probe for the application" + default = null +} + +variable "liveness_probe" { + type = object({ + path = string + port = number + initial_delay_seconds = optional(number) + period_seconds = optional(number) + failure_threshold = optional(number) + timeout_seconds = optional(number) + }) + description = "The liveness probe for the application" + default = null +} + +variable "scaler" { + type = object({ + type = optional(string) + host = optional(string) + replicas = optional(object({ + min = number + max = number + })) + metrics = optional(object({ + cpu = number, + memory = number + })) + }) + description = "The scaler for the application" + default = null +} + +variable "env_secret_refs" { + type = list(string) + description = "The list of secret references to use as environment variables" + default = [] +} + +variable "env_configmap_refs" { + type = list(string) + description = "The list of configmap references to use as environment variables" + default = [] +} + +variable "env" { + type = map(string) + description = "The environment variables for the application" + default = {} +} + +variable "config_path" { + type = string + description = "The path to the config file" + default = "~/.kube/config" +} + +variable "volume_mounts" { + type = list(object({ + claim = string + mount_path = string + sub_path = string + })) + description = "The volume mounts for the application" + default = [] +} diff --git a/modules/kubernetes/ingress/main.tf b/modules/kubernetes/ingress/main.tf new file mode 100644 index 00000000..ad3fa2f8 --- /dev/null +++ b/modules/kubernetes/ingress/main.tf @@ -0,0 +1,65 @@ +terraform { + required_version = "~> 1.3" + + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.20" + } + } + + backend "azurerm" {} +} + +provider "kubernetes" { + config_path = var.config_path +} + +resource "kubernetes_ingress_v1" "ingress" { + count = var.enabled ? 1 : 0 + + metadata { + name = var.name + namespace = var.namespace + annotations = var.annotations + } + + spec { + dynamic "rule" { + for_each = var.rules + + content { + host = rule.value.host + http { + dynamic "path" { + for_each = rule.value.paths + + content { + backend { + service { + name = path.value.service + port { + number = path.value.port + } + } + } + + path = path.value.path + } + } + } + } + } + + tls { + secret_name = "tls-secret-${var.name}" + hosts = flatten([for rule in var.rules : rule.host]) + } + } + + lifecycle { + ignore_changes = [ + metadata[0].labels, + ] + } +} diff --git a/modules/kubernetes/ingress/outputs.tf b/modules/kubernetes/ingress/outputs.tf new file mode 100644 index 00000000..e69de29b diff --git a/modules/kubernetes/ingress/variables.tf b/modules/kubernetes/ingress/variables.tf new file mode 100644 index 00000000..312f89f9 --- /dev/null +++ b/modules/kubernetes/ingress/variables.tf @@ -0,0 +1,40 @@ +variable "name" { + type = string + description = "The name of the ingress" +} + +variable "namespace" { + type = string + description = "The namespace to deploy the application to" +} + +variable "annotations" { + type = map(string) + description = "Annotations for the ingress" + default = {} +} + +variable "rules" { + type = list(object({ + host = string + paths = list(object({ + service = string + port = number + path = string + })) + })) + description = "The rules for the ingress" + default = [] +} + +variable "config_path" { + type = string + description = "The path to the config file" + default = "~/.kube/config" +} + +variable "enabled" { + type = bool + description = "Whether to enable the ingress" + default = true +} diff --git a/modules/kubernetes/pvc/main.tf b/modules/kubernetes/pvc/main.tf new file mode 100644 index 00000000..ecf30d1a --- /dev/null +++ b/modules/kubernetes/pvc/main.tf @@ -0,0 +1,41 @@ +terraform { + required_version = "~> 1.3" + + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.20" + } + } + + backend "azurerm" {} +} + +provider "kubernetes" { + config_path = var.config_path +} + +resource "kubernetes_persistent_volume_claim_v1" "volume" { + metadata { + name = var.name + namespace = var.namespace + } + + spec { + access_modes = [var.access_mode] + + resources { + requests = { + storage = var.size + } + } + + storage_class_name = var.storage_class + } + + lifecycle { + ignore_changes = [ + metadata[0].labels, + ] + } +} diff --git a/modules/kubernetes/pvc/outputs.tf b/modules/kubernetes/pvc/outputs.tf new file mode 100644 index 00000000..e69de29b diff --git a/modules/kubernetes/pvc/variables.tf b/modules/kubernetes/pvc/variables.tf new file mode 100644 index 00000000..e9bb6f13 --- /dev/null +++ b/modules/kubernetes/pvc/variables.tf @@ -0,0 +1,30 @@ +variable "name" { + type = string + description = "The name of the pvc" +} + +variable "namespace" { + type = string + description = "The namespace to deploy the pvc to" +} + +variable "access_mode" { + type = string + description = "The access mode of the pvc" +} + +variable "size" { + type = string + description = "The storage size of the pvc" +} + +variable "storage_class" { + type = string + description = "The storage class of the pvc" +} + +variable "config_path" { + type = string + description = "The path to the config file" + default = "~/.kube/config" +} diff --git a/modules/kubernetes/secret/main.tf b/modules/kubernetes/secret/main.tf new file mode 100644 index 00000000..332399d1 --- /dev/null +++ b/modules/kubernetes/secret/main.tf @@ -0,0 +1,31 @@ +terraform { + required_version = "~> 1.3" + + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = "~> 2.20" + } + } + + backend "azurerm" {} +} + +provider "kubernetes" { + config_path = var.config_path +} + +resource "kubernetes_secret_v1" "secret" { + metadata { + name = var.name + namespace = var.namespace + } + + data = var.data + + lifecycle { + ignore_changes = [ + metadata[0].labels, + ] + } +} diff --git a/modules/kubernetes/secret/outputs.tf b/modules/kubernetes/secret/outputs.tf new file mode 100644 index 00000000..c631ea81 --- /dev/null +++ b/modules/kubernetes/secret/outputs.tf @@ -0,0 +1,3 @@ +output "name" { + value = kubernetes_secret_v1.secret.metadata.0.name +} diff --git a/modules/kubernetes/secret/variables.tf b/modules/kubernetes/secret/variables.tf new file mode 100644 index 00000000..6cd331af --- /dev/null +++ b/modules/kubernetes/secret/variables.tf @@ -0,0 +1,21 @@ +variable "namespace" { + type = string + description = "The namespace to deploy the secret to" +} + +variable "name" { + type = string + description = "The name of the secret" +} + +variable "data" { + type = map(string) + description = "The data to store in the secret" + sensitive = true +} + +variable "config_path" { + type = string + description = "The path to the config file" + default = "~/.kube/config" +}