Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions modules/azure-flexible-server-postgresql/.terraform-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
formatter: "markdown" # this is required

version: ""

header-from: docs/header.md
footer-from: docs/footer.md

recursive:
enabled: false
path: modules
include-main: true

sections:
hide: []
show: []

content: ""

output:
file: "README.md"
mode: inject
template: |-
<!-- BEGIN_TF_DOCS -->
{{ .Content }}
<!-- END_TF_DOCS -->

output-values:
enabled: false
from: ""

sort:
enabled: true
by: name

settings:
anchor: true
color: true
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With output.file set to README.md, enabling color: true can introduce ANSI color codes in some terraform-docs outputs/environments, which would pollute the committed Markdown. Consider setting color: false for deterministic file output.

Suggested change
color: true
color: false

Copilot uses AI. Check for mistakes.
default: true
description: false
escape: true
hide-empty: false
html: true
indent: 2
lockfile: true
read-comments: true
required: true
sensitive: true
type: true
200 changes: 102 additions & 98 deletions modules/azure-flexible-server-postgresql/README.md
Original file line number Diff line number Diff line change
@@ -1,105 +1,22 @@
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.7.0 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | >= 4.35.0 |

To create the postgresql flexible server you must have:
- A resource group.
- A virtual network.
- A keyvault to store/read a secret with the PostgreSQL admin pass.
- The dns and the subnet will be necesary when `public_network_access_enabled=false`.

## Providers

