diff --git a/infra/policy/README.md b/infra/policy/README.md new file mode 100644 index 000000000..8300ba783 --- /dev/null +++ b/infra/policy/README.md @@ -0,0 +1,91 @@ +# DX - Azure Policy + +This directory contains shared Azure Policy rules that any team can choose to apply to its own Azure subscriptions to ensure consistent governance across different environments. +Additionally, the `dev` directory contains Terraform code used to deploy the defined Policy Rules to the DX development subscription on Azure.` + +## Repository Structure + +```shell +infra/ +├── policy/ +│ ├── _policy_rules/ # Contains JSON files defining shared policy rules and parameters +│ ├── dev/ # Policies assigned to the development environment (DEV-ENGINEERING) +``` + +## Policy Rules (`infra/policy/_policy_rules`) + +This directory contains JSON files that define policy rules to be used in Azure, and the JSON file that define the policy rules parameters. These files specify permissions and constraints that can be assigned to users, groups, or services. + +## Environment-Specific Policies (`infra/policy/dev`) + +These directory contain Terraform resources that deploys the defined policy rules into the provided Azure resources (e.g., Subscriptions). + +## Configuration + +Each repository that needs to apply a policy must replicate the same structure within the `infra` directory, excluding `_policy_rules`. Terraform resources must reference the policy rules and parameters definition from the `dx` repository. For example: + +```hcl +# infra/policy/prod/policy_specific_tags.tf + +data "http" "specific_tags_policy_rule" { + url = "https://raw.githubusercontent.com/pagopa/dx/refs/heads/main/infra/policy/_policy_rules/specific_tags_rule_v1.json" +} + +data "http" "specific_tags_policy_parameters" { + url = "https://raw.githubusercontent.com/pagopa/dx/refs/heads/main/infra/policy/_policy_rules/specific_tags_paramenters_v1.json" +} + + +resource "azurerm_policy_definition" "specific_tags_policy" { + name = "${module.naming_convention.project}-specific-tags-policy" + policy_type = "Custom" + mode = "Indexed" + display_name = "DevEx Enforce specific tags and values on resources" + description = "Ensures that resources have specific tags and values during creation." + + metadata = jsonencode({ + category = "Custom DevEx" + version = "1.0.0" + }) + + policy_rule = file(data.http.specific_tags_policy_rule.response_body) + + parameters = file(data.http.specific_tags_policy_parameters.response_body) +} + + +resource "azurerm_subscription_policy_assignment" "specific_tags_assignment" { + name = "${module.naming_convention.project}-specific-tags-assignment" + display_name = "DevEx Enforce specific tags and values on resources" + policy_definition_id = azurerm_policy_definition.specific_tags_policy.id + subscription_id = data.azurerm_subscription.current.id + + parameters = jsonencode({ + "CostCenter" = { + "value" = "TS000 - Tecnologia e Servizi" + }, + "BusinessUnit" = { + "value" = [ + "App IO", + "CGN", + "Carta della Cultura", + "IT Wallet", + ] + }, + "ManagementTeam" = { + "value" = [ + "IO Enti & Servizi", + "IO Platform", + "IO Wallet", + "IO Comunicazione", + "IO Autenticazione", + "IO Bonus & Pagamenti", + "IO Firma", + ] + }, + "SourceOrg" = { + "value" = "pagopa" + } + }) +} +``` diff --git a/infra/policy/_policy_rules/specific_tags_parameters_v1.json b/infra/policy/_policy_rules/specific_tags_parameters_v1.json new file mode 100644 index 000000000..d0d040bf8 --- /dev/null +++ b/infra/policy/_policy_rules/specific_tags_parameters_v1.json @@ -0,0 +1,30 @@ +{ + "CostCenter": { + "type": "String", + "metadata": { + "displayName": "Allowed CostCenter", + "description": "Specify the allowed CostCenter value." + } + }, + "BusinessUnit": { + "type": "Array", + "metadata": { + "displayName": "Allowed Business Units", + "description": "Specify the allowed Business Units." + } + }, + "ManagementTeam": { + "type": "Array", + "metadata": { + "displayName": "Allowed Management Teams", + "description": "Specify the allowed Management Teams." + } + }, + "SourceOrg": { + "type": "String", + "metadata": { + "displayName": "Allowed GitHub Organization", + "description": "Specify the allowed GitHub organization for source tagging." + } + } +} diff --git a/infra/policy/_policy_rules/specific_tags_rule_v1.json b/infra/policy/_policy_rules/specific_tags_rule_v1.json new file mode 100644 index 000000000..fddc35614 --- /dev/null +++ b/infra/policy/_policy_rules/specific_tags_rule_v1.json @@ -0,0 +1,49 @@ +{ + "if": { + "anyOf": [ + { + "field": "tags.CostCenter", + "notEquals": "[parameters('CostCenter')]" + }, + { + "field": "tags.CreatedBy", + "notIn": [ + "Terraform", + "ARM", + "AzurePortal" + ] + }, + { + "field": "tags.Environment", + "notIn": [ + "Prod", + "Dev", + "Uat" + ] + }, + { + "field": "tags.BusinessUnit", + "notIn": "[parameters('BusinessUnit')]" + }, + { + "allOf": [ + { + "field": "tags.CreatedBy", + "equals": "Terraform" + }, + { + "field": "tags.Source", + "notLike": "[concat('https://github.com/', parameters('SourceOrg'), '/*')]" + } + ] + }, + { + "field": "tags.ManagementTeam", + "notIn": "[parameters('ManagementTeam')]" + } + ] + }, + "then": { + "effect": "deny" + } +} diff --git a/infra/policy/dev/.terraform.lock.hcl b/infra/policy/dev/.terraform.lock.hcl new file mode 100644 index 000000000..0a56380c2 --- /dev/null +++ b/infra/policy/dev/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/azurerm" { + version = "4.19.0" + constraints = "~> 4.0" + hashes = [ + "h1:+vSs49DtnEf+xTcNosG96a6NEnoQot9VHz50xymo4BA=", + "h1:Dp5Yah8qu2ulwCdA8/Rv4vAiNkyE3xz7ElmujrY60oE=", + "h1:NGicyVFqUGfPoHWUdZppFK/9lv+TfFNKJN4HEtocvPI=", + "h1:U3glZM34IEgZy2Yhq5zqe0n4DdWYuhQiXILHNI0RoOY=", + "zh:1f4c852bdba8b9d98259cd190af195120a088c12819037e73c5c654197779b04", + "zh:2531bd0c0279958f6f3a1d17a48a39cc5ccaa3d2d0becce6def412aeb4439991", + "zh:3d1d510390041581f10fda5093e2f2dbda34c36fc64550b3a86f895dc3441c44", + "zh:5f4d22484a2d3742efd390f185f7541d857d3349c50f41112945f6d34bdd7da4", + "zh:64e883bfd5d28687c1b6af00d6bb86333b9f9822d5775065c3465b39c839caaf", + "zh:731812c3f8459f12517af20fb63d1eba33e062c6f3832dcbde33fa6e131cd86e", + "zh:7eb714ff68c286333cc2b093a2d9c011c6a1c283c7aa663e4fb101d2e2e6658b", + "zh:855de9d923530f2d207489d4b904a20d32a8ea0f7c639f1f052394ef5cb35422", + "zh:95d0fa6868d07ff4399ca269039aead4dff33fbbd0e5ed8062f04a5e62076cd2", + "zh:9dcdf840c43ac7dd39cf732a3289fb79b834b5f1bcdaa866111d13b4ee7842d4", + "zh:a47776beb983a4f6a635094a9de41916337c50089c4bc628d8c7fa9ca042dd92", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} diff --git a/infra/policy/dev/README.md b/infra/policy/dev/README.md new file mode 100644 index 000000000..1a15a8399 --- /dev/null +++ b/infra/policy/dev/README.md @@ -0,0 +1,37 @@ +# dev + + +## Requirements + +| Name | Version | +|------|---------| +| [azurerm](#requirement\_azurerm) | ~> 4 | + +## Providers + +| Name | Version | +|------|---------| +| [azurerm](#provider\_azurerm) | 4.19.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [naming\_convention](#module\_naming\_convention) | pagopa/dx-azure-naming-convention/azurerm | ~> 0 | + +## Resources + +| Name | Type | +|------|------| +| [azurerm_policy_definition.specific_tags_policy](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/policy_definition) | resource | +| [azurerm_subscription_policy_assignment.specific_tags_assignment](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subscription_policy_assignment) | resource | +| [azurerm_subscription.current](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subscription) | data source | + +## Inputs + +No inputs. + +## Outputs + +No outputs. + diff --git a/infra/policy/dev/data.tf b/infra/policy/dev/data.tf new file mode 100644 index 000000000..634e52c26 --- /dev/null +++ b/infra/policy/dev/data.tf @@ -0,0 +1 @@ +data "azurerm_subscription" "current" {} diff --git a/infra/policy/dev/locals.tf b/infra/policy/dev/locals.tf new file mode 100644 index 000000000..cd9b4ecdb --- /dev/null +++ b/infra/policy/dev/locals.tf @@ -0,0 +1,10 @@ +locals { + environment = { + prefix = "dx" + env_short = "d" + location = "italynorth" + domain = "az" + instance_number = "01" + app_name = "policy" + } +} diff --git a/infra/policy/dev/main.tf b/infra/policy/dev/main.tf new file mode 100644 index 000000000..9dc737670 --- /dev/null +++ b/infra/policy/dev/main.tf @@ -0,0 +1,27 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 4" + } + } + + backend "azurerm" { + resource_group_name = "terraform-state-rg" + storage_account_name = "tfdevdx" + container_name = "terraform-state" + key = "dx.policy.dev.italynorth.tfstate" + } +} + +provider "azurerm" { + features { + } + storage_use_azuread = true +} + +module "naming_convention" { + source = "pagopa/dx-azure-naming-convention/azurerm" + version = "~> 0" + environment = local.environment +} \ No newline at end of file diff --git a/infra/policy/dev/policy_specific_tags.tf b/infra/policy/dev/policy_specific_tags.tf new file mode 100644 index 000000000..0c33b1304 --- /dev/null +++ b/infra/policy/dev/policy_specific_tags.tf @@ -0,0 +1,42 @@ +resource "azurerm_policy_definition" "specific_tags_policy" { + name = "${module.naming_convention.project}-specific-tags-policy" + policy_type = "Custom" + mode = "Indexed" + display_name = "DevEx Enforce specific tags and values on resources" + description = "Ensures that resources have specific tags and values during creation." + + metadata = jsonencode({ + category = "Custom DevEx" + version = "1.0.0" + }) + + policy_rule = file("../_policy_rules/specific_tags_rule_v1.json") + + parameters = file("../_policy_rules/specific_tags_parameters_v1.json") +} + +resource "azurerm_subscription_policy_assignment" "specific_tags_assignment" { + name = "${module.naming_convention.project}-specific-tags-assignment" + display_name = "DevEx Enforce specific tags and values on resources" + policy_definition_id = azurerm_policy_definition.specific_tags_policy.id + subscription_id = data.azurerm_subscription.current.id + + parameters = jsonencode({ + "CostCenter" = { + "value" = "TS000 - Tecnologia e Servizi" + }, + "BusinessUnit" = { + "value" = [ + "DevEx", + ] + }, + "ManagementTeam" = { + "value" = [ + "Developer Experience", + ] + }, + "SourceOrg" = { + "value" = "pagopa" + } + }) +} \ No newline at end of file diff --git a/infra/policy/dev/tfmodules.lock.json b/infra/policy/dev/tfmodules.lock.json new file mode 100644 index 000000000..26b839798 --- /dev/null +++ b/infra/policy/dev/tfmodules.lock.json @@ -0,0 +1,3 @@ +{ + "naming_convention": "5b1d21788783dcf33e17a9842f9f7c874c8c5f736c82e70979eb9c8785a74ce4" +}