package main import future.keywords.in # Import the raw input instead of using tfplan alias import input vms := [r | r := input.planned_values.root_module.resources[_]; r.type == "proxmox_vm_qemu"] # Helper function to check if a value is empty or undefined is_empty(value) if { value == "" } { value == null } { not value } # Helper function to check minimum memory requirements (in MB) min_memory = 512 # Deny if VM allows password authentication deny contains msg if { some vm in vms not is_empty(vm.values.cipassword) msg := sprintf("VM '%s' uses password authentication. Use SSH keys only.", [vm.name]) } # Deny if VM allows root login deny contains msg if { some vm in vms vm.values.ciuser == "root" msg := sprintf("VM '%s' allows root login. Use a non-root user.", [vm.name]) } # Deny if qemu-agent is not enabled deny contains msg if { some vm in vms vm.values.agent != 1 msg := sprintf("VM '%s' does not have qemu-agent enabled (agent = 1).", [vm.name]) } # Deny if VM uses insecure network bridge deny contains msg if { some vm in vms net := vm.values.network[_] net.bridge != "vmbr2" msg := sprintf("VM '%s' uses insecure network bridge '%s'. Use 'vmbr2'.", [vm.name, net.bridge]) } # Deny if IPv6 is not disabled deny contains msg if { some vm in vms not vm.values.skip_ipv6 msg := sprintf("VM '%s' does not have IPv6 disabled (skip_ipv6 = true).", [vm.name]) } # Deny if TLS verification is disabled deny contains msg if { tls_enabled := input.variables.pm_tls_insecure.value tls_enabled == true msg := "TLS verification must be enabled (pm_tls_insecure = false)" } # Deny if provider version is not pinned deny contains msg if { provider := input.configuration.terraform.required_providers.proxmox not startswith(provider.version_constraint, "=") msg := "Provider version must be pinned with '=' constraint" } # Deny if VM memory is below minimum requirement deny contains msg if { some vm in vms memory := to_number(vm.values.memory) memory < min_memory msg := sprintf("VM '%s' has insufficient memory (%dMB). Minimum required: %dMB.", [vm.name, memory, min_memory]) } # Deny if VM does not have a description deny contains msg if { some vm in vms is_empty(vm.values.desc) msg := sprintf("VM '%s' must have a description for documentation purposes.", [vm.name]) } # Deny if VM uses default SCSI controller deny contains msg if { some vm in vms vm.values.scsihw == "lsi" msg := sprintf("VM '%s' uses default SCSI controller. Use virtio-scsi-pci for better performance.", [vm.name]) } # Test rule to verify policy is loaded test_policy_loaded if { true }