diff --git a/terraform/firewall.tf b/terraform/firewall.tf index cb658ec..d9e25a9 100644 --- a/terraform/firewall.tf +++ b/terraform/firewall.tf @@ -209,6 +209,53 @@ resource "hcloud_firewall" "legacy_vm" { } } +# Firewall for bot node (OpenClaw / MoltBot) +# Minimal inbound surface: SSH only. No public web UI/API. +resource "hcloud_firewall" "bot_node" { + name = "bot-node-firewall" + + # SSH access from anywhere (restrict to your admin IP in a follow-up if desired) + rule { + direction = "in" + protocol = "tcp" + port = "22" + source_ips = [ + "0.0.0.0/0", + "::/0" + ] + } + + # Allow all outbound traffic + rule { + direction = "out" + protocol = "tcp" + port = "any" + destination_ips = [ + "0.0.0.0/0", + "::/0" + ] + } + + rule { + direction = "out" + protocol = "udp" + port = "any" + destination_ips = [ + "0.0.0.0/0", + "::/0" + ] + } + + rule { + direction = "out" + protocol = "icmp" + destination_ips = [ + "0.0.0.0/0", + "::/0" + ] + } +} + # Attach firewall to k8s cluster nodes (masters + workers) resource "hcloud_firewall_attachment" "k8s_cluster" { firewall_id = hcloud_firewall.k8s_cluster.id @@ -217,3 +264,9 @@ resource "hcloud_firewall_attachment" "k8s_cluster" { [for server in hcloud_server.k8s_worker : server.id] ) } + +# Attach firewall to bot node +resource "hcloud_firewall_attachment" "bot_node" { + firewall_id = hcloud_firewall.bot_node.id + server_ids = [for server in hcloud_server.bot_node : server.id] +} diff --git a/terraform/main.tf b/terraform/main.tf index a44a12c..3d56b5c 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -88,6 +88,38 @@ resource "hcloud_network_subnet" "k8s_private_subnet" { ip_range = "10.0.1.0/24" } +# Bot node private network (isolated from the Kubernetes cluster) +resource "hcloud_network" "bot_private_net" { + name = "bot-private-net" + ip_range = "10.1.0.0/16" +} + +resource "hcloud_network_subnet" "bot_private_subnet" { + network_id = hcloud_network.bot_private_net.id + type = "cloud" + network_zone = "eu-central" + ip_range = "10.1.1.0/24" +} + +resource "hcloud_server" "bot_node" { + count = 1 + name = "bot-node-${count.index + 1}" + image = "ubuntu-24.04" + server_type = "cx23" + location = "nbg1" + ssh_keys = [hcloud_ssh_key.hetzner_ssh_key.id] + + # Attach each server to the bot private network with explicit IPs + network { + network_id = hcloud_network.bot_private_net.id + ip = "10.1.1.${count.index + 1}" + } + + depends_on = [ + hcloud_network_subnet.bot_private_subnet + ] +} + resource "hcloud_server" "k8s_node" { count = 3 # Create three identical nodes name = "k8s-node-${count.index + 1}" @@ -101,6 +133,23 @@ resource "hcloud_server" "k8s_node" { network_id = hcloud_network.k8s_private_net.id ip = "10.0.1.${count.index + 1}" } + + # Provider does not persist all metadata for these imported servers, + # so ignore the drift to avoid unwanted updates or recreation. + lifecycle { + ignore_changes = [ + location, + datacenter, + labels, + placement_group_id, + ssh_keys, + allow_deprecated_images, + ignore_remote_firewall_ids, + keep_disk, + shutdown_before_deletion, + network, + ] + } } # Worker nodes (separate from masters for flexibility) @@ -123,4 +172,21 @@ resource "hcloud_server" "k8s_worker" { depends_on = [ hcloud_network_subnet.k8s_private_subnet ] + + # Provider does not persist all metadata for this imported server, + # so ignore the drift to avoid unwanted updates or recreation. + lifecycle { + ignore_changes = [ + location, + datacenter, + labels, + placement_group_id, + ssh_keys, + allow_deprecated_images, + ignore_remote_firewall_ids, + keep_disk, + shutdown_before_deletion, + network, + ] + } }