locals { app = { 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" for_each = local.envs name = local.app.name env = each.key } resource "random_password" "admin_initial_password" { 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" { 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"] }