Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
32 changes: 19 additions & 13 deletions modules/azure/postgresql/backplane/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,24 @@ This documentation is intended as a reference for platform engineers deploying t

## Overview

The backplane provisions the automation identity and permissions required to deploy Azure Database for PostgreSQL on behalf of application teams.
The backplane provisions the automation identity and permissions required to deploy Azure Database
for PostgreSQL Flexible Server on behalf of application teams. It creates a
**User-Assigned Managed Identity (UAMI)** with a **federated identity credential** so meshStack can
authenticate via workload identity federation (WIF) — no service principals or client secrets.

## Permissions

This is a simple building block backplane that grants the automation principal access to PostgreSQL
across all subscriptions underneath a management group (typically the top-level management group for landing zones).
The UAMI is granted a custom role definition scoped to `var.scope` (typically the top-level
management group for landing zones) that allows managing PostgreSQL Flexible Servers and their
resource groups, plus registering the required resource providers on freshly created subscriptions.

<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0 |
| <a name="requirement_azuread"></a> [azuread](#requirement\_azuread) | 3.1.0 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | 3.116.0 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | >= 4.64 |

## Modules

Expand All @@ -28,24 +31,27 @@ No modules.

| Name | Type |
|------|------|
| [azurerm_role_assignment.buildingblock_deploy](https://registry.terraform.io/providers/hashicorp/azurerm/3.116.0/docs/resources/role_assignment) | resource |
| [azurerm_role_definition.buildingblock_deploy](https://registry.terraform.io/providers/hashicorp/azurerm/3.116.0/docs/resources/role_definition) | resource |
| [azurerm_federated_identity_credential.backplane](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/federated_identity_credential) | resource |
| [azurerm_resource_group.backplane](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource |
| [azurerm_role_assignment.backplane](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) | resource |
| [azurerm_role_definition.backplane](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_definition) | resource |
| [azurerm_user_assigned_identity.backplane](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/user_assigned_identity) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_name"></a> [name](#input\_name) | n/a | `string` | `"postgresql"` | no |
| <a name="input_principal_ids"></a> [principal\_ids](#input\_principal\_ids) | set of principal ids that will be granted permissions to deploy the building block | `set(string)` | n/a | yes |
| <a name="input_scope"></a> [scope](#input\_scope) | Scope where the building block should be deployable, typically the parent of all Landing Zones. | `string` | n/a | yes |
| <a name="input_location"></a> [location](#input\_location) | Azure region for the UAMI resource. | `string` | n/a | yes |
| <a name="input_name"></a> [name](#input\_name) | Name for the building block identity and role definition. | `string` | n/a | yes |
| <a name="input_scope"></a> [scope](#input\_scope) | Scope for role assignment (management group or subscription ID). | `string` | n/a | yes |
| <a name="input_workload_identity_federation"></a> [workload\_identity\_federation](#input\_workload\_identity\_federation) | WIF issuer and subjects for federated authentication. | <pre>object({<br/> issuer = string<br/> subjects = list(string)<br/> })</pre> | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_role_assignment_ids"></a> [role\_assignment\_ids](#output\_role\_assignment\_ids) | The IDs of the role assignments for the service principals. |
| <a name="output_role_assignment_principal_ids"></a> [role\_assignment\_principal\_ids](#output\_role\_assignment\_principal\_ids) | The principal IDs of the service principals that have been assigned the role. |
| <a name="output_identity"></a> [identity](#output\_identity) | The managed identity used as the automation principal for this building block. |
| <a name="output_role_definition_id"></a> [role\_definition\_id](#output\_role\_definition\_id) | The ID of the role definition that enables deployment of the building block to subscriptions. |
| <a name="output_role_definition_name"></a> [role\_definition\_name](#output\_role\_definition\_name) | The name of the role definition that enables deployment of the building block to subscriptions. |
| <a name="output_scope"></a> [scope](#output\_scope) | The scope where the role definition and role assignments are applied. |
| <a name="output_scope"></a> [scope](#output\_scope) | The scope where the role definition and role assignment are applied. |
<!-- END_TF_DOCS -->
59 changes: 46 additions & 13 deletions modules/azure/postgresql/backplane/main.tf
Original file line number Diff line number Diff line change
@@ -1,24 +1,57 @@
resource "azurerm_role_definition" "buildingblock_deploy" {
resource "azurerm_resource_group" "backplane" {
name = var.name
location = var.location
}

resource "azurerm_user_assigned_identity" "backplane" {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

s:

Suggested change
resource "azurerm_user_assigned_identity" "backplane" {
resource "azurerm_user_assigned_identity" "this" {

the module is already called backplane. I've always wanted to have a rule "single resource type in model must be named this. We should add this to the scorecard.

name = var.name
location = var.location
resource_group_name = azurerm_resource_group.backplane.name
}

resource "azurerm_federated_identity_credential" "backplane" {
for_each = { for i, s in var.workload_identity_federation.subjects : tostring(i) => s }

name = "subject-${each.key}"
resource_group_name = azurerm_resource_group.backplane.name
parent_id = azurerm_user_assigned_identity.backplane.id
audience = ["api://AzureADTokenExchange"]
issuer = var.workload_identity_federation.issuer
subject = each.value
}

resource "azurerm_role_definition" "backplane" {
name = "${var.name}-deploy"
description = "Enables deployment of the ${var.name} building block to subscriptions"
scope = var.scope
permissions {
actions = [
"Microsoft.DBforPostgreSQL/servers/write",
"Microsoft.DBforPostgreSQL/servers/read",
"Microsoft.DBforPostgreSQL/servers/delete",
"Microsoft.DBforPostgreSQL/servers/firewallRules/read",
"Microsoft.DBforPostgreSQL/servers/firewallRules/write",
"Microsoft.DBforPostgreSQL/servers/databases/read",
"Microsoft.DBforPostgreSQL/servers/databases/write"
# resource provider registration — required on freshly created subscriptions

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

n: in particular this stuff here could be hallucinated or outdated.

"*/register/action",

# resource groups
"Microsoft.Resources/subscriptions/resourcegroups/read",
"Microsoft.Resources/subscriptions/resourcegroups/write",
"Microsoft.Resources/subscriptions/resourcegroups/delete",

# postgresql flexible servers
"Microsoft.DBforPostgreSQL/flexibleServers/read",
"Microsoft.DBforPostgreSQL/flexibleServers/write",
"Microsoft.DBforPostgreSQL/flexibleServers/delete",
"Microsoft.DBforPostgreSQL/flexibleServers/firewallRules/read",
"Microsoft.DBforPostgreSQL/flexibleServers/firewallRules/write",
"Microsoft.DBforPostgreSQL/flexibleServers/firewallRules/delete",
"Microsoft.DBforPostgreSQL/flexibleServers/databases/read",
"Microsoft.DBforPostgreSQL/flexibleServers/databases/write",
"Microsoft.DBforPostgreSQL/flexibleServers/databases/delete",
"Microsoft.DBforPostgreSQL/flexibleServers/configurations/read",
"Microsoft.DBforPostgreSQL/flexibleServers/configurations/write",
]
}
}

resource "azurerm_role_assignment" "buildingblock_deploy" {
for_each = var.principal_ids

role_definition_id = azurerm_role_definition.buildingblock_deploy.role_definition_resource_id
principal_id = each.value
resource "azurerm_role_assignment" "backplane" {
scope = var.scope
role_definition_id = azurerm_role_definition.backplane.role_definition_resource_id
principal_id = azurerm_user_assigned_identity.backplane.principal_id
}
26 changes: 12 additions & 14 deletions modules/azure/postgresql/backplane/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
output "identity" {
value = {
client_id = azurerm_user_assigned_identity.backplane.client_id
principal_id = azurerm_user_assigned_identity.backplane.principal_id
tenant_id = azurerm_user_assigned_identity.backplane.tenant_id
}
description = "The managed identity used as the automation principal for this building block."
}

output "role_definition_id" {
value = azurerm_role_definition.buildingblock_deploy.id
value = azurerm_role_definition.backplane.id
description = "The ID of the role definition that enables deployment of the building block to subscriptions."
}

output "role_definition_name" {
value = azurerm_role_definition.buildingblock_deploy.name
value = azurerm_role_definition.backplane.name
description = "The name of the role definition that enables deployment of the building block to subscriptions."
}

output "role_assignment_ids" {
value = [for id in azurerm_role_assignment.buildingblock_deploy : id.id]
description = "The IDs of the role assignments for the service principals."
}

output "role_assignment_principal_ids" {
value = [for id in azurerm_role_assignment.buildingblock_deploy : id.principal_id]
description = "The principal IDs of the service principals that have been assigned the role."
}

output "scope" {
value = var.scope
description = "The scope where the role definition and role assignments are applied."
description = "The scope where the role definition and role assignment are applied."
}

27 changes: 20 additions & 7 deletions modules/azure/postgresql/backplane/variables.tf
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
variable "name" {
type = string
nullable = false
default = "postgresql"
type = string
nullable = false
description = "Name for the building block identity and role definition."
validation {
condition = can(regex("^[-a-z0-9]+$", var.name))
error_message = "Only alphanumeric lowercase characters and dashes are allowed"
}
}

variable "scope" {
type = string
nullable = false
description = "Scope where the building block should be deployable, typically the parent of all Landing Zones."
description = "Scope for role assignment (management group or subscription ID)."
}

variable "location" {
type = string
nullable = false
description = "Azure region for the UAMI resource."
}

variable "principal_ids" {
type = set(string)
variable "workload_identity_federation" {
type = object({
issuer = string
subjects = list(string)
})
nullable = false
description = "set of principal ids that will be granted permissions to deploy the building block"
description = "WIF issuer and subjects for federated authentication."
}
7 changes: 1 addition & 6 deletions modules/azure/postgresql/backplane/versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "3.116.0"
}
azuread = {
source = "hashicorp/azuread"
version = "3.1.0"
version = ">= 4.64"
}
}
}

30 changes: 0 additions & 30 deletions modules/azure/postgresql/bb_description.md

This file was deleted.

Loading
Loading