-
Notifications
You must be signed in to change notification settings - Fork 2
Add new Terraform module for Azure AppConfiguration #1105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Krusty93
merged 12 commits into
main
from
CES-1369-fornire-strumentazione-per-lutilizzo-di-azure-app-configuration
Dec 3, 2025
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
5ef8a5c
add module
Krusty93 83b5082
add unit tests and bug fix
Krusty93 c0b8eb9
add contract tests
Krusty93 7490bb1
add integration tests and fixes
Krusty93 58f7a5c
remove example
Krusty93 92ab113
add changelog
Krusty93 bc52339
remove commented code
Krusty93 77e989f
update description
Krusty93 8e13211
update doc
Krusty93 a7e3a6b
fix unit test
Krusty93 caec3da
reworked variables
Krusty93 d5a59b4
update dx provider in tests to 0.8
Krusty93 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "azure_app_configuration": patch | ||
| --- | ||
|
|
||
| Initial version |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| # azure_app_configuration |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| # DX - Azure App Configuration | ||
|
|
||
|  | ||
|
|
||
| This module deploys an Azure App Configuration, opinionated setup in terms of networking setup and access mode. | ||
|
|
||
| ## Features | ||
|
|
||
| - **App Configuration**: An Azure App Configuration instance to retrieve application settings, secrets and feature flags | ||
| - **Private Endpoint**: To allow only private incoming connections | ||
|
|
||
| ## Use cases Comparison | ||
|
|
||
| | Use case | Description | SLA | Guaranteed Throughput | Request Quota | Soft Delete | Geo Replication | | ||
| | --------- | ------------------------------------------------- | ------ | ------------------------------- | --------------- | ----------- | --------------- | | ||
| | default | Tier for production workfloads | 99.95% | 300 RPS (read) - 60 RPS (write) | 30.000 per hour | Yes | Yes | | ||
| | developer | Tier for experimentation or development scenarios | - | - | 6.000 per hour | No | No | | ||
|
|
||
| ### Allowed Sizes | ||
|
|
||
| The SKU name is determined by the use case, but if you want to override it, you can set the `size` variable when `use_case` is set to `default`. | ||
| The allowed sizes are: | ||
|
|
||
| - `standard` | ||
| - `premium` | ||
|
|
||
| ## Usage Example | ||
|
|
||
| For examples of how to use this module, refer to the [examples](https://github.com/pagopa-dx/terraform-azurerm-azure-app-configuration/tree/main/examples) folder in the module repository. | ||
|
|
||
| <!-- BEGIN_TF_DOCS --> | ||
| ## Requirements | ||
|
|
||
| | Name | Version | | ||
| |------|---------| | ||
| | <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | ~> 4.0 | | ||
| | <a name="requirement_pagopa-dx"></a> [pagopa-dx](#requirement\_pagopa-dx) | ~> 0.8 | | ||
|
|
||
| ## Modules | ||
|
|
||
| | Name | Source | Version | | ||
| |------|--------|---------| | ||
| | <a name="module_app_roles"></a> [app\_roles](#module\_app\_roles) | pagopa-dx/azure-role-assignments/azurerm | ~> 1.3 | | ||
| | <a name="module_appconfig_team_roles"></a> [appconfig\_team\_roles](#module\_appconfig\_team\_roles) | pagopa-dx/azure-role-assignments/azurerm | ~> 1.3 | | ||
|
|
||
| ## Resources | ||
|
|
||
| | Name | Type | | ||
| |------|------| | ||
| | [azurerm_app_configuration.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/app_configuration) | resource | | ||
| | [azurerm_private_endpoint.app_config](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource | | ||
| | [azurerm_private_dns_zone.appconfig](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/private_dns_zone) | data source | | ||
|
|
||
| ## Inputs | ||
|
|
||
| | Name | Description | Type | Default | Required | | ||
| |------|-------------|------|---------|:--------:| | ||
| | <a name="input_authorized_teams"></a> [authorized\_teams](#input\_authorized\_teams) | Object containing lists of principal IDs (Azure AD object IDs) of product teams to be granted read or write permissions on the App Configuration. These represent the teams within the organization that need access to this resource." | <pre>object({<br/> writers = optional(list(string), []),<br/> readers = optional(list(string), [])<br/> })</pre> | <pre>{<br/> "readers": [],<br/> "writers": []<br/>}</pre> | no | | ||
| | <a name="input_environment"></a> [environment](#input\_environment) | Values which are used to generate resource names and location short names. They are all mandatory except for domain, which should not be used only in the case of a resource used by multiple domains. | <pre>object({<br/> prefix = string<br/> env_short = string<br/> location = string<br/> domain = optional(string)<br/> app_name = string<br/> instance_number = string<br/> })</pre> | n/a | yes | | ||
| | <a name="input_key_vaults"></a> [key\_vaults](#input\_key\_vaults) | Optionally, integrate App Configuration with a one or more existing Key Vault for secrets retrieval.<br/> Set `has_rbac_support` to true if the referenced Key Vault uses RBAC model for access control.<br/> Use `app_principal_ids` to set application principal IDs to be granted access to the Key Vault. | <pre>list(object({<br/> name = string<br/> resource_group_name = string<br/> has_rbac_support = bool<br/> app_principal_ids = list(string)<br/> }))</pre> | `null` | no | | ||
| | <a name="input_private_dns_zone_resource_group_name"></a> [private\_dns\_zone\_resource\_group\_name](#input\_private\_dns\_zone\_resource\_group\_name) | Name of the resource group containing the private DNS zone for private endpoints. Default is the resource group of the virtual network. | `string` | `null` | no | | ||
| | <a name="input_resource_group_name"></a> [resource\_group\_name](#input\_resource\_group\_name) | The name of the resource group where resources will be deployed. | `string` | n/a | yes | | ||
| | <a name="input_size"></a> [size](#input\_size) | "App Configuration SKU. Allowed values: 'standard', 'premium'. If not set, it will be determined by the use\_case." | `string` | `null` | no | | ||
| | <a name="input_subnet_pep_id"></a> [subnet\_pep\_id](#input\_subnet\_pep\_id) | ID of the subnet hosting private endpoints. | `string` | n/a | yes | | ||
| | <a name="input_subscription_id"></a> [subscription\_id](#input\_subscription\_id) | Subscription Id of the involved resources | `string` | n/a | yes | | ||
| | <a name="input_tags"></a> [tags](#input\_tags) | A map of tags to assign to the resources. | `map(any)` | n/a | yes | | ||
| | <a name="input_use_case"></a> [use\_case](#input\_use\_case) | Allowed values: 'default', 'development'. | `string` | `"default"` | no | | ||
| | <a name="input_virtual_network"></a> [virtual\_network](#input\_virtual\_network) | Virtual network where the subnet will be created. | <pre>object({<br/> name = string<br/> resource_group_name = string<br/> })</pre> | n/a | yes | | ||
|
|
||
| ## Outputs | ||
|
|
||
| | Name | Description | | ||
| |------|-------------| | ||
| | <a name="output_endpoint"></a> [endpoint](#output\_endpoint) | The service endpoint URL | | ||
| | <a name="output_id"></a> [id](#output\_id) | The ID of the Azure Cosmos DB account. | | ||
| | <a name="output_name"></a> [name](#output\_name) | The name of the Azure Cosmos DB account. | | ||
| | <a name="output_principal_id"></a> [principal\_id](#output\_principal\_id) | The system-assigned managed identity pricipal id | | ||
| | <a name="output_resource_group_name"></a> [resource\_group\_name](#output\_resource\_group\_name) | The name of the resource group containing the Azure Cosmos DB account. | | ||
| <!-- END_TF_DOCS --> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| resource "azurerm_app_configuration" "this" { | ||
| name = provider::pagopa-dx::resource_name(merge(local.naming_config, { resource_type = "app_configuration" })) | ||
| resource_group_name = var.resource_group_name | ||
| location = var.environment.location | ||
|
|
||
| identity { | ||
| type = "SystemAssigned" | ||
| } | ||
|
|
||
| sku = local.appcs.sku_name | ||
| data_plane_proxy_authentication_mode = "Pass-through" | ||
| local_auth_enabled = false | ||
|
|
||
| public_network_access = "Disabled" | ||
| purge_protection_enabled = local.use_case_features.purge_protection_enabled | ||
|
|
||
| tags = local.tags | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| data "azurerm_private_dns_zone" "appconfig" { | ||
| name = "privatelink.azconfig.io" | ||
| resource_group_name = local.private_dns_zone.resource_group_name | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| locals { | ||
| # Distinct principal IDs from all Key Vaults | ||
| distinct_app_principals = var.key_vaults != null ? toset(flatten([ | ||
| for kv in var.key_vaults : kv.app_principal_ids | ||
| ])) : toset([]) | ||
|
|
||
| # For each distinct principal, collect all Key Vaults where they're listed | ||
| app_assignments = { | ||
| for principal_id in local.distinct_app_principals : | ||
| principal_id => { | ||
| principal_id = principal_id | ||
| key_vaults = [ | ||
| for kv in var.key_vaults : | ||
| { | ||
| name = kv.name | ||
| resource_group_name = kv.resource_group_name | ||
| has_rbac_support = kv.has_rbac_support | ||
| } | ||
| if contains(kv.app_principal_ids, principal_id) | ||
| ] | ||
| } | ||
| } | ||
|
|
||
| # App Configuration role assignments for authorized teams | ||
| appconfig_role_assignments = merge( | ||
| { | ||
| for idx, principal_id in var.authorized_teams.writers : "${principal_id}|writer" => { | ||
| principal_id = principal_id | ||
| role = "writer" | ||
| } | ||
| }, | ||
| { | ||
| for idx, principal_id in var.authorized_teams.readers : "${principal_id}|reader" => { | ||
| principal_id = principal_id | ||
| role = "reader" | ||
| } | ||
| } | ||
| ) | ||
| } | ||
|
|
||
| # Assign both Key Vault and App Configuration roles to application principals | ||
| # Each principal gets: | ||
| # - Roles for all Key Vaults where they are listed | ||
| # - A single reader role for the App Configuration | ||
| module "app_roles" { | ||
| for_each = local.app_assignments | ||
|
|
||
| source = "pagopa-dx/azure-role-assignments/azurerm" | ||
| version = "~> 1.3" | ||
|
|
||
| subscription_id = var.subscription_id | ||
| principal_id = each.value.principal_id | ||
|
|
||
| key_vault = [ | ||
| for kv in each.value.key_vaults : { | ||
| name = kv.name | ||
| resource_group_name = kv.resource_group_name | ||
| has_rbac_support = kv.has_rbac_support | ||
| description = "Allow application to read Key Vault secrets" | ||
| roles = { | ||
| secrets = "reader" | ||
| } | ||
| } | ||
| ] | ||
|
|
||
| app_config = [{ | ||
| name = azurerm_app_configuration.this.name | ||
| resource_group_name = azurerm_app_configuration.this.resource_group_name | ||
| description = "Allow application to read App Configuration settings" | ||
| role = "reader" | ||
| }] | ||
| } | ||
|
|
||
| module "appconfig_team_roles" { | ||
| for_each = local.appconfig_role_assignments | ||
|
|
||
| source = "pagopa-dx/azure-role-assignments/azurerm" | ||
| version = "~> 1.3" | ||
|
|
||
| subscription_id = var.subscription_id | ||
| principal_id = each.value.principal_id | ||
|
|
||
| app_config = [ | ||
| { | ||
| name = azurerm_app_configuration.this.name | ||
| resource_group_name = azurerm_app_configuration.this.resource_group_name | ||
| description = "Allow team to access App Configuration" | ||
| role = each.value.role | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| locals { | ||
| tags = merge(var.tags, { ModuleSource = "DX", ModuleVersion = try(jsondecode(file("${path.module}/package.json")).version, "unknown"), ModuleName = try(jsondecode(file("${path.module}/package.json")).name, "unknown") }) | ||
|
|
||
| naming_config = { | ||
| prefix = var.environment.prefix, | ||
| environment = var.environment.env_short, | ||
| location = var.environment.location | ||
| domain = var.environment.domain, | ||
| name = var.environment.app_name, | ||
| instance_number = tonumber(var.environment.instance_number), | ||
| } | ||
|
|
||
| use_cases = { | ||
| default = { | ||
| sku = "standard" | ||
| purge_protection_enabled = true | ||
| } | ||
| development = { | ||
| sku = "developer" | ||
| purge_protection_enabled = false | ||
| } | ||
| } | ||
|
|
||
| use_case_features = local.use_cases[var.use_case] | ||
|
|
||
| private_dns_zone = { | ||
| resource_group_name = var.private_dns_zone_resource_group_name == null ? var.virtual_network.resource_group_name : var.private_dns_zone_resource_group_name | ||
| } | ||
|
|
||
| appcs = { | ||
| sku_name = var.size != null ? var.size : local.use_case_features.sku | ||
| private_endpoint_name = provider::pagopa-dx::resource_name(merge(local.naming_config, { resource_type = "app_configuration_private_endpoint" })) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| terraform { | ||
| required_providers { | ||
| azurerm = { | ||
| source = "hashicorp/azurerm" | ||
| version = "~> 4.0" | ||
| } | ||
| pagopa-dx = { | ||
| source = "pagopa-dx/azure" | ||
| version = "~> 0.8" | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.