variable "users" { description = "List of userpass usernames to create." type = list(string) default = ["ms2k"] } variable "admin_user" { description = "Username from var.users to grant the admin policy. Used to establish non-root administrative access before revoking the initial root token." type = string default = "ms2k" validation { condition = contains(var.users, var.admin_user) error_message = "admin_user must be present in var.users." } } # Auth method resource "vault_auth_backend" "userpass" { type = "userpass" } # Admin policy resource "vault_policy" "admin" { name = "admin" policy = <<-EOT path "*" { capabilities = ["create", "read", "update", "delete", "list", "sudo", "patch", "subscribe"] subscribe_event_types = ["*"] } EOT } # Users resource "random_password" "user" { for_each = toset(var.users) length = 32 special = false # alphanumeric only — avoids quoting issues when pasting into CLI } resource "vault_generic_endpoint" "user" { for_each = toset(var.users) path = "auth/${vault_auth_backend.userpass.path}/users/${each.key}" ignore_absent_fields = true # Terraform sets the initial password and policies on creation only. # Vault is the source of truth after that — re-runs won't reset passwords. lifecycle { ignore_changes = [data_json] } data_json = jsonencode({ password = random_password.user[each.key].result policies = each.key == var.admin_user ? "admin" : "" }) } # Outputs output "user_passwords" { description = "Generated passwords keyed by username. Sensitive — retrieve with: tofu output -json user_passwords" sensitive = true value = { for u in var.users : u => random_password.user[u].result } }