diff --git a/.github/workflows/terraform-postgresqlflexible.yml b/.github/workflows/terraform-postgresqlflexible.yml
new file mode 100644
index 0000000..00c856a
--- /dev/null
+++ b/.github/workflows/terraform-postgresqlflexible.yml
@@ -0,0 +1,29 @@
+name: postgresqlflexible tests
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - "modules/postgresqlflexible/**"
+ - ".github/workflows/terraform-postgresqlflexible.yml"
+
+ pull_request:
+ branches:
+ - main
+ paths:
+ - "modules/postgresqlflexible/**"
+ - ".github/workflows/terraform-postgresqlflexible.yml"
+
+jobs:
+ terraform_dev:
+ uses: ./.github/workflows/_terraformTestTemplate.yml
+ name: "Dev"
+ with:
+ environment: "dev"
+ config: "postgresqlflexible"
+ terraform_version: "1.10.4"
+ node_version: 20
+ tenant_id: "37963dd4-f4e6-40f8-a7d6-24b97919e452"
+ subscription_id: "1fdab118-1638-419a-8b12-06c9543714a0"
+ secrets:
+ CLIENT_ID: ${{ secrets.CLIENT_ID }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7d73f6d..49dc94b 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -16,6 +16,7 @@ exclude: |
modules/fabricworkspace/README.md|
modules/keyvault/README.md|
modules/loganalytics/README.md|
+ modules/postgresqlflexible/README.md|
modules/purview/README.md|
modules/storage/README.md|
modules/userassignedidentity/README.md|
@@ -67,6 +68,8 @@ repos:
args: ["-c", "./.terraform-docs.yml", "./modules/keyvault"]
- id: terraform-docs-go
args: ["-c", "./.terraform-docs.yml", "./modules/loganalytics"]
+ - id: terraform-docs-go
+ args: ["-c", "./.terraform-docs.yml", "./modules/postgresqlflexible"]
- id: terraform-docs-go
args: ["-c", "./.terraform-docs.yml", "./modules/purview"]
- id: terraform-docs-go
diff --git a/README.md b/README.md
index c1b7b3e..f6629a7 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@ This repository contains secure by default Terraform modules for Azure Services.
- [Azure Databricks Workspace](/modules/databricksworkspace/)
- [Azure Key Vault](/modules/keyvault/)
- [Azure Log Analytics Workspace](/modules/loganalytics/)
+- [Azure Postgresql Flexible Server](/modules/postgresqlflexible/)
- [Azure Storage Account](/modules/storage/)
- [Azure User Assigned Identity](/modules/userassignedidentity/)
- [Azure Synapse Private Link Hub](/modules/synapseprivetlinkhub/)
diff --git a/modules/postgresqlflexible/README.md b/modules/postgresqlflexible/README.md
new file mode 100644
index 0000000..29ece24
--- /dev/null
+++ b/modules/postgresqlflexible/README.md
@@ -0,0 +1,259 @@
+
+# Azure Postgresql Flexible Server Terraform Module
+
+## Documentation
+
+
+## Requirements
+
+The following requirements are needed by this module:
+
+- [terraform](#requirement\_terraform) (>=0.12)
+
+- [azurerm](#requirement\_azurerm) (~> 4.0)
+
+- [time](#requirement\_time) (~> 0.9)
+
+## Modules
+
+No modules.
+
+
+
+## Required Inputs
+
+The following input variables are required:
+
+### [location](#input\_location)
+
+Description: Specifies the location of all resources.
+
+Type: `string`
+
+### [postgresql\_name](#input\_postgresql\_name)
+
+Description: Specifies the name of the postgresql flexible server.
+
+Type: `string`
+
+### [resource\_group\_name](#input\_resource\_group\_name)
+
+Description: Specifies the resource group name in which all resources will get deployed.
+
+Type: `string`
+
+### [subnet\_id](#input\_subnet\_id)
+
+Description: Specifies the resource id of a subnet in which the private endpoints get created.
+
+Type: `string`
+
+## Optional Inputs
+
+The following input variables are optional (have default values):
+
+### [connectivity\_delay\_in\_seconds](#input\_connectivity\_delay\_in\_seconds)
+
+Description: Specifies the delay in seconds after the private endpoint deployment (required for the DNS automation via Policies).
+
+Type: `number`
+
+Default: `120`
+
+### [customer\_managed\_key](#input\_customer\_managed\_key)
+
+Description: Specifies the customer managed key configurations.
+
+Type:
+
+```hcl
+object({
+ key_vault_id = string,
+ key_vault_key_versionless_id = string,
+ user_assigned_identity_id = string,
+ user_assigned_identity_client_id = string,
+ })
+```
+
+Default: `null`
+
+### [diagnostics\_configurations](#input\_diagnostics\_configurations)
+
+Description: Specifies the diagnostic configuration for the service.
+
+Type:
+
+```hcl
+list(object({
+ log_analytics_workspace_id = optional(string, ""),
+ storage_account_id = optional(string, "")
+ }))
+```
+
+Default: `[]`
+
+### [postgresql\_active\_directory\_administrator](#input\_postgresql\_active\_directory\_administrator)
+
+Description: Specifies the entra id admin configuration for the postgresql flexible server. Please provide a group name and the object id of teh group.
+
+Type:
+
+```hcl
+object({
+ object_id = optional(string, "")
+ group_name = optional(string, "")
+ })
+```
+
+Default: `{}`
+
+### [postgresql\_auto\_grow\_enabled](#input\_postgresql\_auto\_grow\_enabled)
+
+Description: Specifies whether auto grow is enabled for the postgresql flexible server.
+
+Type: `bool`
+
+Default: `false`
+
+### [postgresql\_backup\_retention\_days](#input\_postgresql\_backup\_retention\_days)
+
+Description: Specifies the backup retention in days of the postgresql flexible server.
+
+Type: `number`
+
+Default: `30`
+
+### [postgresql\_configuration](#input\_postgresql\_configuration)
+
+Description: Specifies the configuration of the postgresql flexible server.
+
+Type: `map(string)`
+
+Default: `{}`
+
+### [postgresql\_databases](#input\_postgresql\_databases)
+
+Description: Specifies the databases of the postgresql flexible server.
+
+Type:
+
+```hcl
+map(object({
+ charset = optional(string, "UTF8")
+ collation = optional(string, "en_US.utf8")
+ }))
+```
+
+Default: `{}`
+
+### [postgresql\_geo\_redundant\_backup\_enabled](#input\_postgresql\_geo\_redundant\_backup\_enabled)
+
+Description: Specifies whether the geo redundant backup should be enabled for the postgresql storage account.
+
+Type: `bool`
+
+Default: `false`
+
+### [postgresql\_high\_availability\_mode](#input\_postgresql\_high\_availability\_mode)
+
+Description: Specifies whether zone redundancy should be enabled for the postgresql flexible server.
+
+Type: `string`
+
+Default: `"ZoneRedundant"`
+
+### [postgresql\_maintenance\_window](#input\_postgresql\_maintenance\_window)
+
+Description: Specifies the maintenance window for the postgresql flexible server.
+
+Type:
+
+```hcl
+object({
+ day_of_week = optional(number, 6)
+ start_hour = optional(number, 0)
+ start_minute = optional(number, 0)
+ })
+```
+
+Default: `{}`
+
+### [postgresql\_sku\_name](#input\_postgresql\_sku\_name)
+
+Description: Specifies the sku of the postgresql flexible server.
+
+Type: `string`
+
+Default: `"B_Standard_B1ms"`
+
+### [postgresql\_storage\_mb](#input\_postgresql\_storage\_mb)
+
+Description: Specifies the storage mb of the postgresql flexible server.
+
+Type: `number`
+
+Default: `32768`
+
+### [postgresql\_storage\_tier](#input\_postgresql\_storage\_tier)
+
+Description: Specifies the storage tier of the postgresql flexible server.
+
+Type: `string`
+
+Default: `null`
+
+### [postgresql\_version](#input\_postgresql\_version)
+
+Description: Specifies the version of the postgresql flexible server.
+
+Type: `number`
+
+Default: `16`
+
+### [postgresql\_zone\_redundancy\_enabled](#input\_postgresql\_zone\_redundancy\_enabled)
+
+Description: Specifies whether zone redundancy should be enabled for the postgresql flexible server.
+
+Type: `bool`
+
+Default: `false`
+
+### [private\_dns\_zone\_id\_postrgesql](#input\_private\_dns\_zone\_id\_postrgesql)
+
+Description: Specifies the resource ID of the private DNS zone for Azure Postgresql flexible server. Not required if DNS A-records get created via Azure Policy.
+
+Type: `string`
+
+Default: `""`
+
+### [tags](#input\_tags)
+
+Description: Specifies a key value map of tags to set on every taggable resources.
+
+Type: `map(string)`
+
+Default: `{}`
+
+## Outputs
+
+The following outputs are exported:
+
+### [postgresql\_flexible\_server\_fqdn](#output\_postgresql\_flexible\_server\_fqdn)
+
+Description: Specifies the fqdn of the postgres flexible server.
+
+### [postgresql\_flexible\_server\_id](#output\_postgresql\_flexible\_server\_id)
+
+Description: Specifies the resource id of the postgres flexible server.
+
+### [postgresql\_flexible\_server\_name](#output\_postgresql\_flexible\_server\_name)
+
+Description: Specifies the resource name of the postgres flexible server.
+
+### [postgresql\_flexible\_server\_setup\_completed](#output\_postgresql\_flexible\_server\_setup\_completed)
+
+Description: Specifies whether the connectivity and identity has been successfully configured.
+
+
+
+
\ No newline at end of file
diff --git a/modules/postgresqlflexible/README_footer.md b/modules/postgresqlflexible/README_footer.md
new file mode 100644
index 0000000..e69de29
diff --git a/modules/postgresqlflexible/README_header.md b/modules/postgresqlflexible/README_header.md
new file mode 100644
index 0000000..7aba925
--- /dev/null
+++ b/modules/postgresqlflexible/README_header.md
@@ -0,0 +1 @@
+# Azure Postgresql Flexible Server Terraform Module
diff --git a/modules/postgresqlflexible/connectivity.tf b/modules/postgresqlflexible/connectivity.tf
new file mode 100644
index 0000000..34632ec
--- /dev/null
+++ b/modules/postgresqlflexible/connectivity.tf
@@ -0,0 +1,38 @@
+resource "azurerm_private_endpoint" "private_endpoint_postgresql_flexible_server" {
+ name = "${azurerm_postgresql_flexible_server.postgresql_flexible_server.name}-pe"
+ location = var.location
+ resource_group_name = azurerm_postgresql_flexible_server.postgresql_flexible_server.resource_group_name
+ tags = var.tags
+
+ custom_network_interface_name = "${azurerm_postgresql_flexible_server.postgresql_flexible_server.name}-nic"
+ private_service_connection {
+ name = "${azurerm_postgresql_flexible_server.postgresql_flexible_server.name}-svc"
+ is_manual_connection = false
+ private_connection_resource_id = azurerm_postgresql_flexible_server.postgresql_flexible_server.id
+ subresource_names = ["postgresqlServer"]
+ }
+ subnet_id = var.subnet_id
+ dynamic "private_dns_zone_group" {
+ for_each = var.private_dns_zone_id_postrgesql == "" ? [] : [1]
+ content {
+ name = "${azurerm_postgresql_flexible_server.postgresql_flexible_server.name}-arecord"
+ private_dns_zone_ids = [
+ var.private_dns_zone_id_postrgesql
+ ]
+ }
+ }
+
+ lifecycle {
+ ignore_changes = [
+ private_dns_zone_group
+ ]
+ }
+}
+
+resource "time_sleep" "sleep_connectivity" {
+ create_duration = "${var.connectivity_delay_in_seconds}s"
+
+ depends_on = [
+ azurerm_private_endpoint.private_endpoint_postgresql_flexible_server
+ ]
+}
diff --git a/modules/postgresqlflexible/data.tf b/modules/postgresqlflexible/data.tf
new file mode 100644
index 0000000..ce1f54f
--- /dev/null
+++ b/modules/postgresqlflexible/data.tf
@@ -0,0 +1,5 @@
+data "azurerm_client_config" "current" {}
+
+data "azurerm_monitor_diagnostic_categories" "diagnostic_categories_postgresql_flexible_server" {
+ resource_id = azurerm_postgresql_flexible_server.postgresql_flexible_server.id
+}
diff --git a/modules/postgresqlflexible/diagnostics.tf b/modules/postgresqlflexible/diagnostics.tf
new file mode 100644
index 0000000..362c08d
--- /dev/null
+++ b/modules/postgresqlflexible/diagnostics.tf
@@ -0,0 +1,29 @@
+resource "azurerm_monitor_diagnostic_setting" "diagnostic_setting_postgresql_flexible_server" {
+ for_each = { for index, value in var.diagnostics_configurations :
+ index => {
+ log_analytics_workspace_id = value.log_analytics_workspace_id,
+ storage_account_id = value.storage_account_id
+ }
+ }
+ name = "applicationLogs-${each.key}"
+ target_resource_id = azurerm_postgresql_flexible_server.postgresql_flexible_server.id
+ log_analytics_workspace_id = each.value.log_analytics_workspace_id == "" ? null : each.value.log_analytics_workspace_id
+ storage_account_id = each.value.storage_account_id == "" ? null : each.value.storage_account_id
+
+ dynamic "enabled_log" {
+ iterator = entry
+ for_each = data.azurerm_monitor_diagnostic_categories.diagnostic_categories_postgresql_flexible_server.log_category_groups
+ content {
+ category_group = entry.value
+ }
+ }
+
+ dynamic "metric" {
+ iterator = entry
+ for_each = data.azurerm_monitor_diagnostic_categories.diagnostic_categories_postgresql_flexible_server.metrics
+ content {
+ category = entry.value
+ enabled = true
+ }
+ }
+}
diff --git a/modules/postgresqlflexible/main.tf b/modules/postgresqlflexible/main.tf
new file mode 100644
index 0000000..814d99e
--- /dev/null
+++ b/modules/postgresqlflexible/main.tf
@@ -0,0 +1,91 @@
+resource "azurerm_postgresql_flexible_server" "postgresql_flexible_server" {
+ name = var.postgresql_name
+ location = var.location
+ resource_group_name = var.resource_group_name
+ tags = var.tags
+ dynamic "identity" {
+ for_each = var.customer_managed_key != null ? [1] : []
+ content {
+ type = "UserAssigned"
+ identity_ids = [
+ var.customer_managed_key.user_assigned_identity_id
+ ]
+ }
+ }
+
+ administrator_login = null
+ administrator_password = null
+ authentication {
+ active_directory_auth_enabled = true
+ password_auth_enabled = false
+ tenant_id = data.azurerm_client_config.current.tenant_id
+ }
+ auto_grow_enabled = var.postgresql_auto_grow_enabled
+ backup_retention_days = var.postgresql_backup_retention_days
+ create_mode = "Default"
+ dynamic "customer_managed_key" {
+ for_each = var.customer_managed_key != null ? [1] : []
+ content {
+ key_vault_key_id = var.customer_managed_key.key_vault_id
+ primary_user_assigned_identity_id = var.customer_managed_key.user_assigned_identity_id
+ }
+ }
+ delegated_subnet_id = null
+ geo_redundant_backup_enabled = var.postgresql_geo_redundant_backup_enabled
+ dynamic "high_availability" {
+ for_each = var.postgresql_zone_redundancy_enabled ? [1] : []
+ content {
+ mode = var.postgresql_high_availability_mode
+ }
+ }
+ maintenance_window {
+ day_of_week = var.postgresql_maintenance_window.day_of_week
+ start_hour = var.postgresql_maintenance_window.start_hour
+ start_minute = var.postgresql_maintenance_window.start_minute
+ }
+ public_network_access_enabled = false
+ replication_role = null
+ sku_name = var.postgresql_sku_name
+ storage_mb = var.postgresql_storage_mb
+ storage_tier = var.postgresql_storage_tier
+ version = var.postgresql_version
+ zone = null
+
+ lifecycle {
+ ignore_changes = [
+ zone,
+ high_availability[0].standby_availability_zone,
+ ]
+ }
+}
+
+resource "azurerm_postgresql_flexible_server_database" "postgresql_flexible_server_database" {
+ for_each = var.postgresql_databases
+
+ server_id = azurerm_postgresql_flexible_server.postgresql_flexible_server.id
+ name = each.key
+
+ charset = each.value.charset
+ collation = each.value.collation
+}
+
+resource "azurerm_postgresql_flexible_server_active_directory_administrator" "postgresql_flexible_server_active_directory_administrator" {
+ count = var.postgresql_active_directory_administrator.object_id != "" && var.postgresql_active_directory_administrator.group_name != "" ? 1 : 0
+
+ server_name = azurerm_postgresql_flexible_server.postgresql_flexible_server.name
+ resource_group_name = azurerm_postgresql_flexible_server.postgresql_flexible_server.resource_group_name
+
+ object_id = var.postgresql_active_directory_administrator.object_id
+ principal_name = var.postgresql_active_directory_administrator.group_name
+ principal_type = "Group"
+ tenant_id = data.azurerm_client_config.current.tenant_id
+}
+
+resource "azurerm_postgresql_flexible_server_configuration" "postgresql_flexible_server_configuration" {
+ for_each = var.postgresql_configuration
+
+ server_id = azurerm_postgresql_flexible_server.postgresql_flexible_server.id
+ name = each.key
+
+ value = each.value
+}
diff --git a/modules/postgresqlflexible/outputs.tf b/modules/postgresqlflexible/outputs.tf
new file mode 100644
index 0000000..908dea2
--- /dev/null
+++ b/modules/postgresqlflexible/outputs.tf
@@ -0,0 +1,28 @@
+output "postgresql_flexible_server_id" {
+ description = "Specifies the resource id of the postgres flexible server."
+ value = azurerm_postgresql_flexible_server.postgresql_flexible_server.id
+ sensitive = false
+}
+
+output "postgresql_flexible_server_name" {
+ description = "Specifies the resource name of the postgres flexible server."
+ value = azurerm_postgresql_flexible_server.postgresql_flexible_server.name
+ sensitive = false
+}
+
+output "postgresql_flexible_server_fqdn" {
+ description = "Specifies the fqdn of the postgres flexible server."
+ value = azurerm_postgresql_flexible_server.postgresql_flexible_server.fqdn
+ sensitive = true
+}
+
+output "postgresql_flexible_server_setup_completed" {
+ description = "Specifies whether the connectivity and identity has been successfully configured."
+ value = true
+ sensitive = false
+
+ depends_on = [
+ azurerm_postgresql_flexible_server_active_directory_administrator.postgresql_flexible_server_active_directory_administrator,
+ time_sleep.sleep_connectivity,
+ ]
+}
diff --git a/modules/postgresqlflexible/terraform.tf b/modules/postgresqlflexible/terraform.tf
new file mode 100644
index 0000000..3e38630
--- /dev/null
+++ b/modules/postgresqlflexible/terraform.tf
@@ -0,0 +1,14 @@
+terraform {
+ required_version = ">=0.12"
+
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "~> 4.0"
+ }
+ time = {
+ source = "hashicorp/time"
+ version = "~> 0.9"
+ }
+ }
+}
diff --git a/modules/postgresqlflexible/tests/test.tftest.hcl b/modules/postgresqlflexible/tests/test.tftest.hcl
new file mode 100644
index 0000000..b0a7849
--- /dev/null
+++ b/modules/postgresqlflexible/tests/test.tftest.hcl
@@ -0,0 +1,47 @@
+run "create_postgresql_flexible_server" {
+ command = apply
+
+ variables {
+ location = "northeurope"
+ resource_group_name = "tfmodule-test-rg"
+ tags = {
+ test = "postgresqlflexibleserver"
+ }
+ postgresql_name = "tftstr-001"
+ postgresql_auto_grow_enabled = false
+ postgresql_backup_retention_days = 30
+ postgresql_geo_redundant_backup_enabled = true
+ postgresql_zone_redundancy_enabled = false
+ postgresql_high_availability_mode = "ZoneRedundant"
+ postgresql_maintenance_window = {
+ day_of_week = 6
+ start_hour = 0
+ start_minute = 0
+ }
+ postgresql_sku_name = "B_Standard_B1ms"
+ postgresql_storage_mb = 32768
+ postgresql_storage_tier = null
+ postgresql_version = 16
+ postgresql_active_directory_administrator = {
+ object_id = ""
+ group_name = ""
+ }
+ postgresql_configuration = {}
+ postgresql_databases = {
+ testdb001 = {
+ charset = "UTF8"
+ collation = "en_US.utf8"
+ }
+ }
+ diagnostics_configurations = []
+ subnet_id = "/subscriptions/1fdab118-1638-419a-8b12-06c9543714a0/resourceGroups/ptt-dev-networking-rg/providers/Microsoft.Network/virtualNetworks/spoke-ptt-dev-vnet001/subnets/TerraformTestSubnet"
+ connectivity_delay_in_seconds = 0
+ private_dns_zone_id_postrgesql = "/subscriptions/e82c5267-9dc4-4f45-ac13-abdd5e130d27/resourceGroups/ptt-dev-privatedns-rg/providers/Microsoft.Network/privateDnsZones/privatelink.postgres.database.azure.com"
+ customer_managed_key = null
+ }
+
+ assert {
+ condition = azurerm_postgresql_flexible_server.postgresql_flexible_server.resource_group_name == "tfmodule-test-rg"
+ error_message = "Failed to deploy."
+ }
+}
diff --git a/modules/postgresqlflexible/variables.tf b/modules/postgresqlflexible/variables.tf
new file mode 100644
index 0000000..adab5b9
--- /dev/null
+++ b/modules/postgresqlflexible/variables.tf
@@ -0,0 +1,266 @@
+# General variables
+variable "location" {
+ description = "Specifies the location of all resources."
+ type = string
+ sensitive = false
+ nullable = false
+}
+
+variable "resource_group_name" {
+ description = "Specifies the resource group name in which all resources will get deployed."
+ type = string
+ sensitive = false
+ nullable = false
+ validation {
+ condition = length(var.resource_group_name) >= 2
+ error_message = "Please specify a valid resource group name."
+ }
+}
+
+variable "tags" {
+ description = "Specifies a key value map of tags to set on every taggable resources."
+ type = map(string)
+ sensitive = false
+ default = {}
+ nullable = false
+}
+
+# Storage variables
+variable "postgresql_name" {
+ description = "Specifies the name of the postgresql flexible server."
+ type = string
+ sensitive = false
+ nullable = false
+ validation {
+ condition = length(var.postgresql_name) >= 2
+ error_message = "Please specify a valid name."
+ }
+}
+
+variable "postgresql_auto_grow_enabled" {
+ description = "Specifies whether auto grow is enabled for the postgresql flexible server."
+ type = bool
+ sensitive = false
+ nullable = false
+ default = false
+}
+
+variable "postgresql_backup_retention_days" {
+ description = "Specifies the backup retention in days of the postgresql flexible server."
+ type = number
+ sensitive = false
+ nullable = false
+ default = 30
+ validation {
+ condition = var.postgresql_backup_retention_days >= 7 && var.postgresql_backup_retention_days <= 35
+ error_message = "Please specify a valid value for backup retention in days between 7 and 35 days."
+ }
+}
+
+variable "postgresql_geo_redundant_backup_enabled" {
+ description = "Specifies whether the geo redundant backup should be enabled for the postgresql storage account."
+ type = bool
+ sensitive = false
+ nullable = false
+ default = false
+}
+
+variable "postgresql_zone_redundancy_enabled" {
+ description = "Specifies whether zone redundancy should be enabled for the postgresql flexible server."
+ type = bool
+ sensitive = false
+ nullable = false
+ default = false
+}
+
+variable "postgresql_high_availability_mode" {
+ description = "Specifies whether zone redundancy should be enabled for the postgresql flexible server."
+ type = string
+ sensitive = false
+ nullable = false
+ default = "ZoneRedundant"
+ validation {
+ condition = contains(["ZoneRedundant", "SameZone"], var.postgresql_high_availability_mode)
+ error_message = "Please specify a valid zone redundancy mode."
+ }
+}
+
+variable "postgresql_maintenance_window" {
+ description = "Specifies the maintenance window for the postgresql flexible server."
+ type = object({
+ day_of_week = optional(number, 6)
+ start_hour = optional(number, 0)
+ start_minute = optional(number, 0)
+ })
+ sensitive = false
+ nullable = false
+ default = {}
+ validation {
+ condition = var.postgresql_maintenance_window.day_of_week >= 0 && var.postgresql_maintenance_window.day_of_week <= 6
+ error_message = "Please specify a valid maintenance window."
+ }
+ validation {
+ condition = var.postgresql_maintenance_window.start_hour >= 0 && var.postgresql_maintenance_window.start_hour <= 23
+ error_message = "Please specify a valid maintenance window."
+ }
+ validation {
+ condition = var.postgresql_maintenance_window.start_minute >= 0 && var.postgresql_maintenance_window.start_minute <= 59
+ error_message = "Please specify a valid maintenance window."
+ }
+}
+
+variable "postgresql_sku_name" {
+ description = "Specifies the sku of the postgresql flexible server."
+ type = string
+ sensitive = false
+ nullable = false
+ default = "B_Standard_B1ms"
+ # validation {
+ # condition = contains(["All", "AAD", "PrivateLink"], var.storage_account_allowed_copy_scope)
+ # error_message = "Please specify a valid allowed copy scope. Allowed values are: [ 'All', 'AAD', 'PrivateLink' ]"
+ # }
+}
+
+variable "postgresql_storage_mb" {
+ description = "Specifies the storage mb of the postgresql flexible server."
+ type = number
+ sensitive = false
+ nullable = false
+ default = 32768
+ validation {
+ condition = contains([32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4193280, 4194304, 8388608, 16777216, 33553408], var.postgresql_storage_mb)
+ error_message = "Please specify a valid allowed storage mb size. Please check the supported values."
+ }
+}
+
+variable "postgresql_storage_tier" {
+ description = "Specifies the storage tier of the postgresql flexible server."
+ type = string
+ sensitive = false
+ nullable = true
+ default = null
+ validation {
+ condition = var.postgresql_storage_tier == null || contains(["P4", "P6", "P10", "P15", "P20", "P30", "P40", "P50", "P60", "P70", "P80"], var.postgresql_storage_mb)
+ error_message = "Please specify a valid storage tier that can be used in combination with the provided storage mb size."
+ }
+}
+
+variable "postgresql_version" {
+ description = "Specifies the version of the postgresql flexible server."
+ type = number
+ sensitive = false
+ nullable = false
+ default = 16
+ validation {
+ condition = contains([11, 12, 13, 14, 15, 16], var.postgresql_version)
+ error_message = "Please specify a valid version."
+ }
+}
+
+variable "postgresql_active_directory_administrator" {
+ description = "Specifies the entra id admin configuration for the postgresql flexible server. Please provide a group name and the object id of teh group."
+ type = object({
+ object_id = optional(string, "")
+ group_name = optional(string, "")
+ })
+ sensitive = false
+ nullable = false
+ default = {}
+ validation {
+ condition = (var.postgresql_active_directory_administrator.object_id == "" && var.postgresql_active_directory_administrator.group_name == "") || (length(var.postgresql_active_directory_administrator.object_id) > 2 && length(var.postgresql_active_directory_administrator.group_name) > 2)
+ error_message = "Please specify a valid entra id administrator config and provide both values or none."
+ }
+}
+
+variable "postgresql_configuration" {
+ description = "Specifies the configuration of the postgresql flexible server."
+ type = map(string)
+ sensitive = false
+ nullable = false
+ default = {}
+}
+
+variable "postgresql_databases" {
+ description = "Specifies the databases of the postgresql flexible server."
+ type = map(object({
+ charset = optional(string, "UTF8")
+ collation = optional(string, "en_US.utf8")
+ }))
+ sensitive = false
+ nullable = false
+ default = {}
+}
+
+# Diagnostics variables
+variable "diagnostics_configurations" {
+ description = "Specifies the diagnostic configuration for the service."
+ type = list(object({
+ log_analytics_workspace_id = optional(string, ""),
+ storage_account_id = optional(string, "")
+ }))
+ sensitive = false
+ default = []
+ validation {
+ condition = alltrue([
+ length([for diagnostics_configuration in toset(var.diagnostics_configurations) : diagnostics_configuration if diagnostics_configuration.log_analytics_workspace_id == "" && diagnostics_configuration.storage_account_id == ""]) <= 0
+ ])
+ error_message = "Please specify a valid resource ID."
+ }
+}
+
+# Network variables
+variable "subnet_id" {
+ description = "Specifies the resource id of a subnet in which the private endpoints get created."
+ type = string
+ sensitive = false
+ validation {
+ condition = length(split("/", var.subnet_id)) == 11
+ error_message = "Please specify a valid subnet id."
+ }
+}
+
+variable "connectivity_delay_in_seconds" {
+ description = "Specifies the delay in seconds after the private endpoint deployment (required for the DNS automation via Policies)."
+ type = number
+ sensitive = false
+ nullable = false
+ default = 120
+ validation {
+ condition = var.connectivity_delay_in_seconds >= 0
+ error_message = "Please specify a valid non-negative number."
+ }
+}
+
+variable "private_dns_zone_id_postrgesql" {
+ description = "Specifies the resource ID of the private DNS zone for Azure Postgresql flexible server. Not required if DNS A-records get created via Azure Policy."
+ type = string
+ sensitive = false
+ default = ""
+ validation {
+ condition = var.private_dns_zone_id_postrgesql == "" || (length(split("/", var.private_dns_zone_id_postrgesql)) == 9 && endswith(var.private_dns_zone_id_postrgesql, "privatelink.postgres.database.azure.com"))
+ error_message = "Please specify a valid resource ID for the private DNS Zone."
+ }
+}
+
+# Customer-managed key variables
+variable "customer_managed_key" {
+ description = "Specifies the customer managed key configurations."
+ type = object({
+ key_vault_id = string,
+ key_vault_key_versionless_id = string,
+ user_assigned_identity_id = string,
+ user_assigned_identity_client_id = string,
+ })
+ sensitive = false
+ nullable = true
+ default = null
+ validation {
+ condition = alltrue([
+ var.customer_managed_key == null || length(split("/", try(var.customer_managed_key.key_vault_id, ""))) == 9,
+ var.customer_managed_key == null || startswith(try(var.customer_managed_key.key_vault_key_versionless_id, ""), "https://"),
+ var.customer_managed_key == null || length(split("/", try(var.customer_managed_key.user_assigned_identity_id, ""))) == 9,
+ var.customer_managed_key == null || length(try(var.customer_managed_key.user_assigned_identity_client_id, "")) >= 2,
+ ])
+ error_message = "Please specify a valid resource ID."
+ }
+}