Back
Architecture diagram of Azure PostgreSQL Flexible Server deployed with Terraform/OpenTofu using Private DNS and delegated subnet.

Deploying Azure PostgreSQL Flexible Server with Terraform/OpenTofu — Private DNS, Subnet Delegation, and Lifecycle Control

In this post, we’ll explore how to deploy Azure PostgreSQL Terraform, using Private DNS, subnet delegation, and full lifecycle control.

Databases are the heart of every cloud deployment. While compute instances can spin up and down in seconds, your data layer demands stability, privacy, and precision. In Azure, that’s where PostgreSQL Flexible Server comes in — a fully managed database service that you can provision, secure, and connect privately using Terraform or OpenTofu. Let’s walk through a real example straight from my Multicloud Foundations training.

Step 1 — Deploying Azure PostgreSQL Terraform

Here’s a complete Terraform definition that creates a managed PostgreSQL instance in Azure.
You’ll notice a few important arguments that go beyond the basics:

resource "azurerm_postgresql_flexible_server" "foggykitchen_pg" {
  name                   = "foggykitchen-pg"
  resource_group_name    = azurerm_resource_group.foggykitchen_rg.name
  location               = azurerm_resource_group.foggykitchen_rg.location
  version                = "13"
  administrator_login    = var.pg_admin_username
  administrator_password = var.pg_admin_password
  storage_mb             = 32768
  sku_name               = "GP_Standard_D2s_v3"
  delegated_subnet_id    = azurerm_subnet.foggykitchen_db_subnet.id
  private_dns_zone_id    = azurerm_private_dns_zone.foggykitchen_pg_dns.id
  public_network_access_enabled = false

  maintenance_window {
    day_of_week  = 0
    start_hour   = 22
    start_minute = 0
  }

  lifecycle {
    ignore_changes = [
      zone
    ]
  }

  depends_on = [
    azurerm_private_dns_zone_virtual_network_link.foggykitchen_pg_dns_link
  ]
}

💡 Let’s break down the most interesting parts:

  • delegated_subnet_id – the database runs in a delegated subnet, meaning it has no public IP and relies entirely on your VNet.

  • private_dns_zone_id – this links the server to a private DNS zone, so applications can connect via foggykitchen-pg.postgres.database.azure.com internally.

  • public_network_access_enabled = false – this ensures your database never goes over the public Internet.

  • ignore_changes – prevents Terraform from trying to recreate the resource when Azure automatically assigns an availability zone.

This setup gives you an enterprise-grade database — fully private and fully automated.

Step 2 — Configuring Private DNS

To make private connections work, Terraform first needs to define a DNS zone and link it to your virtual network:

resource "azurerm_private_dns_zone" "foggykitchen_pg_dns" {
  name                = "privatelink.postgres.database.azure.com"
  resource_group_name = azurerm_resource_group.foggykitchen_rg.name
}

resource "azurerm_private_dns_zone_virtual_network_link" "foggykitchen_pg_dns_link" {
  name                  = "pg-dns-link"
  resource_group_name   = azurerm_resource_group.foggykitchen_rg.name
  private_dns_zone_name = azurerm_private_dns_zone.foggykitchen_pg_dns.name
  virtual_network_id    = azurerm_virtual_network.foggykitchen_vnet.id
}

This is where the magic happens.
Once this zone is linked, any VM inside the VNet can resolve the private PostgreSQL hostname — without exposing a single packet outside your network.

Step 3 — Creating a Database

After provisioning the Flexible Server, Terraform can immediately create databases on it:

resource "azurerm_postgresql_flexible_server_database" "foggykitchen_db" {
  name      = "foggydb"
  server_id = azurerm_postgresql_flexible_server.foggykitchen_pg.id
  collation = "en_US.utf8"
  charset   = "UTF8"
}

Simple, predictable, and fully automatable.
At this point, your backend VMs (for example foggykitchen_backend_vm1) can connect directly using private DNS — no firewall rules, no public endpoint, and no secrets exposed.

Step 4 — Putting It All Together

Here’s what the full architecture looks like:

🖼️ Figure 1. Azure PostgreSQL Flexible Server with Private DNS and Subnet Delegation.

Step 5 — Lifecycle and Maintenance

When managing databases as code, the lifecycle block in Terraform becomes your best friend.
Azure sometimes moves resources across zones or adjusts metadata during maintenance.
By ignoring those non-critical changes, you keep your deployments idempotent and your CI/CD pipelines smooth.

lifecycle {
  ignore_changes = [ zone ]
}

In production, this single line can save hours of troubleshooting.

FoggyKitchen Takeaway

At FoggyKitchen, we don’t just spin up managed databases — we cook them with precision.
From subnet delegation to DNS linking, every ingredient matters when you want a reliable, private, and reproducible data layer.

Azure’s abstractions make life easier, but Terraform ensures you stay in control.
And when you combine both, you get the best of both worlds: speed and transparency.

🎓 Explore More

👉 Multicloud Foundations: Azure & OCI deployed with Terraform/OpenTofu
Learn how this PostgreSQL database becomes part of a real multicloud topology — securely connected to Oracle Cloud workloads.

🔗 You might also like:

Multicloud Azure OCI Terraform architecture diagram

From Cloud Recipes to Real Automation

Learn how to connect Azure PostgreSQL and OCI workloads using Terraform/OpenTofu — securely, privately, and reproducibly.

Hands-on training that unifies Azure and OCI automation — compute, storage, networking, and databases — all in Terraform/OpenTofu.

🔒 Lifetime • ⏱️ Self-paced • 🧪 Real labs

Check also other courses:​

Leave A Reply

🌍 Master the Multicloud Foundations with Terraform

Build your first production-ready multicloud architectures step by step. Learn how to connect Azure and OCI with Terraform/OpenTofu, and gain the practical skills that cloud engineers need for hybrid environments.

Multicloud Azure OCI Terraform architecture diagram