| Name | Version |
|------|---------|
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | >= 4.35.0 |
| <a name="provider_random"></a> [random](#provider\_random) | n/a |

## Resources

| Name | Type |
|------|------|
| [azurerm_key_vault_secret.password_create](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) | resource |
| [azurerm_postgresql_flexible_server.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server) | resource |
| [azurerm_postgresql_flexible_server_configuration.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server_configuration) | resource |
| [azurerm_postgresql_flexible_server_firewall_rule.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server_firewall_rule) | resource |
| [random_password.password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource |
| [azurerm_key_vault_secret.administrator_password](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault_secret) | data source |
| [azurerm_private_dns_zone.dns_private_zone](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/private_dns_zone) | data source |
| [azurerm_resource_group.resource_group](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source |
| [azurerm_resources.key_vault_from_name](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resources) | data source |
| [azurerm_resources.key_vault_from_tags](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resources) | data source |
| [azurerm_resources.vnet_from_name](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resources) | data source |
| [azurerm_resources.vnet_from_tags](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resources) | data source |
| [azurerm_subnet.subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subnet) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_administrator_password_key_vault_secret_name"></a> [administrator\_password\_key\_vault\_secret\_name](#input\_administrator\_password\_key\_vault\_secret\_name) | Name of the Key Vault secret containing the administrator password | `string` | `null` | no |
| <a name="input_dns_private_zone_name"></a> [dns\_private\_zone\_name](#input\_dns\_private\_zone\_name) | Name of the private DNS zone for the PostgreSQL server | `string` | `null` | no |
| <a name="input_firewall_rule"></a> [firewall\_rule](#input\_firewall\_rule) | List of firewall rules to allow access to the server | <pre>list(object({<br/> name = optional(string)<br/> start_ip_address = optional(string)<br/> end_ip_address = optional(string)<br/> }))</pre> | `[]` | no |
| <a name="input_key_vault"></a> [key\_vault](#input\_key\_vault) | Key Vault configuration object (name, resource group, tags) | <pre>object({<br/> name = optional(string)<br/> resource_group_name = optional(string)<br/> tags = optional(map(string))<br/> })</pre> | `{}` | no |
| <a name="input_password_length"></a> [password\_length](#input\_password\_length) | Length of the generated administrator password | `number` | `20` | no |
| <a name="input_postgresql_flexible_server"></a> [postgresql\_flexible\_server](#input\_postgresql\_flexible\_server) | Configuration object for the PostgreSQL Flexible Server | <pre>object({<br/> name = string<br/> location = string<br/> version = optional(number)<br/> public_network_access_enabled = optional(bool)<br/> administrator_login = optional(string)<br/> zone = optional(string)<br/> storage_tier = optional(string)<br/> storage_mb = optional(number)<br/> sku_name = optional(string)<br/> replication_role = optional(string)<br/> create_mode = optional(string)<br/> source_server_id = optional(string)<br/> point_in_time_restore_time_in_utc = optional(string)<br/> backup_retention_days = optional(number)<br/> maintenance_window = optional(object({<br/> day_of_week = number<br/> start_hour = number<br/> start_minute = number<br/> }))<br/> authentication = optional(object({<br/> active_directory_auth_enabled = bool<br/> password_auth_enabled = bool<br/> tenant_id = optional(string)<br/> }))<br/> })</pre> | n/a | yes |
| <a name="input_postgresql_flexible_server_configuration"></a> [postgresql\_flexible\_server\_configuration](#input\_postgresql\_flexible\_server\_configuration) | Map of configuration parameters for the PostgreSQL Flexible Server | <pre>map(object({<br/> name = optional(string)<br/> value = optional(string)<br/> }))</pre> | n/a | yes |
| <a name="input_resource_group"></a> [resource\_group](#input\_resource\_group) | Name of the resource group where resources will be created | `string` | n/a | yes |
| <a name="input_subnet_name"></a> [subnet\_name](#input\_subnet\_name) | Name of the subnet for the PostgreSQL Flexible Server | `string` | `null` | no |
| <a name="input_tags"></a> [tags](#input_tags) | Map of tags to assign to resources | `map(string)` | `{}` | no |
| <a name="input_tags_from_rg"></a> [tags\_from\_rg](#input_tags_from_rg) | Whether to inherit tags from the resource group | `bool` | `false` | no |
| <a name="input_vnet"></a> [vnet](#input_vnet) | Virtual Network configuration object (name, resource group, tags) | <pre>object({<br/> name = optional(string)<br/> resource_group_name = optional(string)<br/> tags = optional(map(string))<br/> })</pre> | `{}` | no |

### Notes
You can create the `administrator_password_key_vault_secret_name` with the `random_password` resource or you can add it as a input. Also, if you create the password with this resource, you will need to do a `terraform apply` on the resource `azurerm_key_vault_secret.password_create` before create the postresql flexible server.

You can use `name` and `resource_group_name` in `vnet` and `key_vault` variables as inputs to get the `data.azurerm_resource` or you can use `tags` as a input (`vnet.tags` and `key_vault.tags`) to get the data.

If you set `public_network_access_enabled: true` you won't need the inputs `subnet_name` and `dns_private_zone_name`. You will need to add a list of IP's in `firewall_rule` to have access to the postresql flexible server instead.

When you set `create_mode` to `PointInTimeRestore` you will need to add the outputs `source_server_id` and `point_in_time_restore_time_in_utc`. Read more about the PITR in the next paragraph (`create_mode` is set to `default` by default).

<!-- BEGIN_TF_DOCS -->
# Azure PostgreSQL Flexible Server Terraform Module

## PITR creation explanation

When `create_mode = PointInTimeRestore`, you need to provide:

1. source_server_id: The resource ID of the original server from which to restore.

2. point_in_time_restore_time_in_utc: The timestamp (UTC) to restore from.

PointInTimeRestore will do:

1. **Creates a new server**: This does not modify the original server, it creates a new one with a different name instead.

2. **Requieres a `source_server_id`**: The original server must have avaliable backups.

3. **Must provide a restore timestamp**: `point_in_time_restore_time_in_utc` must be within the backup retention period.

4. Once restored, you may want to change `create_mode` to `Default` to avoid reapplying the restore when running `terraform apply` again.

5. If the original server is deleted, the PITR server remains unafected.

6. If `point_in_time_restore_time_in_utc` is not within the retention period, the restore will fail.

7. The format of `point_in_time_restore_time_in_utc` must be `Year-Month-DayTHour:Min:sec+00:00` or the restore will fail, for example `2025-03-14T08:26:31Z`(https://en.wikipedia.org/wiki/ISO_8601).

## Get list of PiTRs backups

```yaml
az postgres flexible-server backup list --resource-group my-resource-group --name my-server-name
```
## Overview

## Outputs
Este módulo de Terraform permite crear y gestionar un servidor PostgreSQL Flexible en Azure, con soporte para:
- Creación de servidor, configuraciones, firewall y restauración PITR.
- Integración con Key Vault para contraseñas seguras.
- Soporte para redes privadas, subredes y DNS privados.
- Configuración avanzada de autenticación, backup y mantenimiento.

| Name | Description |
|------|-------------|
| <a name="id"></a> [id](#output\_id) | The ID of the postgresql flexible server |
## Características principales
- Creación de PostgreSQL Flexible Server con opciones avanzadas.
- Soporte para restauración Point-in-Time (PITR).
- Gestión de configuraciones y reglas de firewall.
- Integración con Key Vault y redes privadas.
- Ejemplo realista de configuración.

## Example Usage
## Ejemplo completo de uso

Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README YAML example wraps inputs under a top-level values: key, but _examples/basic/values.yaml is flat (top-level keys). Unless there’s a specific tooling convention requiring values:, this inconsistency can confuse users and lead to non-working configs. Recommend aligning the README example structure with the actual example values file (or explicitly documenting why the values: wrapper is required).

Copilot uses AI. Check for mistakes.
```yaml
values:
Expand Down Expand Up @@ -146,3 +63,90 @@ values:
name: "example-configuration"
value: "TRUE"
```

## Notas
- Puedes usar Key Vault para gestionar la contraseña del administrador.
- Si usas red privada, debes especificar subnet y DNS privado.
- Para restauración PITR, consulta la sección de la documentación sobre create\_mode.

Comment on lines +70 to +71
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README references a PITR create_mode documentation section, but the earlier detailed PITR explanation appears to have been removed in this PR. Consider re-adding a short PITR section (required inputs, timestamp format, and the 'don’t keep PointInTimeRestore on subsequent applies' caveat) or linking directly to the relevant Azure/Terraform docs so the note isn’t a dead-end.

Suggested change
- Para restauración PITR, consulta la sección de la documentación sobre create\_mode.
- Para restauración PITR, consulta la sección siguiente sobre restauración Point-in-Time (PITR).
## Restauración Point-in-Time (PITR)
Este módulo soporta restauración en un punto en el tiempo (Point-in-Time Restore) para servidores PostgreSQL Flexible existentes.
Para usar PITR, debes configurar los siguientes campos en `postgresql_flexible_server`:
- `create_mode = "PointInTimeRestore"`
- `source_server_id`: ID completo del servidor origen a restaurar.
- `point_in_time_restore_time_in_utc`: marca de tiempo en formato UTC (RFC3339), por ejemplo: `"2025-02-21T09:35:43Z"`.
Ten en cuenta:
- `create_mode = "PointInTimeRestore"` solo debe usarse en la creación inicial del servidor restaurado.
- Después de un `apply` exitoso, es recomendable quitar o cambiar `create_mode` (por ejemplo, a `Default`) para evitar que Terraform intente recrear el servidor en futuros `apply`.
Para más detalles, consulta también:
- Documentación de Terraform para `azurerm_postgresql_flexible_server`: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server
- Conceptos de backup y restauración de Azure Database for PostgreSQL Flexible Server: https://learn.microsoft.com/azure/postgresql/flexible-server/concepts-backup-restore

Copilot uses AI. Check for mistakes.
## Estructura de archivos

```
.
├── main.tf
├── variables.tf
├── outputs.tf
├── README.md
├── CHANGELOG.md
└── docs/
├── header.md
└── footer.md
```

## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.7.0 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | >= 4.35.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | >= 4.35.0 |
| <a name="provider_random"></a> [random](#provider\_random) | n/a |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [azurerm_key_vault_secret.password_create](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) | resource |
| [azurerm_postgresql_flexible_server.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server) | resource |
| [azurerm_postgresql_flexible_server_configuration.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server_configuration) | resource |
| [azurerm_postgresql_flexible_server_firewall_rule.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server_firewall_rule) | resource |
| [random_password.password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource |
| [azurerm_key_vault_secret.administrator_password](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault_secret) | data source |
| [azurerm_private_dns_zone.dns_private_zone](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/private_dns_zone) | data source |
| [azurerm_resource_group.resource_group](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source |
| [azurerm_resources.key_vault_from_name](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resources) | data source |
| [azurerm_resources.key_vault_from_tags](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resources) | data source |
| [azurerm_resources.vnet_from_name](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resources) | data source |
| [azurerm_resources.vnet_from_tags](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resources) | data source |
| [azurerm_subnet.subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subnet) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_administrator_password_key_vault_secret_name"></a> [administrator\_password\_key\_vault\_secret\_name](#input\_administrator\_password\_key\_vault\_secret\_name) | n/a | `string` | `null` | no |
| <a name="input_dns_private_zone_name"></a> [dns\_private\_zone\_name](#input\_dns\_private\_zone\_name) | n/a | `string` | `null` | no |
| <a name="input_firewall_rule"></a> [firewall\_rule](#input\_firewall\_rule) | n/a | <pre>list(object({<br/> name = optional(string)<br/> start_ip_address = optional(string)<br/> end_ip_address = optional(string)<br/> }))</pre> | `[]` | no |
| <a name="input_key_vault"></a> [key\_vault](#input\_key\_vault) | n/a | <pre>object({<br/> name = optional(string)<br/> resource_group_name = optional(string)<br/> tags = optional(map(string))<br/> })</pre> | `{}` | no |
| <a name="input_password_length"></a> [password\_length](#input\_password\_length) | n/a | `number` | `20` | no |
| <a name="input_postgresql_flexible_server"></a> [postgresql\_flexible\_server](#input\_postgresql\_flexible\_server) | n/a | <pre>object({<br/> name = string<br/> location = string<br/> version = optional(number)<br/> public_network_access_enabled = optional(bool)<br/> administrator_login = optional(string)<br/> zone = optional(string)<br/> storage_tier = optional(string)<br/> storage_mb = optional(number)<br/> sku_name = optional(string)<br/> replication_role = optional(string)<br/> create_mode = optional(string)<br/> source_server_id = optional(string)<br/> point_in_time_restore_time_in_utc = optional(string)<br/> backup_retention_days = optional(number)<br/> maintenance_window = optional(object({<br/> day_of_week = number<br/> start_hour = number<br/> start_minute = number<br/> }))<br/> authentication = optional(object({<br/> active_directory_auth_enabled = bool<br/> password_auth_enabled = bool<br/> tenant_id = optional(string)<br/> }))<br/> })</pre> | n/a | yes |
| <a name="input_postgresql_flexible_server_configuration"></a> [postgresql\_flexible\_server\_configuration](#input\_postgresql\_flexible\_server\_configuration) | n/a | <pre>map(object({<br/> name = optional(string)<br/> value = optional(string)<br/> }))</pre> | n/a | yes |
| <a name="input_resource_group"></a> [resource\_group](#input\_resource\_group) | n/a | `string` | n/a | yes |
| <a name="input_subnet_name"></a> [subnet\_name](#input\_subnet\_name) | n/a | `string` | `null` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | n/a | `map(string)` | `{}` | no |
| <a name="input_tags_from_rg"></a> [tags\_from\_rg](#input\_tags\_from\_rg) | n/a | `bool` | `false` | no |
| <a name="input_vnet"></a> [vnet](#input\_vnet) | n/a | <pre>object({<br/> name = optional(string)<br/> resource_group_name = optional(string)<br/> tags = optional(map(string))<br/> })</pre> | `{}` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_id"></a> [id](#output\_id) | n/a |

## Recursos y soporte

- [Documentación oficial de Azure PostgreSQL Flexible Server](https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/)
- [Referencia de Terraform para azurerm\_postgresql\_flexible\_server](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/postgresql_flexible_server)
- [Soporte de la comunidad](https://github.com/prefapp/terraform-modules/discussions)

¿Necesitas ayuda? Abre un issue o participa en la comunidad Prefapp.
<!-- END_TF_DOCS -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
module "azure_flexible_server_postgresql" {
source = "../../"

resource_group = "example-resource-group"
tags_from_rg = true

key_vault = {
tags = {
value = "tag1"
}
}

vnet = {
tags = {
value = "tag1"
}
}

subnet_name = "example-subnet"
dns_private_zone_name = "dns.private.zone.example.com"
administrator_password_key_vault_secret_name = "flexible-server-secret-example-test"
password_length = 10

postgresql_flexible_server = {
location = "westeurope"
name = "example-flexible-server"
version = 15
administrator_login = "psqladmin"
public_network_access_enabled = false
storage_mb = 65536
sku_name = "GP_Standard_D2ds_v5"
backup_retention_days = 30
maintenance_window = {
day_of_week = 6
start_hour = 0
start_minute = 0
}
authentication = {
active_directory_auth_enabled = false
password_auth_enabled = true
}
}

postgresql_flexible_server_configuration = {
"azure.extensions" = {
name = "azure.extensions"
value = "extension1,extension2"
}
"configuration1" = {
name = "example-configuration"
value = "TRUE"
}
}

firewall_rule = []

tags = {
environment = "dev"
}
}
Loading