variable "hcloud_token" { description = "Read/Write API-Token des Hetzner-Cloud-Projekts." type = string sensitive = true nullable = false validation { condition = length(trimspace(var.hcloud_token)) == 64 && !startswith(var.hcloud_token, "REPLACE_") error_message = "hcloud_token muss durch einen gültigen, 64 Zeichen langen Hetzner-Cloud-API-Token ersetzt werden." } } variable "server_name" { description = "Name des Hetzner-Servers und Präfix der zugehörigen Ressourcen." type = string default = "watermaps" validation { condition = can(regex("^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$", var.server_name)) error_message = "server_name muss ein gültiger Hostname aus Kleinbuchstaben, Ziffern und Bindestrichen sein." } } variable "dns_name" { description = "Öffentlicher DNS-Name. Der DNS-Eintrag selbst wird bewusst nicht von OpenTofu verwaltet." type = string default = "watermaps.incoso.eu" validation { condition = can(regex("^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$", var.dns_name)) error_message = "dns_name muss ein gültiger, vollständig qualifizierter DNS-Name sein." } } variable "location" { description = "Hetzner-Cloud-Location für Server, Primary IP und Volume." type = string default = "fsn1" validation { condition = length(trimspace(var.location)) > 0 error_message = "location darf nicht leer sein." } } variable "server_type" { description = "Hetzner-Cloud-Servertyp. cx33 ist für den initialen Routing- und Ereignisdaten-Import konservativ gewählt." type = string default = "cx33" validation { condition = length(trimspace(var.server_type)) > 0 error_message = "server_type darf nicht leer sein." } } variable "ssh_public_key" { description = "Öffentlicher SSH-Schlüssel für root und den Deploy-Benutzer." type = string nullable = false validation { condition = ( !strcontains(var.ssh_public_key, "REPLACE_") && can(regex( "^(ssh-(ed25519|rsa)|ecdsa-sha2-nistp(256|384|521)|sk-ssh-ed25519@openssh\\.com|sk-ecdsa-sha2-nistp256@openssh\\.com) ", trimspace(var.ssh_public_key) )) ) error_message = "ssh_public_key muss ein gültiger öffentlicher OpenSSH-Schlüssel sein." } } variable "admin_cidrs" { description = "IPv4- oder IPv6-CIDRs, aus denen SSH auf Port 22 erlaubt ist, zum Beispiel [\"203.0.113.10/32\"]." type = list(string) nullable = false validation { condition = ( length(var.admin_cidrs) > 0 && alltrue([for cidr in var.admin_cidrs : can(cidrhost(cidr, 0))]) && !contains(var.admin_cidrs, "203.0.113.10/32") ) error_message = "admin_cidrs muss mindestens ein gültiges, echtes IPv4- oder IPv6-CIDR enthalten; die Beispieladresse muss ersetzt werden." } } variable "deploy_user" { description = "Unprivilegierter Benutzer für Upload und Betrieb der Anwendung." type = string default = "deploy" validation { condition = ( var.deploy_user != "root" && can(regex("^[a-z_][a-z0-9_-]{0,30}$", var.deploy_user)) ) error_message = "deploy_user muss ein gültiger Linux-Benutzername sein und darf nicht root heißen." } } variable "routing_volume_size_gb" { description = "Größe des persistenten ext4-Volumes für Deutschland-/Niederlande-PBFs, Routingindex und PostGIS-Ereignisdaten." type = number default = 40 validation { condition = ( var.routing_volume_size_gb >= 10 && var.routing_volume_size_gb <= 10000 && floor(var.routing_volume_size_gb) == var.routing_volume_size_gb ) error_message = "routing_volume_size_gb muss eine ganze Zahl zwischen 10 und 10000 sein." } } variable "initialize_empty_routing_volume" { description = "Erlaubt genau bei einem nachweislich leeren Volume die initiale ext4-Formatierung. Für importierte oder bestehende Volumes muss dies false bleiben." type = bool default = false } variable "enable_server_protection" { description = "Aktiviert Hetzner-Lösch- und Rebuild-Schutz für den austauschbaren Server." type = bool default = true } variable "enable_primary_ip_protection" { description = "Aktiviert Hetzner-Löschschutz für die persistente öffentliche IPv4." type = bool default = true } variable "enable_volume_protection" { description = "Aktiviert Hetzner-Löschschutz für das persistente Datenvolume." type = bool default = true }