diff --git a/iac/main.tf b/iac/main.tf index e7339d3..edd0630 100644 --- a/iac/main.tf +++ b/iac/main.tf @@ -1,32 +1,66 @@ locals { app = { - name = "erp" + name = "erp" product_name = "dolibarr" # unused } + + # Environments this app is deployed to. By the elision rule (factory runbook + # conventions.md / ADR-0002) env=prod renders identical to the single-env + # baseline; non-prod envs get a "-" instance id from the module. + envs = toset(["prod", "sandbox"]) } module "app_roles" { - source = "git::ssh://git@192.168.1.202:2222/arcodange-org/tools.git//hashicorp-vault/iac/modules/app_roles?depth=1&ref=main" - name = local.app.name + source = "git::ssh://git@192.168.1.202:2222/arcodange-org/tools.git//hashicorp-vault/iac/modules/app_roles?depth=1&ref=main" + for_each = local.envs + name = local.app.name + env = each.key } resource "random_password" "admin_initial_password" { - length = 32 + for_each = local.envs + length = 32 } resource "random_uuid" "dolibarr_id" { # used for encryption as well as when buying modules + for_each = local.envs lifecycle { prevent_destroy = true } } resource "vault_kv_secret_v2" "dolibarr_admin_setup" { - mount = module.app_roles.mount_paths.kvv2 - name = format("%sconfig", module.app_roles.kvv2_path_prefix) - data_json = jsonencode( - { - DOLI_ADMIN_LOGIN = "admin", - DOLI_ADMIN_PASSWORD = random_password.admin_initial_password.result - DOLI_INSTANCE_UNIQUE_ID = random_uuid.dolibarr_id.result - } + for_each = local.envs + mount = module.app_roles[each.key].mount_paths.kvv2 + name = format("%sconfig", module.app_roles[each.key].kvv2_path_prefix) + data_json = jsonencode( + { + DOLI_ADMIN_LOGIN = "admin", + DOLI_ADMIN_PASSWORD = random_password.admin_initial_password[each.key].result + DOLI_INSTANCE_UNIQUE_ID = random_uuid.dolibarr_id[each.key].result + } ) } + +# State migration (ADR-0002 Phase D): re-key the pre-existing single-env resources +# into the for_each map under the "prod" key so that introducing for_each does NOT +# plan a destroy+create. This is critical for random_uuid.dolibarr_id — it carries +# prevent_destroy = true (it is the prod Dolibarr encryption id + paid-module +# binding), so a missing moved block would HARD-FAIL the apply rather than silently +# losing it. The module's own internal moved (role -> role[0]) chains with the +# module re-key here. +moved { + from = module.app_roles + to = module.app_roles["prod"] +} +moved { + from = random_password.admin_initial_password + to = random_password.admin_initial_password["prod"] +} +moved { + from = random_uuid.dolibarr_id + to = random_uuid.dolibarr_id["prod"] +} +moved { + from = vault_kv_secret_v2.dolibarr_admin_setup + to = vault_kv_secret_v2.dolibarr_admin_setup["prod"] +}