Some checks failed
PR Checks / tofu-checks (pull_request) Failing after 2s
1/1 projects applied successfully.
Reusable OpenTofu module for creating isolated tenant VMs with: - Public IP on vmbr1 (bridged, firewall=true) - Cloud-init: password auth, fail2ban, UFW hardening - Per-VM Proxmox firewall (IN: SSH+ICMP, OUT: allow, block SMTP) Includes test-tenant VM (185.47.204.227) for verification. Changes: - modules/tenant-vm/ — reusable module (VM + FW + cloud-init) - environments/production/tenant-vms.tf — tenant VM definitions - policies/security.rego — require firewall=true on vmbr1 - atlantis.yaml — trigger on module file changes - main.tf — updated host prerequisites comment Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
39 lines
1.4 KiB
Rego
39 lines
1.4 KiB
Rego
package main
|
|
|
|
import rego.v1
|
|
|
|
# NOTE: Per-NIC Proxmox firewall (bridge-nf-call-iptables) conflicts with NAT
|
|
# routing on bridges without physical uplink (vmbr0). Security is ensured by:
|
|
# - NAT isolation (VMs not reachable from outside)
|
|
# - Host-level Proxmox firewall (default DROP on input/output)
|
|
# - SSH key-only authentication via cloud-init
|
|
|
|
# No password authentication on VMs using user_account block
|
|
# (Tenant VMs use cloud-init snippets with user_data_file_id instead,
|
|
# so this rule does not apply to them)
|
|
deny contains msg if {
|
|
some resource in input.resource_changes
|
|
resource.type == "proxmox_virtual_environment_vm"
|
|
resource.change.actions[_] in {"create", "update"}
|
|
resource.change.after_sensitive.initialization[0].user_account[0].password == true
|
|
|
|
msg := sprintf(
|
|
"SECURITY: VM '%s' uses password auth via user_account. Use SSH keys or cloud-init snippet.",
|
|
[resource.address],
|
|
)
|
|
}
|
|
|
|
# VMs on vmbr1 (bridged, public IP) MUST have firewall=true on NIC
|
|
deny contains msg if {
|
|
some resource in input.resource_changes
|
|
resource.type == "proxmox_virtual_environment_vm"
|
|
resource.change.actions[_] in {"create", "update"}
|
|
resource.change.after.network_device[0].bridge == "vmbr1"
|
|
not resource.change.after.network_device[0].firewall
|
|
|
|
msg := sprintf(
|
|
"SECURITY: VM '%s' on vmbr1 (public bridge) must have firewall=true on NIC.",
|
|
[resource.address],
|
|
)
|
|
}
|