diff --git a/.github/workflows/deploy-backoffice-app.yaml b/.github/workflows/deploy-backoffice-app.yaml
index 16520deb..1b098cf4 100644
--- a/.github/workflows/deploy-backoffice-app.yaml
+++ b/.github/workflows/deploy-backoffice-app.yaml
@@ -4,10 +4,13 @@ on:
workflow_dispatch: {}
jobs:
- deploy_workspace_to_azure:
+ deploy:
name: Deploy
- uses: pagopa/io-std/.github/workflows/deploy-workspace.yaml@main
- with:
- environment: io-p-sign-backoffice-app
- workspace-name: io-sign-backoffice-app
+ uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
secrets: inherit
+ with:
+ workspace_name: io-sign-backoffice-app
+ environment: app-prod
+ resource_group_name: io-p-sign-backend-rg
+ web_app_name: io-p-sign-backoffice-app
+ use_staging_slot: true
\ No newline at end of file
diff --git a/.github/workflows/deploy-backoffice-func.yaml b/.github/workflows/deploy-backoffice-func.yaml
index dc0e8e48..ea0b30a0 100644
--- a/.github/workflows/deploy-backoffice-func.yaml
+++ b/.github/workflows/deploy-backoffice-func.yaml
@@ -4,10 +4,13 @@ on:
workflow_dispatch: {}
jobs:
- deploy_workspace_to_azure:
+ deploy:
name: Deploy
- uses: pagopa/io-std/.github/workflows/deploy-workspace.yaml@main
- with:
- environment: io-p-sign-backoffice-func
- workspace-name: io-sign-backoffice-func
+ uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
secrets: inherit
+ with:
+ workspace_name: io-sign-backoffice-func
+ environment: app-prod
+ resource_group_name: io-p-sign-backend-rg
+ web_app_name: io-p-sign-backoffice-func
+ use_staging_slot: true
\ No newline at end of file
diff --git a/.github/workflows/deploy-issuer-func.yaml b/.github/workflows/deploy-issuer-func.yaml
index b1cdb75c..2062dbee 100644
--- a/.github/workflows/deploy-issuer-func.yaml
+++ b/.github/workflows/deploy-issuer-func.yaml
@@ -6,11 +6,14 @@ on:
jobs:
deploy_workspace_to_azure:
name: Deploy
- uses: pagopa/io-std/.github/workflows/deploy-workspace.yaml@main
- with:
- environment: io-p-sign-issuer-func
- workspace-name: io-func-sign-issuer
+ uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
secrets: inherit
+ with:
+ workspace_name: io-func-sign-issuer
+ environment: app-prod
+ resource_group_name: io-p-sign-backend-rg
+ web_app_name: io-p-sign-issuer-func
+ use_staging_slot: true
# tag the current commit as "latest" in order to make the latest
# released version easily referenceable in the documentation
diff --git a/.github/workflows/deploy-support-func.yaml b/.github/workflows/deploy-support-func.yaml
index e41ee8dc..c4722b0f 100644
--- a/.github/workflows/deploy-support-func.yaml
+++ b/.github/workflows/deploy-support-func.yaml
@@ -4,10 +4,13 @@ on:
workflow_dispatch: {}
jobs:
- deploy_workspace_to_azure:
+ deploy:
name: Deploy
- uses: pagopa/io-std/.github/workflows/deploy-workspace.yaml@main
- with:
- environment: io-p-sign-support-func
- workspace-name: io-func-sign-support
+ uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
secrets: inherit
+ with:
+ workspace_name: io-func-sign-support
+ environment: app-prod
+ resource_group_name: io-p-sign-backend-rg
+ web_app_name: io-p-sign-support-func
+ use_staging_slot: true
\ No newline at end of file
diff --git a/.github/workflows/deploy-user-func.yaml b/.github/workflows/deploy-user-func.yaml
index 8e21ae66..6edcf425 100644
--- a/.github/workflows/deploy-user-func.yaml
+++ b/.github/workflows/deploy-user-func.yaml
@@ -4,10 +4,13 @@ on:
workflow_dispatch: {}
jobs:
- deploy_workspace_to_azure:
+ deploy:
name: Deploy
- uses: pagopa/io-std/.github/workflows/deploy-workspace.yaml@main
- with:
- environment: io-p-sign-user-func
- workspace-name: io-func-sign-user
+ uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
secrets: inherit
+ with:
+ workspace_name: io-func-sign-user
+ environment: app-prod
+ resource_group_name: io-p-sign-backend-rg
+ web_app_name: io-p-sign-user-func
+ use_staging_slot: true
\ No newline at end of file
diff --git a/.github/workflows/opex_api_issuer.yaml b/.github/workflows/opex_api_issuer.yaml
index 2a7d5fba..5d90756d 100644
--- a/.github/workflows/opex_api_issuer.yaml
+++ b/.github/workflows/opex_api_issuer.yaml
@@ -40,8 +40,12 @@ jobs:
environment: prod
api-name: ${{ env.API_NAME }}
config: .opex/${{ env.API_NAME }}/env/prod/config.yaml
- tenant-id: ${{ secrets.AZURE_TENANT_ID }}
- client-id: ${{ secrets.AZURE_CLIENT_ID_CD }}
- subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ tenant-id: ${{ env.ARM_TENANT_ID }}
+ client-id: ${{ env.ARM_CLIENT_ID }}
+ subscription-id: ${{ env.ARM_SUBSCRIPTION_ID }}
# from https://github.com/pagopa/opex-dashboard-azure-action/pkgs/container/opex-dashboard-azure-action
docker-version: sha256:7e454c1892b2aaf3717782c07a2fa01504db5cc7d07979fae863dfc00a9f0173
+ env:
+ ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
+ ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
+ ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
diff --git a/.github/workflows/opex_api_support.yaml b/.github/workflows/opex_api_support.yaml
index b7b6d483..49fe1200 100644
--- a/.github/workflows/opex_api_support.yaml
+++ b/.github/workflows/opex_api_support.yaml
@@ -38,8 +38,13 @@ jobs:
environment: prod
api-name: ${{ env.API_NAME }}
config: .opex/${{ env.API_NAME }}/env/prod/config.yaml
- tenant-id: ${{ secrets.AZURE_TENANT_ID }}
- client-id: ${{ secrets.AZURE_CLIENT_ID_CD }}
- subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ tenant-id: ${{ env.ARM_TENANT_ID }}
+ client-id: ${{ env.ARM_CLIENT_ID }}
+ subscription-id: ${{ env.ARM_SUBSCRIPTION_ID }}
# from https://github.com/pagopa/opex-dashboard-azure-action/pkgs/container/opex-dashboard-azure-action
docker-version: sha256:7e454c1892b2aaf3717782c07a2fa01504db5cc7d07979fae863dfc00a9f0173
+ env:
+ ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
+ ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
+ ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
+
diff --git a/.github/workflows/opex_api_user.yaml b/.github/workflows/opex_api_user.yaml
index 24c61b5e..8c190f40 100644
--- a/.github/workflows/opex_api_user.yaml
+++ b/.github/workflows/opex_api_user.yaml
@@ -38,8 +38,12 @@ jobs:
environment: prod
api-name: ${{ env.API_NAME }}
config: .opex/${{ env.API_NAME }}/env/prod/config.yaml
- tenant-id: ${{ secrets.AZURE_TENANT_ID }}
- client-id: ${{ secrets.AZURE_CLIENT_ID_CD }}
- subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ tenant-id: ${{ env.ARM_TENANT_ID }}
+ client-id: ${{ env.ARM_CLIENT_ID }}
+ subscription-id: ${{ env.ARM_SUBSCRIPTION_ID }}
# from https://github.com/pagopa/opex-dashboard-azure-action/pkgs/container/opex-dashboard-azure-action
docker-version: sha256:04d8ead53c772d23b094c2a395292dc159e6f2905e1b13b5f828f31eac6eb27f
+ env:
+ ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
+ ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
+ ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
diff --git a/.github/workflows/tf-code-review.yaml b/.github/workflows/tf-code-review.yaml
new file mode 100644
index 00000000..8cebf00a
--- /dev/null
+++ b/.github/workflows/tf-code-review.yaml
@@ -0,0 +1,23 @@
+name: PR - IO Sign TF Validation
+
+on:
+ workflow_dispatch:
+ pull_request:
+ types:
+ - opened
+ - edited
+ - synchronize
+ - reopened
+ - ready_for_review
+ paths:
+ - "infra/resources/prod/**"
+ - ".github/workflows/tf-code-review.yaml"
+
+jobs:
+ prod_itn_core_code_review:
+ uses: pagopa/dx/.github/workflows/infra_plan.yaml@main
+ name: Prod - Code Review
+ secrets: inherit
+ with:
+ environment: prod
+ base_path: infra/resources
diff --git a/.github/workflows/tf-deploy.yaml b/.github/workflows/tf-deploy.yaml
new file mode 100644
index 00000000..fa9d8254
--- /dev/null
+++ b/.github/workflows/tf-deploy.yaml
@@ -0,0 +1,19 @@
+name: PR - IO Sign TF Apply
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - main
+ paths:
+ - "infra/resources/prod/**"
+ - ".github/workflows/tf-deploy.yaml"
+
+jobs:
+ prod_itn_core_deploy:
+ uses: pagopa/dx/.github/workflows/infra_apply.yaml@main
+ name: Prod - Code Deploy
+ secrets: inherit
+ with:
+ environment: prod
+ base_path: infra/resources
diff --git a/.identity/.gitignore b/.identity/.gitignore
deleted file mode 100644
index 45544ad9..00000000
--- a/.identity/.gitignore
+++ /dev/null
@@ -1,48 +0,0 @@
-# Local .terraform directories
-**/.terraform/*
-
-# .tfstate files
-*.tfstate
-*.tfstate.*
-
-# Crash log files
-crash.log
-
-# Ignore any .tfvars files that are generated automatically for each Terraform run. Most
-# .tfvars files are managed as part of configuration and so should be included in
-# version control.
-#
-# example.tfvars
-
-# Ignore override files as they are usually used to override resources locally and so
-# are not checked in
-override.tf
-override.tf.json
-*_override.tf
-*_override.tf.json
-
-# Include override files you do wish to add to version control using negated pattern
-#
-# !example_override.tf
-
-# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
-# example: *tfplan*
-
-**/.tfsec/*
-**/.ignore/*
-
-*.DS_Store
-*.log
-*.h2.db
-settings.json
-__TMP
-.metals/
-*.log
-*.h2.db
-settings.json
-__TMP
-.metals/
-__azurite_*
-/.idea
-
-**/modules/**/.terraform.lock.hcl
diff --git a/.identity/.terraform.lock.hcl b/.identity/.terraform.lock.hcl
deleted file mode 100644
index 854d0c44..00000000
--- a/.identity/.terraform.lock.hcl
+++ /dev/null
@@ -1,73 +0,0 @@
-# This file is maintained automatically by "terraform init".
-# Manual edits may be lost in future updates.
-
-provider "registry.terraform.io/hashicorp/azuread" {
- version = "2.33.0"
- constraints = "2.33.0"
- hashes = [
- "h1:PDiZA9QpXCkaSuWu6jiCRcjVtKJETqjcOZq4I434zfE=",
- "h1:QAQe2+WSqGnHYAVoA+NN4Oeuoqg5sXq3U9Qmj6S1P5M=",
- "h1:XIvCW3Nl4bW1bc9f8jyGhft+fQjaed4yy/LFzDAeVJ8=",
- "h1:Z28tjly5UfKOE+HL/oALxCPhmCuBwUgZ4uaYt68VR3M=",
- "zh:0602d03d7d7e38819f78dc377e64f365427496edf1065bfbb113e3921ab1c34e",
- "zh:08843838f4fe146084592472648d4ea7191931eabe042a96c3b3c6eaf8ddfb43",
- "zh:1c3e89cf19118fc07d7b04257251fc9897e722c16e0a0df7b07fcd261f8c12e7",
- "zh:26a0d8a186e3b47ea0b7217a8e420b03fda59b7a680bb3ea52cf7d3e6d965ef3",
- "zh:352a1cacaacd39e796de15a52d192ab0e6eb98dd36b5fbf8ebddd37e6dafa4ac",
- "zh:3702ad4c534e67e2e07b060bfe5e6edc244c59c911906c8b15b96e7fecb0ff2c",
- "zh:93b5248d26bdd44845b2ab051a2168c7edad788ae9836f62ea5fb632fd59d7ea",
- "zh:a7b880155f4a67b52a5bfe78de33dc55254ef80006234f00e36aaf6533b1de4a",
- "zh:a7cf0829364127c9bca26ec01ea3d66988b43987b2d26a3290487d1fc0da50eb",
- "zh:b1f82b0d30af733b36a2f849799e0b1ed6a72888fa32a438c829c4e5cff88e20",
- "zh:b6c2b23770852de8f56b549579c2f5a82afd84a9ca0616d53a25d48488f7aaf0",
- "zh:d87dfbdfe8ab9d3a2e33f210333d40f211ea7d33bfa671063e6807c6ddd85a52",
- ]
-}
-
-provider "registry.terraform.io/hashicorp/azurerm" {
- version = "3.84.0"
- constraints = "3.84.0"
- hashes = [
- "h1:1Ucponuagrx5kNeIlcZwG2urqoRXBCTddDKqL265+xM=",
- "h1:3KYwbI62e6u2f7ob9Ps8yahnIaNHkE56UsF0130zRzE=",
- "h1:aoqNC2sfLKyblgQh0SfQW0BHl3UP1mMAUJLYLGG3PxE=",
- "h1:y/NWRLvnJmyJ5lf/AnLFy25jfyJqp6xwwxLxZnvovAs=",
- "zh:14a96daf672541dbc27137d9cc0a96a737710597262ecaaa64a328eb1174e5df",
- "zh:16d8e794fdd87ed8e64291fe8a617f420d8263f21672033333a020d06f4c9618",
- "zh:64e5cd1bb6a81bccffff0d1f77790286ab46179cf12442134c3f3bca722afc1b",
- "zh:7010ada67fbae971ac8b7204a30b1317aee7ccac7227afc6ac27277c642996a1",
- "zh:77c2616ecd29685d2a4dc3ec3e9771e5ecf652e127946767d9b7ef19bbf58a21",
- "zh:861922cfae724eacf1bd915efd5dbf6c23e4e762a2bbe60993099648e64aedb5",
- "zh:8fb797c98bb08e7342995317810d28c41bb519fbc128adaa170896356b9eaebd",
- "zh:982e85a4a9d282e3c8f7d7836037ccc98ff3ef50af246fad2e04684a81d16201",
- "zh:a2ef29ff907cf6622e58afa0a27e23a3160ba3d70d531795b4d9a6c42c354630",
- "zh:c46ccc4eecb79d096bcb652af0cffe300ec480d80a13a5b302c71b1aac9f9f1c",
- "zh:cc6a06bf6d5e811fe8c0d9ad652e143b4e94bd16a03fb8a86f5086f0ae5abfa9",
- "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
- ]
-}
-
-provider "registry.terraform.io/integrations/github" {
- version = "5.39.0"
- constraints = "5.39.0"
- hashes = [
- "h1:AMn+8x91H4L0bNXgfGA4mEmjumfd7lslBRNsf+Z3J9Q=",
- "h1:B2pPhXlLR5IHfoO6MQ70EgfavVLUlFd8FQw2zxy04RM=",
- "h1:EsDsxcxdtvQ6D64PNbkGG6PbAC2l2ECeCryGPw6uKIw=",
- "h1:mpO68ifHJruMIuSvOuCa4PQt841arZr50O+uCxjhVak=",
- "zh:1bd8eae3b590ca0d765af0d316fe5500b6a55cc75b84997aed38549fef3f3e3e",
- "zh:3fb718473bcf42ce48f71ad79f527988b5ad8bc744cbcf2e4ac84f389c17b32a",
- "zh:43b6cdd6471478baddf4326f23a68ec5bce5a64aa4792cafa0d87708429e18de",
- "zh:54d577bebc29cfb9a8f29c8335fe533b55c1e7bf79d7a7acb1d8dfcc305f2824",
- "zh:6aa1b7cb45e7d9e116b3e6c234c92b9cc6598819d0d6b0cb330a707f8e6f007b",
- "zh:8824653f311a4993b5ce355bbe5f74d8ed1eed2ed2fd25d6e902831263566b40",
- "zh:8b9a256730cf48d3b8a91d86393a4787d119fc9990ab864c6069ec83bbaf0a17",
- "zh:9e87d3cc56dfba33c9a8f41b1f39b8624d680c8e5498bbdccccca251825c9529",
- "zh:9fa3ac69297416c619e812e79bf634064cc09fdea242088bbf65fb34ffd6db9f",
- "zh:c0aa2b2e488eefd7a4739d9b6893b977b5249d7f2ccfa55b64ce529a50b64fd7",
- "zh:cbe26313f9d2dcfcbaa91a0c4f064ed6e34c2e2eff05dfe092332f50530fc61b",
- "zh:dc2ca63d044304352ac66d969c5acb0dc689a48d4d97ee5d0a28414bc5bc95ee",
- "zh:f6351cb0ff7ff17771c415349f0b9828ec54f19f40c6c3a53a8092f2c78c6f65",
- "zh:f8c06856928f55475e9ae63958f5f38a45ceee728f9ec0114ffebd5b6b56f44e",
- ]
-}
diff --git a/.identity/01_data.tf b/.identity/01_data.tf
deleted file mode 100644
index e47c59d7..00000000
--- a/.identity/01_data.tf
+++ /dev/null
@@ -1,18 +0,0 @@
-data "azurerm_resource_group" "rg_identity" {
- name = "${local.prefix}-identity-rg"
-}
-
-data "azurerm_resources" "web_apps" {
- resource_group_name = local.resource_group_name
- type = "Microsoft.Web/sites"
-}
-
-data "azurerm_linux_web_app" "web_apps" {
- for_each = local.web_apps_map
- resource_group_name = local.resource_group_name
- name = each.value.name
-}
-
-data "github_team" "maintainers" {
- slug = "io-sign-maintainers"
-}
diff --git a/.identity/99_locals.tf b/.identity/99_locals.tf
deleted file mode 100644
index 395819da..00000000
--- a/.identity/99_locals.tf
+++ /dev/null
@@ -1,28 +0,0 @@
-locals {
- prefix = "${var.prefix}-${var.env_short}"
- project = "${var.prefix}-${var.env_short}-${var.domain}"
-
- resource_group_name = "${local.project}-backend-rg"
-
- web_apps_map = { for w in data.azurerm_resources.web_apps.resources : w.name => w }
-
- github_federations = tolist([
- for w in local.web_apps_map : {
- repository = "io-sign"
- subject = github_repository_environment.web_apps[w.name].environment
- }
- ])
-
- repo_secrets = {
- "AZURE_SUBSCRIPTION_ID" = data.azurerm_client_config.current.subscription_id
- "AZURE_TENANT_ID" = data.azurerm_client_config.current.tenant_id
- }
-
- opex_env_ci_secrets = {
- "AZURE_CLIENT_ID_CI" = module.opex_identity_ci.identity_client_id
- }
-
- opex_env_cd_secrets = {
- "AZURE_CLIENT_ID_CD" = module.opex_identity_cd.identity_client_id
- }
-}
diff --git a/.identity/99_main.tf b/.identity/99_main.tf
deleted file mode 100644
index 4f778003..00000000
--- a/.identity/99_main.tf
+++ /dev/null
@@ -1,34 +0,0 @@
-terraform {
- required_version = ">=1.6.0"
-
- required_providers {
- azuread = {
- source = "hashicorp/azuread"
- version = "2.33.0"
- }
- azurerm = {
- source = "hashicorp/azurerm"
- version = "3.84.0"
- }
- github = {
- source = "integrations/github"
- version = "5.39.0"
- }
- }
-
- backend "azurerm" {}
-}
-
-provider "azurerm" {
- features {}
-}
-
-provider "github" {
- owner = var.github.org
- write_delay_ms = "200"
- read_delay_ms = "200"
-}
-
-data "azurerm_subscription" "current" {}
-
-data "azurerm_client_config" "current" {}
diff --git a/.identity/99_outputs.tf b/.identity/99_outputs.tf
deleted file mode 100644
index ad02b586..00000000
--- a/.identity/99_outputs.tf
+++ /dev/null
@@ -1,28 +0,0 @@
-output "tenant_id" {
- value = data.azurerm_client_config.current.tenant_id
-}
-
-output "subscription_id" {
- value = data.azurerm_subscription.current.subscription_id
-}
-
-output "web_apps_managed_identities" {
- value = {
- app_name = module.web_apps_identity_cd.identity_app_name
- client_id = module.web_apps_identity_cd.identity_client_id
- }
-}
-
-output "opex_ci_managed_identities" {
- value = {
- app_name = module.opex_identity_ci.identity_app_name
- client_id = module.opex_identity_ci.identity_client_id
- }
-}
-
-output "opex_cd_managed_identities" {
- value = {
- app_name = module.opex_identity_cd.identity_app_name
- client_id = module.opex_identity_cd.identity_client_id
- }
-}
diff --git a/.identity/99_variables.tf b/.identity/99_variables.tf
deleted file mode 100644
index a3e9e983..00000000
--- a/.identity/99_variables.tf
+++ /dev/null
@@ -1,80 +0,0 @@
-variable "tags" {
- type = map(any)
-}
-
-variable "prefix" {
- type = string
- validation {
- condition = (
- length(var.prefix) <= 6
- )
- error_message = "Max length is 6 chars."
- }
-}
-
-variable "env" {
- type = string
- description = "Environment"
-}
-
-variable "env_short" {
- type = string
- validation {
- condition = (
- length(var.env_short) <= 1
- )
- error_message = "Max length is 1 chars."
- }
-}
-
-variable "domain" {
- type = string
- description = "The applicative domain"
- validation {
- condition = (
- length(var.domain) < 6
- )
- error_message = "Max length is 6 chars."
- }
-}
-
-variable "github" {
- type = object({
- org = string
- repository = string
- })
- description = "GitHub Organization and repository name"
- default = {
- org = "pagopa"
- repository = "io-sign"
- }
-}
-
-variable "opex_environment_ci_roles" {
- type = object({
- subscription = list(string)
- resource_groups = map(list(string))
- })
- description = "Continous Integration roles for opex managed identiy"
-}
-
-variable "opex_environment_cd_roles" {
- type = object({
- subscription = list(string)
- resource_groups = map(list(string))
- })
- description = "Continous Delivery roles for opex managed identiy"
-}
-
-variable "web_apps_environment_cd_roles" {
- type = object({
- subscription = list(string)
- resource_groups = map(list(string))
- })
- description = "GitHub Continous Delivery roles for web apps managed identity"
-}
-
-variable "location" {
- type = string
- default = "westeurope"
-}
diff --git a/.identity/env/prod/backend.ini b/.identity/env/prod/backend.ini
deleted file mode 100644
index cf83055f..00000000
--- a/.identity/env/prod/backend.ini
+++ /dev/null
@@ -1 +0,0 @@
-subscription=PROD-IO
diff --git a/.identity/env/prod/backend.tfvars b/.identity/env/prod/backend.tfvars
deleted file mode 100644
index 5941c328..00000000
--- a/.identity/env/prod/backend.tfvars
+++ /dev/null
@@ -1,4 +0,0 @@
-resource_group_name = "io-p-sign-infra-rg"
-storage_account_name = "iopsigninfrast"
-container_name = "azurermstate"
-key = "identity.tfstate"
diff --git a/.identity/env/prod/terraform.tfvars b/.identity/env/prod/terraform.tfvars
deleted file mode 100644
index a3e51875..00000000
--- a/.identity/env/prod/terraform.tfvars
+++ /dev/null
@@ -1,49 +0,0 @@
-domain = "sign"
-env = "prod"
-env_short = "p"
-prefix = "io"
-
-tags = {
- CreatedBy = "Terraform"
- Environment = "Prod"
- Owner = "io"
- Source = "https://github.com/pagopa/io-sign"
- CostCenter = "TS310 - PAGAMENTI & SERVIZI"
-}
-
-opex_environment_ci_roles = {
- subscription = ["Reader"]
- resource_groups = {
- "dashboards" = [
- "Reader"
- ],
- "terraform-state-rg" = [
- "Storage Blob Data Reader"
- ]
- }
-}
-
-opex_environment_cd_roles = {
- subscription = ["Reader"]
- resource_groups = {
- "dashboards" = [
- "Contributor"
- ],
- "terraform-state-rg" = [
- "Storage Blob Data Contributor",
- "Reader and Data Access"
- ]
- }
-}
-
-web_apps_environment_cd_roles = {
- subscription = []
- resource_groups = {
- "io-p-github-runner-rg" = [
- "Contributor",
- ],
- "io-p-sign-backend-rg" = [
- "Contributor",
- ]
- }
-}
diff --git a/.identity/github_environment_opex.tf b/.identity/github_environment_opex.tf
deleted file mode 100644
index cf8212b9..00000000
--- a/.identity/github_environment_opex.tf
+++ /dev/null
@@ -1,33 +0,0 @@
-resource "github_repository_environment" "github_repository_environment_opex_ci" {
- environment = "opex-${var.env}-ci"
- repository = var.github.repository
- deployment_branch_policy {
- protected_branches = false
- custom_branch_policies = true
- }
-}
-
-resource "github_repository_environment" "github_repository_environment_opex_cd" {
- environment = "opex-${var.env}-cd"
- repository = var.github.repository
- deployment_branch_policy {
- protected_branches = false
- custom_branch_policies = true
- }
-}
-
-resource "github_actions_environment_secret" "opex_env_ci_secrets" {
- for_each = local.opex_env_ci_secrets
- repository = var.github.repository
- environment = github_repository_environment.github_repository_environment_opex_ci.environment
- secret_name = each.key
- plaintext_value = each.value
-}
-
-resource "github_actions_environment_secret" "opex_env_cd_secrets" {
- for_each = local.opex_env_cd_secrets
- repository = var.github.repository
- environment = github_repository_environment.github_repository_environment_opex_cd.environment
- secret_name = each.key
- plaintext_value = each.value
-}
diff --git a/.identity/github_environment_web_apps.tf b/.identity/github_environment_web_apps.tf
deleted file mode 100644
index c34b75fe..00000000
--- a/.identity/github_environment_web_apps.tf
+++ /dev/null
@@ -1,40 +0,0 @@
-resource "github_repository_environment" "web_apps" {
- for_each = local.web_apps_map
- environment = each.value.name
- repository = var.github.repository
- reviewers {
- teams = [data.github_team.maintainers.id]
- }
-}
-
-resource "github_actions_environment_secret" "web_app_client_id" {
- for_each = local.web_apps_map
- repository = var.github.repository
- environment = github_repository_environment.web_apps[each.key].environment
- secret_name = "AZURE_CLIENT_ID"
- plaintext_value = module.web_apps_identity_cd.identity_client_id
-}
-
-resource "github_actions_environment_variable" "web_app_resouce_group" {
- for_each = local.web_apps_map
- repository = var.github.repository
- environment = github_repository_environment.web_apps[each.key].environment
- variable_name = "AZURE_WEB_APP_RESOURCE_GROUP"
- value = local.resource_group_name
-}
-
-resource "github_actions_environment_variable" "web_app_names" {
- for_each = local.web_apps_map
- repository = var.github.repository
- environment = github_repository_environment.web_apps[each.key].environment
- variable_name = "AZURE_WEB_APP_NAME"
- value = each.value.name
-}
-
-resource "github_actions_environment_variable" "health_check_path" {
- for_each = local.web_apps_map
- repository = var.github.repository
- environment = github_repository_environment.web_apps[each.key].environment
- variable_name = "HEALTH_CHECK_PATH"
- value = coalesce(data.azurerm_linux_web_app.web_apps[each.key].site_config[0].health_check_path, "/")
-}
diff --git a/.identity/identity_opex.tf b/.identity/identity_opex.tf
deleted file mode 100644
index 6cc5808d..00000000
--- a/.identity/identity_opex.tf
+++ /dev/null
@@ -1,49 +0,0 @@
-module "opex_identity_ci" {
- source = "github.com/pagopa/terraform-azurerm-v3//github_federated_identity?ref=v7.34.2"
-
- prefix = var.prefix
- env_short = var.env_short
- domain = var.domain
- app_name = "opex"
-
- identity_role = "ci"
-
- github_federations = [
- {
- repository = "io-sign"
- subject = github_repository_environment.github_repository_environment_opex_ci.environment
- }
- ]
-
- ci_rbac_roles = {
- subscription_roles = var.opex_environment_ci_roles.subscription
- resource_groups = var.opex_environment_ci_roles.resource_groups
- }
-
- tags = var.tags
-}
-
-module "opex_identity_cd" {
- source = "github.com/pagopa/terraform-azurerm-v3//github_federated_identity?ref=v7.34.2"
-
- prefix = var.prefix
- env_short = var.env_short
- domain = var.domain
- app_name = "opex"
-
- identity_role = "cd"
-
- github_federations = [
- {
- repository = "io-sign"
- subject = github_repository_environment.github_repository_environment_opex_cd.environment
- }
- ]
-
- cd_rbac_roles = {
- subscription_roles = var.opex_environment_cd_roles.subscription
- resource_groups = var.opex_environment_cd_roles.resource_groups
- }
-
- tags = var.tags
-}
diff --git a/.identity/identity_web_apps.tf b/.identity/identity_web_apps.tf
deleted file mode 100644
index 671835ef..00000000
--- a/.identity/identity_web_apps.tf
+++ /dev/null
@@ -1,18 +0,0 @@
-module "web_apps_identity_cd" {
- source = "github.com/pagopa/terraform-azurerm-v3//github_federated_identity?ref=v7.34.2"
-
- prefix = var.prefix
- env_short = var.env_short
- domain = var.domain
-
- identity_role = "cd"
-
- github_federations = local.github_federations
-
- cd_rbac_roles = {
- subscription_roles = var.web_apps_environment_cd_roles.subscription
- resource_groups = var.web_apps_environment_cd_roles.resource_groups
- }
-
- tags = var.tags
-}
diff --git a/.identity/terraform.sh b/.identity/terraform.sh
deleted file mode 100755
index 982f6a00..00000000
--- a/.identity/terraform.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/bash
-
-set -e
-
-action=$1
-env=$2
-IFS=" " read -r -a other <<< "${@:3}"
-
-if [ -z "$action" ]; then
- echo "Missed action: init, apply, plan"
- exit 0
-fi
-
-if [ -z "$env" ]; then
- echo "env should be: dev, uat or prod."
- exit 0
-fi
-
-# shellcheck source=./env/prod/backend.ini
-source "./env/$env/backend.ini"
-az account set -s "${subscription}"
-
-export TF_VAR_github_token="${GITHUB_TOKEN}"
-
-if echo "init plan apply refresh import output state taint destroy" | grep -w "$action" > /dev/null; then
- if [ "$action" = "init" ]; then
- echo "🧠terraform INIT in env: ${env}"
-
- terraform "$action" -reconfigure -backend-config="./env/$env/backend.tfvars" "${other[@]}"
- elif [ "$action" = "output" ] || [ "$action" = "state" ] || [ "$action" = "taint" ]; then
- echo "🧠terraform (output|state|taint) launched with action: ${action} in env: ${env}"
-
- terraform init -reconfigure -backend-config="./env/$env/backend.tfvars"
- terraform "$action" "${other[@]}"
- else
- echo "🧠terraform launched with action: ${action} in env: ${env} into folder $(pwd)"
-
- terraform init -reconfigure -backend-config="./env/$env/backend.tfvars"
- terraform "$action" -var-file="./env/$env/terraform.tfvars" "${other[@]}"
- fi
-else
- echo "Action not allowed."
- exit 1
-fi
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 00000000..c82e5ce7
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,11 @@
+repos:
+ - repo: https://github.com/antonbabenko/pre-commit-terraform
+ rev: v1.86.0
+ hooks:
+ - id: terraform_fmt
+ - id: terraform_docs
+ - id: terraform_validate
+ args:
+ - --args=-json
+ - --args=-no-color
+ exclude: '(\/_?modules\/.*)'
\ No newline at end of file
diff --git a/.identity/.terraform-version b/.terraform-version
similarity index 100%
rename from .identity/.terraform-version
rename to .terraform-version
diff --git a/CODEOWNERS b/CODEOWNERS
index 6552397b..b80f78ba 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1 +1,7 @@
-@lucacavallaro @grausof
\ No newline at end of file
+# see https://help.github.com/en/articles/about-code-owners#example-of-a-codeowners-file
+
+* @lucacavallaro @grausof
+
+# engineering-team-cloud-eng
+/infra/ @pagopa/engineering-team-cloud-eng
+/.github/ @pagopa/engineering-team-cloud-eng
\ No newline at end of file
diff --git a/infra/github-runner/prod/.terraform.lock.hcl b/infra/github-runner/prod/.terraform.lock.hcl
new file mode 100644
index 00000000..cc7d59a2
--- /dev/null
+++ b/infra/github-runner/prod/.terraform.lock.hcl
@@ -0,0 +1,48 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/azure/azapi" {
+ version = "1.13.1"
+ constraints = "~> 1.12"
+ hashes = [
+ "h1:2cnqo8u7YMuBexFZv8/lXGxIn1dXuEnC44LAL90GAa0=",
+ "h1:EHLgSlpuzCcWaDBCB3J1D5xkHKoEeX8TkeYNlnRA1qc=",
+ "h1:Q10vF78s0i71/CfRYbeoRLAWuJrat2kxIrHK9/yaEYk=",
+ "h1:xDZG4lbtQJeyJa3Gzo8qecYxyw+AIXYcdDRlkaSLNz8=",
+ "zh:1f2aceddd67ceeb82a75c2f15dc01e54781e9aed5968507dbc29590c165b2e2b",
+ "zh:397f0bfbac899d48e23cecf38d362c27562150aa20b19157b5bd370b8e6801ee",
+ "zh:652263b7d00623684e29ef7b8ff285a17c5bd7cc8ba7d22967c66d0b3a3c568a",
+ "zh:652c53320a41434942877515780296a1509be03f32d54e60178f39200f960a67",
+ "zh:666426faf686401e54ec09fe06e9d7c06a6455ec398764f70558440c73aeb7f9",
+ "zh:6aa91ae8ba78f2494f99b4c99e66d15ed0b14d735cd1f77adc12ff9dfa075807",
+ "zh:a529e5a13c37d1805c469227f08cdbe7527d04dd64d18709d26627c6a0b588b1",
+ "zh:a589c049205e8e5bf94a13d56b28f400d908ad27e13e16df64408ee82eb8a0ff",
+ "zh:a9a50defdee230f315f74be6c77ff104fe2610a1b3ad6b87326f555e80d13b18",
+ "zh:ba49ef70d96e13795e2dbffd6cb2ff976dfe84e0373a5971ebe3b4c9c9b7af60",
+ "zh:d3ed50efe5f8c80d3d7d464ab9a13ccf82440d871c9ce3032ce476845364c6b9",
+ "zh:e3eb48ee8c36ee4f81850d8a21fc59b81886c729d7c3b7adece4a25f355bed2f",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/azurerm" {
+ version = "3.108.0"
+ constraints = "~> 3.50, ~> 3.86, <= 3.108.0"
+ hashes = [
+ "h1:36WHCMjguUKG15iS3WNqmk2/FQH2AwFL0mJl0VWCfps=",
+ "h1:Hi1qvx4ADlHsEArf05M5DAqN6PA9g1eYFVQhUFiyHnM=",
+ "h1:RIFBFTXz4X48JDHjbQHX4y400ax1/uEzMVFZgX3/z3w=",
+ "h1:pNUojXaVobFjmYvp9HViTZ9FKp6yFy+coPbn4/GR138=",
+ "zh:2afecf948fd702bc08c87d9114595809d011f99a70a12dbf6bc67a12d0bee5fc",
+ "zh:395b6d1384a579867064e62d49b0b91e15919c33b03ea8b5031c2779bfa16b3d",
+ "zh:3e5594c59b6b02bc6e0f4c3de71aa2ab992494c53725fb3c64d36745f3814ef3",
+ "zh:4613e190609377309f6a4ac44f631c9469efab3ae148dbb09e73718201dc4f42",
+ "zh:624f01cb7604d58100068401bd07ab09a141e7bd318f8214127838cf202e4868",
+ "zh:65709950c9933e38704e2075a2339951e1259a6e882f35d390be36e1844ebc72",
+ "zh:af82657fad4e3a177f2ebb8035b45bda40f8856eb999288533321028794d03e5",
+ "zh:c40b331eba08830d16c0e6795fa7cbf08231073df2cfdb0f34e9d908a915981a",
+ "zh:d6ccd533a0bd984ca7ed1ae860e057e9e2f88468745be9712236d2d240353de4",
+ "zh:f361fd398e8772f8554a010331d161d6f7284a43238fd28bfa7b41795a5538b8",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ "zh:f8c2132c77d35930203ec66f1bf9bbf633a2406e9f7b572ff425d65b8aa8c492",
+ ]
+}
diff --git a/infra/github-runner/prod/README.md b/infra/github-runner/prod/README.md
new file mode 100644
index 00000000..c7edc2a2
--- /dev/null
+++ b/infra/github-runner/prod/README.md
@@ -0,0 +1,34 @@
+# IO SIGN - GitHub Self-Hosted runner
+
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [azurerm](#requirement\_azurerm) | <= 3.108.0 |
+
+## Providers
+
+No providers.
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [container\_app\_job\_selfhosted\_runner](#module\_container\_app\_job\_selfhosted\_runner) | github.com/pagopa/dx//infra/modules/github_selfhosted_runner_on_container_app_jobs | main |
+
+## Resources
+
+No resources.
+
+## Inputs
+
+No inputs.
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [container\_app\_job](#output\_container\_app\_job) | n/a |
+
diff --git a/infra/github-runner/prod/container_app_job.tf b/infra/github-runner/prod/container_app_job.tf
new file mode 100644
index 00000000..66248c8b
--- /dev/null
+++ b/infra/github-runner/prod/container_app_job.tf
@@ -0,0 +1,20 @@
+module "container_app_job_selfhosted_runner" {
+ source = "github.com/pagopa/dx//infra/modules/github_selfhosted_runner_on_container_app_jobs?ref=main"
+
+ prefix = local.prefix
+ env_short = local.env_short
+
+ repo_name = "io-sign"
+
+ container_app_environment = {
+ name = "${local.prefix}-${local.env_short}-github-runner-cae"
+ resource_group_name = "${local.prefix}-${local.env_short}-github-runner-rg"
+ }
+
+ key_vault = {
+ name = "${local.prefix}-${local.env_short}-kv-common"
+ resource_group_name = "${local.prefix}-${local.env_short}-rg-common"
+ }
+
+ tags = local.tags
+}
diff --git a/infra/github-runner/prod/locals.tf b/infra/github-runner/prod/locals.tf
new file mode 100644
index 00000000..76198cf5
--- /dev/null
+++ b/infra/github-runner/prod/locals.tf
@@ -0,0 +1,13 @@
+locals {
+ prefix = "io"
+ env_short = "p"
+
+ tags = {
+ CostCenter = "TS310 - PAGAMENTI & SERVIZI"
+ CreatedBy = "Terraform"
+ Environment = "Prod"
+ Owner = "IO"
+ Source = "https://github.com/pagopa/io-sign/infra/github-runner/prod"
+ ManagementTeam = "IO Firma"
+ }
+}
diff --git a/infra/github-runner/prod/main.tf b/infra/github-runner/prod/main.tf
new file mode 100644
index 00000000..20aaf9d2
--- /dev/null
+++ b/infra/github-runner/prod/main.tf
@@ -0,0 +1,20 @@
+terraform {
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "<= 3.108.0"
+ }
+ }
+
+ backend "azurerm" {
+ resource_group_name = "terraform-state-rg"
+ storage_account_name = "tfappprodio"
+ container_name = "terraform-state"
+ key = "io-sign.github-runner.tfstate"
+ }
+}
+
+provider "azurerm" {
+ features {
+ }
+}
diff --git a/infra/github-runner/prod/outputs.tf b/infra/github-runner/prod/outputs.tf
new file mode 100644
index 00000000..75a41704
--- /dev/null
+++ b/infra/github-runner/prod/outputs.tf
@@ -0,0 +1,7 @@
+output "container_app_job" {
+ value = {
+ id = module.container_app_job_selfhosted_runner.container_app_job.id
+ name = module.container_app_job_selfhosted_runner.container_app_job.name
+ resource_group_name = module.container_app_job_selfhosted_runner.container_app_job.resource_group_name
+ }
+}
diff --git a/infra/identity/prod/.terraform.lock.hcl b/infra/identity/prod/.terraform.lock.hcl
new file mode 100644
index 00000000..0bf2312c
--- /dev/null
+++ b/infra/identity/prod/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/azurerm" {
+ version = "3.108.0"
+ constraints = "~> 3.30, ~> 3.86, ~> 3.106, <= 3.108.0"
+ hashes = [
+ "h1:36WHCMjguUKG15iS3WNqmk2/FQH2AwFL0mJl0VWCfps=",
+ "zh:2afecf948fd702bc08c87d9114595809d011f99a70a12dbf6bc67a12d0bee5fc",
+ "zh:395b6d1384a579867064e62d49b0b91e15919c33b03ea8b5031c2779bfa16b3d",
+ "zh:3e5594c59b6b02bc6e0f4c3de71aa2ab992494c53725fb3c64d36745f3814ef3",
+ "zh:4613e190609377309f6a4ac44f631c9469efab3ae148dbb09e73718201dc4f42",
+ "zh:624f01cb7604d58100068401bd07ab09a141e7bd318f8214127838cf202e4868",
+ "zh:65709950c9933e38704e2075a2339951e1259a6e882f35d390be36e1844ebc72",
+ "zh:af82657fad4e3a177f2ebb8035b45bda40f8856eb999288533321028794d03e5",
+ "zh:c40b331eba08830d16c0e6795fa7cbf08231073df2cfdb0f34e9d908a915981a",
+ "zh:d6ccd533a0bd984ca7ed1ae860e057e9e2f88468745be9712236d2d240353de4",
+ "zh:f361fd398e8772f8554a010331d161d6f7284a43238fd28bfa7b41795a5538b8",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ "zh:f8c2132c77d35930203ec66f1bf9bbf633a2406e9f7b572ff425d65b8aa8c492",
+ ]
+}
diff --git a/infra/identity/prod/README.md b/infra/identity/prod/README.md
new file mode 100644
index 00000000..837cc0dc
--- /dev/null
+++ b/infra/identity/prod/README.md
@@ -0,0 +1,34 @@
+# IO Sign - GitHub federated Managed Identities
+
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [azurerm](#requirement\_azurerm) | <= 3.108.0 |
+
+## Providers
+
+No providers.
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [federated\_identities](#module\_federated\_identities) | github.com/pagopa/dx//infra/modules/azure_federated_identity_with_github | main |
+| [federated\_identities\_opex](#module\_federated\_identities\_opex) | github.com/pagopa/dx//infra/modules/azure_federated_identity_with_github | main |
+| [federated\_identities\_web\_apps](#module\_federated\_identities\_web\_apps) | github.com/pagopa/dx//infra/modules/azure_federated_identity_with_github | main |
+
+## Resources
+
+No resources.
+
+## Inputs
+
+No inputs.
+
+## Outputs
+
+No outputs.
+
diff --git a/infra/identity/prod/locals.tf b/infra/identity/prod/locals.tf
new file mode 100644
index 00000000..ab5cfaa1
--- /dev/null
+++ b/infra/identity/prod/locals.tf
@@ -0,0 +1,18 @@
+locals {
+ prefix = "io"
+ env_short = "p"
+ env = "prod"
+ project = "${local.prefix}-${local.env_short}"
+ domain = "sign"
+
+ repo_name = "io-sign"
+
+ tags = {
+ CostCenter = "TS310 - PAGAMENTI & SERVIZI"
+ CreatedBy = "Terraform"
+ Environment = "Prod"
+ Owner = "IO"
+ Source = "https://github.com/pagopa/io-sign/blob/main/src/identity/prod"
+ ManagementTeam = "IO Firma"
+ }
+}
diff --git a/infra/identity/prod/main.tf b/infra/identity/prod/main.tf
new file mode 100644
index 00000000..2f4db416
--- /dev/null
+++ b/infra/identity/prod/main.tf
@@ -0,0 +1,166 @@
+terraform {
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "<= 3.108.0"
+ }
+ }
+
+ backend "azurerm" {
+ resource_group_name = "terraform-state-rg"
+ storage_account_name = "tfappprodio"
+ container_name = "terraform-state"
+ key = "io-sign.identity.tfstate"
+ }
+}
+
+provider "azurerm" {
+ features {
+ }
+}
+
+module "federated_identities" {
+ source = "github.com/pagopa/dx//infra/modules/azure_federated_identity_with_github?ref=main"
+
+ prefix = local.prefix
+ env_short = local.env_short
+ env = local.env
+ domain = local.domain
+
+ repositories = [local.repo_name]
+
+ continuos_integration = {
+ enable = true
+ roles = {
+ subscription = [
+ "Reader",
+ "Reader and Data Access",
+ "PagoPA IaC Reader",
+ "DocumentDB Account Contributor",
+ "Storage Blob Data Reader",
+ "Storage File Data SMB Share Reader",
+ "Storage Queue Data Reader",
+ "Storage Table Data Reader",
+ "Key Vault Reader",
+ ]
+ resource_groups = {
+ terraform-state-rg = [
+ "Storage Blob Data Contributor"
+ ]
+ }
+ }
+ }
+
+ continuos_delivery = {
+ enable = true
+ roles = {
+ subscription = [
+ "Contributor",
+ "Storage Account Contributor",
+ "Storage Blob Data Contributor",
+ "Storage File Data SMB Share Contributor",
+ "Storage Queue Data Contributor",
+ "Storage Table Data Contributor",
+ "Key Vault Contributor",
+ ]
+ resource_groups = {}
+ }
+ }
+
+
+ tags = local.tags
+}
+
+module "federated_identities_web_apps" {
+ source = "github.com/pagopa/dx//infra/modules/azure_federated_identity_with_github?ref=main"
+
+ prefix = local.prefix
+ env_short = local.env_short
+ env = "app-${local.env}"
+ domain = "${local.domain}-app"
+
+ repositories = [local.repo_name]
+ continuos_integration = {
+ enable = false
+ }
+
+ continuos_delivery = {
+ enable = true
+
+ roles = {
+ subscription = []
+ resource_groups = {
+ "io-p-github-runner-rg" = [
+ "Contributor",
+ ],
+ "io-p-sign-backend-rg" = [
+ "Contributor",
+ ]
+ }
+ }
+ }
+
+ tags = local.tags
+}
+
+module "federated_identities_opex" {
+ source = "github.com/pagopa/dx//infra/modules/azure_federated_identity_with_github?ref=main"
+
+ prefix = local.prefix
+ env_short = local.env_short
+ env = "opex-${local.env}"
+ domain = "${local.domain}-opex"
+
+ repositories = [local.repo_name]
+ continuos_integration = {
+ enable = true
+
+ roles = {
+ subscription = []
+ resource_groups = {
+ dashboards = [
+ "Reader"
+ ]
+ terraform-state-rg = [
+ "Storage Blob Data Reader",
+ "Reader and Data Access"
+ ]
+ }
+ }
+ }
+
+ continuos_delivery = {
+ enable = true
+
+ roles = {
+ subscription = []
+ resource_groups = {
+ dashboards = [
+ "Contributor"
+ ]
+ terraform-state-rg = [
+ "Storage Blob Data Contributor",
+ "Reader and Data Access"
+ ]
+ }
+ }
+ }
+
+ tags = local.tags
+}
+
+# Access Policy
+module "roles_ci" {
+ source = "github.com/pagopa/dx//infra/modules/azure_role_assignments?ref=main"
+ principal_id = module.federated_identities.federated_ci_identity.id
+
+ key_vault = [
+ {
+ name = "io-p-sign-kv"
+ resource_group_name = "io-p-sign-sec-rg"
+ roles = {
+ secrets = "reader"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/infra/repository/.terraform.lock.hcl b/infra/repository/.terraform.lock.hcl
new file mode 100644
index 00000000..327b845a
--- /dev/null
+++ b/infra/repository/.terraform.lock.hcl
@@ -0,0 +1,50 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/azurerm" {
+ version = "3.105.0"
+ constraints = "<= 3.105.0"
+ hashes = [
+ "h1:MK83TecMdabDD+HjbxdTt3emXp8G6djLj7KvvUGstM0=",
+ "h1:OtWRTAMNOruOmwVB72QSGXC5IIGGQcHwEqnCCmsGbGM=",
+ "h1:SOC7EdvKd5YowghQvb6hu209F1PQqtb8LulbQkxOZQQ=",
+ "h1:zWkzhP2fx0WQIAUp6Amk/We3WNcbtiWagpKF5PJP5+M=",
+ "zh:2f81bca6a3bf3d37604bf99fdb2c77d6118520aa379ab65fd28e6b76bed399cd",
+ "zh:3578eb79d175af9544b0dc543124d551c0fed4c48f51773ee17e1dc62e22833a",
+ "zh:377dbb56caea3fa1e6a6599193b55c8594204c40c054fc2ace4f576fdfe750a2",
+ "zh:3d1cf01929cb213ff9a0f9753e35699bf13f60f7f0f15b38f1b216fa2cbb5f72",
+ "zh:481376d79224a0e4aebc6e39dee10de3cc14efd1c7c58b6d74c538e356cf4bb2",
+ "zh:625119aec0d24ff693c589d802b7983ffce3fcf1e9c3351396af02799dd176ca",
+ "zh:65981e62a6e9eb8a39dd332632617e8c929dcce6af48d3829f590f5c0f14362f",
+ "zh:72db82697f4e694c21defa8d0efb22f71d373676d078d71d567e8b4d9a134df7",
+ "zh:a0fa43cf78716ff98eccd7506b017c5c487034d9d9cce88c1accdba9314a4822",
+ "zh:b073f60b68b0102128815251dd895ec7f24bddec84a1b725fc0777de8a78dc7e",
+ "zh:b601e509eb9735756b6b7ccacc15d6333769a7bb2f8ac8c394e39b29cfc6ee55",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ ]
+}
+
+provider "registry.terraform.io/integrations/github" {
+ version = "6.1.0"
+ constraints = "6.1.0"
+ hashes = [
+ "h1:0BC1bA6irof4GXsbOCltW2f18OB/vp3kYhQ598IvOu0=",
+ "h1:LZeec2qr5cNz6MIVrQArl11E1hRnEdzkS7JUrc/8cus=",
+ "h1:MWD2GsKJ92kgyegYPGPjQKM0SqFaFbvOibMfDQdJsP0=",
+ "h1:Z1C0pLLJQF2fit8PKwc1e5Vm64q73RpayCmkDSMihqw=",
+ "zh:03c2a7d7fa334b5abb1ea4962bb2ffabfff96ec883b1a62445fe724d4a541313",
+ "zh:144f77865c87843635a3f6a0d52530ab3a6270b04dfa2da744a9fc0003b64900",
+ "zh:4cfa42e679be22e516b8e0294688d6cfc896c0e1456387fd9d10d09d84e99c6d",
+ "zh:5ff9e90b7bc9008f5b7fb0d9ef0c7c67eb8fb29439309620de1b0b1810b3e7f9",
+ "zh:7bfe85fcbef2b4b6ff5eff8bc82a590f2471e71297207616014c852e7385921b",
+ "zh:a105ec4828973821a9618c0e058f5a597de014edf7aa64d97b7f4fc528abbc36",
+ "zh:a495c5b3bc6ce3d6261e9d1ba7f285e7e463b5f6ad15e533d5b7037ab985530f",
+ "zh:a4d7e43b7b59f41022e9137115440df46aa9de62a187ae4a35fb9fc388fca4c3",
+ "zh:a75ab20f5032e2ebcfe288e06d0f4f8eafd8fed569be7ac7c384e55c294ada43",
+ "zh:cb6e9cde411355ad477a60fecb8ed9b665d8475761949e03aceed57851842385",
+ "zh:d833d63b5374841e667647fde74d2388d1249a097a633b4bba20ad175b7db681",
+ "zh:e4e5aab1a6e37fb8220621673384b62a3f2693ca1052487eb4ca38426a40bc8b",
+ "zh:f06a84ddf6723e880997c0f773b500b3fabcecb1230d9ed2d93943700802c876",
+ "zh:f9695f2ceddfc243834a10bd91cfb8aa1b0e7cdb9eee14d17d49b4f439440b86",
+ ]
+}
diff --git a/infra/repository/README.md b/infra/repository/README.md
new file mode 100644
index 00000000..20d797a2
--- /dev/null
+++ b/infra/repository/README.md
@@ -0,0 +1,58 @@
+# IO Sign - Repository
+
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [azurerm](#requirement\_azurerm) | <= 3.105.0 |
+| [github](#requirement\_github) | 6.1.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azurerm](#provider\_azurerm) | 3.105.0 |
+| [github](#provider\_github) | 6.1.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [github_actions_environment_secret.env_opex_prod_cd_secrets](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/actions_environment_secret) | resource |
+| [github_actions_environment_secret.env_opex_prod_ci_secrets](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/actions_environment_secret) | resource |
+| [github_actions_environment_secret.env_prod_cd_secrets](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/actions_environment_secret) | resource |
+| [github_actions_environment_secret.env_prod_ci_secrets](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/actions_environment_secret) | resource |
+| [github_actions_environment_secret.web_app_client_id](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/actions_environment_secret) | resource |
+| [github_actions_secret.repo_secrets](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/actions_secret) | resource |
+| [github_branch_default.default_main](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/branch_default) | resource |
+| [github_branch_protection.main](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/branch_protection) | resource |
+| [github_repository.this](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/repository) | resource |
+| [github_repository_environment.github_repository_environment_opex_prod_cd](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/repository_environment) | resource |
+| [github_repository_environment.github_repository_environment_opex_prod_ci](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/repository_environment) | resource |
+| [github_repository_environment.github_repository_environment_prod_cd](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/repository_environment) | resource |
+| [github_repository_environment.github_repository_environment_prod_ci](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/repository_environment) | resource |
+| [github_repository_environment.github_repository_environment_web_apps_cd](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/resources/repository_environment) | resource |
+| [azurerm_client_config.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/client_config) | data source |
+| [azurerm_resources.web_apps](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resources) | data source |
+| [azurerm_subscription.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subscription) | data source |
+| [azurerm_user_assigned_identity.identity_app_prod_cd](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/user_assigned_identity) | data source |
+| [azurerm_user_assigned_identity.identity_opex_prod_cd](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/user_assigned_identity) | data source |
+| [azurerm_user_assigned_identity.identity_opex_prod_ci](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/user_assigned_identity) | data source |
+| [azurerm_user_assigned_identity.identity_prod_cd](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/user_assigned_identity) | data source |
+| [azurerm_user_assigned_identity.identity_prod_ci](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/user_assigned_identity) | data source |
+| [github_organization_teams.all](https://registry.terraform.io/providers/integrations/github/6.1.0/docs/data-sources/organization_teams) | data source |
+
+## Inputs
+
+No inputs.
+
+## Outputs
+
+No outputs.
+
diff --git a/infra/repository/data.tf b/infra/repository/data.tf
new file mode 100644
index 00000000..5275cfc3
--- /dev/null
+++ b/infra/repository/data.tf
@@ -0,0 +1,41 @@
+data "azurerm_user_assigned_identity" "identity_prod_ci" {
+ name = "${local.project}-sign-github-ci-identity"
+ resource_group_name = local.identity_resource_group_name
+}
+
+data "azurerm_user_assigned_identity" "identity_prod_cd" {
+ name = "${local.project}-sign-github-cd-identity"
+ resource_group_name = local.identity_resource_group_name
+}
+
+data "azurerm_user_assigned_identity" "identity_opex_prod_ci" {
+ name = "${local.project}-sign-opex-github-ci-identity"
+ resource_group_name = local.identity_resource_group_name
+}
+
+data "azurerm_user_assigned_identity" "identity_opex_prod_cd" {
+ name = "${local.project}-sign-opex-github-cd-identity"
+ resource_group_name = local.identity_resource_group_name
+}
+
+data "azurerm_user_assigned_identity" "identity_app_prod_cd" {
+ name = "${local.project}-sign-app-github-cd-identity"
+ resource_group_name = local.identity_resource_group_name
+}
+
+data "github_organization_teams" "all" {
+ root_teams_only = true
+ summary_only = true
+}
+
+# Web app configuration
+data "azurerm_resources" "web_apps" {
+ resource_group_name = local.backend_resource_group_name
+ type = "Microsoft.Web/sites"
+}
+
+# data "azurerm_linux_web_app" "web_apps" {
+# for_each = local.web_apps_map
+# resource_group_name = local.backend_resource_group_name
+# name = each.value.name
+# }
\ No newline at end of file
diff --git a/infra/repository/github_branch_rules.tf b/infra/repository/github_branch_rules.tf
new file mode 100644
index 00000000..c003676f
--- /dev/null
+++ b/infra/repository/github_branch_rules.tf
@@ -0,0 +1,35 @@
+resource "github_branch_default" "default_main" {
+ repository = github_repository.this.name
+ branch = "main"
+}
+
+resource "github_branch_protection" "main" {
+ repository_id = github_repository.this.name
+ pattern = "main"
+
+ force_push_bypassers = []
+
+ required_status_checks {
+ strict = true
+ contexts = []
+ }
+
+ require_conversation_resolution = true
+ required_linear_history = true
+
+ #tfsec:ignore:github-branch_protections-require_signed_commits
+ require_signed_commits = true #false
+
+ required_pull_request_reviews {
+ dismiss_stale_reviews = false
+ require_code_owner_reviews = true
+ required_approving_review_count = 1
+ dismissal_restrictions = [
+ "/lucacavallaro",
+ ]
+ pull_request_bypassers = []
+ restrict_dismissals = true
+ }
+
+ allows_deletions = false
+}
diff --git a/infra/repository/github_environment_cd.tf b/infra/repository/github_environment_cd.tf
new file mode 100644
index 00000000..f6210c26
--- /dev/null
+++ b/infra/repository/github_environment_cd.tf
@@ -0,0 +1,78 @@
+resource "github_repository_environment" "github_repository_environment_prod_cd" {
+ environment = "prod-cd"
+ repository = github_repository.this.name
+
+ deployment_branch_policy {
+ protected_branches = false
+ custom_branch_policies = true
+ }
+
+ reviewers {
+ teams = matchkeys(
+ data.github_organization_teams.all.teams[*].id,
+ data.github_organization_teams.all.teams[*].slug,
+ local.cd.reviewers_teams
+ )
+ }
+}
+
+resource "github_actions_environment_secret" "env_prod_cd_secrets" {
+ for_each = local.cd.secrets
+
+ repository = github_repository.this.name
+ environment = github_repository_environment.github_repository_environment_prod_cd.environment
+ secret_name = each.key
+ plaintext_value = each.value
+}
+
+# -------------- OPEX ----------------
+
+resource "github_repository_environment" "github_repository_environment_opex_prod_cd" {
+ environment = "opex-prod-cd"
+ repository = github_repository.this.name
+
+ deployment_branch_policy {
+ protected_branches = false
+ custom_branch_policies = true
+ }
+ reviewers {
+ teams = matchkeys(
+ data.github_organization_teams.all.teams[*].id,
+ data.github_organization_teams.all.teams[*].slug,
+ local.cd_opex.reviewers_teams
+ )
+ }
+}
+
+resource "github_actions_environment_secret" "env_opex_prod_cd_secrets" {
+ for_each = local.cd_opex.secrets
+
+ repository = github_repository.this.name
+ environment = github_repository_environment.github_repository_environment_opex_prod_cd.environment
+ secret_name = each.key
+ plaintext_value = each.value
+}
+
+# -------------- WEB-APP ----------------
+
+resource "github_repository_environment" "github_repository_environment_web_apps_cd" {
+ environment = "app-prod-cd"
+ repository = github_repository.this.name
+
+ reviewers {
+ teams = matchkeys(
+ data.github_organization_teams.all.teams[*].id,
+ data.github_organization_teams.all.teams[*].slug,
+ local.cd_web_apps.reviewers_teams
+ )
+ }
+}
+
+resource "github_actions_environment_secret" "web_app_client_id" {
+ for_each = local.cd_web_apps.secrets
+
+ repository = github_repository.this.name
+ environment = github_repository_environment.github_repository_environment_web_apps_cd.environment
+ secret_name = each.key
+ plaintext_value = each.value
+}
\ No newline at end of file
diff --git a/infra/repository/github_environment_ci.tf b/infra/repository/github_environment_ci.tf
new file mode 100644
index 00000000..6f6c6064
--- /dev/null
+++ b/infra/repository/github_environment_ci.tf
@@ -0,0 +1,42 @@
+resource "github_repository_environment" "github_repository_environment_prod_ci" {
+ environment = "prod-ci"
+ repository = github_repository.this.name
+
+ deployment_branch_policy {
+ protected_branches = false
+ custom_branch_policies = true
+ }
+
+}
+
+resource "github_actions_environment_secret" "env_prod_ci_secrets" {
+ for_each = local.ci.secrets
+
+ repository = github_repository.this.name
+ environment = github_repository_environment.github_repository_environment_prod_ci.environment
+ secret_name = each.key
+ plaintext_value = each.value
+}
+
+# -------------- OPEX ----------------
+
+resource "github_repository_environment" "github_repository_environment_opex_prod_ci" {
+ environment = "opex-prod-ci"
+ repository = github_repository.this.name
+
+ prevent_self_review = false
+
+ deployment_branch_policy {
+ protected_branches = false
+ custom_branch_policies = true
+ }
+}
+
+resource "github_actions_environment_secret" "env_opex_prod_ci_secrets" {
+ for_each = local.ci_opex.secrets
+
+ repository = github_repository.this.name
+ environment = github_repository_environment.github_repository_environment_opex_prod_ci.environment
+ secret_name = each.key
+ plaintext_value = each.value
+}
diff --git a/.identity/github_repo_secrets.tf b/infra/repository/github_repo_secrets.tf
similarity index 56%
rename from .identity/github_repo_secrets.tf
rename to infra/repository/github_repo_secrets.tf
index 3494f189..3c47ba4b 100644
--- a/.identity/github_repo_secrets.tf
+++ b/infra/repository/github_repo_secrets.tf
@@ -1,6 +1,7 @@
resource "github_actions_secret" "repo_secrets" {
- for_each = local.repo_secrets
- repository = var.github.repository
+ for_each = local.repo_secrets
+
+ repository = github_repository.this.name
secret_name = each.key
plaintext_value = each.value
-}
\ No newline at end of file
+}
diff --git a/infra/repository/github_repository.tf b/infra/repository/github_repository.tf
new file mode 100644
index 00000000..2fabb3aa
--- /dev/null
+++ b/infra/repository/github_repository.tf
@@ -0,0 +1,31 @@
+resource "github_repository" "this" {
+ name = "io-sign"
+ description = "IO platform feature that allows the signing of PDF documents"
+
+ #tfsec:ignore:github-repositories-private
+ visibility = "public"
+
+ allow_auto_merge = false
+ allow_update_branch = true
+ allow_rebase_merge = false
+ allow_merge_commit = false
+ allow_squash_merge = true
+ squash_merge_commit_title = "PR_TITLE"
+ squash_merge_commit_message = "BLANK"
+
+ delete_branch_on_merge = true
+
+ has_projects = false
+ has_wiki = false
+ has_discussions = false
+ has_issues = false
+ has_downloads = true
+
+ homepage_url = "https://firma.io.italia.it/"
+
+ topics = ["io-sign", "io"]
+
+ vulnerability_alerts = true
+
+ archive_on_destroy = false
+}
diff --git a/infra/repository/locals.tf b/infra/repository/locals.tf
new file mode 100644
index 00000000..9e0eea7d
--- /dev/null
+++ b/infra/repository/locals.tf
@@ -0,0 +1,48 @@
+locals {
+ project = "io-p"
+
+ identity_resource_group_name = "${local.project}-identity-rg"
+ backend_resource_group_name = "${local.project}-sign-backend-rg"
+
+ repo_secrets = {
+ "ARM_TENANT_ID" = data.azurerm_client_config.current.tenant_id,
+ "ARM_SUBSCRIPTION_ID" = data.azurerm_subscription.current.subscription_id
+ }
+
+ ci = {
+ secrets = {
+ "ARM_CLIENT_ID" = data.azurerm_user_assigned_identity.identity_prod_ci.client_id
+ }
+ }
+
+ cd = {
+ secrets = {
+ "ARM_CLIENT_ID" = data.azurerm_user_assigned_identity.identity_prod_cd.client_id
+ }
+ reviewers_teams = ["io-sign-admins", "io-sign-maintainers", "engineering-team-cloud-eng"]
+ }
+
+ # OPEX
+ ci_opex = {
+ secrets = {
+ "ARM_CLIENT_ID" = data.azurerm_user_assigned_identity.identity_opex_prod_ci.client_id
+ }
+ }
+
+ cd_opex = {
+ secrets = {
+ "ARM_CLIENT_ID" = data.azurerm_user_assigned_identity.identity_opex_prod_cd.client_id
+ }
+ reviewers_teams = ["io-sign-admins", "io-sign-maintainers", "engineering-team-cloud-eng"]
+ }
+
+ # WEB-APP
+ # web_apps_map = { for w in data.azurerm_resources.web_apps.resources : w.name => w }
+
+ cd_web_apps = {
+ secrets = {
+ "ARM_CLIENT_ID" = data.azurerm_user_assigned_identity.identity_app_prod_cd.client_id
+ }
+ reviewers_teams = ["io-sign-admins", "io-sign-maintainers", "engineering-team-cloud-eng"]
+ }
+}
diff --git a/infra/repository/main.tf b/infra/repository/main.tf
new file mode 100644
index 00000000..ca89f279
--- /dev/null
+++ b/infra/repository/main.tf
@@ -0,0 +1,34 @@
+terraform {
+
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "<= 3.105.0"
+ }
+
+ github = {
+ source = "integrations/github"
+ version = "6.1.0"
+ }
+ }
+
+ backend "azurerm" {
+ resource_group_name = "terraform-state-rg"
+ storage_account_name = "tfappprodio"
+ container_name = "terraform-state"
+ key = "io-sign.repository.tfstate"
+ }
+}
+
+provider "azurerm" {
+ features {
+ }
+}
+
+provider "github" {
+ owner = "pagopa"
+}
+
+data "azurerm_client_config" "current" {}
+
+data "azurerm_subscription" "current" {}
diff --git a/infra/resources/prod/.terraform.lock.hcl b/infra/resources/prod/.terraform.lock.hcl
new file mode 100644
index 00000000..f02c34e7
--- /dev/null
+++ b/infra/resources/prod/.terraform.lock.hcl
@@ -0,0 +1,93 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/azuread" {
+ version = "2.33.0"
+ constraints = "<= 2.33.0"
+ hashes = [
+ "h1:PDiZA9QpXCkaSuWu6jiCRcjVtKJETqjcOZq4I434zfE=",
+ "h1:QAQe2+WSqGnHYAVoA+NN4Oeuoqg5sXq3U9Qmj6S1P5M=",
+ "h1:XIvCW3Nl4bW1bc9f8jyGhft+fQjaed4yy/LFzDAeVJ8=",
+ "h1:Z28tjly5UfKOE+HL/oALxCPhmCuBwUgZ4uaYt68VR3M=",
+ "zh:0602d03d7d7e38819f78dc377e64f365427496edf1065bfbb113e3921ab1c34e",
+ "zh:08843838f4fe146084592472648d4ea7191931eabe042a96c3b3c6eaf8ddfb43",
+ "zh:1c3e89cf19118fc07d7b04257251fc9897e722c16e0a0df7b07fcd261f8c12e7",
+ "zh:26a0d8a186e3b47ea0b7217a8e420b03fda59b7a680bb3ea52cf7d3e6d965ef3",
+ "zh:352a1cacaacd39e796de15a52d192ab0e6eb98dd36b5fbf8ebddd37e6dafa4ac",
+ "zh:3702ad4c534e67e2e07b060bfe5e6edc244c59c911906c8b15b96e7fecb0ff2c",
+ "zh:93b5248d26bdd44845b2ab051a2168c7edad788ae9836f62ea5fb632fd59d7ea",
+ "zh:a7b880155f4a67b52a5bfe78de33dc55254ef80006234f00e36aaf6533b1de4a",
+ "zh:a7cf0829364127c9bca26ec01ea3d66988b43987b2d26a3290487d1fc0da50eb",
+ "zh:b1f82b0d30af733b36a2f849799e0b1ed6a72888fa32a438c829c4e5cff88e20",
+ "zh:b6c2b23770852de8f56b549579c2f5a82afd84a9ca0616d53a25d48488f7aaf0",
+ "zh:d87dfbdfe8ab9d3a2e33f210333d40f211ea7d33bfa671063e6807c6ddd85a52",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/azurerm" {
+ version = "3.113.0"
+ constraints = "~> 3.30, ~> 3.76, ~> 3.95, != 3.97.0, != 3.97.1, <= 3.113.0"
+ hashes = [
+ "h1:32/ivdUXEkPBOQE9aVmuUafSbJNjvptDLHtOk/PXtvQ=",
+ "h1:SMgp1in4oxxVeICJMy8qg3WG00jDmLwUfgd9jlO3Ysw=",
+ "h1:SbNQLapCxbTbhM37LaRALPizAZMiA5sTRC09sUWgZOo=",
+ "h1:eEUtt0lrLdpVaF6FiDq8BGQPgEcykmhj0aNIL7hTOGw=",
+ "zh:12479f5664288943400447b55e50df675c28ae82ad8d373cc2e5682f3a3411f0",
+ "zh:1b42a14e80e568429d3b55fed753ca3ef0df9dcdfa107890d7264599c020940f",
+ "zh:381be6ca617f848de3baa3985a6e1788e91a803afe04a3c5c727453528b6310d",
+ "zh:3e70e2e07b6db1c363de3e5d0ca47f27fc956473df03329c7d2e54d3ac29176b",
+ "zh:87c7633aeaa828098c6055da9e67d4acaf4b46748b6b3f0267e105e55f05de25",
+ "zh:8d0d98226901f874770dd5220d4701a12ae8bd586994615aa7dcba12b9736bec",
+ "zh:9fd913acd42a60c3a90a18ce803567ef861db8779a59aacced91f2cbd86de9d9",
+ "zh:b6f3f7ae0a055437fb36c139af9bb3135e7f4dad172157ae1eb0177dc74d703f",
+ "zh:b927027ba2bf40d34e03d742fd2b6c5299023b5ab8e6f05e50aac76a46ad1094",
+ "zh:ceb5187b9d2a439f4e48944f3ffeeeaf47a03dbe6f3325ea1775bf659ce0aa88",
+ "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
+ "zh:fb9d78dfeca7489bffca9b1a1f3abee7f16dbbcba31388aea1102062c1d6dce8",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/http" {
+ version = "3.4.4"
+ hashes = [
+ "h1:EqpXf0aaUCTyYzlNP9XhjzAMMImD1T5bAy1pgLjWx4s=",
+ "h1:WSgOdMqgN48NIZy0CTKY2hMTNdc4rChYPUDEWYXeaTQ=",
+ "h1:dDGRXAVxwKgjVzA7VsO7MpYxt+eHnJosFV7rPZ4842o=",
+ "h1:rkI0TvsuQLwWFwbYG0+X/u726CVj6C6TwUebmMMlOMU=",
+ "zh:28910c348aff60df15cb70c2838c5dac463de5d52fe41a511f122b0b5fa6032d",
+ "zh:61ddcdb703900b01a8d38c67bd68304e87e05aa82c2d6636a5c49813b0cee8bf",
+ "zh:6d7ba9fcebff1079b9cbad066874d83680a4aedc997baa597927f59b29a69186",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:82caa166f57808dd8421e9edf51bca0692135ca06ab548d5a2e3fe612bdd45a6",
+ "zh:95cb8ece59966d8f4020660879728dabaa158b3d188f22c0b92229347e740346",
+ "zh:ae56558b4262a4de250eec83e200ea4647badde10d1a14ed273f4daff650336f",
+ "zh:c1c5051eab9d9759fdb31bca6d7575a693558887a1156fa5f268963e05be4d92",
+ "zh:c90234ce3877e54be5b43493f51b582c6f9cb09138844cb048f63e9cd9f230fa",
+ "zh:cb237c6c47f085bf15149d6d2727b8bf108267582a30e7e2cd7393115896d003",
+ "zh:e7d782985f8b422cf265a856541ddb14f0d3ab0b54eb1aad6087ccfedacc7335",
+ "zh:ed0cc12d15226499fc7d173ad2b156c1934efae718cf254e79ca7f0ccd686b6d",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/null" {
+ version = "3.2.2"
+ constraints = "~> 3.2"
+ hashes = [
+ "h1:IMVAUHKoydFrlPrl9OzasDnw/8ntZFerCC9iXw1rXQY=",
+ "h1:m467k2tZ9cdFFgHW7LPBK2GLPH43LC6wc3ppxr8yvoE=",
+ "h1:vWAsYRd7MjYr3adj8BVKRohVfHpWQdvkIwUQ2Jf5FVM=",
+ "h1:zT1ZbegaAYHwQa+QwIFugArWikRJI9dqohj8xb0GY88=",
+ "zh:3248aae6a2198f3ec8394218d05bd5e42be59f43a3a7c0b71c66ec0df08b69e7",
+ "zh:32b1aaa1c3013d33c245493f4a65465eab9436b454d250102729321a44c8ab9a",
+ "zh:38eff7e470acb48f66380a73a5c7cdd76cc9b9c9ba9a7249c7991488abe22fe3",
+ "zh:4c2f1faee67af104f5f9e711c4574ff4d298afaa8a420680b0cb55d7bbc65606",
+ "zh:544b33b757c0b954dbb87db83a5ad921edd61f02f1dc86c6186a5ea86465b546",
+ "zh:696cf785090e1e8cf1587499516b0494f47413b43cb99877ad97f5d0de3dc539",
+ "zh:6e301f34757b5d265ae44467d95306d61bef5e41930be1365f5a8dcf80f59452",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:913a929070c819e59e94bb37a2a253c228f83921136ff4a7aa1a178c7cce5422",
+ "zh:aa9015926cd152425dbf86d1abdbc74bfe0e1ba3d26b3db35051d7b9ca9f72ae",
+ "zh:bb04798b016e1e1d49bcc76d62c53b56c88c63d6f2dfe38821afef17c416a0e1",
+ "zh:c23084e1b23577de22603cff752e59128d83cfecc2e6819edadd8cf7a10af11e",
+ ]
+}
diff --git a/infra/resources/prod/README.md b/infra/resources/prod/README.md
new file mode 100644
index 00000000..6cceb081
--- /dev/null
+++ b/infra/resources/prod/README.md
@@ -0,0 +1,181 @@
+
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [azuread](#requirement\_azuread) | >= 2.33.0 |
+| [azurerm](#requirement\_azurerm) | >= 3.40.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [azuread](#provider\_azuread) | 2.33.0 |
+| [azurerm](#provider\_azurerm) | 3.40.0 |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [apim\_io\_sign\_issuer\_api\_v1](#module\_apim\_io\_sign\_issuer\_api\_v1) | git::https://github.com/pagopa/terraform-azurerm-v3.git//api_management_api | v4.1.3 |
+| [apim\_io\_sign\_product](#module\_apim\_io\_sign\_product) | git::https://github.com/pagopa/terraform-azurerm-v3.git//api_management_product | v4.1.3 |
+| [apim\_io\_sign\_support\_api\_v1](#module\_apim\_io\_sign\_support\_api\_v1) | git::https://github.com/pagopa/terraform-azurerm-v3.git//api_management_api | v4.1.3 |
+| [apim\_io\_sign\_support\_product](#module\_apim\_io\_sign\_support\_product) | git::https://github.com/pagopa/terraform-azurerm-v3.git//api_management_product | v4.1.3 |
+| [cosmosdb\_account](#module\_cosmosdb\_account) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cosmosdb_account | v4.1.8 |
+| [cosmosdb\_sql\_container\_issuer-dossiers](#module\_cosmosdb\_sql\_container\_issuer-dossiers) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cosmosdb_sql_container | v4.1.11 |
+| [cosmosdb\_sql\_container\_issuer-issuers](#module\_cosmosdb\_sql\_container\_issuer-issuers) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cosmosdb_sql_container | v4.1.11 |
+| [cosmosdb\_sql\_container\_issuer-issuers-by-vat-number](#module\_cosmosdb\_sql\_container\_issuer-issuers-by-vat-number) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cosmosdb_sql_container | v4.1.11 |
+| [cosmosdb\_sql\_container\_issuer-issuers-whitelist](#module\_cosmosdb\_sql\_container\_issuer-issuers-whitelist) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cosmosdb_sql_container | v4.1.11 |
+| [cosmosdb\_sql\_container\_issuer-signature-requests](#module\_cosmosdb\_sql\_container\_issuer-signature-requests) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cosmosdb_sql_container | v4.1.11 |
+| [cosmosdb\_sql\_container\_issuer-uploads](#module\_cosmosdb\_sql\_container\_issuer-uploads) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cosmosdb_sql_container | v4.1.11 |
+| [cosmosdb\_sql\_container\_user-signature-requests](#module\_cosmosdb\_sql\_container\_user-signature-requests) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cosmosdb_sql_container | v4.1.11 |
+| [cosmosdb\_sql\_container\_user-signatures](#module\_cosmosdb\_sql\_container\_user-signatures) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cosmosdb_sql_container | v4.1.11 |
+| [cosmosdb\_sql\_database\_issuer](#module\_cosmosdb\_sql\_database\_issuer) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cosmosdb_sql_database | v4.1.3 |
+| [cosmosdb\_sql\_database\_user](#module\_cosmosdb\_sql\_database\_user) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cosmosdb_sql_database | v4.1.3 |
+| [event\_hub](#module\_event\_hub) | git::https://github.com/pagopa/terraform-azurerm-v3.git//eventhub | v4.1.7 |
+| [io\_sign\_eventhub\_snet](#module\_io\_sign\_eventhub\_snet) | git::https://github.com/pagopa/terraform-azurerm-v3.git//subnet | v4.1.4 |
+| [io\_sign\_issuer\_func](#module\_io\_sign\_issuer\_func) | git::https://github.com/pagopa/terraform-azurerm-v3.git//function_app | v6.2.1 |
+| [io\_sign\_issuer\_func\_staging\_slot](#module\_io\_sign\_issuer\_func\_staging\_slot) | git::https://github.com/pagopa/terraform-azurerm-v3.git//function_app_slot | v6.0.1 |
+| [io\_sign\_snet](#module\_io\_sign\_snet) | git::https://github.com/pagopa/terraform-azurerm-v3.git//subnet | v4.1.4 |
+| [io\_sign\_storage](#module\_io\_sign\_storage) | git::https://github.com/pagopa/terraform-azurerm-v3.git//storage_account | v4.1.5 |
+| [io\_sign\_support\_func](#module\_io\_sign\_support\_func) | git::https://github.com/pagopa/terraform-azurerm-v3.git//function_app | v6.1.0 |
+| [io\_sign\_support\_func\_staging\_slot](#module\_io\_sign\_support\_func\_staging\_slot) | git::https://github.com/pagopa/terraform-azurerm-v3.git//function_app_slot | v6.1.0 |
+| [io\_sign\_support\_snet](#module\_io\_sign\_support\_snet) | git::https://github.com/pagopa/terraform-azurerm-v3.git//subnet | v4.1.4 |
+| [io\_sign\_user\_func](#module\_io\_sign\_user\_func) | git::https://github.com/pagopa/terraform-azurerm-v3.git//function_app | v6.2.1 |
+| [io\_sign\_user\_func\_staging\_slot](#module\_io\_sign\_user\_func\_staging\_slot) | git::https://github.com/pagopa/terraform-azurerm-v3.git//function_app_slot | v6.0.1 |
+| [io\_sign\_user\_snet](#module\_io\_sign\_user\_snet) | git::https://github.com/pagopa/terraform-azurerm-v3.git//subnet | v4.1.4 |
+| [key\_vault](#module\_key\_vault) | git::https://github.com/pagopa/terraform-azurerm-v3.git//key_vault | v6.2.2 |
+| [key\_vault\_secrets](#module\_key\_vault\_secrets) | git::https://github.com/pagopa/terraform-azurerm-v3.git//key_vault_secrets_query | v4.1.3 |
+| [landing\_cdn](#module\_landing\_cdn) | git::https://github.com/pagopa/terraform-azurerm-v3.git//cdn | v6.3.1 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [azurerm_api_management_api_operation_policy.get_signer_by_fiscal_code_policy](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/api_management_api_operation_policy) | resource |
+| [azurerm_api_management_named_value.io_fn_sign_issuer_key](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/api_management_named_value) | resource |
+| [azurerm_api_management_named_value.io_fn_sign_issuer_url](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/api_management_named_value) | resource |
+| [azurerm_api_management_named_value.io_fn_sign_support_key](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/api_management_named_value) | resource |
+| [azurerm_api_management_named_value.io_fn_sign_support_url](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/api_management_named_value) | resource |
+| [azurerm_api_management_named_value.io_sign_cosmosdb_issuer_container_name](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/api_management_named_value) | resource |
+| [azurerm_api_management_named_value.io_sign_cosmosdb_issuer_issuers_collection_name](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/api_management_named_value) | resource |
+| [azurerm_api_management_named_value.io_sign_cosmosdb_issuer_whitelist_collection_name_new](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/api_management_named_value) | resource |
+| [azurerm_api_management_named_value.io_sign_cosmosdb_key](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/api_management_named_value) | resource |
+| [azurerm_api_management_named_value.io_sign_cosmosdb_name](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/api_management_named_value) | resource |
+| [azurerm_dns_cname_record.dkim1_mailup_firma_io_pagopa_it](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/dns_cname_record) | resource |
+| [azurerm_dns_cname_record.dkim2_mailup_firma_io_pagopa_it](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/dns_cname_record) | resource |
+| [azurerm_dns_cname_record.ses_validation_firma_io_pagopa_it](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/dns_cname_record) | resource |
+| [azurerm_dns_mx_record.ses_mx_firma_io_pagopa_it](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/dns_mx_record) | resource |
+| [azurerm_dns_txt_record.dmarc_mailup_firma_io_pagopa_it](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/dns_txt_record) | resource |
+| [azurerm_dns_txt_record.spf1_mailup_firma_io_pagopa_it](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/dns_txt_record) | resource |
+| [azurerm_dns_zone.firma_io_pagopa_it](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/dns_zone) | resource |
+| [azurerm_key_vault_access_policy.adgroup_admin](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
+| [azurerm_key_vault_access_policy.adgroup_contributors](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
+| [azurerm_key_vault_access_policy.adgroup_developers](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
+| [azurerm_key_vault_access_policy.adgroup_sign](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
+| [azurerm_key_vault_access_policy.azdevops_platform_iac_policy](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_access_policy) | resource |
+| [azurerm_key_vault_secret.integration_event_hub_jaas_connection_string](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) | resource |
+| [azurerm_key_vault_secret.integration_event_hub_secrets](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault_secret) | resource |
+| [azurerm_monitor_action_group.email_fci_tech](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_action_group) | resource |
+| [azurerm_monitor_action_group.slack_fci_tech](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_action_group) | resource |
+| [azurerm_monitor_autoscale_setting.io_sign_issuer_func](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_autoscale_setting) | resource |
+| [azurerm_monitor_autoscale_setting.io_sign_support_func](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_autoscale_setting) | resource |
+| [azurerm_monitor_autoscale_setting.io_sign_user_func](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_autoscale_setting) | resource |
+| [azurerm_monitor_metric_alert.io_sign_issuer_http_server_errors](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_metric_alert) | resource |
+| [azurerm_monitor_metric_alert.io_sign_issuer_response_time](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_metric_alert) | resource |
+| [azurerm_monitor_metric_alert.io_sign_support_http_server_errors](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_metric_alert) | resource |
+| [azurerm_monitor_metric_alert.io_sign_support_response_time](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_metric_alert) | resource |
+| [azurerm_monitor_metric_alert.io_sign_user_helathcheck](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_metric_alert) | resource |
+| [azurerm_monitor_metric_alert.io_sign_user_http_server_errors](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_metric_alert) | resource |
+| [azurerm_monitor_metric_alert.io_sign_user_response_time](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_metric_alert) | resource |
+| [azurerm_monitor_scheduled_query_rules_alert.io_sign_qtsp_avg_async_time](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_scheduled_query_rules_alert) | resource |
+| [azurerm_network_security_group.io_sign_eventhub_nsg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_group) | resource |
+| [azurerm_network_security_group.io_sign_issuer_nsg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_group) | resource |
+| [azurerm_network_security_group.io_sign_support_nsg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_group) | resource |
+| [azurerm_network_security_group.io_sign_user_nsg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_group) | resource |
+| [azurerm_portal_dashboard.io_sign_user_dashboard](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/portal_dashboard) | resource |
+| [azurerm_private_endpoint.blob](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
+| [azurerm_private_endpoint.io_sign_issuer_func](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
+| [azurerm_private_endpoint.io_sign_issuer_func_staging](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
+| [azurerm_private_endpoint.io_sign_support_func](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
+| [azurerm_private_endpoint.io_sign_support_func_staging](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
+| [azurerm_private_endpoint.io_sign_user_func](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
+| [azurerm_private_endpoint.io_sign_user_func_staging](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
+| [azurerm_private_endpoint.queue](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_endpoint) | resource |
+| [azurerm_resource_group.backend_rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource |
+| [azurerm_resource_group.data_rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource |
+| [azurerm_resource_group.integration_rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource |
+| [azurerm_resource_group.sec_rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource |
+| [azurerm_storage_container.filled_modules](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_container) | resource |
+| [azurerm_storage_container.signed_documents](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_container) | resource |
+| [azurerm_storage_container.uploaded_documents](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_container) | resource |
+| [azurerm_storage_container.validated_documents](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_container) | resource |
+| [azurerm_storage_management_policy.io_sign_storage_management_policy](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_management_policy) | resource |
+| [azurerm_storage_queue.on_signature_request_ready](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_queue) | resource |
+| [azurerm_storage_queue.on_signature_request_rejected](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_queue) | resource |
+| [azurerm_storage_queue.on_signature_request_signed](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_queue) | resource |
+| [azurerm_storage_queue.on_signature_request_wait_for_signature](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_queue) | resource |
+| [azurerm_storage_queue.waiting_for_documents_to_fill](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_queue) | resource |
+| [azurerm_storage_queue.waiting_for_qtsp](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_queue) | resource |
+| [azurerm_storage_queue.waiting_for_signature_request_updates](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_queue) | resource |
+| [azurerm_subnet_nat_gateway_association.io_sign_issuer_snet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_nat_gateway_association) | resource |
+| [azurerm_subnet_nat_gateway_association.io_sign_support_snet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_nat_gateway_association) | resource |
+| [azurerm_subnet_nat_gateway_association.io_sign_user_snet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_nat_gateway_association) | resource |
+| [azuread_group.adgroup_admin](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/group) | data source |
+| [azuread_group.adgroup_contributors](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/group) | data source |
+| [azuread_group.adgroup_developers](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/group) | data source |
+| [azuread_group.adgroup_externals](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/group) | data source |
+| [azuread_group.adgroup_security](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/group) | data source |
+| [azuread_group.adgroup_sign](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/group) | data source |
+| [azuread_service_principal.platform_iac_sp](https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/data-sources/service_principal) | data source |
+| [azurerm_api_management.apim_api](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/api_management) | data source |
+| [azurerm_application_insights.application_insights](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/application_insights) | data source |
+| [azurerm_client_config.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/client_config) | data source |
+| [azurerm_dns_zone.io_italia_it](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/dns_zone) | data source |
+| [azurerm_key_vault.core_kv_common](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault) | data source |
+| [azurerm_key_vault_secret.monitor_fci_tech_email](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault_secret) | data source |
+| [azurerm_key_vault_secret.monitor_fci_tech_slack_email](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault_secret) | data source |
+| [azurerm_monitor_action_group.email](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/monitor_action_group) | data source |
+| [azurerm_monitor_action_group.slack](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/monitor_action_group) | data source |
+| [azurerm_nat_gateway.nat_gateway](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/nat_gateway) | data source |
+| [azurerm_private_dns_zone.privatelink_azurewebsites_net](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/private_dns_zone) | data source |
+| [azurerm_private_dns_zone.privatelink_blob_core_windows_net](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/private_dns_zone) | data source |
+| [azurerm_private_dns_zone.privatelink_documents_azure_com](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/private_dns_zone) | data source |
+| [azurerm_private_dns_zone.privatelink_file_core_windows_net](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/private_dns_zone) | data source |
+| [azurerm_private_dns_zone.privatelink_queue_core_windows_net](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/private_dns_zone) | data source |
+| [azurerm_private_dns_zone.privatelink_servicebus_windows_net](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/private_dns_zone) | data source |
+| [azurerm_private_dns_zone.privatelink_table_core_windows_net](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/private_dns_zone) | data source |
+| [azurerm_resource_group.core_ext](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source |
+| [azurerm_resource_group.core_rg_common](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source |
+| [azurerm_subnet.apim](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subnet) | data source |
+| [azurerm_subnet.private_endpoints_subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subnet) | data source |
+| [azurerm_subscription.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subscription) | data source |
+| [azurerm_virtual_network.vnet_common](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/virtual_network) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [cosmos](#input\_cosmos) | n/a |
object({
zone_redundant = bool
additional_geo_locations = list(object({
location = string
failover_priority = number
zone_redundant = bool
}))
})
| n/a | yes |
+| [dns\_default\_ttl\_sec](#input\_dns\_default\_ttl\_sec) | Default TTL for DNS | `number` | `3600` | no |
+| [dns\_ses\_validation](#input\_dns\_ses\_validation) | CNAME records to validate SES domain identity | list(object({
name = string
record = string
}))
| n/a | yes |
+| [dns\_zone\_name](#input\_dns\_zone\_name) | The name for the DNS zone | `string` | n/a | yes |
+| [domain](#input\_domain) | n/a | `string` | n/a | yes |
+| [env\_short](#input\_env\_short) | n/a | `string` | n/a | yes |
+| [integration\_hub](#input\_integration\_hub) | The configuration, hubs and keys of the event hub relative to external integration | object({
auto_inflate_enabled = bool
sku_name = string
capacity = number
maximum_throughput_units = number
zone_redundant = bool
alerts_enabled = bool
ip_rules = list(object({
ip_mask = string
action = string
}))
hubs = list(object({
name = string
partitions = number
message_retention = number
consumers = list(string)
keys = list(object({
name = string
listen = bool
send = bool
manage = bool
}))
}))
})
| n/a | yes |
+| [io\_sign\_database\_issuer](#input\_io\_sign\_database\_issuer) | n/a | map(
object({
max_throughput = number
ttl = number
})
)
| n/a | yes |
+| [io\_sign\_database\_user](#input\_io\_sign\_database\_user) | n/a | map(
object({
max_throughput = number
ttl = number
})
)
| n/a | yes |
+| [io\_sign\_issuer\_func](#input\_io\_sign\_issuer\_func) | n/a | object({
sku_tier = string
sku_size = string
autoscale_default = number
autoscale_minimum = number
autoscale_maximum = number
})
| n/a | yes |
+| [io\_sign\_support\_func](#input\_io\_sign\_support\_func) | n/a | object({
sku_tier = string
sku_size = string
autoscale_default = number
autoscale_minimum = number
autoscale_maximum = number
})
| n/a | yes |
+| [io\_sign\_user\_func](#input\_io\_sign\_user\_func) | n/a | object({
sku_tier = string
sku_size = string
autoscale_default = number
autoscale_minimum = number
autoscale_maximum = number
})
| n/a | yes |
+| [location](#input\_location) | n/a | `string` | n/a | yes |
+| [prefix](#input\_prefix) | n/a | `string` | n/a | yes |
+| [storage\_account](#input\_storage\_account) | The configuration of the storage account storing documents | object({
enable_versioning = bool
delete_after_days = number
replication_type = string
enable_low_availability_alert = bool
})
| n/a | yes |
+| [subnets\_cidrs](#input\_subnets\_cidrs) | The CIDR address prefixes of the subnets | map(
list(string)
)
| n/a | yes |
+| [tags](#input\_tags) | n/a | `map(any)` | {
"CreatedBy": "Terraform"
}
| no |
+
+## Outputs
+
+No outputs.
+
\ No newline at end of file
diff --git a/infra/resources/prod/api/backoffice/v1/base_policy.xml b/infra/resources/prod/api/backoffice/v1/base_policy.xml
new file mode 100644
index 00000000..b84876a9
--- /dev/null
+++ b/infra/resources/prod/api/backoffice/v1/base_policy.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ {{io-fn-sign-backoffice-key}}
+
+
+
+ *
+
+
+ *
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/infra/resources/prod/api/base_policy.xml b/infra/resources/prod/api/base_policy.xml
new file mode 100644
index 00000000..ce1df461
--- /dev/null
+++ b/infra/resources/prod/api/base_policy.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/infra/resources/prod/api/issuer/v1/base_policy.xml b/infra/resources/prod/api/issuer/v1/base_policy.xml
new file mode 100644
index 00000000..2e0887de
--- /dev/null
+++ b/infra/resources/prod/api/issuer/v1/base_policy.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+ {{io-fn-sign-issuer-key}}
+
+
+ @(context.Subscription.Id)
+
+
+
+ *
+
+
+ *
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/infra/resources/prod/api/issuer/v1/get_signer_by_fiscal_code_policy/policy.xml b/infra/resources/prod/api/issuer/v1/get_signer_by_fiscal_code_policy/policy.xml
new file mode 100644
index 00000000..72194021
--- /dev/null
+++ b/infra/resources/prod/api/issuer/v1/get_signer_by_fiscal_code_policy/policy.xml
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+ https://{{io-sign-cosmosdb-name}}.documents.azure.com/dbs/{{io-sign-backoffice-database-name}}/colls/{{io-sign-backoffice-api-keys-collection-name}}/docs
+ POST
+
+ @{
+ var verb = "post";
+ var resourceType = "docs";
+ var resourceLink = "dbs/{{io-sign-backoffice-database-name}}/colls/{{io-sign-backoffice-api-keys-collection-name}}";
+ var key = "{{io-sign-cosmosdb-key}}";
+ var keyType = "master";
+ var tokenVersion = "1.0";
+ var date = context.Variables.GetValueOrDefault("requestDateString");
+
+ var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = Convert.FromBase64String(key) };
+
+ string payLoad = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n",
+ verb.ToLowerInvariant(),
+ resourceType.ToLowerInvariant(),
+ resourceLink,
+ date.ToLowerInvariant(),
+ ""
+ );
+
+ byte[] hashPayLoad = hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payLoad));
+ string signature = Convert.ToBase64String(hashPayLoad);
+
+ return System.Uri.EscapeDataString(String.Format("type={0}&ver={1}&sig={2}",
+ keyType,
+ tokenVersion,
+ signature));
+ }
+
+
+ application/query+json
+
+
+ True
+
+
+ True
+
+
+ @(context.Variables.GetValueOrDefault("requestDateString"))
+
+
+ 2018-12-31
+
+ @("{\"query\": \"SELECT w.testers FROM whitelist w WHERE w.id = @id\", " +
+ "\"parameters\": [{ \"name\": \"@id\", \"value\": \"" + context.Subscription.Id + "\"}]}")
+
+
+ ())" />
+
+
+
+
+
+
+
+
+
+ https://{{io-sign-cosmosdb-name}}.documents.azure.com/dbs/{{io-sign-backoffice-database-name}}/colls/{{io-sign-backoffice-api-keys-collection-name}}/docs
+ POST
+
+ @{
+ var verb = "post";
+ var resourceType = "docs";
+ var resourceLink = "dbs/{{io-sign-backoffice-database-name}}/colls/{{io-sign-backoffice-api-keys-collection-name}}";
+ var key = "{{io-sign-cosmosdb-key}}";
+ var keyType = "master";
+ var tokenVersion = "1.0";
+ var date = context.Variables.GetValueOrDefault("requestDateString");
+
+ var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = Convert.FromBase64String(key) };
+
+ string payLoad = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n",
+ verb.ToLowerInvariant(),
+ resourceType.ToLowerInvariant(),
+ resourceLink,
+ date.ToLowerInvariant(),
+ ""
+ );
+
+ byte[] hashPayLoad = hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payLoad));
+ string signature = Convert.ToBase64String(hashPayLoad);
+
+ return System.Uri.EscapeDataString(String.Format("type={0}&ver={1}&sig={2}",
+ keyType,
+ tokenVersion,
+ signature));
+ }
+
+
+ application/query+json
+
+
+ True
+
+
+ True
+
+
+ @(context.Variables.GetValueOrDefault("requestDateString"))
+
+
+ 2018-12-31
+
+ @("{\"query\": \"SELECT i.environment FROM issuers i WHERE i.id = @subscriptionId\", " +
+ "\"parameters\": [{ \"name\": \"@subscriptionId\", \"value\": \"" + context.Subscription.Id + "\"}]}")
+
+
+ ())" />
+
+
+
+
+
+
+ @{
+ var environmentQueryResponse = context.Variables.GetValueOrDefault("issuerEnvironment");
+ if (environmentQueryResponse != null && environmentQueryResponse.ContainsKey("Documents")){
+ JArray envDocuments = (JArray) environmentQueryResponse["Documents"];
+ if (envDocuments.Count > 0){
+ JObject envFirstDocument = (JObject) envDocuments[0];
+ if(envFirstDocument.ContainsKey("environment")){
+ string issuerEnvironment = (string)envFirstDocument["environment"];
+
+ //If the issuer is not in the test environment then I do not perform any checks
+ if (issuerEnvironment!="test"){
+ return "true";
+ }
+ }
+ }
+ }
+
+ var whitelistFiscalCodeQueryResponse = context.Variables.GetValueOrDefault("issuerWhitelistFiscalCodes");
+ JObject requestBody = context.Request.Body.As(preserveContent: true);
+ if(requestBody.ContainsKey("fiscal_code")){
+ string requestFiscalCodeString = (string)requestBody["fiscal_code"];
+ if (whitelistFiscalCodeQueryResponse != null && whitelistFiscalCodeQueryResponse.ContainsKey("Documents")){
+ JArray documents = (JArray) whitelistFiscalCodeQueryResponse["Documents"];
+ if (documents.Count > 0){
+ JObject firstDocument = (JObject) documents[0];
+ if(firstDocument.ContainsKey("testers")){
+ JArray whiteListFiscalCodes = (JArray)firstDocument["testers"];
+ foreach (var fiscalCode in whiteListFiscalCodes) {
+ string fiscalCodeString = (string)fiscalCode;
+ if(fiscalCodeString==requestFiscalCodeString){
+ return "true";
+ }
+ }
+ }
+ }
+ }
+ }
+ return "false";
+ }
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/infra/resources/prod/api/issuer/v1/openapi.yaml b/infra/resources/prod/api/issuer/v1/openapi.yaml
new file mode 100644
index 00000000..d61feee2
--- /dev/null
+++ b/infra/resources/prod/api/issuer/v1/openapi.yaml
@@ -0,0 +1,841 @@
+openapi: 3.0.3
+info:
+ title: Firma con IO - Issuer API
+ version: 1.2.1
+servers:
+ - url: https://api.io.pagopa.it/api/v1/sign
+ description: production
+security:
+ - SubscriptionKey: []
+paths:
+ /dossiers:
+ post:
+ operationId: createDossier
+ tags:
+ - Dossier
+ summary: Create a Dossier
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/CreateDossierBody"
+ responses:
+ "201":
+ description: The Dossier detail
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/DossierDetailView"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ default:
+ $ref: "#/components/responses/Unexpected"
+
+ /dossiers/{id}:
+ get:
+ operationId: getDossier
+ tags:
+ - Dossier
+ summary: Get a Dossier by Id
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ $ref: "#/components/schemas/Id"
+ responses:
+ "200":
+ description: The Dossier detail
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/DossierDetailView"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ default:
+ $ref: "#/components/responses/Unexpected"
+
+ /dossiers/{id}/signature-requests:
+ get:
+ operationId: getRequestsByDossier
+ tags:
+ - Dossier
+ summary: Get the Signature Requests created from a Dossier
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ $ref: "#/components/schemas/Id"
+ - in: query
+ name: continuationToken
+ required: false
+ schema:
+ type: string
+ - in: query
+ name: limit
+ required: false
+ schema:
+ type: integer
+ minimum: 25
+ maximum: 100
+ responses:
+ "200":
+ description: The Dossier detail
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SignatureRequestList"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ default:
+ $ref: "#/components/responses/Unexpected"
+
+ /signers:
+ post:
+ operationId: getSignerByFiscalCode
+ tags:
+ - Signer
+ summary: Get Signer By Fiscal COde
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/GetSignerByFiscalCodeBody"
+ responses:
+ "201":
+ description: The Signer detail
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SignerDetailView"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ default:
+ $ref: "#/components/responses/Unexpected"
+
+ /signature-requests:
+ post:
+ operationId: createSignatureRequest
+ tags:
+ - Signature Request
+ summary: Create a Signature Request
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/CreateSignatureRequestBody"
+ responses:
+ "201":
+ description: The Signature Request detail
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SignatureRequestDetailView"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "422":
+ $ref: "#/components/responses/UnprocessableContent"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ default:
+ $ref: "#/components/responses/Unexpected"
+
+ /signature-requests/{id}:
+ get:
+ operationId: getSignatureRequest
+ tags:
+ - Signature Request
+ summary: Get a Signature Request by Id
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ $ref: "#/components/schemas/Id"
+ responses:
+ "200":
+ description: The Signature Request detail
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SignatureRequestDetailView"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ default:
+ $ref: "#/components/responses/Unexpected"
+
+ /signature-requests/{id}/status:
+ put:
+ operationId: setSignatureRequestStatus
+ tags:
+ - Signature Request
+ summary: Set the status of a Signature Request
+ parameters:
+ - in: path
+ name: id
+ required: true
+ schema:
+ $ref: "#/components/schemas/Id"
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SetSignatureRequestStatusBody"
+ responses:
+ "204":
+ description: Signature Request status successfully set
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ "422":
+ $ref: "#/components/responses/UnprocessableContent"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ default:
+ $ref: "#/components/responses/Unexpected"
+
+ /signature-requests/{req_id}/documents/{doc_id}/upload_url:
+ get:
+ operationId: getDocumentUploadUrl
+ tags:
+ - Signature Request
+ summary: Get the Upload Url for the specified document
+ parameters:
+ - in: path
+ name: req_id
+ required: true
+ schema:
+ $ref: "#/components/schemas/Id"
+ - in: path
+ name: doc_id
+ required: true
+ schema:
+ $ref: "#/components/schemas/Id"
+ responses:
+ "200":
+ description: The Upload Url
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UploadUrl"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ default:
+ $ref: "#/components/responses/Unexpected"
+
+ /signature-requests/{req_id}/notification:
+ put:
+ operationId: sendNotification
+ tags:
+ - Signature Request
+ summary: Send a signature request notification to user via IO message
+ parameters:
+ - in: path
+ name: req_id
+ required: true
+ schema:
+ $ref: "#/components/schemas/Id"
+ responses:
+ "201":
+ description: The notification detail
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/NotificationDetailView"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ default:
+ $ref: "#/components/responses/Unexpected"
+
+ /validate-document:
+ post:
+ operationId: validateDocument
+ tags:
+ - Utility
+ summary: Validate a PDF document against a list of signature fields
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ document:
+ type: string
+ format: binary
+ signature_fields:
+ type: array
+ items:
+ $ref: "#/components/schemas/SignatureField"
+ required:
+ - document
+ encoding:
+ document:
+ contentType: application/pdf
+ responses:
+ "200":
+ description: the validation result
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/DocumentValidationResult"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+ "403":
+ $ref: "#/components/responses/Forbidden"
+ "429":
+ $ref: "#/components/responses/TooManyRequests"
+ default:
+ $ref: "#/components/responses/Unexpected"
+
+components:
+ securitySchemes:
+ SubscriptionKey:
+ type: apiKey
+ name: Ocp-Apim-Subscription-Key
+ in: header
+ description: The API key obtained through the developer portal
+
+ responses:
+ NotFound:
+ description: The specified resource was not found
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ProblemDetail"
+
+ BadRequest:
+ description: Validation error on body
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ProblemDetail"
+
+ Forbidden:
+ description: You don't have enough privileges to perform this action
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ProblemDetail"
+
+ Unauthorized:
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ProblemDetail"
+
+ UnprocessableContent:
+ description: Unprocessable Content
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ProblemDetail"
+
+ TooManyRequests:
+ description: Too Many Requests
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ProblemDetail"
+
+ Unexpected:
+ description: Unexpected error
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ProblemDetail"
+
+ schemas:
+ ProblemDetail:
+ type: object
+ properties:
+ type:
+ type: string
+ format: uri
+ description: |-
+ An absolute URI that identifies the problem type. When dereferenced,
+ it SHOULD provide human-readable documentation for the problem type
+ (e.g., using HTML).
+ default: about:blank
+ example: https://example.com/problem/constraint-violation
+ title:
+ type: string
+ description: >-
+ A short, summary of the problem type. Written in english and
+ readable
+
+ for engineers (usually not suited for non technical stakeholders and
+
+ not localized); example: Service Unavailable
+ status:
+ type: integer
+ format: int32
+ description: >-
+ The HTTP status code generated by the origin server for this
+ occurrence of the problem.
+ minimum: 100
+ maximum: 600
+ exclusiveMaximum: true
+ example: 200
+ detail:
+ type: string
+ description: |-
+ A human readable explanation specific to this occurrence of the
+ problem.
+ example: There was an error processing the request
+ instance:
+ type: string
+ format: uri
+ description: >-
+ An absolute URI that identifies the specific occurrence of the
+ problem. It may or may not yield further information if
+ dereferenced.
+
+ Clause:
+ type: object
+ properties:
+ title:
+ type: string
+ minLength: 5
+ maxLength: 80
+ type:
+ type: string
+ enum: ["REQUIRED", "UNFAIR", "OPTIONAL"]
+ required:
+ - title
+ - type
+
+ ExistingSignatureFieldAttrs:
+ type: object
+ properties:
+ unique_name:
+ type: string
+ required:
+ - unique_name
+
+ SignatureFieldToBeCreatedAttrs:
+ type: object
+ properties:
+ coordinates:
+ type: object
+ properties:
+ x: { type: number }
+ y: { type: number }
+ required: [x, y]
+ page:
+ type: number
+ minimum: 0
+ size:
+ type: object
+ properties:
+ w: { type: number, minimum: 0 }
+ h: { type: number, minimum: 0 }
+ required: [w, h]
+ required:
+ - coordinates
+ - page
+ - size
+
+ SignatureFieldAttrs:
+ oneOf:
+ - $ref: "#/components/schemas/ExistingSignatureFieldAttrs"
+ - $ref: "#/components/schemas/SignatureFieldToBeCreatedAttrs"
+
+ SignatureField:
+ type: object
+ properties:
+ attrs:
+ $ref: "#/components/schemas/SignatureFieldAttrs"
+ clause:
+ $ref: "#/components/schemas/Clause"
+ required:
+ - attrs
+ - clause
+
+ DocumentMetadata:
+ type: object
+ properties:
+ title:
+ type: string
+ minLength: 3
+ maxLength: 60
+ signature_fields:
+ type: array
+ items:
+ $ref: "#/components/schemas/SignatureField"
+ required:
+ - title
+
+ DocumentMetadataList:
+ type: array
+ items:
+ $ref: "#/components/schemas/DocumentMetadata"
+ minLength: 1
+
+ DossierSupportEmail:
+ type: string
+ description: Issuer's support email for a specific dossier.
+ format: email
+ example: demo@example.com
+
+ DossierTitle:
+ type: string
+ minLength: 3
+
+ CreateDossierBody:
+ type: object
+ properties:
+ title:
+ $ref: "#/components/schemas/DossierTitle"
+ support_email:
+ $ref: "#/components/schemas/DossierSupportEmail"
+ documents_metadata:
+ $ref: "#/components/schemas/DocumentMetadataList"
+ required:
+ - title
+ - documents_metadata
+
+ SetSignatureRequestStatusBody:
+ type: string
+ x-extensible-enum:
+ - READY
+ - CANCELLED
+
+ DossierDetailView:
+ type: object
+ properties:
+ id:
+ $ref: "#/components/schemas/Id"
+ title:
+ $ref: "#/components/schemas/DossierTitle"
+ support_email:
+ $ref: "#/components/schemas/DossierSupportEmail"
+ documents_metadata:
+ $ref: "#/components/schemas/DocumentMetadataList"
+ created_at:
+ $ref: "#/components/schemas/Timestamp"
+ updated_at:
+ $ref: "#/components/schemas/Timestamp"
+ required:
+ - id
+ - title
+ - documents_metadata
+ - created_at
+ - updated_at
+
+ Timestamp:
+ type: string
+ format: UTCISODateFromString
+ description: A date-time field in ISO-8601 format and UTC timezone.
+ x-import: "@pagopa/ts-commons/lib/dates"
+ example: "2018-10-13T00:00:00.000Z"
+
+ Id:
+ type: string
+ description: Entity Id
+ format: NonEmptyString
+ example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
+ x-import: "@pagopa/ts-commons/lib/strings"
+
+ FiscalCode:
+ type: string
+ description: User's fiscal code.
+ format: FiscalCode
+ x-import: "@pagopa/ts-commons/lib/strings"
+ example: SPNDNL80R13C555X
+
+ GetSignerByFiscalCodeBody:
+ type: object
+ properties:
+ fiscal_code:
+ $ref: "#/components/schemas/FiscalCode"
+ required:
+ - fiscal_code
+
+ SignerDetailView:
+ type: object
+ properties:
+ id:
+ $ref: "#/components/schemas/Id"
+ required:
+ - id
+
+ CreateSignatureRequestBody:
+ type: object
+ properties:
+ dossier_id:
+ $ref: "#/components/schemas/Id"
+ signer_id:
+ $ref: "#/components/schemas/Id"
+ expires_at:
+ $ref: "#/components/schemas/Timestamp"
+ required:
+ - dossier_id
+ - signer_id
+
+ Document:
+ type: object
+ properties:
+ id:
+ $ref: "#/components/schemas/Id"
+ metadata:
+ $ref: "#/components/schemas/DocumentMetadata"
+ created_at:
+ $ref: "#/components/schemas/Timestamp"
+ updated_at:
+ $ref: "#/components/schemas/Timestamp"
+ required:
+ - id
+ - metadata
+ - created_at
+ - updated_at
+
+ DocumentToBeUploaded:
+ allOf:
+ - $ref: "#/components/schemas/Document"
+ - type: object
+ properties:
+ status:
+ type: string
+ enum:
+ - WAIT_FOR_UPLOAD
+ required:
+ - status
+
+ DocumentToBeValidated:
+ allOf:
+ - $ref: "#/components/schemas/Document"
+ - type: object
+ properties:
+ status:
+ type: string
+ enum:
+ - WAIT_FOR_VALIDATION
+ uploaded_at:
+ $ref: "#/components/schemas/Timestamp"
+ required:
+ - status
+ - uploaded_at
+
+ DocumentReady:
+ allOf:
+ - $ref: "#/components/schemas/Document"
+ - type: object
+ properties:
+ status:
+ type: string
+ enum:
+ - READY
+ uploaded_at:
+ $ref: "#/components/schemas/Timestamp"
+ url:
+ type: string
+ format: uri
+ required:
+ - status
+ - uploaded_at
+ - url
+
+ DocumentRejected:
+ allOf:
+ - $ref: "#/components/schemas/Document"
+ - type: object
+ properties:
+ status:
+ type: string
+ enum:
+ - REJECTED
+ uploaded_at:
+ $ref: "#/components/schemas/Timestamp"
+ rejected_at:
+ $ref: "#/components/schemas/Timestamp"
+ reject_reason:
+ type: string
+ required:
+ - status
+ - uploaded_at
+ - rejected_at
+ - reject_reason
+
+ DocumentDetailView:
+ oneOf:
+ - $ref: "#/components/schemas/DocumentToBeUploaded"
+ - $ref: "#/components/schemas/DocumentToBeValidated"
+ - $ref: "#/components/schemas/DocumentReady"
+ - $ref: "#/components/schemas/DocumentRejected"
+
+ SignatureRequestStatus:
+ type: string
+ x-extensible-enum:
+ - DRAFT
+ - READY
+ - WAIT_FOR_SIGNATURE
+ - SIGNED
+ - REJECTED
+ - CANCELLED
+
+ SignatureRequestDetailView:
+ type: object
+ properties:
+ id:
+ $ref: "#/components/schemas/Id"
+ status:
+ $ref: "#/components/schemas/SignatureRequestStatus"
+ dossier_id:
+ $ref: "#/components/schemas/Id"
+ signer_id:
+ $ref: "#/components/schemas/Id"
+ expires_at:
+ $ref: "#/components/schemas/Timestamp"
+ documents:
+ type: array
+ items:
+ $ref: "#/components/schemas/DocumentDetailView"
+ notification:
+ $ref: "#/components/schemas/NotificationDetailView"
+ created_at:
+ $ref: "#/components/schemas/Timestamp"
+ updated_at:
+ $ref: "#/components/schemas/Timestamp"
+ signed_at:
+ $ref: "#/components/schemas/Timestamp"
+ rejected_at:
+ $ref: "#/components/schemas/Timestamp"
+ reject_reason:
+ type: string
+ qr_code_url:
+ type: string
+ format: uri
+ required:
+ - id
+ - status
+ - dossier_id
+ - signer_id
+ - expires_at
+ - documents
+ - created_at
+ - updated_at
+
+ SignatureRequestListView:
+ type: object
+ properties:
+ id:
+ $ref: "#/components/schemas/Id"
+ signer_id:
+ $ref: "#/components/schemas/Id"
+ dossier_id:
+ $ref: "#/components/schemas/Id"
+ status:
+ $ref: "#/components/schemas/SignatureRequestStatus"
+ created_at:
+ $ref: "#/components/schemas/Timestamp"
+ updated_at:
+ $ref: "#/components/schemas/Timestamp"
+ expires_at:
+ $ref: "#/components/schemas/Timestamp"
+ required:
+ - id
+ - signer_id
+ - dossier_id
+ - status
+ - created_at
+ - updated_at
+ - expires_at
+
+ SignatureRequestList:
+ type: object
+ properties:
+ items:
+ type: array
+ items:
+ $ref: "#/components/schemas/SignatureRequestListView"
+ continuation_token:
+ type: string
+ required:
+ - items
+
+ UploadUrl:
+ type: string
+ format: uri
+
+ NotificationDetailView:
+ type: object
+ properties:
+ io_message_id:
+ type: string
+ required:
+ - io_message_id
+
+ DocumentValidationResult:
+ type: object
+ properties:
+ is_valid:
+ type: boolean
+ violations:
+ type: array
+ items:
+ type: string
+ required:
+ - is_valid
diff --git a/infra/resources/prod/api/support/v1/base_policy.xml b/infra/resources/prod/api/support/v1/base_policy.xml
new file mode 100644
index 00000000..dd8b65dc
--- /dev/null
+++ b/infra/resources/prod/api/support/v1/base_policy.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+ {{io-fn-sign-support-key}}
+
+
+ @(context.Subscription.Id)
+
+
+
+ *
+
+
+ *
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/infra/resources/prod/api/support/v1/openapi.yaml b/infra/resources/prod/api/support/v1/openapi.yaml
new file mode 100644
index 00000000..fa78fd98
--- /dev/null
+++ b/infra/resources/prod/api/support/v1/openapi.yaml
@@ -0,0 +1,336 @@
+openapi: 3.0.3
+info:
+ title: Firma con IO - Support API
+ version: 1.0.0
+servers:
+ - url: https://api.io.pagopa.it/api/v1/sign/support
+ description: production
+ - url: http://localhost:7071/api/v1/sign/support
+ description: local
+paths:
+ /signature-requests/{id}:
+ post:
+ operationId: getSignatureRequestById
+ tags:
+ - signature request
+ summary: Find Signature Request by Id
+ requestBody:
+ $ref: "#/components/requestBodies/GetSignatureRequestById"
+ parameters:
+ - in: path
+ name: id
+ description: the signature request id
+ required: true
+ schema:
+ $ref: "#/components/schemas/Id"
+ responses:
+ 200:
+ description: the signature request
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SignatureRequest"
+ 400:
+ $ref: "#/components/responses/ValidationProblem"
+ 401:
+ $ref: "#/components/responses/HttpUnauthorized"
+ 404:
+ $ref: "#/components/responses/HttpNotFound"
+ 500:
+ $ref: "#/components/responses/HttpInternalServerError"
+
+components:
+ requestBodies:
+ GetSignatureRequestById:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/RequireFiscalCodeOrVatNumber"
+
+ responses:
+ HttpNotFound:
+ description: The specified resource was not found
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ title:
+ type: string
+ enum: ["Not found"]
+ status:
+ type: number
+ enum: [404]
+ required:
+ - title
+ - status
+
+ HttpInternalServerError:
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ title:
+ type: string
+ enum: ["Internal Server Error"]
+ status:
+ type: number
+ enum: [500]
+ detail:
+ type: string
+ required:
+ - title
+ - status
+
+ HttpUnauthorized:
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ title:
+ type: string
+ enum: ["Unauthorized"]
+ status:
+ type: number
+ enum: [401]
+ detail:
+ type: string
+ enum:
+ ["You must provide a valid API key to access this resource."]
+ required:
+ - title
+ - status
+ - detail
+
+ ValidationProblem:
+ description: Error on request validation
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ type:
+ type: string
+ enum: ["/problems/validation-error"]
+ title:
+ type: string
+ detail:
+ type: string
+ status:
+ type: number
+ enum: [400]
+ violations:
+ type: array
+ items:
+ type: string
+ required:
+ - type
+ - title
+ - detail
+ - status
+
+ schemas:
+ FiscalCode:
+ type: string
+ description: User's fiscal code.
+ format: FiscalCode
+ x-import: "@pagopa/ts-commons/lib/strings"
+ example: SPNDNL80R13C555X
+
+ Id:
+ type: string
+ description: Entity Id
+ format: NonEmptyString
+ example: 01ARZ3NDEKTSV4RRFFQ69G5FAV
+ x-import: "@pagopa/ts-commons/lib/strings"
+
+ Timestamp:
+ type: string
+ format: UTCISODateFromString
+ description: A date-time field in ISO-8601 format and UTC timezone.
+ x-import: "@pagopa/ts-commons/lib/dates"
+ example: "2018-10-13T00:00:00.000Z"
+
+ RequireFiscalCodeOrVatNumber:
+ oneOf:
+ - type: object
+ properties:
+ fiscal_code:
+ $ref: "#/components/schemas/FiscalCode"
+ required:
+ - fiscal_code
+ - type: object
+ properties:
+ vat_number:
+ type: string
+ required:
+ - vat_number
+
+ Clause:
+ type: object
+ properties:
+ title:
+ type: string
+ minLength: 5
+ maxLength: 80
+ type:
+ type: string
+ enum: ["REQUIRED", "UNFAIR", "OPTIONAL"]
+ required:
+ - title
+ - type
+
+ ExistingSignatureFieldAttrs:
+ type: object
+ properties:
+ unique_name:
+ type: string
+ required:
+ - unique_name
+
+ SignatureFieldToBeCreatedAttrs:
+ type: object
+ properties:
+ coordinates:
+ type: object
+ properties:
+ x: { type: number }
+ y: { type: number }
+ required: [x, y]
+ page:
+ type: number
+ minimum: 0
+ size:
+ type: object
+ properties:
+ w: { type: number, minimum: 0 }
+ h: { type: number, minimum: 0 }
+ required: [w, h]
+ required:
+ - coordinates
+ - page
+ - size
+
+ SignatureFieldAttrs:
+ oneOf:
+ - $ref: "#/components/schemas/ExistingSignatureFieldAttrs"
+ - $ref: "#/components/schemas/SignatureFieldToBeCreatedAttrs"
+
+ SignatureField:
+ type: object
+ properties:
+ attrs:
+ $ref: "#/components/schemas/SignatureFieldAttrs"
+ clause:
+ $ref: "#/components/schemas/Clause"
+ required:
+ - attrs
+ - clause
+
+ DocumentMetadata:
+ type: object
+ properties:
+ title:
+ type: string
+ minLength: 3
+ maxLength: 60
+ signature_fields:
+ type: array
+ items:
+ $ref: "#/components/schemas/SignatureField"
+ required:
+ - title
+
+ Document:
+ type: object
+ properties:
+ id:
+ $ref: "#/components/schemas/Id"
+ metadata:
+ $ref: "#/components/schemas/DocumentMetadata"
+ status:
+ type: string
+ enum:
+ - WAIT_FOR_UPLOAD
+ - WAIT_FOR_VALIDATION
+ - READY
+ - REJECTED
+ created_at:
+ $ref: "#/components/schemas/Timestamp"
+ url:
+ type: string
+ format: url
+ uploaded_at:
+ $ref: "#/components/schemas/Timestamp"
+ updated_at:
+ $ref: "#/components/schemas/Timestamp"
+ rejected_at:
+ $ref: "#/components/schemas/Timestamp"
+ reject_reason:
+ type: string
+ required:
+ - id
+ - metadata
+ - created_at
+ - status
+
+ Notification:
+ type: object
+ properties:
+ io_message_id:
+ $ref: "#/components/schemas/Id"
+ required:
+ - io_message_id
+
+ SignatureRequest:
+ type: object
+ properties:
+ id:
+ $ref: "#/components/schemas/Id"
+ issuer_id:
+ $ref: "#/components/schemas/Id"
+ signer_id:
+ $ref: "#/components/schemas/Id"
+ dossier_id:
+ $ref: "#/components/schemas/Id"
+ status:
+ type: string
+ enum:
+ - DRAFT
+ - READY
+ - WAIT_FOR_SIGNATURE
+ - WAIT_FOR_QTSP
+ - SIGNED
+ - REJECTED
+ created_at:
+ $ref: "#/components/schemas/Timestamp"
+ updated_at:
+ $ref: "#/components/schemas/Timestamp"
+ expires_at:
+ $ref: "#/components/schemas/Timestamp"
+ rejected_at:
+ $ref: "#/components/schemas/Timestamp"
+ signed_at:
+ $ref: "#/components/schemas/Timestamp"
+ reject_reason:
+ type: string
+ documents:
+ type: array
+ items:
+ $ref: "#/components/schemas/Document"
+ notification:
+ $ref: "#/components/schemas/Notification"
+ required:
+ - id
+ - issuer_id
+ - signer_id
+ - dossier_id
+ - status
+ - created_at
+ - updated_at
+ - expires_at
diff --git a/infra/resources/prod/api_product/backoffice/_base_policy.xml b/infra/resources/prod/api_product/backoffice/_base_policy.xml
new file mode 100644
index 00000000..85cf608b
--- /dev/null
+++ b/infra/resources/prod/api_product/backoffice/_base_policy.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/infra/resources/prod/api_product/sign/_base_policy.xml b/infra/resources/prod/api_product/sign/_base_policy.xml
new file mode 100644
index 00000000..69064bb4
--- /dev/null
+++ b/infra/resources/prod/api_product/sign/_base_policy.xml
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ https://{{io-sign-cosmosdb-name}}.documents.azure.com/dbs/{{io-sign-backoffice-database-name}}/colls/{{io-sign-backoffice-api-keys-collection-name}}/docs
+ POST
+
+ @{
+ var verb = "post";
+ var resourceType = "docs";
+ var resourceLink = "dbs/{{io-sign-backoffice-database-name}}/colls/{{io-sign-backoffice-api-keys-collection-name}}";
+ var key = "{{io-sign-cosmosdb-key}}";
+ var keyType = "master";
+ var tokenVersion = "1.0";
+ var date = context.Variables.GetValueOrDefault("requestDateString");
+
+ var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = Convert.FromBase64String(key) };
+
+ string payLoad = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n",
+ verb.ToLowerInvariant(),
+ resourceType.ToLowerInvariant(),
+ resourceLink,
+ date.ToLowerInvariant(),
+ ""
+ );
+
+ byte[] hashPayLoad = hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payLoad));
+ string signature = Convert.ToBase64String(hashPayLoad);
+
+ return System.Uri.EscapeDataString(String.Format("type={0}&ver={1}&sig={2}",
+ keyType,
+ tokenVersion,
+ signature));
+ }
+
+
+ application/query+json
+
+
+ True
+
+
+ True
+
+
+ @(context.Variables.GetValueOrDefault("requestDateString"))
+
+
+ 2018-12-31
+
+ @("{\"query\": \"SELECT w.cidrs FROM whitelist w WHERE w.id = @id\", " +
+ "\"parameters\": [{ \"name\": \"@id\", \"value\": \"" + context.Subscription.Id + "\"}]}")
+
+
+ ())" />
+
+
+
+
+
+
+
+ @{
+ int HostToNetworkOrder(int host) {
+ return (((int)HostToNetworkOrderShort((short)host) & 0xFFFF) << 16)
+ | ((int)HostToNetworkOrderShort((short)(host >> 16)) & 0xFFFF);
+ }
+ short HostToNetworkOrderShort(short host) {
+ return (short)((((int)host & 0xFF) << 8) | (int)((host >> 8) & 0xFF));
+ }
+
+ bool IsPrivate(string ipAddress)
+ {
+ int[] ipParts = ipAddress.Split(new String[] { "." }, StringSplitOptions.RemoveEmptyEntries)
+ .Select(s => int.Parse(s)).ToArray();
+ // in private ip range
+ if (ipParts[0] == 127 ||
+ ipParts[0] == 10 ||
+ (ipParts[0] == 192 && ipParts[1] == 168) ||
+ (ipParts[0] == 172 && (ipParts[1] >= 16 && ipParts[1] <= 31))) {
+ return true;
+ }
+
+ // IP Address is probably public.
+ // This doesn't catch some VPN ranges like OpenVPN and Hamachi.
+ return false;
+ }
+
+ /*
+ * If a request goes through multiple proxies, the IP addresses of each successive proxy is listed.
+ * This means that, given well-behaved client and proxies, the rightmost IP address is the IP address of the most recent proxy.
+ * For this reason we take the last IP in the list that is not a reserved IP
+ */
+ string GetRightmostIp(string[] ipAddressList){
+ for(int i = ipAddressList.Count()-1; i>=0; i--)
+ {
+ string ip = ipAddressList[i];
+ string ipAddress = String.Concat(ip.Where(c => !Char.IsWhiteSpace(c)));
+ if(!IsPrivate(ipAddress)){
+ return ipAddress;
+ }
+ }
+ return "127.0.0.1";
+ }
+
+ string forwardedFor = context.Request.Headers.GetValueOrDefault("x-forwarded-for","");
+ if (!string.IsNullOrEmpty(forwardedFor)) {
+ string[] ipAddressList = forwardedFor.Split(',');
+ string ipAddress = GetRightmostIp(ipAddressList);
+
+ string[] tokens = ipAddress.Split(':');
+ if(tokens.Length == 2) {
+ ipAddress = tokens[0];
+ }
+
+ var queryResponse = context.Variables.GetValueOrDefault("issuerWhitelist");
+ if (queryResponse != null && queryResponse.ContainsKey("Documents"))
+ {
+ JArray documents = (JArray) queryResponse["Documents"];
+ if (documents.Count > 0){
+ JObject firstDocument = (JObject) documents[0];
+ if(firstDocument.ContainsKey("cidrs")){
+ JArray whiteListCidrs = (JArray)firstDocument["cidrs"];
+ foreach (var cidr in whiteListCidrs) {
+ string cidrAddress = (string)cidr;
+ // Avoid checking in this case because all IPs are enabled
+ if(cidrAddress=="0.0.0.0/0"){
+ return "true";
+ }
+
+ string[] cidrParts = cidrAddress.Split('/');
+ string[] inputIPParts = ipAddress.Split('.');
+ string[] cidrIPArray = cidrParts[0].Split('.');
+
+ if (inputIPParts.Length == 4 && cidrIPArray.Length == 4) {
+ byte[] inputIPBytes = new byte[] {Convert.ToByte(int.Parse(inputIPParts[0])),
+ Convert.ToByte(int.Parse(inputIPParts[1])),
+ Convert.ToByte(int.Parse(inputIPParts[2])),
+ Convert.ToByte(int.Parse(inputIPParts[3])), };
+ byte[] cidrIPBytes = new byte[] {Convert.ToByte(int.Parse(cidrIPArray[0])),
+ Convert.ToByte(int.Parse(cidrIPArray[1])),
+ Convert.ToByte(int.Parse(cidrIPArray[2])),
+ Convert.ToByte(int.Parse(cidrIPArray[3])), };
+
+ int cidrAddr = BitConverter.ToInt32(inputIPBytes,0);
+ int ipAddr = BitConverter.ToInt32(cidrIPBytes,0);
+
+ var host = int.Parse(cidrParts[1]);
+ host = -1 << (32-host);
+ var mask = HostToNetworkOrder(host);
+
+ if (((ipAddr & mask) == (cidrAddr & mask))) {
+ return "true";
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return "false";
+ }
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/infra/resources/prod/api_product/support/_base_policy.xml b/infra/resources/prod/api_product/support/_base_policy.xml
new file mode 100644
index 00000000..85cf608b
--- /dev/null
+++ b/infra/resources/prod/api_product/support/_base_policy.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/infra/resources/prod/apim_v2.tf b/infra/resources/prod/apim_v2.tf
new file mode 100644
index 00000000..78917360
--- /dev/null
+++ b/infra/resources/prod/apim_v2.tf
@@ -0,0 +1,247 @@
+data "azurerm_api_management" "apim_v2_api" {
+ name = "io-p-apim-v2-api"
+ resource_group_name = "io-p-rg-internal"
+}
+
+resource "azurerm_api_management_named_value" "io_fn_sign_issuer_url_v2" {
+ name = "io-fn-sign-issuer-url"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-fn-sign-issuer-url"
+ value = format("https://%s-sign-issuer-func.azurewebsites.net", local.product)
+}
+
+resource "azurerm_api_management_named_value" "io_fn_sign_issuer_key_v2" {
+ name = "io-fn-sign-issuer-key"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-fn-sign-issuer-key"
+ value = module.key_vault_secrets.values["io-fn-sign-issuer-key"].value
+ secret = true
+}
+
+resource "azurerm_api_management_named_value" "io_fn_sign_support_url_v2" {
+ name = "io-fn-sign-support-url"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-fn-sign-support-url"
+ value = format("https://%s-sign-support-func.azurewebsites.net", local.product)
+}
+
+resource "azurerm_api_management_named_value" "io_fn_sign_support_key_v2" {
+ name = "io-fn-sign-support-key"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-fn-sign-support-key"
+ value = module.key_vault_secrets.values["io-fn-sign-support-key"].value
+ secret = true
+}
+
+
+resource "azurerm_api_management_named_value" "io_sign_cosmosdb_name_v2" {
+ name = "io-sign-cosmosdb-name"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-sign-cosmosdb-name"
+ value = module.cosmosdb_account.name
+ secret = false
+}
+
+resource "azurerm_api_management_named_value" "io_sign_cosmosdb_key_v2" {
+ name = "io-sign-cosmosdb-key"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-sign-cosmosdb-key"
+ value = module.cosmosdb_account.primary_readonly_key
+ secret = true
+}
+
+# legacy, it can be removed once the backoffice is released
+resource "azurerm_api_management_named_value" "io_sign_cosmosdb_issuer_container_name_v2" {
+ name = "io-sign-cosmosdb-issuer-container-name"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-sign-cosmosdb-issuer-container-name"
+ value = module.cosmosdb_sql_database_issuer.name
+ secret = false
+}
+resource "azurerm_api_management_named_value" "io_sign_cosmosdb_issuer_whitelist_collection_name_new_v2" {
+ name = "io-sign-cosmosdb-issuer-whitelist-collection-name"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-sign-cosmosdb-issuer-whitelist-collection-name"
+ value = module.cosmosdb_sql_container_issuer-issuers-whitelist.name
+ secret = false
+}
+resource "azurerm_api_management_named_value" "io_sign_cosmosdb_issuer_issuers_collection_name_v2" {
+ name = "io-sign-cosmosdb-issuer-issuers-name"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-sign-cosmosdb-issuer-issuers-name"
+ value = module.cosmosdb_sql_container_issuer-issuers.name
+ secret = false
+}
+# end legacy
+
+resource "azurerm_api_management_named_value" "backoffice-database-name" {
+ name = "io-sign-backoffice-database-name"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-sign-backoffice-database-name"
+ value = module.cosmosdb_sql_database_backoffice.name
+ secret = false
+}
+
+resource "azurerm_api_management_named_value" "backoffice-api-keys-collection-name" {
+ name = "io-sign-backoffice-api-keys-collection-name"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-sign-backoffice-api-keys-collection-name"
+ value = module.cosmosdb_sql_container_backoffice-api-keys.name
+ secret = false
+}
+
+module "apim_v2_io_sign_product" {
+ source = "github.com/pagopa/terraform-azurerm-v3//api_management_product?ref=v8.35.0"
+
+ product_id = "io-sign-api"
+ display_name = "IO SIGN API"
+ description = "Product for IO sign"
+
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+
+ published = true
+ subscription_required = true
+ approval_required = false
+
+ policy_xml = file("./api_product/sign/_base_policy.xml")
+}
+
+resource "azurerm_api_management_api_operation_policy" "get_signer_by_fiscal_code_policy_v2" {
+ api_name = module.apim_v2_io_sign_issuer_api_v1.name
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ operation_id = "getSignerByFiscalCode"
+
+ xml_content = file("./api/issuer/v1/get_signer_by_fiscal_code_policy/policy.xml")
+}
+
+module "apim_v2_io_sign_issuer_api_v1" {
+ source = "github.com/pagopa/terraform-azurerm-v3//api_management_api?ref=v8.35.0"
+
+ name = format("%s-sign-issuer-api", local.product)
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ product_ids = [module.apim_v2_io_sign_product.product_id]
+ subscription_required = true
+ service_url = null
+
+ description = "IO Sign - Issuer API"
+ display_name = "IO Sign - Issuer API"
+ path = "api/v1/sign"
+ protocols = ["https"]
+
+ content_format = "openapi"
+
+ content_value = file("./api/issuer/v1/openapi.yaml")
+
+ xml_content = file("./api/issuer/v1/base_policy.xml")
+}
+
+module "apim_v2_io_sign_support_product" {
+ source = "github.com/pagopa/terraform-azurerm-v3//api_management_product?ref=v8.35.0"
+
+ product_id = "io-sign-support-api"
+ display_name = "IO SIGN SUPPORT Product"
+ description = "Support Product for IO SIGN"
+
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+
+ published = true
+ subscription_required = true
+ approval_required = false
+
+ policy_xml = file("./api_product/support/_base_policy.xml")
+}
+
+module "apim_v2_io_sign_support_api_v1" {
+ source = "github.com/pagopa/terraform-azurerm-v3//api_management_api?ref=v8.35.0"
+
+ name = format("%s-sign-support-api", local.product)
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ product_ids = [module.apim_v2_io_sign_support_product.product_id]
+ subscription_required = true
+ service_url = null
+
+ description = "IO Sign - Support API"
+ display_name = "IO Sign - Support API"
+ path = "api/v1/sign/support"
+ protocols = ["https"]
+
+ content_format = "openapi"
+
+ content_value = file("./api/support/v1/openapi.yaml")
+
+ xml_content = file("./api/support/v1/base_policy.xml")
+}
+
+# BACK OFFICE
+
+resource "azurerm_api_management_named_value" "io_fn_sign_backoffice_url_v2" {
+ name = "io-fn-sign-backoffice-url"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-fn-sign-backoffice-url"
+ value = format("https://%s-sign-backoffice-func.azurewebsites.net", local.product)
+}
+
+resource "azurerm_api_management_named_value" "io_fn_sign_backoffice_key_v2" {
+ name = "io-fn-sign-backoffice-key"
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ display_name = "io-fn-sign-backoffice-key"
+ value = module.key_vault_secrets.values["io-sign-backoffice-func-key"].value
+ secret = true
+}
+
+module "apim_v2_io_sign_backoffice_product" {
+ source = "github.com/pagopa/terraform-azurerm-v3//api_management_product?ref=v8.35.0"
+
+ product_id = format("%s-sign-backoffice-apim-product", local.product)
+ display_name = "IO SIGN BACKOFFICE"
+ description = "Api Management product for io-sign-backoffice REST APIs"
+
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+
+ published = true
+ subscription_required = true
+ approval_required = false
+
+ policy_xml = file("./api_product/backoffice/_base_policy.xml")
+}
+
+module "apim_v2_io_sign_backoffice_api_v1" {
+ source = "github.com/pagopa/terraform-azurerm-v3//api_management_api?ref=v8.35.0"
+
+ name = format("%s-sign-backoffice-apim-api", local.product)
+ api_management_name = data.azurerm_api_management.apim_v2_api.name
+ resource_group_name = data.azurerm_api_management.apim_v2_api.resource_group_name
+ product_ids = [module.apim_v2_io_sign_backoffice_product.product_id]
+ subscription_required = true
+ service_url = null
+
+ display_name = "IO SIGN BACKOFFICE API"
+ description = "io-sign-backoffice REST APIs"
+
+ path = "api/v1/sign/backoffice"
+ protocols = ["https"]
+
+ content_format = "openapi"
+ content_value = file("../../../apps/io-sign-backoffice-func/openapi.yaml")
+
+ xml_content = file("./api/backoffice/v1/base_policy.xml")
+}
diff --git a/infra/resources/prod/azuread.tf b/infra/resources/prod/azuread.tf
new file mode 100644
index 00000000..099ca18d
--- /dev/null
+++ b/infra/resources/prod/azuread.tf
@@ -0,0 +1,22 @@
+# Azure AD
+data "azuread_group" "adgroup_admin" {
+ display_name = format("%s-adgroup-admin", local.product)
+}
+
+data "azuread_group" "adgroup_developers" {
+ display_name = format("%s-adgroup-developers", local.product)
+}
+
+# tflint-ignore: terraform_unused_declarations
+data "azuread_group" "adgroup_externals" {
+ display_name = format("%s-adgroup-externals", local.product)
+}
+
+# tflint-ignore: terraform_unused_declarations
+data "azuread_group" "adgroup_security" {
+ display_name = format("%s-adgroup-security", local.product)
+}
+
+data "azuread_group" "adgroup_sign" {
+ display_name = format("%s-adgroup-sign", local.product)
+}
diff --git a/infra/resources/prod/cosmos.tf b/infra/resources/prod/cosmos.tf
new file mode 100644
index 00000000..623db840
--- /dev/null
+++ b/infra/resources/prod/cosmos.tf
@@ -0,0 +1,33 @@
+module "cosmosdb_account" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_account?ref=v8.35.0"
+ name = format("%s-cosmos", local.project)
+ domain = var.domain
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ kind = "GlobalDocumentDB"
+ main_geo_location_location = azurerm_resource_group.data_rg.location
+ main_geo_location_zone_redundant = var.cosmos.zone_redundant
+
+ additional_geo_locations = var.cosmos.additional_geo_locations
+
+ # Having multiple region requires
+ # maximum lag must be between 5 minutes and 1 day
+ # and between 100000 operations and 1000000 operations
+ consistency_policy = {
+ consistency_level = "BoundedStaleness"
+ max_interval_in_seconds = 300
+ max_staleness_prefix = 100000
+ }
+
+ public_network_access_enabled = false
+
+ is_virtual_network_filter_enabled = true
+
+ private_endpoint_enabled = true
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+ private_dns_zone_sql_ids = [data.azurerm_private_dns_zone.privatelink_documents_azure_com.id]
+ private_endpoint_sql_name = "${local.project}-cosmos"
+ private_service_connection_sql_name = "${local.project}-cosmos-private-endpoint"
+
+ tags = var.tags
+}
diff --git a/infra/resources/prod/cosmos_backoffice.tf b/infra/resources/prod/cosmos_backoffice.tf
new file mode 100644
index 00000000..c8e742d4
--- /dev/null
+++ b/infra/resources/prod/cosmos_backoffice.tf
@@ -0,0 +1,68 @@
+module "cosmosdb_sql_database_backoffice" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_database?ref=v8.35.0"
+ name = "backoffice"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+}
+
+module "cosmosdb_sql_container_backoffice-api-keys" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "api-keys"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_backoffice.name
+ partition_key_path = "/institutionId"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_backoffice.api_keys.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_backoffice.api_keys.ttl
+}
+
+module "cosmosdb_sql_container_backoffice-api-keys-by-id" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "api-keys-by-id"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_backoffice.name
+ partition_key_path = "/id"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_backoffice.api_keys_by_id.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_backoffice.api_keys_by_id.ttl
+}
+
+module "cosmosdb_sql_container_backoffice-issuers" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "issuers"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_backoffice.name
+ partition_key_path = "/institutionId"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_backoffice.issuers.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_backoffice.issuers.ttl
+}
+
+module "cosmosdb_sql_container_backoffice-consents" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "consents"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_backoffice.name
+ partition_key_path = "/institutionId"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_backoffice.consents.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_backoffice.consents.ttl
+}
+
+
diff --git a/infra/resources/prod/cosmos_issuer.tf b/infra/resources/prod/cosmos_issuer.tf
new file mode 100644
index 00000000..218e6ffe
--- /dev/null
+++ b/infra/resources/prod/cosmos_issuer.tf
@@ -0,0 +1,111 @@
+module "cosmosdb_sql_database_issuer" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_database?ref=v8.35.0"
+ name = "issuer"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+}
+
+module "cosmosdb_sql_container_issuer-dossiers" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "dossiers"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_issuer.name
+ partition_key_path = "/issuerId"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_issuer.dossiers.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_issuer.dossiers.ttl
+}
+
+module "cosmosdb_sql_container_issuer-signature-requests" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "signature-requests"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_issuer.name
+ partition_key_path = "/issuerId"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_issuer.signature_requests.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_issuer.signature_requests.ttl
+}
+
+module "cosmosdb_sql_container_issuer-uploads" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "uploads"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_issuer.name
+ partition_key_path = "/id"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_issuer.uploads.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_issuer.uploads.ttl
+}
+
+module "cosmosdb_sql_container_issuer-issuers" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "issuers"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_issuer.name
+ partition_key_path = "/subscriptionId"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_issuer.uploads.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_issuer.issuers.ttl
+}
+
+module "cosmosdb_sql_container_issuer-issuers-by-vat-number" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "issuers-by-vat-number"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_issuer.name
+ partition_key_path = "/id"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_issuer.uploads.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_issuer.issuers.ttl
+}
+
+module "cosmosdb_sql_container_issuer-issuers-by-subscription-id" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "issuers-by-subscription-id"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_issuer.name
+ partition_key_path = "/id"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_issuer.uploads.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_issuer.issuers.ttl
+}
+
+module "cosmosdb_sql_container_issuer-issuers-whitelist" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "issuers-whitelist"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_issuer.name
+ partition_key_path = "/id"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_issuer.uploads.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_issuer.issuers.ttl
+}
diff --git a/infra/resources/prod/cosmos_user.tf b/infra/resources/prod/cosmos_user.tf
new file mode 100644
index 00000000..865974a2
--- /dev/null
+++ b/infra/resources/prod/cosmos_user.tf
@@ -0,0 +1,36 @@
+module "cosmosdb_sql_database_user" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_database?ref=v8.35.0"
+ name = "user"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+}
+
+module "cosmosdb_sql_container_user-signature-requests" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "signature-requests"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_user.name
+ partition_key_path = "/signerId"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_user.signature_requests.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_user.signature_requests.ttl
+}
+
+module "cosmosdb_sql_container_user-signatures" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cosmosdb_sql_container?ref=v8.35.0"
+ name = "signatures"
+ resource_group_name = azurerm_resource_group.data_rg.name
+ account_name = module.cosmosdb_account.name
+ database_name = module.cosmosdb_sql_database_user.name
+ partition_key_path = "/signerId"
+
+ autoscale_settings = {
+ max_throughput = var.io_sign_database_user.signatures.max_throughput
+ }
+
+ default_ttl = var.io_sign_database_user.signatures.ttl
+}
diff --git a/infra/resources/prod/dns.tf b/infra/resources/prod/dns.tf
new file mode 100644
index 00000000..7ad38363
--- /dev/null
+++ b/infra/resources/prod/dns.tf
@@ -0,0 +1,68 @@
+resource "azurerm_dns_zone" "firma_io_pagopa_it" {
+ count = var.env_short == "p" ? 1 : 0
+
+ name = var.dns_zone_names.website
+ resource_group_name = azurerm_resource_group.integration_rg.name
+
+ tags = var.tags
+}
+
+resource "azurerm_dns_mx_record" "ses_mx_firma_io_pagopa_it" {
+ name = "@"
+ zone_name = azurerm_dns_zone.firma_io_pagopa_it[0].name
+ resource_group_name = azurerm_resource_group.integration_rg.name
+ ttl = var.dns_default_ttl_sec
+
+ record {
+ preference = 10
+ exchange = "inbound-smtp.eu-west-1.amazonaws.com."
+ }
+}
+
+resource "azurerm_dns_cname_record" "ses_validation_firma_io_pagopa_it" {
+ for_each = { for v in var.dns_ses_validation : v.name => v }
+
+ name = each.value.name
+ record = each.value.record
+ zone_name = azurerm_dns_zone.firma_io_pagopa_it[0].name
+ resource_group_name = azurerm_resource_group.integration_rg.name
+ ttl = var.dns_default_ttl_sec
+}
+
+resource "azurerm_dns_txt_record" "spf1_mailup_firma_io_pagopa_it" {
+ name = "@"
+ zone_name = azurerm_dns_zone.firma_io_pagopa_it[0].name
+ resource_group_name = azurerm_resource_group.integration_rg.name
+ ttl = var.dns_default_ttl_sec
+
+ record {
+ value = "v=spf1 include:musvc.com -all"
+ }
+}
+
+resource "azurerm_dns_cname_record" "dkim1_mailup_firma_io_pagopa_it" {
+ name = "ml01._domainkey"
+ record = "ml01.dkim.musvc.com."
+ zone_name = azurerm_dns_zone.firma_io_pagopa_it[0].name
+ resource_group_name = azurerm_resource_group.integration_rg.name
+ ttl = var.dns_default_ttl_sec
+}
+
+resource "azurerm_dns_cname_record" "dkim2_mailup_firma_io_pagopa_it" {
+ name = "ml02._domainkey"
+ record = "ml02.dkim.musvc.com."
+ zone_name = azurerm_dns_zone.firma_io_pagopa_it[0].name
+ resource_group_name = azurerm_resource_group.integration_rg.name
+ ttl = var.dns_default_ttl_sec
+}
+
+resource "azurerm_dns_txt_record" "dmarc_mailup_firma_io_pagopa_it" {
+ name = "_dmarc"
+ zone_name = azurerm_dns_zone.firma_io_pagopa_it[0].name
+ resource_group_name = azurerm_resource_group.integration_rg.name
+ ttl = var.dns_default_ttl_sec
+
+ record {
+ value = "v=DMARC1; p=reject; pct=100; adkim=s; aspf=s"
+ }
+}
\ No newline at end of file
diff --git a/infra/resources/prod/integration.tf b/infra/resources/prod/integration.tf
new file mode 100644
index 00000000..f29c9def
--- /dev/null
+++ b/infra/resources/prod/integration.tf
@@ -0,0 +1,125 @@
+# Needed to integrate Firma con IO with external domains, products or platforms (ie. eventhub for billing, ...)
+module "event_hub" {
+ source = "github.com/pagopa/terraform-azurerm-v3//eventhub?ref=v8.35.0"
+ name = format("%s-eventhub-ns", local.project)
+ location = azurerm_resource_group.integration_rg.location
+ resource_group_name = azurerm_resource_group.integration_rg.name
+ auto_inflate_enabled = var.integration_hub.auto_inflate_enabled
+ sku = var.integration_hub.sku_name
+ capacity = var.integration_hub.capacity
+ maximum_throughput_units = var.integration_hub.maximum_throughput_units
+ zone_redundant = var.integration_hub.zone_redundant
+
+ virtual_network_ids = [data.azurerm_virtual_network.vnet_common.id]
+
+ private_dns_zone_record_A_name = null
+
+ eventhubs = var.integration_hub.hubs
+
+ # Configuration in accordance to the inttegration defined at
+ # https://pagopa.atlassian.net/wiki/search?text=firma%20con%20io%20fatturazione
+ public_network_access_enabled = true
+
+ network_rulesets = [
+ {
+ default_action = "Deny",
+ virtual_network_rule = [
+ {
+ subnet_id = module.io_sign_eventhub_snet.id,
+ ignore_missing_virtual_network_service_endpoint = false
+ }
+ ],
+ ip_rule = var.integration_hub.ip_rules
+ trusted_service_access_enabled = false
+ }
+ ]
+
+ private_endpoint_created = true
+ private_dns_zones = {
+ id = [data.azurerm_private_dns_zone.privatelink_servicebus_windows_net.id]
+ name = [data.azurerm_private_dns_zone.privatelink_servicebus_windows_net.name]
+ resource_group_name = data.azurerm_private_dns_zone.privatelink_servicebus_windows_net.resource_group_name
+ }
+ private_endpoint_resource_group_name = azurerm_resource_group.integration_rg.name
+ private_endpoint_subnet_id = module.io_sign_eventhub_snet.id
+
+ alerts_enabled = var.integration_hub.alerts_enabled
+ metric_alerts = {
+ no_trx = {
+ aggregation = "Total"
+ metric_name = "IncomingMessages"
+ description = "No transactions received from acquirer in the last 24h"
+ operator = "LessThanOrEqual"
+ threshold = 1000
+ frequency = "PT1H"
+ window_size = "P1D"
+ dimension = [
+ {
+ name = "EntityName"
+ operator = "Include"
+ values = ["rtd-trx"]
+ }
+ ],
+ },
+ active_connections = {
+ aggregation = "Average"
+ metric_name = "ActiveConnections"
+ description = null
+ operator = "LessThanOrEqual"
+ threshold = 0
+ frequency = "PT5M"
+ window_size = "PT15M"
+ dimension = [],
+ },
+ error_trx = {
+ aggregation = "Total"
+ metric_name = "IncomingMessages"
+ description = "Transactions rejected from one acquirer file received. trx write on eventhub. check immediately"
+ operator = "GreaterThan"
+ threshold = 0
+ frequency = "PT5M"
+ window_size = "PT30M"
+ dimension = [
+ {
+ name = "EntityName"
+ operator = "Include"
+ values = [
+ "bpd-trx-error",
+ "rtd-trx-error"
+ ]
+ }
+ ],
+ },
+ }
+
+ action = [
+ {
+ action_group_id = data.azurerm_monitor_action_group.error_action_group.id
+ webhook_properties = null
+ }
+ ]
+
+ tags = var.tags
+}
+
+#tfsec:ignore:AZU023
+resource "azurerm_key_vault_secret" "integration_event_hub_secrets" {
+ for_each = module.event_hub.key_ids
+
+ name = format("%s-integration-evthub-key", replace(each.key, ".", "-"))
+ value = module.event_hub.keys[each.key].primary_key
+ content_type = "text/plain"
+
+ key_vault_id = module.key_vault.id
+}
+
+#tfsec:ignore:AZU023
+resource "azurerm_key_vault_secret" "integration_event_hub_jaas_connection_string" {
+ for_each = module.event_hub.key_ids
+
+ name = format("%s-integration-evthub-conn-string", replace(each.key, ".", "-"))
+ value = "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"$ConnectionString\" password=\"${module.event_hub.keys[each.key].primary_connection_string}\";"
+ content_type = "text/plain"
+
+ key_vault_id = module.key_vault.id
+}
diff --git a/infra/resources/prod/io_sign_backoffice_app.tf b/infra/resources/prod/io_sign_backoffice_app.tf
new file mode 100644
index 00000000..8a6d97c0
--- /dev/null
+++ b/infra/resources/prod/io_sign_backoffice_app.tf
@@ -0,0 +1,192 @@
+locals {
+ backoffice_app_settings = merge({
+ AZURE_SUBSCRIPTION_ID = data.azurerm_subscription.current.subscription_id
+ COSMOS_DB_CONNECTION_STRING = module.cosmosdb_account.connection_strings[0],
+ COSMOS_DB_NAME = module.cosmosdb_sql_database_backoffice.name
+ APIM_RESOURCE_GROUP_NAME = data.azurerm_api_management.apim_v2_api.resource_group_name,
+ APIM_SERVICE_NAME = data.azurerm_api_management.apim_v2_api.name,
+ APIM_PRODUCT_NAME = module.apim_v2_io_sign_product.product_id
+ APPINSIGHTS_INSTRUMENTATIONKEY = sensitive(data.azurerm_application_insights.application_insights.instrumentation_key)
+ },
+ {
+ for s in var.io_sign_backoffice_app.app_settings :
+ s.name => s.key_vault_secret_name != null ? "@Microsoft.KeyVault(VaultName=${module.key_vault.name};SecretName=${s.key_vault_secret_name})" : s.value
+ })
+}
+
+module "io_sign_backoffice_snet" {
+ source = "github.com/pagopa/terraform-azurerm-v3//subnet?ref=v8.35.0"
+ name = format("%s-backoffice-snet", local.project)
+ resource_group_name = data.azurerm_virtual_network.vnet_common.resource_group_name
+ virtual_network_name = data.azurerm_virtual_network.vnet_common.name
+ address_prefixes = var.subnets_cidrs.backoffice
+
+ private_endpoint_network_policies_enabled = false
+
+ service_endpoints = [
+ "Microsoft.Web",
+ "Microsoft.AzureCosmosDB",
+ ]
+
+ delegation = {
+ name = "default"
+ service_delegation = {
+ name = "Microsoft.Web/serverFarms"
+ actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
+ }
+ }
+}
+
+data "azurerm_subnet" "appgateway_snet" {
+ name = var.io_common.appgateway_snet_name
+ virtual_network_name = var.io_common.vnet_common_name
+ resource_group_name = var.io_common.resource_group_name
+}
+
+module "io_sign_backoffice_app" {
+ source = "github.com/pagopa/terraform-azurerm-v3//app_service?ref=v8.35.0"
+
+ name = format("%s-backoffice-app", local.project)
+ location = azurerm_resource_group.backend_rg.location
+ resource_group_name = azurerm_resource_group.backend_rg.name
+
+ plan_name = format("%s-backoffice-plan", local.project)
+ sku_name = var.io_sign_backoffice_app.sku_name
+
+ node_version = "18-lts"
+ health_check_path = "/health"
+ app_command_line = "node server.js"
+
+ app_settings = local.backoffice_app_settings
+
+ always_on = true
+ vnet_integration = true
+
+ subnet_id = module.io_sign_backoffice_snet.id
+
+ allowed_subnets = [
+ data.azurerm_subnet.appgateway_snet.id,
+ data.azurerm_subnet.apim_v2.id
+ ]
+
+ ip_restriction_default_action = "Deny"
+
+ tags = var.tags
+}
+
+resource "azurerm_key_vault_access_policy" "backoffice_key_vault_access_policy" {
+ key_vault_id = module.key_vault.id
+ tenant_id = data.azurerm_client_config.current.tenant_id
+ object_id = module.io_sign_backoffice_app.principal_id
+
+ secret_permissions = ["Get"]
+ storage_permissions = []
+ certificate_permissions = []
+}
+
+resource "azurerm_role_assignment" "firmaconio_selfcare_apim_contributor_role" {
+ scope = data.azurerm_api_management.apim_v2_api.id
+ role_definition_name = "API Management Service Contributor"
+ principal_id = module.io_sign_backoffice_app.principal_id
+}
+
+resource "azurerm_role_assignment" "backoffice_app_api_keys_queue_sender_role" {
+ scope = azurerm_storage_queue.api_keys.resource_manager_id
+ role_definition_name = "Storage Queue Data Message Sender"
+ principal_id = module.io_sign_backoffice_app.principal_id
+}
+
+resource "azurerm_private_endpoint" "io_sign_backoffice_app" {
+ name = format("%s-backoffice-endpoint", local.project)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-backoffice-endpoint", local.project)
+ private_connection_resource_id = module.io_sign_backoffice_app.id
+ is_manual_connection = false
+ subresource_names = ["sites"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_azurewebsites_net.id]
+ }
+
+ tags = var.tags
+}
+
+module "io_sign_backoffice_app_staging_slot" {
+ source = "github.com/pagopa/terraform-azurerm-v3//app_service_slot?ref=v8.35.0"
+
+ name = "staging"
+ location = azurerm_resource_group.backend_rg.location
+ resource_group_name = azurerm_resource_group.backend_rg.name
+
+ app_service_id = module.io_sign_backoffice_app.id
+ app_service_name = module.io_sign_backoffice_app.name
+
+ node_version = "18-lts"
+ health_check_path = "/health"
+ app_command_line = "node server.js"
+
+ app_settings = local.backoffice_app_settings
+
+ always_on = true
+ vnet_integration = true
+
+ subnet_id = module.io_sign_backoffice_snet.id
+
+ allowed_subnets = [
+ data.azurerm_subnet.appgateway_snet.id,
+ data.azurerm_subnet.apim_v2.id
+ ]
+
+ ip_restriction_default_action = "Deny"
+
+ tags = var.tags
+}
+
+resource "azurerm_key_vault_access_policy" "backoffice_staging_key_vault_access_policy" {
+ key_vault_id = module.key_vault.id
+ tenant_id = data.azurerm_client_config.current.tenant_id
+ object_id = module.io_sign_backoffice_app_staging_slot.principal_id
+
+ secret_permissions = ["Get"]
+ storage_permissions = []
+ certificate_permissions = []
+}
+
+resource "azurerm_role_assignment" "firmaconio_selfcare_staging_apim_contributor_role" {
+ scope = data.azurerm_api_management.apim_v2_api.id
+ role_definition_name = "API Management Service Contributor"
+ principal_id = module.io_sign_backoffice_app_staging_slot.principal_id
+}
+
+resource "azurerm_role_assignment" "backoffice_app_staging_api_keys_queue_sender_role" {
+ scope = azurerm_storage_queue.api_keys.resource_manager_id
+ role_definition_name = "Storage Queue Data Message Sender"
+ principal_id = module.io_sign_backoffice_app_staging_slot.principal_id
+}
+
+resource "azurerm_private_endpoint" "io_sign_backoffice_app_staging_slot" {
+ name = format("%s-backoffice-staging-endpoint", local.project)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-backoffice-staging-endpoint", local.project)
+ private_connection_resource_id = module.io_sign_backoffice_app.id
+ is_manual_connection = false
+ subresource_names = ["sites-staging"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_azurewebsites_net.id]
+ }
+
+ tags = var.tags
+}
diff --git a/infra/resources/prod/io_sign_backoffice_func.tf b/infra/resources/prod/io_sign_backoffice_func.tf
new file mode 100644
index 00000000..ef70de8d
--- /dev/null
+++ b/infra/resources/prod/io_sign_backoffice_func.tf
@@ -0,0 +1,117 @@
+locals {
+ backoffice_func_settings = merge({
+ COSMOS_DB_CONNECTION_STRING = module.cosmosdb_account.connection_strings[0],
+ COSMOS_DB_NAME = module.cosmosdb_sql_database_backoffice.name
+ }, {
+ for s in var.io_sign_backoffice_func.app_settings :
+ s.name => s.key_vault_secret_name != null ? "@Microsoft.KeyVault(VaultName=${module.key_vault.name};SecretName=${s.key_vault_secret_name})" : s.value
+ })
+ io_sign_backoffice_func = {
+ staging_disabled = ["onSelfcareContractsMessage"]
+ }
+}
+
+module "io_sign_backoffice_func" {
+ source = "github.com/pagopa/terraform-azurerm-v3//function_app?ref=v8.35.0"
+
+ name = format("%s-backoffice-func", local.project)
+ location = azurerm_resource_group.backend_rg.location
+ resource_group_name = azurerm_resource_group.backend_rg.name
+
+ health_check_path = "/health"
+ health_check_maxpingfailures = 2
+
+ node_version = "18"
+ runtime_version = "~4"
+ always_on = true
+
+ app_settings = local.backoffice_func_settings
+
+ subnet_id = module.io_sign_backoffice_snet.id
+
+ sticky_app_setting_names = [
+ for to_disable in local.io_sign_backoffice_func.staging_disabled :
+ format("AzureWebJobs.%s.Disabled", to_disable)
+ ]
+
+ allowed_subnets = [
+ module.io_sign_snet.id
+ ]
+
+ app_service_plan_id = module.io_sign_backoffice_app.plan_id
+
+ application_insights_instrumentation_key = data.azurerm_application_insights.application_insights.instrumentation_key
+ system_identity_enabled = true
+
+ tags = var.tags
+}
+
+resource "azurerm_private_endpoint" "io_sign_backoffice_func" {
+ name = format("%s-backoffice-func-endpoint", local.project)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-backoffice-endpoint", local.project)
+ private_connection_resource_id = module.io_sign_backoffice_func.id
+ is_manual_connection = false
+ subresource_names = ["sites"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_azurewebsites_net.id]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_key_vault_access_policy" "backoffice_func_key_vault_access_policy" {
+ key_vault_id = module.key_vault.id
+ tenant_id = data.azurerm_client_config.current.tenant_id
+ object_id = module.io_sign_backoffice_func.system_identity_principal
+
+ secret_permissions = ["Get"]
+ storage_permissions = []
+ certificate_permissions = []
+}
+
+module "io_sign_backoffice_func_staging_slot" {
+ source = "github.com/pagopa/terraform-azurerm-v3//function_app_slot?ref=v8.35.0"
+
+ name = "staging"
+ location = azurerm_resource_group.backend_rg.location
+ resource_group_name = azurerm_resource_group.backend_rg.name
+
+ function_app_id = module.io_sign_backoffice_func.id
+ app_service_plan_id = module.io_sign_backoffice_func.app_service_plan_id
+
+ health_check_path = "/health"
+ health_check_maxpingfailures = 2
+
+ storage_account_name = module.io_sign_backoffice_func.storage_account.name
+ storage_account_access_key = module.io_sign_backoffice_func.storage_account.primary_access_key
+
+ node_version = "18"
+ runtime_version = "~4"
+ always_on = true
+ application_insights_instrumentation_key = data.azurerm_application_insights.application_insights.instrumentation_key
+
+ app_settings = merge(
+ local.backoffice_func_settings,
+ {
+ # Disabled functions on slot triggered by queue and timer
+ for to_disable in local.io_sign_backoffice_func.staging_disabled :
+ format("AzureWebJobs.%s.Disabled", to_disable) => "true"
+ }
+ )
+
+ subnet_id = module.io_sign_backoffice_snet.id
+
+ allowed_subnets = [
+ module.io_sign_snet.id
+ ]
+
+ tags = var.tags
+}
diff --git a/infra/resources/prod/io_sign_issuer_func.tf b/infra/resources/prod/io_sign_issuer_func.tf
new file mode 100644
index 00000000..67665544
--- /dev/null
+++ b/infra/resources/prod/io_sign_issuer_func.tf
@@ -0,0 +1,240 @@
+locals {
+ io_sign_issuer_func = {
+ staging_disabled = [
+ "MarkAsRejected",
+ "MarkAsSigned",
+ "MarkAsWaitForSignature",
+ "ValidateUpload",
+ "CreateIssuer",
+ "CreateIssuerByVatNumberView"
+ ]
+ disabled = [
+ "CreateIssuer"
+ ]
+ app_settings = {
+ FUNCTIONS_WORKER_PROCESS_COUNT = 4
+ AzureWebJobsDisableHomepage = "true"
+ NODE_ENV = "production"
+ CosmosDbConnectionString = module.cosmosdb_account.connection_strings[0]
+ CosmosDbDatabaseName = module.cosmosdb_sql_database_issuer.name
+ StorageAccountConnectionString = module.io_sign_storage.primary_connection_string
+ IssuerUploadedBlobContainerName = azurerm_storage_container.uploaded_documents.name
+ IssuerValidatedBlobContainerName = azurerm_storage_container.validated_documents.name
+ IoServicesApiBasePath = "https://api.io.pagopa.it"
+ IoServicesSubscriptionKey = module.key_vault_secrets.values["IoServicesSubscriptionKey"].value
+ IoServicesConfigurationId = module.key_vault_secrets.values["io-services-configuration-id"].value
+ PdvTokenizerApiBasePath = "https://api.tokenizer.pdv.pagopa.it"
+ PdvTokenizerApiKey = module.key_vault_secrets.values["PdvTokenizerApiKey"].value
+ AnalyticsEventHubConnectionString = module.event_hub.keys["analytics.io-sign-func-issuer"].primary_connection_string
+ BillingEventHubConnectionString = module.event_hub.keys["billing.io-sign-func-issuer"].primary_connection_string
+ SelfCareEventHubConnectionString = module.key_vault_secrets.values["SelfCareEventHubConnectionString"].value
+ SelfCareApiBasePath = "https://api.selfcare.pagopa.it"
+ SelfCareApiKey = module.key_vault_secrets.values["SelfCareApiKey"].value
+ SlackWebhookUrl = module.key_vault_secrets.values["SlackWebhookUrl"].value
+ BackOfficeApiBasePath = "https://api.io.pagopa.it/api/v1/sign/backoffice"
+ BackOfficeApiKey = module.key_vault_secrets.values["BackOfficeApiKey"].value
+ }
+ }
+}
+
+module "io_sign_issuer_func" {
+ source = "github.com/pagopa/terraform-azurerm-v3//function_app?ref=v8.35.0"
+
+ name = format("%s-issuer-func", local.project)
+ location = azurerm_resource_group.backend_rg.location
+ resource_group_name = azurerm_resource_group.backend_rg.name
+
+ health_check_path = "/api/v1/sign/info"
+ health_check_maxpingfailures = 2
+
+ node_version = "18"
+ runtime_version = "~4"
+ always_on = true
+
+ app_service_plan_info = {
+ kind = "Linux"
+ sku_size = var.io_sign_issuer_func.sku_size
+ maximum_elastic_worker_count = 0
+ worker_count = 1
+ zone_balancing_enabled = false
+ }
+
+ app_settings = merge(
+ local.io_sign_issuer_func.app_settings,
+ {
+ # Enable functions on production triggered by queue and timer
+ for to_disable in local.io_sign_issuer_func.staging_disabled :
+ format("AzureWebJobs.%s.Disabled", to_disable) => contains(local.io_sign_issuer_func.disabled, to_disable) ? "true" : "false"
+ }
+ )
+
+ sticky_app_setting_names = [
+ # Sticky the settings enabling triggered by queue and timer
+ for to_disable in local.io_sign_issuer_func.staging_disabled :
+ format("AzureWebJobs.%s.Disabled", to_disable)
+ ]
+
+ subnet_id = module.io_sign_snet.id
+ allowed_subnets = [
+ module.io_sign_snet.id,
+ data.azurerm_subnet.apim_v2.id,
+ ]
+
+ application_insights_instrumentation_key = data.azurerm_application_insights.application_insights.instrumentation_key
+ system_identity_enabled = true
+
+ tags = var.tags
+}
+
+resource "azurerm_role_assignment" "issuer_func_api_keys_queue_processor_role" {
+ scope = azurerm_storage_queue.api_keys.resource_manager_id
+ role_definition_name = "Storage Queue Data Message Processor"
+ principal_id = module.io_sign_issuer_func.system_identity_principal
+}
+
+module "io_sign_issuer_func_staging_slot" {
+ count = var.io_sign_issuer_func.sku_tier == "PremiumV3" ? 1 : 0
+ source = "github.com/pagopa/terraform-azurerm-v3//function_app_slot?ref=v8.35.0"
+
+ name = "staging"
+ location = azurerm_resource_group.backend_rg.location
+ resource_group_name = azurerm_resource_group.backend_rg.name
+ function_app_id = module.io_sign_issuer_func.id
+ app_service_plan_id = module.io_sign_issuer_func.app_service_plan_id
+
+ health_check_path = "/api/v1/sign/info"
+ health_check_maxpingfailures = 2
+
+ storage_account_name = module.io_sign_issuer_func.storage_account.name
+ storage_account_access_key = module.io_sign_issuer_func.storage_account.primary_access_key
+
+ node_version = "18"
+ runtime_version = "~4"
+ always_on = true
+ application_insights_instrumentation_key = data.azurerm_application_insights.application_insights.instrumentation_key
+
+ app_settings = merge(
+ local.io_sign_issuer_func.app_settings,
+ {
+ # Disabled functions on slot triggered by queue and timer
+ for to_disable in local.io_sign_issuer_func.staging_disabled :
+ format("AzureWebJobs.%s.Disabled", to_disable) => "true"
+ }
+ )
+
+ subnet_id = module.io_sign_snet.id
+ allowed_subnets = [
+ module.io_sign_snet.id,
+ data.azurerm_subnet.apim_v2.id,
+ ]
+
+ tags = var.tags
+}
+
+resource "azurerm_monitor_autoscale_setting" "io_sign_issuer_func" {
+ count = var.io_sign_issuer_func.sku_tier == "PremiumV3" ? 1 : 0
+ name = format("%s-autoscale", module.io_sign_issuer_func.name)
+ resource_group_name = azurerm_resource_group.backend_rg.name
+ location = azurerm_resource_group.backend_rg.location
+ target_resource_id = module.io_sign_issuer_func.app_service_plan_id
+
+ profile {
+ name = "default"
+
+ capacity {
+ default = var.io_sign_issuer_func.autoscale_default
+ minimum = var.io_sign_issuer_func.autoscale_minimum
+ maximum = var.io_sign_issuer_func.autoscale_maximum
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "Requests"
+ metric_resource_id = module.io_sign_issuer_func.id
+ metric_namespace = "microsoft.web/sites"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "GreaterThan"
+ threshold = 3500
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Increase"
+ type = "ChangeCount"
+ value = "2"
+ cooldown = "PT5M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "CpuPercentage"
+ metric_resource_id = module.io_sign_issuer_func.app_service_plan_id
+ metric_namespace = "microsoft.web/serverfarms"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "GreaterThan"
+ threshold = 60
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Increase"
+ type = "ChangeCount"
+ value = "2"
+ cooldown = "PT5M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "Requests"
+ metric_resource_id = module.io_sign_issuer_func.id
+ metric_namespace = "microsoft.web/sites"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "LessThan"
+ threshold = 2500
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Decrease"
+ type = "ChangeCount"
+ value = "1"
+ cooldown = "PT20M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "CpuPercentage"
+ metric_resource_id = module.io_sign_issuer_func.app_service_plan_id
+ metric_namespace = "microsoft.web/serverfarms"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "LessThan"
+ threshold = 30
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Decrease"
+ type = "ChangeCount"
+ value = "1"
+ cooldown = "PT20M"
+ }
+ }
+ }
+
+ tags = var.tags
+}
diff --git a/infra/resources/prod/io_sign_support_func.tf b/infra/resources/prod/io_sign_support_func.tf
new file mode 100644
index 00000000..01e8dbaa
--- /dev/null
+++ b/infra/resources/prod/io_sign_support_func.tf
@@ -0,0 +1,192 @@
+locals {
+ io_sign_support_func = {
+ app_settings = {
+ FUNCTIONS_WORKER_PROCESS_COUNT = 4
+ AzureWebJobsDisableHomepage = "true"
+ NODE_ENV = "production"
+ CosmosDbConnectionString = module.cosmosdb_account.connection_strings[0]
+ CosmosDbIssuerDatabaseName = module.cosmosdb_sql_database_issuer.name
+ CosmosDbUserDatabaseName = module.cosmosdb_sql_database_user.name
+ PdvTokenizerApiBasePath = "https://api.tokenizer.pdv.pagopa.it"
+ PdvTokenizerApiKey = module.key_vault_secrets.values["PdvTokenizerApiKey"].value
+ }
+ }
+}
+
+module "io_sign_support_func" {
+ source = "github.com/pagopa/terraform-azurerm-v3//function_app?ref=v8.35.0"
+
+ name = format("%s-support-func", local.project)
+ location = azurerm_resource_group.backend_rg.location
+ resource_group_name = azurerm_resource_group.backend_rg.name
+
+ # TODO Activate when in production
+ # health_check_path = "/api/v1/sign/support/info"
+
+ always_on = true
+
+ runtime_version = "~4"
+ node_version = "18"
+
+ app_service_plan_info = {
+ kind = "Linux"
+ sku_tier = var.io_sign_support_func.sku_tier
+ sku_size = var.io_sign_support_func.sku_size
+ maximum_elastic_worker_count = 0
+ worker_count = 1
+ zone_balancing_enabled = false
+ }
+
+ app_settings = local.io_sign_support_func.app_settings
+
+ subnet_id = module.io_sign_support_snet.id
+ allowed_subnets = [
+ module.io_sign_support_snet.id,
+ data.azurerm_subnet.apim_v2.id,
+ ]
+
+ application_insights_instrumentation_key = data.azurerm_application_insights.application_insights.instrumentation_key
+ system_identity_enabled = true
+
+ tags = var.tags
+}
+
+module "io_sign_support_func_staging_slot" {
+ count = var.io_sign_support_func.sku_tier == "PremiumV3" ? 1 : 0
+ source = "github.com/pagopa/terraform-azurerm-v3//function_app_slot?ref=v8.35.0"
+
+ name = "staging"
+ location = azurerm_resource_group.backend_rg.location
+ resource_group_name = azurerm_resource_group.backend_rg.name
+ function_app_id = module.io_sign_support_func.id
+ app_service_plan_id = module.io_sign_support_func.app_service_plan_id
+
+ # TODO Activate when in production
+ # health_check_path = "/api/v1/sign/support/info"
+
+ storage_account_name = module.io_sign_support_func.storage_account.name
+ storage_account_access_key = module.io_sign_support_func.storage_account.primary_access_key
+
+ runtime_version = "~4"
+ always_on = true
+ node_version = "18"
+ application_insights_instrumentation_key = data.azurerm_application_insights.application_insights.instrumentation_key
+
+ app_settings = local.io_sign_support_func.app_settings
+
+ subnet_id = module.io_sign_support_snet.id
+ allowed_subnets = [
+ module.io_sign_support_snet.id,
+ data.azurerm_subnet.apim_v2.id,
+ ]
+
+ tags = var.tags
+}
+
+resource "azurerm_monitor_autoscale_setting" "io_sign_support_func" {
+ count = var.io_sign_support_func.sku_tier == "PremiumV3" ? 1 : 0
+ name = format("%s-autoscale", module.io_sign_support_func.name)
+ resource_group_name = azurerm_resource_group.backend_rg.name
+ location = azurerm_resource_group.backend_rg.location
+ target_resource_id = module.io_sign_support_func.app_service_plan_id
+
+ profile {
+ name = "default"
+
+ capacity {
+ default = var.io_sign_support_func.autoscale_default
+ minimum = var.io_sign_support_func.autoscale_minimum
+ maximum = var.io_sign_support_func.autoscale_maximum
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "Requests"
+ metric_resource_id = module.io_sign_support_func.id
+ metric_namespace = "microsoft.web/sites"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "GreaterThan"
+ threshold = 3500
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Increase"
+ type = "ChangeCount"
+ value = "2"
+ cooldown = "PT5M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "CpuPercentage"
+ metric_resource_id = module.io_sign_support_func.app_service_plan_id
+ metric_namespace = "microsoft.web/serverfarms"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "GreaterThan"
+ threshold = 60
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Increase"
+ type = "ChangeCount"
+ value = "2"
+ cooldown = "PT5M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "Requests"
+ metric_resource_id = module.io_sign_support_func.id
+ metric_namespace = "microsoft.web/sites"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "LessThan"
+ threshold = 2500
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Decrease"
+ type = "ChangeCount"
+ value = "1"
+ cooldown = "PT20M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "CpuPercentage"
+ metric_resource_id = module.io_sign_support_func.app_service_plan_id
+ metric_namespace = "microsoft.web/serverfarms"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "LessThan"
+ threshold = 30
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Decrease"
+ type = "ChangeCount"
+ value = "1"
+ cooldown = "PT20M"
+ }
+ }
+ }
+
+ tags = var.tags
+}
diff --git a/infra/resources/prod/io_sign_user_func.tf b/infra/resources/prod/io_sign_user_func.tf
new file mode 100644
index 00000000..ba2166fc
--- /dev/null
+++ b/infra/resources/prod/io_sign_user_func.tf
@@ -0,0 +1,234 @@
+locals {
+ io_sign_user_func = {
+ staging_disabled = [
+ "CreateSignatureRequest",
+ "FillDocument",
+ "UpdateSignatureRequest",
+ "ValidateQtspSignature",
+ ]
+ app_settings = {
+ FUNCTIONS_WORKER_PROCESS_COUNT = 4
+ AzureWebJobsDisableHomepage = "true"
+ NODE_ENV = "production"
+ NODE_TLS_REJECT_UNAUTHORIZED = 0
+ CosmosDbConnectionString = module.cosmosdb_account.connection_strings[0]
+ CosmosDbDatabaseName = module.cosmosdb_sql_database_user.name
+ StorageAccountConnectionString = module.io_sign_storage.primary_connection_string
+ userUploadedBlobContainerName = azurerm_storage_container.uploaded_documents.name
+ userValidatedBlobContainerName = azurerm_storage_container.validated_documents.name
+ IoServicesApiBasePath = "https://api.io.pagopa.it"
+ IoServicesSubscriptionKey = module.key_vault_secrets.values["IoServicesSubscriptionKey"].value
+ IoServicesConfigurationId = module.key_vault_secrets.values["io-services-configuration-id"].value
+ PdvTokenizerApiBasePath = "https://api.tokenizer.pdv.pagopa.it"
+ PdvTokenizerApiKey = module.key_vault_secrets.values["PdvTokenizerApiKey"].value
+ NamirialApiBasePath = "https://pagopa.namirial.com"
+ NamirialUsername = "api"
+ NamirialPassword = module.key_vault_secrets.values["NamirialPassword"].value
+ NamirialTestApiBasePath = "https://pagopa-test.namirial.com"
+ NamirialTestUsername = "api"
+ NamirialTestPassword = module.key_vault_secrets.values["NamirialTestPassword"].value
+ AnalyticsEventHubConnectionString = module.event_hub.keys["analytics.io-sign-func-user"].primary_connection_string
+ BillingEventHubConnectionString = module.event_hub.keys["billing.io-sign-func-issuer"].primary_connection_string
+ SelfCareEventHubConnectionString = module.key_vault_secrets.values["SelfCareEventHubConnectionString"].value
+ SelfCareApiBasePath = "https://api.selfcare.pagopa.it"
+ SelfCareApiKey = module.key_vault_secrets.values["SelfCareApiKey"].value
+ LollipopApiBasePath = "https://api.io.pagopa.it"
+ LollipopApiKey = module.key_vault_secrets.values["LollipopPrimaryApiKey"].value
+ SlackWebhookUrl = module.key_vault_secrets.values["SlackWebhookUrl"].value
+ IoLinkBaseUrl = "https://continua.io.pagopa.it"
+ }
+ }
+}
+
+module "io_sign_user_func" {
+ source = "github.com/pagopa/terraform-azurerm-v3//function_app?ref=v8.35.0"
+
+ name = format("%s-user-func", local.project)
+ location = azurerm_resource_group.backend_rg.location
+ resource_group_name = azurerm_resource_group.backend_rg.name
+
+ health_check_path = "/api/v1/sign/info"
+
+ node_version = "18"
+ runtime_version = "~4"
+ always_on = true
+
+ app_service_plan_info = {
+ kind = "Linux"
+ sku_size = var.io_sign_user_func.sku_size
+ maximum_elastic_worker_count = 0
+ worker_count = 1
+ zone_balancing_enabled = false
+ }
+
+ app_settings = merge(
+ local.io_sign_user_func.app_settings,
+ {
+ # Enable functions on production triggered by queue and timer
+ for to_disable in local.io_sign_user_func.staging_disabled :
+ format("AzureWebJobs.%s.Disabled", to_disable) => "false"
+ }
+ )
+
+ sticky_app_setting_names = [
+ # Sticky the settings enabling triggered by queue and timer
+ for to_disable in local.io_sign_user_func.staging_disabled :
+ format("AzureWebJobs.%s.Disabled", to_disable)
+ ]
+
+ subnet_id = module.io_sign_user_snet.id
+ allowed_subnets = [
+ module.io_sign_user_snet.id,
+ ]
+
+ application_insights_instrumentation_key = data.azurerm_application_insights.application_insights.instrumentation_key
+ system_identity_enabled = true
+
+ tags = var.tags
+}
+
+module "io_sign_user_func_staging_slot" {
+ count = var.io_sign_user_func.sku_tier == "PremiumV3" ? 1 : 0
+ source = "github.com/pagopa/terraform-azurerm-v3//function_app_slot?ref=v8.35.0"
+
+ name = "staging"
+ location = azurerm_resource_group.backend_rg.location
+ resource_group_name = azurerm_resource_group.backend_rg.name
+ function_app_id = module.io_sign_user_func.id
+ app_service_plan_id = module.io_sign_user_func.app_service_plan_id
+
+ health_check_path = "/api/v1/sign/info"
+ health_check_maxpingfailures = 2
+
+ storage_account_name = module.io_sign_user_func.storage_account.name
+ storage_account_access_key = module.io_sign_user_func.storage_account.primary_access_key
+
+ node_version = "18"
+ runtime_version = "~4"
+ always_on = true
+ application_insights_instrumentation_key = data.azurerm_application_insights.application_insights.instrumentation_key
+
+ app_settings = merge(
+ local.io_sign_user_func.app_settings,
+ {
+ # Disabled functions on slot triggered by queue and timer
+ for to_disable in local.io_sign_user_func.staging_disabled :
+ format("AzureWebJobs.%s.Disabled", to_disable) => "true"
+ }
+ )
+
+ subnet_id = module.io_sign_user_snet.id
+ allowed_subnets = [
+ module.io_sign_user_snet.id,
+ ]
+
+ tags = var.tags
+}
+
+resource "azurerm_monitor_autoscale_setting" "io_sign_user_func" {
+ count = var.io_sign_user_func.sku_tier == "PremiumV3" ? 1 : 0
+ name = format("%s-autoscale", module.io_sign_user_func.name)
+ resource_group_name = azurerm_resource_group.backend_rg.name
+ location = azurerm_resource_group.backend_rg.location
+ target_resource_id = module.io_sign_user_func.app_service_plan_id
+
+ profile {
+ name = "default"
+
+ capacity {
+ default = var.io_sign_user_func.autoscale_default
+ minimum = var.io_sign_user_func.autoscale_minimum
+ maximum = var.io_sign_user_func.autoscale_maximum
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "Requests"
+ metric_resource_id = module.io_sign_user_func.id
+ metric_namespace = "microsoft.web/sites"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "GreaterThan"
+ threshold = 3500
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Increase"
+ type = "ChangeCount"
+ value = "2"
+ cooldown = "PT5M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "CpuPercentage"
+ metric_resource_id = module.io_sign_user_func.app_service_plan_id
+ metric_namespace = "microsoft.web/serverfarms"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "GreaterThan"
+ threshold = 60
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Increase"
+ type = "ChangeCount"
+ value = "2"
+ cooldown = "PT5M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "Requests"
+ metric_resource_id = module.io_sign_user_func.id
+ metric_namespace = "microsoft.web/sites"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "LessThan"
+ threshold = 2500
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Decrease"
+ type = "ChangeCount"
+ value = "1"
+ cooldown = "PT20M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "CpuPercentage"
+ metric_resource_id = module.io_sign_user_func.app_service_plan_id
+ metric_namespace = "microsoft.web/serverfarms"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "LessThan"
+ threshold = 30
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Decrease"
+ type = "ChangeCount"
+ value = "1"
+ cooldown = "PT20M"
+ }
+ }
+ }
+
+ tags = var.tags
+}
diff --git a/infra/resources/prod/key_vault.tf b/infra/resources/prod/key_vault.tf
new file mode 100644
index 00000000..4e5fb7b5
--- /dev/null
+++ b/infra/resources/prod/key_vault.tf
@@ -0,0 +1,121 @@
+data "azurerm_user_assigned_identity" "infra_ci" {
+ name = "${local.product}-infra-github-ci-identity"
+ resource_group_name = "${local.product}-identity-rg"
+}
+
+data "azurerm_user_assigned_identity" "infra_cd" {
+ name = "${local.product}-infra-github-cd-identity"
+ resource_group_name = "${local.product}-identity-rg"
+}
+
+module "key_vault_secrets" {
+ source = "github.com/pagopa/terraform-azurerm-v3//key_vault_secrets_query?ref=v8.35.0"
+
+ resource_group = azurerm_resource_group.sec_rg.name
+ key_vault_name = module.key_vault.name
+
+ secrets = [
+ "IoServicesSubscriptionKey",
+ "io-fn-sign-issuer-key",
+ "io-fn-sign-support-key",
+ "NamirialPassword",
+ "NamirialTestPassword",
+ "SelfCareEventHubConnectionString",
+ "SelfCareApiKey",
+ "SlackWebhookUrl",
+ "LollipopPrimaryApiKey",
+ "LollipopSecondaryApiKey",
+ "PdvTokenizerApiKey",
+ "BackOfficeApiKey",
+ "io-services-configuration-id",
+ "io-sign-backoffice-func-key"
+ ]
+}
+
+module "key_vault" {
+ source = "github.com/pagopa/terraform-azurerm-v3//key_vault?ref=v8.35.0"
+
+ name = format("%s-%s-kv", local.product, var.domain)
+ location = azurerm_resource_group.sec_rg.location
+ resource_group_name = azurerm_resource_group.sec_rg.name
+ tenant_id = data.azurerm_client_config.current.tenant_id
+ soft_delete_retention_days = 90
+
+ tags = var.tags
+}
+
+## adgroup_admin group policy ##
+resource "azurerm_key_vault_access_policy" "adgroup_admin" {
+ key_vault_id = module.key_vault.id
+
+ tenant_id = data.azurerm_client_config.current.tenant_id
+ object_id = data.azuread_group.adgroup_admin.object_id
+
+ key_permissions = ["Get", "List", "Update", "Create", "Import", "Delete", ]
+ secret_permissions = ["Get", "List", "Set", "Delete", "Restore", "Recover", ]
+ storage_permissions = []
+ certificate_permissions = ["Get", "List", "Update", "Create", "Import", "Delete", "Restore", "Recover", ]
+}
+
+## adgroup_developers group policy ##
+resource "azurerm_key_vault_access_policy" "adgroup_developers" {
+ key_vault_id = module.key_vault.id
+
+ tenant_id = data.azurerm_client_config.current.tenant_id
+ object_id = data.azuread_group.adgroup_developers.object_id
+
+ key_permissions = ["Get", "List", "Update", "Create", "Import", "Delete", ]
+ secret_permissions = ["Get", "List", "Set", "Delete", "Restore", "Recover", ]
+ storage_permissions = []
+ certificate_permissions = ["Get", "List", "Update", "Create", "Import", "Delete", "Restore", "Recover", ]
+}
+
+## adgroup_sign group policy ##
+resource "azurerm_key_vault_access_policy" "adgroup_sign" {
+ key_vault_id = module.key_vault.id
+
+ tenant_id = data.azurerm_client_config.current.tenant_id
+ object_id = data.azuread_group.adgroup_sign.object_id
+
+ key_permissions = ["Get", "List", "Update", "Create", "Import", "Delete", ]
+ secret_permissions = ["Get", "List", "Set", "Delete", "Restore", "Recover", ]
+ storage_permissions = []
+ certificate_permissions = ["Get", "List", "Update", "Create", "Import", "Delete", "Restore", "Recover", ]
+}
+
+resource "azurerm_key_vault_access_policy" "infra_ci" {
+ key_vault_id = module.key_vault.id
+
+ tenant_id = data.azurerm_client_config.current.tenant_id
+ object_id = data.azurerm_user_assigned_identity.infra_ci.principal_id
+
+ secret_permissions = ["Get", "List"]
+}
+
+resource "azurerm_key_vault_access_policy" "infra_cd" {
+ key_vault_id = module.key_vault.id
+
+ tenant_id = data.azurerm_client_config.current.tenant_id
+ object_id = data.azurerm_user_assigned_identity.infra_cd.principal_id
+
+ secret_permissions = ["Get", "List", "Set"]
+}
+
+#
+# azure devops policy
+#
+
+#pagopaspa-io-platform-iac-projects-{subscription}
+data "azuread_service_principal" "platform_iac_sp" {
+ display_name = format("pagopaspa-io-platform-iac-projects-%s", data.azurerm_subscription.current.subscription_id)
+}
+
+resource "azurerm_key_vault_access_policy" "azdevops_platform_iac_policy" {
+ key_vault_id = module.key_vault.id
+ tenant_id = data.azurerm_client_config.current.tenant_id
+ object_id = data.azuread_service_principal.platform_iac_sp.object_id
+
+ secret_permissions = ["Get", "List", "Set", ]
+ storage_permissions = []
+ certificate_permissions = ["SetIssuers", "DeleteIssuers", "Purge", "List", "Get", "ManageContacts", ]
+}
diff --git a/infra/resources/prod/landing.tf b/infra/resources/prod/landing.tf
new file mode 100644
index 00000000..aff368ca
--- /dev/null
+++ b/infra/resources/prod/landing.tf
@@ -0,0 +1,74 @@
+data "azurerm_resource_group" "core_ext" {
+ name = format("%s-rg-external", local.product)
+}
+
+data "azurerm_resource_group" "core_rg_common" {
+ name = format("%s-rg-common", local.product)
+}
+
+data "azurerm_key_vault" "core_kv_common" {
+ name = format("%s-kv-common", local.product)
+ resource_group_name = data.azurerm_resource_group.core_rg_common.name
+}
+
+data "azurerm_dns_zone" "io_italia_it" {
+ name = "io.italia.it"
+ resource_group_name = data.azurerm_resource_group.core_ext.name
+}
+
+data "azurerm_log_analytics_workspace" "common" {
+ name = var.io_common.log_analytics_workspace_name
+ resource_group_name = var.io_common.resource_group_name
+}
+
+module "landing_cdn" {
+ source = "github.com/pagopa/terraform-azurerm-v3//cdn?ref=v8.35.0"
+
+ name = "landing"
+ prefix = local.project
+ resource_group_name = azurerm_resource_group.integration_rg.name
+ location = azurerm_resource_group.integration_rg.location
+ hostname = "firma.io.italia.it"
+ https_rewrite_enabled = true
+
+ storage_account_replication_type = "GZRS"
+
+ index_document = "index.html"
+ error_404_document = "index.html"
+
+ dns_zone_name = data.azurerm_dns_zone.io_italia_it.name
+ dns_zone_resource_group_name = data.azurerm_resource_group.core_ext.name
+
+ keyvault_vault_name = data.azurerm_key_vault.core_kv_common.name
+ keyvault_resource_group_name = data.azurerm_resource_group.core_rg_common.name
+ keyvault_subscription_id = data.azurerm_subscription.current.subscription_id
+
+ querystring_caching_behaviour = "BypassCaching"
+
+ global_delivery_rule = {
+ cache_expiration_action = []
+ cache_key_query_string_action = []
+ modify_request_header_action = []
+
+ # HSTS
+ modify_response_header_action = [
+ {
+ action = "Overwrite"
+ name = "Strict-Transport-Security"
+ value = "max-age=31536000"
+ },
+ # Content-Security-Policy (in Report mode)
+ {
+ action = "Append"
+ name = "Content-Security-Policy"
+ value = "script-src 'self' 'unsafe-inline'; script-src-elem 'self' 'unsafe-inline' https://cdn.matomo.cloud/pagopa.matomo.cloud/ https://pagopa.matomo.cloud/ https://recaptcha.net/ https://www.recaptcha.net/recaptcha/ https://www.gstatic.com/recaptcha/; style-src 'self' 'unsafe-inline' recaptcha.net; worker-src 'none'; font-src data: 'self'; img-src data: 'self' recaptcha.net; object-src 'none'; "
+ }
+ ]
+ }
+
+ log_analytics_workspace_id = data.azurerm_log_analytics_workspace.common.id
+
+ advanced_threat_protection_enabled = false
+
+ tags = var.tags
+}
diff --git a/infra/resources/prod/locals.tf b/infra/resources/prod/locals.tf
new file mode 100644
index 00000000..e95d0c9e
--- /dev/null
+++ b/infra/resources/prod/locals.tf
@@ -0,0 +1,4 @@
+locals {
+ project = format("%s-%s-%s", var.prefix, var.env_short, var.domain)
+ product = format("%s-%s", var.prefix, var.env_short)
+}
diff --git a/infra/resources/prod/main.tf b/infra/resources/prod/main.tf
new file mode 100644
index 00000000..eded645b
--- /dev/null
+++ b/infra/resources/prod/main.tf
@@ -0,0 +1,31 @@
+terraform {
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "<= 3.113.0"
+ }
+ azuread = {
+ source = "hashicorp/azuread"
+ version = "<= 2.33.0"
+ }
+ }
+
+ backend "azurerm" {
+ resource_group_name = "terraform-state-rg"
+ storage_account_name = "tfinfprodio"
+ container_name = "terraform-state"
+ key = "io-sign.resources.prod.tfstate"
+ }
+
+ # tflint-ignore: terraform_required_version
+ # Due to precommit check update required
+ # required_version = ">= 1.3.7"
+}
+
+provider "azurerm" {
+ features {}
+}
+
+data "azurerm_subscription" "current" {}
+
+data "azurerm_client_config" "current" {}
diff --git a/infra/resources/prod/monitoring.tf b/infra/resources/prod/monitoring.tf
new file mode 100644
index 00000000..295cad9f
--- /dev/null
+++ b/infra/resources/prod/monitoring.tf
@@ -0,0 +1,309 @@
+data "azurerm_application_insights" "application_insights" {
+ name = "io-p-ai-common"
+ resource_group_name = "io-p-rg-common"
+}
+
+data "azurerm_key_vault_secret" "monitor_fci_tech_email" {
+ name = "monitor-fci-tech-email"
+ key_vault_id = module.key_vault.id
+}
+
+data "azurerm_key_vault_secret" "monitor_fci_tech_slack_email" {
+ name = "monitor-fci-tech-slack"
+ key_vault_id = module.key_vault.id
+}
+
+data "azurerm_monitor_action_group" "slack" {
+ resource_group_name = "io-p-rg-common"
+ name = "SlackPagoPA"
+}
+
+data "azurerm_monitor_action_group" "email" {
+ resource_group_name = "io-p-rg-common"
+ name = "EmailPagoPA"
+}
+
+resource "azurerm_monitor_action_group" "email_fci_tech" {
+ name = "EmailFirmaConIoTech"
+ resource_group_name = azurerm_resource_group.integration_rg.name
+ short_name = "EmailFCITech"
+
+ email_receiver {
+ name = "sendtooperations"
+ email_address = data.azurerm_key_vault_secret.monitor_fci_tech_email.value
+ use_common_alert_schema = true
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_monitor_action_group" "slack_fci_tech" {
+ name = "SlackFirmaConIoTech"
+ resource_group_name = azurerm_resource_group.integration_rg.name
+ short_name = "SlackFCITech"
+
+ email_receiver {
+ name = "sendtoslack"
+ email_address = data.azurerm_key_vault_secret.monitor_fci_tech_slack_email.value
+ use_common_alert_schema = true
+ }
+
+ tags = var.tags
+}
+
+data "azurerm_monitor_action_group" "error_action_group" {
+ resource_group_name = "io-p-rg-common"
+ name = "${var.prefix}${var.env_short}error"
+}
+
+resource "azurerm_monitor_metric_alert" "io_sign_user_helathcheck" {
+ name = format("%s-helathcheck", module.io_sign_user_func.name)
+ resource_group_name = azurerm_resource_group.backend_rg.name
+ scopes = [module.io_sign_user_func.id]
+ description = format("%s health check status is less than 100", module.io_sign_user_func.name)
+ severity = 1
+ frequency = "PT5M"
+ auto_mitigate = false
+
+ criteria {
+ metric_namespace = "Microsoft.Web/sites"
+ metric_name = "HealthCheckStatus"
+ aggregation = "Maximum"
+ operator = "LessThan"
+ threshold = 1
+ }
+
+ action {
+ action_group_id = azurerm_monitor_action_group.email_fci_tech.id
+ }
+
+ action {
+ action_group_id = azurerm_monitor_action_group.slack_fci_tech.id
+ }
+}
+
+resource "azurerm_monitor_scheduled_query_rules_alert" "rejected_requests" {
+ name = format("%s-rejected-requests", local.project)
+ resource_group_name = azurerm_resource_group.backend_rg.name
+ location = azurerm_resource_group.backend_rg.location
+
+ data_source_id = data.azurerm_application_insights.application_insights.id
+ description = "[IO-SIGN] There are REJECTED signature requests. Runbook: https://pagopa.atlassian.net/wiki/spaces/SFEQS/pages/935592503/Richieste+di+firma+in+stato+REJECTED"
+ enabled = true
+ auto_mitigation_enabled = false
+
+ query = <<-QUERY
+customEvents
+| where name == "io.sign.signature_request.rejected"
+| where customDimensions.environment == "DEFAULT"
+| summarize AggregatedValue = count() by bin(timestamp, 30m)
+| where AggregatedValue > 1
+ QUERY
+
+ severity = 3
+ frequency = 30
+ time_window = 30
+
+ trigger {
+ operator = "GreaterThanOrEqual"
+ threshold = 1
+ }
+
+ action {
+ action_group = [
+ azurerm_monitor_action_group.email_fci_tech.id,
+ azurerm_monitor_action_group.slack_fci_tech.id,
+ data.azurerm_monitor_action_group.error_action_group.id
+ ]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_monitor_scheduled_query_rules_alert" "rejected_test_requests" {
+ name = format("%s-rejected-test-requests", local.project)
+ resource_group_name = azurerm_resource_group.backend_rg.name
+ location = azurerm_resource_group.backend_rg.location
+
+ data_source_id = data.azurerm_application_insights.application_insights.id
+ description = "[IO-SIGN] There are REJECTED signature requests in TEST environment. No action required"
+ enabled = true
+ auto_mitigation_enabled = false
+
+ query = <<-QUERY
+customEvents
+| where name == "io.sign.signature_request.rejected"
+| where customDimensions.environment == "TEST"
+| summarize AggregatedValue = count() by bin(timestamp, 30m)
+| where AggregatedValue > 1
+ QUERY
+
+ severity = 3
+ frequency = 30
+ time_window = 30
+
+ trigger {
+ operator = "GreaterThanOrEqual"
+ threshold = 1
+ }
+
+ action {
+ action_group = [
+ azurerm_monitor_action_group.slack_fci_tech.id
+ ]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_monitor_autoscale_setting" "io_sign_backoffice_func" {
+ name = format("%s-autoscale", module.io_sign_backoffice_func.name)
+ resource_group_name = azurerm_resource_group.backend_rg.name
+ location = azurerm_resource_group.backend_rg.location
+ target_resource_id = module.io_sign_backoffice_func.app_service_plan_id
+
+ profile {
+ name = "default"
+
+ capacity {
+ default = var.io_sign_backoffice_func.autoscale_default
+ minimum = var.io_sign_backoffice_func.autoscale_minimum
+ maximum = var.io_sign_backoffice_func.autoscale_maximum
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "Requests"
+ metric_resource_id = module.io_sign_backoffice_func.id
+ metric_namespace = "microsoft.web/sites"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "GreaterThan"
+ threshold = 3500
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Increase"
+ type = "ChangeCount"
+ value = "2"
+ cooldown = "PT5M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "Requests"
+ metric_resource_id = module.io_sign_backoffice_app.id
+ metric_namespace = "microsoft.web/sites"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "GreaterThan"
+ threshold = 3500
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Increase"
+ type = "ChangeCount"
+ value = "2"
+ cooldown = "PT5M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "CpuPercentage"
+ metric_resource_id = module.io_sign_backoffice_func.app_service_plan_id
+ metric_namespace = "microsoft.web/serverfarms"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "GreaterThan"
+ threshold = 60
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Increase"
+ type = "ChangeCount"
+ value = "2"
+ cooldown = "PT5M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "Requests"
+ metric_resource_id = module.io_sign_backoffice_func.id
+ metric_namespace = "microsoft.web/sites"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "LessThan"
+ threshold = 2500
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Decrease"
+ type = "ChangeCount"
+ value = "1"
+ cooldown = "PT20M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "Requests"
+ metric_resource_id = module.io_sign_backoffice_app.id
+ metric_namespace = "microsoft.web/sites"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "LessThan"
+ threshold = 2500
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Decrease"
+ type = "ChangeCount"
+ value = "1"
+ cooldown = "PT20M"
+ }
+ }
+
+ rule {
+ metric_trigger {
+ metric_name = "CpuPercentage"
+ metric_resource_id = module.io_sign_backoffice_func.app_service_plan_id
+ metric_namespace = "microsoft.web/serverfarms"
+ time_grain = "PT1M"
+ statistic = "Average"
+ time_window = "PT5M"
+ time_aggregation = "Average"
+ operator = "LessThan"
+ threshold = 30
+ divide_by_instance_count = false
+ }
+
+ scale_action {
+ direction = "Decrease"
+ type = "ChangeCount"
+ value = "1"
+ cooldown = "PT20M"
+ }
+ }
+ }
+
+ tags = var.tags
+}
+
diff --git a/infra/resources/prod/network.tf b/infra/resources/prod/network.tf
new file mode 100644
index 00000000..56b451b6
--- /dev/null
+++ b/infra/resources/prod/network.tf
@@ -0,0 +1,445 @@
+data "azurerm_virtual_network" "vnet_common" {
+ name = format("%s-vnet-common", local.product)
+ resource_group_name = format("%s-rg-common", local.product)
+}
+
+data "azurerm_virtual_network" "itn_vnet_common" {
+ name = format("%s-itn-common-vnet-01", local.product)
+ resource_group_name = format("%s-itn-common-rg-01", local.product)
+}
+
+data "azurerm_subnet" "private_endpoints_subnet" {
+ name = "pendpoints"
+ virtual_network_name = format("%s-vnet-common", local.product)
+ resource_group_name = format("%s-rg-common", local.product)
+}
+
+data "azurerm_subnet" "itn_private_endpoints_subnet" {
+ name = format("%s-itn-pep-snet-01", local.product)
+ virtual_network_name = data.azurerm_virtual_network.itn_vnet_common.name
+ resource_group_name = data.azurerm_virtual_network.itn_vnet_common.resource_group_name
+}
+
+data "azurerm_subnet" "apim_v2" {
+ name = "apimv2api"
+ virtual_network_name = format("%s-vnet-common", local.product)
+ resource_group_name = format("%s-rg-common", local.product)
+}
+
+data "azurerm_nat_gateway" "nat_gateway" {
+ name = format("%s-natgw", local.product)
+ resource_group_name = format("%s-rg-common", local.product)
+}
+
+module "io_sign_snet" {
+ source = "github.com/pagopa/terraform-azurerm-v3//subnet?ref=v8.35.0"
+ name = format("%s-snet", local.project)
+ resource_group_name = data.azurerm_virtual_network.vnet_common.resource_group_name
+ virtual_network_name = data.azurerm_virtual_network.vnet_common.name
+ address_prefixes = var.subnets_cidrs.issuer
+
+ private_endpoint_network_policies_enabled = false
+
+ # network_security_group_id = azurerm_network_security_group.io_sign_issuer_nsg.id
+
+ service_endpoints = [
+ "Microsoft.Web",
+ "Microsoft.AzureCosmosDB",
+ "Microsoft.Storage",
+ ]
+
+ delegation = {
+ name = "default"
+ service_delegation = {
+ name = "Microsoft.Web/serverFarms"
+ actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
+ }
+ }
+}
+
+resource "azurerm_subnet_nat_gateway_association" "io_sign_issuer_snet" {
+ nat_gateway_id = data.azurerm_nat_gateway.nat_gateway.id
+ subnet_id = module.io_sign_snet.id
+}
+
+resource "azurerm_network_security_group" "io_sign_issuer_nsg" {
+ name = format("%s-issuer-nsg", local.project)
+ location = data.azurerm_virtual_network.vnet_common.location
+ resource_group_name = data.azurerm_virtual_network.vnet_common.resource_group_name
+
+ tags = var.tags
+}
+
+module "io_sign_user_snet" {
+ source = "github.com/pagopa/terraform-azurerm-v3//subnet?ref=v8.35.0"
+ name = format("%s-user-snet", local.project)
+ resource_group_name = data.azurerm_virtual_network.vnet_common.resource_group_name
+ virtual_network_name = data.azurerm_virtual_network.vnet_common.name
+ address_prefixes = var.subnets_cidrs.user
+
+ private_endpoint_network_policies_enabled = false
+
+ # network_security_group_id = azurerm_network_security_group.io_sign_user_nsg.id
+
+ service_endpoints = [
+ "Microsoft.Web",
+ "Microsoft.AzureCosmosDB",
+ "Microsoft.Storage",
+ ]
+
+ delegation = {
+ name = "default"
+ service_delegation = {
+ name = "Microsoft.Web/serverFarms"
+ actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
+ }
+ }
+}
+
+resource "azurerm_subnet_nat_gateway_association" "io_sign_user_snet" {
+ nat_gateway_id = data.azurerm_nat_gateway.nat_gateway.id
+ subnet_id = module.io_sign_user_snet.id
+}
+
+resource "azurerm_network_security_group" "io_sign_user_nsg" {
+ name = format("%s-user-nsg", local.project)
+ location = data.azurerm_virtual_network.vnet_common.location
+ resource_group_name = data.azurerm_virtual_network.vnet_common.resource_group_name
+
+ tags = var.tags
+}
+
+module "io_sign_support_snet" {
+ source = "github.com/pagopa/terraform-azurerm-v3//subnet?ref=v8.35.0"
+ name = format("%s-support-snet", local.project)
+ resource_group_name = data.azurerm_virtual_network.vnet_common.resource_group_name
+ virtual_network_name = data.azurerm_virtual_network.vnet_common.name
+ address_prefixes = var.subnets_cidrs.support
+
+ private_endpoint_network_policies_enabled = false
+
+ # network_security_group_id = azurerm_network_security_group.io_sign_user_nsg.id
+
+ service_endpoints = [
+ "Microsoft.Web",
+ "Microsoft.AzureCosmosDB",
+ ]
+
+ delegation = {
+ name = "default"
+ service_delegation = {
+ name = "Microsoft.Web/serverFarms"
+ actions = ["Microsoft.Network/virtualNetworks/subnets/action"]
+ }
+ }
+}
+
+resource "azurerm_subnet_nat_gateway_association" "io_sign_support_snet" {
+ nat_gateway_id = data.azurerm_nat_gateway.nat_gateway.id
+ subnet_id = module.io_sign_support_snet.id
+}
+
+resource "azurerm_network_security_group" "io_sign_support_nsg" {
+ name = format("%s-support-nsg", local.project)
+ location = data.azurerm_virtual_network.vnet_common.location
+ resource_group_name = data.azurerm_virtual_network.vnet_common.resource_group_name
+
+ tags = var.tags
+}
+
+module "io_sign_eventhub_snet" {
+ source = "github.com/pagopa/terraform-azurerm-v3//subnet?ref=v8.35.0"
+ name = format("%s-eventhub-snet", local.project)
+ resource_group_name = data.azurerm_virtual_network.vnet_common.resource_group_name
+ virtual_network_name = data.azurerm_virtual_network.vnet_common.name
+ address_prefixes = var.subnets_cidrs.eventhub
+
+ private_endpoint_network_policies_enabled = false
+
+ service_endpoints = ["Microsoft.EventHub"]
+}
+
+resource "azurerm_network_security_group" "io_sign_eventhub_nsg" {
+ name = format("%s-eventhub-nsg", local.project)
+ location = data.azurerm_virtual_network.vnet_common.location
+ resource_group_name = data.azurerm_virtual_network.vnet_common.resource_group_name
+
+ tags = var.tags
+}
+
+data "azurerm_private_dns_zone" "privatelink_documents_azure_com" {
+ name = "privatelink.documents.azure.com"
+ resource_group_name = format("%s-rg-common", local.product)
+}
+
+data "azurerm_private_dns_zone" "privatelink_blob_core_windows_net" {
+ name = "privatelink.blob.core.windows.net"
+ resource_group_name = format("%s-rg-common", local.product)
+}
+
+data "azurerm_private_dns_zone" "privatelink_queue_core_windows_net" {
+ name = "privatelink.queue.core.windows.net"
+ resource_group_name = format("%s-rg-common", local.product)
+}
+
+data "azurerm_private_dns_zone" "privatelink_azurewebsites_net" {
+ name = "privatelink.azurewebsites.net"
+ resource_group_name = format("%s-rg-common", local.product)
+}
+
+data "azurerm_private_dns_zone" "privatelink_servicebus_windows_net" {
+ name = "privatelink.servicebus.windows.net"
+ resource_group_name = format("%s-evt-rg", local.product)
+}
+
+# Unused at the moment
+# tflint-ignore: terraform_unused_declarations
+data "azurerm_private_dns_zone" "privatelink_file_core_windows_net" {
+ name = "privatelink.file.core.windows.net"
+ resource_group_name = format("%s-rg-common", local.product)
+}
+
+# Unused at the moment
+# tflint-ignore: terraform_unused_declarations
+data "azurerm_private_dns_zone" "privatelink_table_core_windows_net" {
+ name = "privatelink.table.core.windows.net"
+ resource_group_name = format("%s-rg-common", local.product)
+}
+
+resource "azurerm_private_endpoint" "blob" {
+ name = format("%s-blob-endpoint", module.io_sign_storage.name)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-blob", module.io_sign_storage.name)
+ private_connection_resource_id = module.io_sign_storage.id
+ is_manual_connection = false
+ subresource_names = ["blob"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_blob_core_windows_net.id]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_private_endpoint" "itn_blob" {
+ name = format("%s-itn-sign-blob-pep-01", local.product)
+ location = azurerm_resource_group.sign.location
+ resource_group_name = azurerm_resource_group.sign.name
+ subnet_id = data.azurerm_subnet.itn_private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-itn-sign-blob-pep-01", local.product)
+ private_connection_resource_id = module.io_sign_storage_itn.id
+ is_manual_connection = false
+ subresource_names = ["blob"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_blob_core_windows_net.id]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_private_endpoint" "queue" {
+ name = format("%s-queue-endpoint", module.io_sign_storage.name)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-queue", module.io_sign_storage.name)
+ private_connection_resource_id = module.io_sign_storage.id
+ is_manual_connection = false
+ subresource_names = ["queue"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_queue_core_windows_net.id]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_private_endpoint" "itn_queue" {
+ name = format("%s-itn-sign-queue-pep-01", local.product)
+ location = azurerm_resource_group.sign.location
+ resource_group_name = azurerm_resource_group.sign.name
+ subnet_id = data.azurerm_subnet.itn_private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-itn-sign-queue-pep-01", local.product)
+ private_connection_resource_id = module.io_sign_storage_itn.id
+ is_manual_connection = false
+ subresource_names = ["queue"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_queue_core_windows_net.id]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_private_endpoint" "io_sign_user_func" {
+ name = format("%s-endpoint", module.io_sign_user_func.name)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-endpoint", module.io_sign_user_func.name)
+ private_connection_resource_id = module.io_sign_user_func.id
+ is_manual_connection = false
+ subresource_names = ["sites"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_azurewebsites_net.id]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_private_endpoint" "io_sign_user_func_staging" {
+ count = var.io_sign_user_func.sku_tier == "PremiumV3" ? 1 : 0
+
+ name = format("%s-staging-endpoint", module.io_sign_user_func.name)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-staging-endpoint", module.io_sign_user_func.name)
+ private_connection_resource_id = module.io_sign_user_func.id
+ is_manual_connection = false
+ subresource_names = ["sites-staging"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_azurewebsites_net.id]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_private_endpoint" "io_sign_issuer_func" {
+ name = format("%s-endpoint", module.io_sign_issuer_func.name)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-endpoint", module.io_sign_issuer_func.name)
+ private_connection_resource_id = module.io_sign_issuer_func.id
+ is_manual_connection = false
+ subresource_names = ["sites"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_azurewebsites_net.id]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_private_endpoint" "io_sign_issuer_func_staging" {
+ count = var.io_sign_issuer_func.sku_tier == "PremiumV3" ? 1 : 0
+
+ name = format("%s-staging-endpoint", module.io_sign_issuer_func.name)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-staging-endpoint", module.io_sign_issuer_func.name)
+ private_connection_resource_id = module.io_sign_issuer_func.id
+ is_manual_connection = false
+ subresource_names = ["sites-staging"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_azurewebsites_net.id]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_private_endpoint" "io_sign_support_func" {
+ name = format("%s-endpoint", module.io_sign_support_func.name)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-endpoint", module.io_sign_support_func.name)
+ private_connection_resource_id = module.io_sign_support_func.id
+ is_manual_connection = false
+ subresource_names = ["sites"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_azurewebsites_net.id]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_private_endpoint" "io_sign_support_func_staging" {
+ count = var.io_sign_support_func.sku_tier == "PremiumV3" ? 1 : 0
+
+ name = format("%s-staging-endpoint", module.io_sign_support_func.name)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-staging-endpoint", module.io_sign_support_func.name)
+ private_connection_resource_id = module.io_sign_support_func.id
+ is_manual_connection = false
+ subresource_names = ["sites-staging"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_azurewebsites_net.id]
+ }
+
+ tags = var.tags
+}
+
+resource "azurerm_private_endpoint" "io_sign_backoffice_func_staging" {
+
+ name = format("%s-staging-endpoint", module.io_sign_backoffice_func.name)
+ location = azurerm_resource_group.data_rg.location
+ resource_group_name = azurerm_resource_group.data_rg.name
+ subnet_id = data.azurerm_subnet.private_endpoints_subnet.id
+
+ private_service_connection {
+ name = format("%s-staging-endpoint", module.io_sign_backoffice_func.name)
+ private_connection_resource_id = module.io_sign_backoffice_func.id
+ is_manual_connection = false
+ subresource_names = ["sites-staging"]
+ }
+
+ private_dns_zone_group {
+ name = "private-dns-zone-group"
+ private_dns_zone_ids = [data.azurerm_private_dns_zone.privatelink_azurewebsites_net.id]
+ }
+
+ tags = var.tags
+}
diff --git a/infra/resources/prod/resource_groups.tf b/infra/resources/prod/resource_groups.tf
new file mode 100644
index 00000000..482544b8
--- /dev/null
+++ b/infra/resources/prod/resource_groups.tf
@@ -0,0 +1,35 @@
+resource "azurerm_resource_group" "data_rg" {
+ name = format("%s-data-rg", local.project)
+ location = var.location
+
+ tags = var.tags
+}
+
+resource "azurerm_resource_group" "sign" {
+ name = format("%s-itn-sign-rg-01", local.product)
+ location = "italynorth"
+
+ tags = var.tags
+}
+
+resource "azurerm_resource_group" "backend_rg" {
+ name = format("%s-backend-rg", local.project)
+ location = var.location
+
+ tags = var.tags
+}
+
+resource "azurerm_resource_group" "sec_rg" {
+ name = format("%s-sec-rg", local.project)
+ location = var.location
+
+ tags = var.tags
+}
+
+# Needed to integrate Firma con IO with external domains, products or platforms (ie. eventhub for billing, ...)
+resource "azurerm_resource_group" "integration_rg" {
+ name = format("%s-integration-rg", local.project)
+ location = var.location
+
+ tags = var.tags
+}
diff --git a/infra/resources/prod/storage.tf b/infra/resources/prod/storage.tf
new file mode 100644
index 00000000..cf5809aa
--- /dev/null
+++ b/infra/resources/prod/storage.tf
@@ -0,0 +1,245 @@
+module "io_sign_storage" {
+ source = "github.com/pagopa/terraform-azurerm-v3//storage_account?ref=v8.35.0"
+ name = replace(format("%s-st", local.project), "-", "")
+ account_kind = "StorageV2"
+ account_tier = "Standard"
+ account_replication_type = var.storage_account.replication_type
+ access_tier = "Hot"
+ blob_versioning_enabled = var.storage_account.enable_versioning
+ blob_change_feed_enabled = var.storage_account.change_feed_enabled
+ resource_group_name = azurerm_resource_group.data_rg.name
+ location = azurerm_resource_group.data_rg.location
+ advanced_threat_protection = true
+ use_legacy_defender_version = true
+ allow_nested_items_to_be_public = false
+ public_network_access_enabled = true
+
+ network_rules = {
+ default_action = "Allow"
+ ip_rules = []
+ bypass = [
+ "Logging",
+ "Metrics",
+ "AzureServices",
+ ]
+ virtual_network_subnet_ids = []
+ }
+
+ action = var.storage_account.enable_low_availability_alert ? [
+ {
+ action_group_id = data.azurerm_monitor_action_group.error_action_group.id
+ webhook_properties = {}
+ }
+ ] : []
+
+ tags = var.tags
+}
+
+module "io_sign_storage_itn" {
+ source = "github.com/pagopa/terraform-azurerm-v3//storage_account?ref=v8.35.0"
+ name = replace(format("%s-itn-sign-st-01", local.product), "-", "")
+ account_kind = "StorageV2"
+ account_tier = "Standard"
+ account_replication_type = "ZRS"
+ access_tier = "Hot"
+ blob_versioning_enabled = true
+ blob_change_feed_enabled = false
+ resource_group_name = azurerm_resource_group.sign.name
+ location = azurerm_resource_group.sign.location
+ advanced_threat_protection = false
+ use_legacy_defender_version = false
+ allow_nested_items_to_be_public = false
+ public_network_access_enabled = true
+
+ network_rules = {
+ default_action = "Allow"
+ ip_rules = []
+ bypass = [
+ "Logging",
+ "Metrics",
+ "AzureServices",
+ ]
+ virtual_network_subnet_ids = []
+ }
+
+ action = var.storage_account.enable_low_availability_alert ? [
+ {
+ action_group_id = data.azurerm_monitor_action_group.error_action_group.id
+ webhook_properties = {}
+ }
+ ] : []
+
+ tags = var.tags
+}
+
+resource "azurerm_storage_management_policy" "io_sign_storage_management_policy" {
+ storage_account_id = module.io_sign_storage.id
+
+ rule {
+ name = "deleteafterdays"
+ enabled = true
+ filters {
+ prefix_match = [
+ "uploaded-documents",
+ "validated-documents",
+ "signed-documents",
+ ]
+ blob_types = ["blockBlob"]
+ }
+ actions {
+ base_blob {
+ delete_after_days_since_modification_greater_than = var.storage_account.delete_after_days
+ }
+ }
+ }
+}
+
+resource "azurerm_storage_management_policy" "io_sign_storage_itn_management_policy" {
+ storage_account_id = module.io_sign_storage_itn.id
+
+ rule {
+ name = "deleteafterdays"
+ enabled = true
+ filters {
+ prefix_match = [
+ "uploaded-documents",
+ "validated-documents",
+ "signed-documents",
+ ]
+ blob_types = ["blockBlob"]
+ }
+ actions {
+ base_blob {
+ delete_after_days_since_modification_greater_than = var.storage_account.delete_after_days
+ }
+ }
+ }
+}
+
+resource "azurerm_storage_container" "uploaded_documents" {
+ name = "uploaded-documents"
+ storage_account_name = module.io_sign_storage.name
+ container_access_type = "private"
+}
+
+resource "azurerm_storage_container" "itn_uploaded_documents" {
+ name = "uploaded-documents"
+ storage_account_name = module.io_sign_storage_itn.name
+ container_access_type = "private"
+}
+
+resource "azurerm_storage_container" "validated_documents" {
+ name = "validated-documents"
+ storage_account_name = module.io_sign_storage.name
+ container_access_type = "private"
+}
+
+resource "azurerm_storage_container" "itn_validated_documents" {
+ name = "validated-documents"
+ storage_account_name = module.io_sign_storage_itn.name
+ container_access_type = "private"
+}
+
+resource "azurerm_storage_container" "signed_documents" {
+ name = "signed-documents"
+ storage_account_name = module.io_sign_storage.name
+ container_access_type = "private"
+}
+
+resource "azurerm_storage_container" "itn_signed_documents" {
+ name = "signed-documents"
+ storage_account_name = module.io_sign_storage_itn.name
+ container_access_type = "private"
+}
+
+resource "azurerm_storage_container" "filled_modules" {
+ name = "filled-modules"
+ storage_account_name = module.io_sign_storage.name
+ container_access_type = "private"
+}
+
+resource "azurerm_storage_container" "itn_filled_modules" {
+ name = "filled-modules"
+ storage_account_name = module.io_sign_storage_itn.name
+ container_access_type = "private"
+}
+
+resource "azurerm_storage_queue" "waiting_for_documents_to_fill" {
+ name = "waiting-for-documents-to-fill"
+ storage_account_name = module.io_sign_storage.name
+}
+
+resource "azurerm_storage_queue" "itn_waiting_for_documents_to_fill" {
+ name = "waiting-for-documents-to-fill"
+ storage_account_name = module.io_sign_storage_itn.name
+}
+
+resource "azurerm_storage_queue" "on_signature_request_ready" {
+ name = "on-signature-request-ready"
+ storage_account_name = module.io_sign_storage.name
+}
+
+resource "azurerm_storage_queue" "itn_on_signature_request_ready" {
+ name = "on-signature-request-ready"
+ storage_account_name = module.io_sign_storage_itn.name
+}
+
+resource "azurerm_storage_queue" "on_signature_request_wait_for_signature" {
+ name = "on-signature-request-wait-for-signature"
+ storage_account_name = module.io_sign_storage.name
+}
+
+resource "azurerm_storage_queue" "itn_on_signature_request_wait_for_signature" {
+ name = "on-signature-request-wait-for-signature"
+ storage_account_name = module.io_sign_storage_itn.name
+}
+
+resource "azurerm_storage_queue" "on_signature_request_rejected" {
+ name = "on-signature-request-rejected"
+ storage_account_name = module.io_sign_storage.name
+}
+
+resource "azurerm_storage_queue" "itn_on_signature_request_rejected" {
+ name = "on-signature-request-rejected"
+ storage_account_name = module.io_sign_storage_itn.name
+}
+
+resource "azurerm_storage_queue" "on_signature_request_signed" {
+ name = "on-signature-request-signed"
+ storage_account_name = module.io_sign_storage.name
+}
+
+resource "azurerm_storage_queue" "itn_on_signature_request_signed" {
+ name = "on-signature-request-signed"
+ storage_account_name = module.io_sign_storage_itn.name
+}
+
+resource "azurerm_storage_queue" "waiting_for_qtsp" {
+ name = "waiting-for-qtsp"
+ storage_account_name = module.io_sign_storage.name
+}
+
+resource "azurerm_storage_queue" "itn_waiting_for_qtsp" {
+ name = "waiting-for-qtsp"
+ storage_account_name = module.io_sign_storage_itn.name
+}
+
+resource "azurerm_storage_queue" "waiting_for_signature_request_updates" {
+ name = "waiting-for-signature-request-updates"
+ storage_account_name = module.io_sign_storage.name
+}
+
+resource "azurerm_storage_queue" "itn_waiting_for_signature_request_updates" {
+ name = "waiting-for-signature-request-updates"
+ storage_account_name = module.io_sign_storage_itn.name
+}
+
+resource "azurerm_storage_queue" "api_keys" {
+ name = "api-keys"
+ storage_account_name = module.io_sign_storage.name
+}
+
+resource "azurerm_storage_queue" "itn_api_keys" {
+ name = "api-keys"
+ storage_account_name = module.io_sign_storage_itn.name
+}
diff --git a/infra/resources/prod/terraform.tfvars b/infra/resources/prod/terraform.tfvars
new file mode 100644
index 00000000..724f54d2
--- /dev/null
+++ b/infra/resources/prod/terraform.tfvars
@@ -0,0 +1,303 @@
+prefix = "io"
+env_short = "p"
+domain = "sign"
+location = "westeurope"
+
+tags = {
+ CreatedBy = "Terraform"
+ Environment = "Prod"
+ Owner = "IO"
+ Source = "https://github.com/pagopa/io-infra/src/sign"
+ CostCenter = "BD100 - STRATEGIC INNOVATION"
+}
+
+# Container App Job GitHub Runner
+key_vault_common = {
+ resource_group_name = "io-p-rg-common"
+ name = "io-p-kv-common"
+ pat_secret_name = "github-runner-pat"
+}
+
+# You can retrieve the list of current defined subnets using the CLI command
+# az network vnet subnet list --subscription PROD-IO --vnet-name io-p-vnet-common --resource-group io-p-rg-common --output table
+# and thus define new CIDRs according to the unallocated address space
+subnets_cidrs = {
+ issuer = ["10.0.102.0/24"]
+ user = ["10.0.103.0/24"]
+ eventhub = ["10.0.104.0/24"],
+ support = ["10.0.147.0/24"]
+ backoffice = ["10.0.115.0/24"]
+}
+
+storage_account = {
+ enable_versioning = true
+ change_feed_enabled = true
+ delete_after_days = 90
+ replication_type = "GZRS"
+ enable_low_availability_alert = true
+}
+
+cosmos = {
+ zone_redundant = false
+ additional_geo_locations = [
+ {
+ location = "northeurope"
+ failover_priority = 1
+ zone_redundant = false
+ }
+ ]
+}
+
+io_sign_database_issuer = {
+ dossiers = {
+ max_throughput = 1000
+ ttl = null
+ }
+ signature_requests = {
+ max_throughput = 1000
+ ttl = null
+ }
+ uploads = {
+ max_throughput = 1000
+ ttl = 604800
+ }
+ issuers = {
+ max_throughput = 1000
+ ttl = null
+ }
+}
+
+io_sign_database_user = {
+ signature_requests = {
+ max_throughput = 1000
+ ttl = null
+ }
+ signatures = {
+ max_throughput = 1000
+ ttl = null
+ }
+}
+
+io_sign_database_backoffice = {
+ api_keys = {
+ max_throughput = 1000
+ ttl = null
+ }
+ api_keys_by_id = {
+ max_throughput = 1000
+ ttl = null
+ }
+ issuers = {
+ max_throughput = 1000
+ ttl = null
+ }
+ consents = {
+ max_throughput = 1000
+ ttl = null
+ }
+}
+
+io_sign_issuer_func = {
+ sku_tier = "PremiumV3"
+ sku_size = "P1v3"
+ autoscale_default = 1
+ autoscale_minimum = 1
+ autoscale_maximum = 5
+}
+
+io_sign_support_func = {
+ sku_tier = "PremiumV3"
+ sku_size = "P1v3"
+ autoscale_default = 1
+ autoscale_minimum = 1
+ autoscale_maximum = 5
+}
+
+io_sign_user_func = {
+ sku_tier = "PremiumV3"
+ sku_size = "P1v3"
+ autoscale_default = 1
+ autoscale_minimum = 1
+ autoscale_maximum = 5
+}
+
+io_sign_backoffice_app = {
+ sku_name = "P1v3"
+ app_settings = [
+ {
+ name = "NODE_ENV",
+ value = "production"
+ },
+ {
+ name = "HOSTNAME",
+ value = "0.0.0.0"
+ },
+ {
+ name = "WEBSITE_RUN_FROM_PACKAGE",
+ value = "1"
+ },
+ {
+ name = "AUTH_SESSION_SECRET",
+ key_vault_secret_name = "bo-auth-session-secret"
+ },
+ {
+ name = "SELFCARE_API_KEY",
+ key_vault_secret_name = "selfcare-prod-api-key"
+ },
+ {
+ name = "PDV_TOKENIZER_API_KEY"
+ key_vault_secret_name = "pdv-tokenizer-api-key"
+ },
+ {
+ name = "SLACK_WEB_HOOK_URL",
+ key_vault_secret_name = "slack-webhook-url"
+ }
+ ]
+}
+
+io_sign_backoffice_func = {
+ autoscale_default = 1
+ autoscale_minimum = 1
+ autoscale_maximum = 3
+ app_settings = [
+ {
+ name = "NODE_ENV",
+ value = "production"
+ },
+ {
+ name = "SELFCARE_EVENT_HUB_CONTRACTS_NAME",
+ value = "sc-contracts"
+ },
+ {
+ name = "BACK_OFFICE_API_BASE_PATH"
+ value = "https://api.io.pagopa.it/api/v1/sign/backoffice"
+ },
+ {
+ name = "SelfCareEventHubConnectionString",
+ key_vault_secret_name = "SelfCareEventHubConnectionString"
+ },
+ {
+ name = "SLACK_WEBHOOK_URL",
+ key_vault_secret_name = "slack-webhook-url"
+ },
+ {
+ name = "BACK_OFFICE_API_KEY"
+ key_vault_secret_name = "BackOfficeApiKey"
+ },
+ {
+ name = "GOOGLE_PRIVATE_KEY",
+ key_vault_secret_name = "bo-google-private-key"
+ },
+ {
+ name = "GOOGLE_CLIENT_EMAIL",
+ key_vault_secret_name = "bo-google-client-email"
+ },
+ {
+ name = "GOOGLE_SPREADSHEET_ID",
+ key_vault_secret_name = "bo-google-spreadsheet-id"
+ },
+ {
+ name = "SELFCARE_API_KEY",
+ key_vault_secret_name = "selfcare-prod-api-key"
+ },
+ ]
+}
+
+integration_hub = {
+ auto_inflate_enabled = true
+ sku_name = "Standard"
+ capacity = 1
+ maximum_throughput_units = 5
+ zone_redundant = true
+ alerts_enabled = true
+ ip_rules = [
+ {
+ ip_mask = "18.192.147.151", # PDND-DATALAKE
+ action = "Allow"
+ },
+ {
+ ip_mask = "18.159.227.69", # PDND-DATALAKE
+ action = "Allow"
+ },
+ {
+ ip_mask = "3.126.198.129", # PDND-DATALAKE
+ action = "Allow"
+ }
+ ]
+ hubs = [
+ {
+ name = "billing"
+ partitions = 3
+ message_retention = 7
+ consumers = []
+ keys = [
+ {
+ name = "io-sign-func-issuer"
+ listen = false
+ send = true
+ manage = false
+ },
+ {
+ name = "pdnd-invoicing"
+ listen = true
+ send = false
+ manage = false
+ }
+ ]
+ },
+ {
+ name = "analytics"
+ partitions = 3
+ message_retention = 7
+ consumers = []
+ keys = [
+ {
+ name = "io-sign-func-user"
+ listen = false
+ send = true
+ manage = false
+ },
+ {
+ name = "io-sign-func-issuer"
+ listen = false
+ send = true
+ manage = false
+ },
+ {
+ name = "pdnd-invoicing"
+ listen = true
+ send = false
+ manage = false
+ }
+ ]
+ }
+ ]
+}
+
+# DNS
+
+dns_zone_names = {
+ website = "firma.io.pagopa.it"
+}
+
+dns_ses_validation = [
+ {
+ name = "usgxww7qq2vgfzl4da6yv4qb4f7ls5kq._domainkey"
+ record = "usgxww7qq2vgfzl4da6yv4qb4f7ls5kq.dkim.amazonses.com"
+ },
+ {
+ name = "e4m2laccz356yraixvndjtoivkwf4sc2._domainkey"
+ record = "e4m2laccz356yraixvndjtoivkwf4sc2.dkim.amazonses.com"
+ },
+ {
+ name = "43al7wmot7uxzzz6dfq7fnkcqilx6q6l._domainkey"
+ record = "43al7wmot7uxzzz6dfq7fnkcqilx6q6l.dkim.amazonses.com"
+ },
+]
+
+io_common = {
+ resource_group_name = "io-p-rg-common"
+ log_analytics_workspace_name = "io-p-law-common"
+ appgateway_snet_name = "io-p-appgateway-snet"
+ vnet_common_name = "io-p-vnet-common"
+}
diff --git a/infra/resources/prod/variables.tf b/infra/resources/prod/variables.tf
new file mode 100644
index 00000000..f28cbd0c
--- /dev/null
+++ b/infra/resources/prod/variables.tf
@@ -0,0 +1,225 @@
+# general
+
+variable "prefix" {
+ type = string
+ validation {
+ condition = (
+ length(var.prefix) < 6
+ )
+ error_message = "Max length is 6 chars."
+ }
+}
+
+variable "env_short" {
+ type = string
+ validation {
+ condition = (
+ length(var.env_short) <= 1
+ )
+ error_message = "Max length is 1 chars."
+ }
+}
+
+variable "domain" {
+ type = string
+ validation {
+ condition = (
+ length(var.domain) < 6
+ )
+ error_message = "Max length is 6 chars."
+ }
+}
+
+variable "location" {
+ type = string
+}
+
+variable "tags" {
+ type = map(any)
+ default = {
+ CreatedBy = "Terraform"
+ }
+}
+
+# domain specific
+
+variable "key_vault_common" {
+ type = object({
+ resource_group_name = string
+ name = string
+ pat_secret_name = string
+ })
+}
+
+# DNS
+variable "dns_ses_validation" {
+ type = list(object({
+ name = string
+ record = string
+ }))
+ description = "CNAME records to validate SES domain identity"
+}
+
+variable "dns_default_ttl_sec" {
+ type = number
+ description = "Default TTL for DNS"
+ default = 3600
+}
+
+variable "dns_zone_names" {
+ type = object({
+ website = string
+ })
+ description = "The names for the DNS zones"
+}
+
+variable "subnets_cidrs" {
+ type = map(
+ list(string)
+ )
+ description = "The CIDR address prefixes of the subnets"
+}
+
+variable "storage_account" {
+ type = object({
+ enable_versioning = bool
+ change_feed_enabled = bool
+ delete_after_days = number
+ replication_type = string
+ enable_low_availability_alert = bool
+ })
+ description = "The configuration of the storage account storing documents"
+}
+
+variable "cosmos" {
+ type = object({
+ zone_redundant = bool
+ additional_geo_locations = list(object({
+ location = string
+ failover_priority = number
+ zone_redundant = bool
+ }))
+ })
+}
+
+variable "io_sign_database_issuer" {
+ type = map(
+ object({
+ max_throughput = number
+ ttl = number
+ })
+ )
+}
+
+variable "io_sign_database_user" {
+ type = map(
+ object({
+ max_throughput = number
+ ttl = number
+ })
+ )
+}
+
+variable "io_sign_database_backoffice" {
+ type = map(
+ object({
+ max_throughput = number
+ ttl = number
+ })
+ )
+}
+
+variable "io_sign_issuer_func" {
+ type = object({
+ sku_tier = string
+ sku_size = string
+ autoscale_default = number
+ autoscale_minimum = number
+ autoscale_maximum = number
+ })
+}
+
+variable "io_sign_support_func" {
+ type = object({
+ sku_tier = string
+ sku_size = string
+ autoscale_default = number
+ autoscale_minimum = number
+ autoscale_maximum = number
+ })
+}
+
+
+variable "io_sign_user_func" {
+ type = object({
+ sku_tier = string
+ sku_size = string
+ autoscale_default = number
+ autoscale_minimum = number
+ autoscale_maximum = number
+ })
+}
+
+variable "integration_hub" {
+ type = object({
+ auto_inflate_enabled = bool
+ sku_name = string
+ capacity = number
+ maximum_throughput_units = number
+ zone_redundant = bool
+ alerts_enabled = bool
+ ip_rules = list(object({
+ ip_mask = string
+ action = string
+ }))
+ hubs = list(object({
+ name = string
+ partitions = number
+ message_retention = number
+ consumers = list(string)
+ keys = list(object({
+ name = string
+ listen = bool
+ send = bool
+ manage = bool
+ }))
+ }))
+ })
+ description = "The configuration, hubs and keys of the event hub relative to external integration"
+}
+
+variable "io_common" {
+ type = object({
+ resource_group_name = string
+ log_analytics_workspace_name = string
+ appgateway_snet_name = string
+ vnet_common_name = string
+ })
+ description = "Name of common resources of IO platform"
+}
+
+variable "io_sign_backoffice_app" {
+ type = object({
+ sku_name = string
+ app_settings = list(object({
+ name = string
+ value = optional(string, "")
+ key_vault_secret_name = optional(string)
+ }))
+ })
+ description = "Configuration of the io-sign-backoffice app service"
+}
+
+variable "io_sign_backoffice_func" {
+ type = object({
+ autoscale_default = number
+ autoscale_minimum = number
+ autoscale_maximum = number
+ app_settings = list(object({
+ name = string
+ value = optional(string, "")
+ key_vault_secret_name = optional(string)
+ }))
+ })
+ description = "Configuration of the io-sign-backoffice func app"
+}