commit d0327a22638f9f3506f644d04eba1f6af34940c4 Author: hahnjan Date: Mon Dec 22 14:54:16 2025 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6fe6dec --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# ---> Terraform +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +# *.tfvars +# *.tfvars.json + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Ignore transient lock info files created by terraform apply +.terraform.tfstate.lock.info + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +# Ignore Images + PRIMARY-DISK.qcow2 + AUXILIARY-DISK.qcow2 \ No newline at end of file diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl new file mode 100644 index 0000000..854a658 --- /dev/null +++ b/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/stackitcloud/stackit" { + version = "0.69.0" + constraints = ">= 0.50.0" + hashes = [ + "h1:ZJT3yMWfm4f2+L8XOJlp4x9dAej6TOz0POQi6yvRimc=", + "zh:0062c29953695943f44561264542c65050c35b45fc5fd279d07db40a856c7e33", + "zh:01f74068286ebbb9e7a280e893b6a941214444986ec0aad156b0a349ab3efbab", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:23f695fc9299cbdff0cef3e99eccdfd6dbc85266d71f9e7eb917066821f97b2d", + "zh:2cb58760e26de6afc93b26452e1987eca0713ecca5a252e3baf4b6a9adce5ab0", + "zh:33b72f438dccbbba5015bd3e265db83fa69f693f5e93cfaf1735bcfd92f2198b", + "zh:4d22147d5881b6ea824ca11d8676dd3c24b378a87e72d849485d87c412d57c0d", + "zh:7373e3036eee52c5d915992bcd42df3227603714e9b814d1f8513e0891b87a54", + "zh:7ea4ad058e2767d7461c4b0cc02adf8591f0c3541274481611ca7c8bc4396f9d", + "zh:82e2568b28874ded800a592b84e6cd570a2f3488214422041a41918076a2db49", + "zh:ae2d827c2328c225d279e37f6e1de2605b670b2f1bddf5d43e7c932ef4ff52a3", + "zh:b206487c97f87f0cde19ef0ab1cfdeafa60ad9fbabdf0d771d96bb56d6d2e94f", + "zh:bdbbe0ba3b3b80b0f2bc09b59ea72f9564f9b93d80949f69f6469b0ab8d6b91c", + "zh:c955889cbb87227031233b2226ebe591e4a30699e3f0fc9f32b61ff2c3836dd7", + "zh:cf51867c75f3c0b58a2e8a2404d4468d0520588aa892c3b30e5beb8a8d20ce79", + ] +} diff --git a/00-variables.auto.tfvars b/00-variables.auto.tfvars new file mode 100644 index 0000000..76e043b --- /dev/null +++ b/00-variables.auto.tfvars @@ -0,0 +1,42 @@ +# ----------------------------------------------------------------------------- +# STACKIT Cloud: Core Configuration +# ----------------------------------------------------------------------------- +project_id = "6f9528aa-27c8-4e97-a0f7-51bbf3be417c" +service_account_key_path = "/Users/hahnjan/.stackit/sa-key_JSP.json" +default_region = "eu01" +default_az = "eu01-3" + +# ----------------------------------------------------------------------------- +# Network Settings +# ----------------------------------------------------------------------------- +sophos_nets_routed = true +sophos_wan_nameservers = ["1.1.1.1", "8.8.8.8"] +sophos_default_nameservers = ["8.8.8.8", "9.9.9.9"] + +# --- Network Ranges --- +sophos_wan_net_range = "10.220.1.0/24" +sophos_lan_net_range = "10.220.0.0/24" +sophos_mgmt_net_range = "10.220.2.0/24" +sophos_sync_net_range = "10.220.3.0/24" + +# --- HA VIP --- +sophos_wan_vip = "10.220.1.60" + +# ----------------------------------------------------------------------------- +# VM Configuration +# ----------------------------------------------------------------------------- + +# --- IPs: Sophos 1 --- +sophos1_mgmt_ip = "10.220.2.10" +sophos1_wan_ip = "10.220.1.11" +sophos1_lan_ip = "10.220.0.12" + +# --- IPs: Sophos 2 --- +sophos2_mgmt_ip = "10.220.2.20" +sophos2_wan_ip = "10.220.1.21" +sophos2_lan_ip = "10.220.0.22" + +# --- Core VM Config --- +sophos_primary_image_path = "./PRIMARY-DISK.qcow2" +sophos_secondary_image_path = "./AUXILIARY-DISK.qcow2" +flavor = "m2i.2" \ No newline at end of file diff --git a/01-provider.tf b/01-provider.tf new file mode 100644 index 0000000..74f07ba --- /dev/null +++ b/01-provider.tf @@ -0,0 +1,15 @@ + +terraform { + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">=0.50.0" + } + } +} + +provider "stackit" { + default_region = var.default_region + service_account_key_path = var.service_account_key_path +} + diff --git a/02-config.tf b/02-config.tf new file mode 100644 index 0000000..4d19cf7 --- /dev/null +++ b/02-config.tf @@ -0,0 +1,147 @@ +# ----------------------------------------------------------------------------- +# STACKIT Cloud: Core Configuration Variables +# ----------------------------------------------------------------------------- + +variable "project_id" { + type = string +} + +variable "service_account_key_path" { + type = string +} + +variable "default_region" { + type = string + default ="eu01" +} + +variable "default_az" { + type = string +} + +# ----------------------------------------------------------------------------- +# Network Variables +# ----------------------------------------------------------------------------- + +# --- Global Settings --- + +variable "sophos_nets_routed" { + description = "Defines if the networks should be routed (true/false)" + type = bool + default = true +} + +# --- Nameservers --- + +variable "sophos_wan_nameservers" { + description = "List of Nameservers for the WAN interface" + type = list(string) + default = ["1.1.1.1", "8.8.8.8"] +} + +variable "sophos_default_nameservers" { + description = "List of Nameservers for internal networks (LAN, MGMT, SYNC)" + type = list(string) + default = ["8.8.8.8", "9.9.9.9"] +} + +# --- Network Ranges (Prefixes) --- + +variable "sophos_wan_net_range" { + description = "CIDR block for the WAN network" + type = string + default = "10.220.1.0/24" +} + +variable "sophos_lan_net_range" { + description = "CIDR block for the LAN network" + type = string + default = "10.220.0.0/24" +} + +variable "sophos_mgmt_net_range" { + description = "CIDR block for the MGMT network" + type = string + default = "10.220.2.0/24" +} + +variable "sophos_sync_net_range" { + description = "CIDR block for the SYNC network" + type = string + default = "10.220.3.0/24" +} + +# --- Specific Wan HA VIP --- + +variable "sophos_wan_vip" { + description = "The specific IPv4 address for the High Availability VIP interface" + type = string + default = "10.220.1.60" +} + +# ----------------------------------------------------------------------------- +# VM Variables +# ----------------------------------------------------------------------------- + +# --- Image File Paths --- + +variable "sophos_primary_image_path" { + description = "Local path to the primary Sophos QCOW2 image file" + type = string + default = "./PRIMARY-DISK.qcow2" +} + +variable "sophos_secondary_image_path" { + description = "Local path to the secondary (auxiliary) Sophos QCOW2 image file" + type = string + default = "./AUXILIARY-DISK.qcow2" +} + +# --- VM Flavor --- + +variable "flavor" { + type = string + description = "Flavor of the Sophos Appliances" + default = "m2i.2" +} + +# --- IPs Sophos 1 --- + +variable "sophos1_mgmt_ip" { + description = "Management IP Sophos 1" + type = string + default = "10.220.2.10" +} + +variable "sophos1_wan_ip" { + description = "WAN IP Sophos 1" + type = string + default = "10.220.1.11" +} + +variable "sophos1_lan_ip" { + description = "LAN IP Sophos 1" + type = string + default = "10.220.0.12" +} + +# --- IPs Sophos 2 --- + +variable "sophos2_mgmt_ip" { + description = "Management IP Sophos 2" + type = string + default = "10.220.2.20" +} + +variable "sophos2_wan_ip" { + description = "WAN IP Sophos 2" + type = string + default = "10.220.1.22" +} + +variable "sophos2_lan_ip" { + description = "LAN IP Sophos 2" + type = string + default = "10.220.0.22" +} + diff --git a/03-sophos-image.tf b/03-sophos-image.tf new file mode 100644 index 0000000..65224b3 --- /dev/null +++ b/03-sophos-image.tf @@ -0,0 +1,24 @@ +# ----------------------------------------------------------------------------- +# Images +# ----------------------------------------------------------------------------- +resource "stackit_image" "sophos_primary_image" { + project_id = var.project_id + name = "sophos-primary-disk-image" + local_file_path = "./PRIMARY-DISK.qcow2" + disk_format = "qcow2" + min_disk_size = 100 + config = { + uefi = false + } +} + +resource "stackit_image" "sophos_secondary_image" { + project_id = var.project_id + name = "sophos-secondary-disk-image" + local_file_path = "./AUXILIARY-DISK.qcow2" + disk_format = "qcow2" + min_disk_size = 100 + config = { + uefi = false + } +} \ No newline at end of file diff --git a/04-sophos-network.tf b/04-sophos-network.tf new file mode 100644 index 0000000..057b60a --- /dev/null +++ b/04-sophos-network.tf @@ -0,0 +1,112 @@ +# ----------------------------------------------------------------------------- +# Network +# ----------------------------------------------------------------------------- + +resource "stackit_network" "sophos_lan_net" { + project_id = var.project_id + name = "sophos_lan_net" + ipv4_nameservers = var.sophos_default_nameservers + ipv4_prefix = var.sophos_lan_net_range + routed = var.sophos_nets_routed +} + +resource "stackit_network" "sophos_wan_net" { + project_id = var.project_id + name = "sophos_wan_net" + ipv4_prefix = var.sophos_wan_net_range + ipv4_nameservers = var.sophos_wan_nameservers + routed = var.sophos_nets_routed +} + +resource "stackit_network" "sophos_mgmt_net" { + project_id = var.project_id + name = "sophos_mgmt_net" + ipv4_prefix = var.sophos_mgmt_net_range + ipv4_nameservers = var.sophos_default_nameservers + routed = var.sophos_nets_routed +} + +resource "stackit_network" "sophos_sync_net" { + project_id = var.project_id + name = "sophos_sync_net" + ipv4_prefix = var.sophos_sync_net_range + ipv4_nameservers = var.sophos_default_nameservers + routed = var.sophos_nets_routed +} + +# ----------------------------------------------------------------------------- +# VIP Interface - others are located directly at the appliances +# ----------------------------------------------------------------------------- + +resource "stackit_network_interface" "vip" { + project_id = var.project_id + network_id = stackit_network.sophos_wan_net.network_id + security = true + name = "VIP" + ipv4 = var.sophos_wan_vip + security_group_ids = [ stackit_security_group.sophos.security_group_id ] +} + +resource "stackit_public_ip" "public-vip" { + project_id = var.project_id + network_interface_id = stackit_network_interface.vip.network_interface_id +} + +output "public-vip" { + value = { + "public_ip_sophos" = stackit_public_ip.public-vip.ip + } +} + +# ----------------------------------------------------------------------------- +# Security Groups / Rules +# ----------------------------------------------------------------------------- + +resource "stackit_security_group" "sophos" { + project_id = var.project_id + name = "Sophos" +} + +resource "stackit_security_group_rule" "tcp-ingress" { + project_id = var.project_id + security_group_id = stackit_security_group.sophos.security_group_id + direction = "ingress" + protocol = { + name = "tcp" + } +} + +resource "stackit_security_group_rule" "icmp-ingress" { + project_id = var.project_id + security_group_id = stackit_security_group.sophos.security_group_id + direction = "ingress" + protocol = { + name = "icmp" + } + icmp_parameters = { + code = 0 + type = 8 + } +} + +resource "stackit_security_group_rule" "tcp-egress" { + project_id = var.project_id + security_group_id = stackit_security_group.sophos.security_group_id + direction = "egress" + protocol = { + name = "tcp" + } +} + +resource "stackit_security_group_rule" "icmp-egress" { + project_id = var.project_id + security_group_id = stackit_security_group.sophos.security_group_id + direction = "egress" + protocol = { + name = "icmp" + } + icmp_parameters = { + code = 0 + type = 8 + } +} \ No newline at end of file diff --git a/05-sophos-appliance1.tf b/05-sophos-appliance1.tf new file mode 100644 index 0000000..56dc803 --- /dev/null +++ b/05-sophos-appliance1.tf @@ -0,0 +1,118 @@ + +# ----------------------------------------------------------------------------- +# Volumes Sophos 1 +# ----------------------------------------------------------------------------- +resource "stackit_volume" "sophos_primary_vol1" { + project_id = var.project_id + name = "sophos-primary-disk1" + availability_zone = var.default_az + size = 150 + performance_class = "storage_premium_perf4" + source = { + id = stackit_image.sophos_primary_image.image_id + type = "image" + } +} + +resource "stackit_volume" "sophos_data_vol1" { + project_id = var.project_id + name = "sophos-data-disk1" + availability_zone = var.default_az + size = 100 + performance_class = "storage_premium_perf4" + source = { + id = stackit_image.sophos_secondary_image.image_id + type = "image" + } +} + +# ----------------------------------------------------------------------------- +# Sophos VM 1 +# ----------------------------------------------------------------------------- + +resource "stackit_server" "sophos_appliance1" { + project_id = var.project_id + name = "Sophos-Appliance1" + boot_volume = { + source_type = "volume" + source_id = stackit_volume.sophos_primary_vol1.volume_id + } + availability_zone = var.default_az + machine_type = var.flavor +} + +resource "stackit_server_volume_attach" "sophos_data_attachment1" { + project_id = var.project_id + server_id = stackit_server.sophos_appliance1.server_id + volume_id = stackit_volume.sophos_data_vol1.volume_id + depends_on = [ stackit_server.sophos_appliance1 ] +} + +# ----------------------------------------------------------------------------- +# Interfaces Sophos 1 +# ----------------------------------------------------------------------------- + +resource "stackit_network_interface" "nic_mgmt_sophos1" { + project_id = var.project_id + network_id = stackit_network.sophos_mgmt_net.network_id + name = "nic_mgmt_sophos1" + security = false + ipv4 = var.sophos1_mgmt_ip +} + +resource "stackit_network_interface" "nic_wan_sophos1" { + project_id = var.project_id + network_id = stackit_network.sophos_wan_net.network_id + security = true + name = "nic_wan_sophos1" + allowed_addresses = ["${stackit_network_interface.vip.ipv4}/32", "0.0.0.0/0"] + security_group_ids = [stackit_security_group.sophos.security_group_id] + ipv4 = var.sophos1_wan_ip +} + +resource "stackit_network_interface" "nic_lan_sophos1" { + project_id = var.project_id + network_id = stackit_network.sophos_lan_net.network_id + security = false + name = "nic_lan_sophos1" + ipv4 = var.sophos1_lan_ip +} + +resource "stackit_network_interface" "nic_sync_sophos1" { + project_id = var.project_id + network_id = stackit_network.sophos_sync_net.network_id + security = false + #security_group_ids = [ stackit_security_group.sophos.security_group_id ] + name = "nic_sync_sophos1" +} + +# ----------------------------------------------------------------------------- +# Interface Attachements 1 +# ----------------------------------------------------------------------------- + +resource "stackit_server_network_interface_attach" "nic-attachment-mgmt1" { + project_id = var.project_id + server_id = stackit_server.sophos_appliance1.server_id + network_interface_id = stackit_network_interface.nic_mgmt_sophos1.network_interface_id +} + +resource "stackit_server_network_interface_attach" "nic-attachment-wan1" { + project_id = var.project_id + server_id = stackit_server.sophos_appliance1.server_id + network_interface_id = stackit_network_interface.nic_wan_sophos1.network_interface_id + depends_on = [stackit_server_network_interface_attach.nic-attachment-mgmt1] +} + +resource "stackit_server_network_interface_attach" "nic-attachment-lan1" { + project_id = var.project_id + server_id = stackit_server.sophos_appliance1.server_id + network_interface_id = stackit_network_interface.nic_lan_sophos1.network_interface_id + depends_on = [stackit_server_network_interface_attach.nic-attachment-wan1] +} + +resource "stackit_server_network_interface_attach" "nic-attachment-sync1" { + project_id = var.project_id + server_id = stackit_server.sophos_appliance1.server_id + network_interface_id = stackit_network_interface.nic_sync_sophos1.network_interface_id + depends_on = [stackit_server_network_interface_attach.nic-attachment-lan1] +} diff --git a/06-sophos-appliance2.tf b/06-sophos-appliance2.tf new file mode 100644 index 0000000..772ea34 --- /dev/null +++ b/06-sophos-appliance2.tf @@ -0,0 +1,118 @@ + +# ----------------------------------------------------------------------------- +# Volumes Sophos 2 +# ----------------------------------------------------------------------------- +resource "stackit_volume" "sophos_primary_vol2" { + project_id = var.project_id + name = "sophos-primary-disk2" + availability_zone = var.default_az + size = 150 + performance_class = "storage_premium_perf4" + source = { + id = stackit_image.sophos_primary_image.image_id + type = "image" + } +} + +resource "stackit_volume" "sophos_data_vol2" { + project_id = var.project_id + name = "sophos-data-disk2" + availability_zone = var.default_az + size = 100 + performance_class = "storage_premium_perf4" + source = { + id = stackit_image.sophos_secondary_image.image_id + type = "image" + } +} + +# ----------------------------------------------------------------------------- +# Sophos VM 2 +# ----------------------------------------------------------------------------- + +resource "stackit_server" "sophos_appliance2" { + project_id = var.project_id + name = "Sophos-Appliance2" + boot_volume = { + source_type = "volume" + source_id = stackit_volume.sophos_primary_vol2.volume_id + } + availability_zone = var.default_az + machine_type = var.flavor +} + +resource "stackit_server_volume_attach" "sophos_data_attachment2" { + project_id = var.project_id + server_id = stackit_server.sophos_appliance2.server_id + volume_id = stackit_volume.sophos_data_vol2.volume_id + depends_on = [ stackit_server.sophos_appliance2 ] +} + +# ----------------------------------------------------------------------------- +# Interfaces Sophos 2 +# ----------------------------------------------------------------------------- + +resource "stackit_network_interface" "nic_mgmt_sophos2" { + project_id = var.project_id + network_id = stackit_network.sophos_mgmt_net.network_id + name = "nic_mgmt_sophos2" + security = false + ipv4 = var.sophos2_mgmt_ip +} + +resource "stackit_network_interface" "nic_wan_sophos2" { + project_id = var.project_id + network_id = stackit_network.sophos_wan_net.network_id + security = true + name = "nic_wan_sophos2" + allowed_addresses = ["${stackit_network_interface.vip.ipv4}/32", "0.0.0.0/0"] + security_group_ids = [stackit_security_group.sophos.security_group_id] + ipv4 = var.sophos2_wan_ip +} + +resource "stackit_network_interface" "nic_lan_sophos2" { + project_id = var.project_id + network_id = stackit_network.sophos_lan_net.network_id + security = false + name = "nic_lan_sophos2" + ipv4 = var.sophos2_lan_ip +} + +resource "stackit_network_interface" "nic_sync_sophos2" { + project_id = var.project_id + network_id = stackit_network.sophos_sync_net.network_id + security = false + #security_group_ids = [ stackit_security_group.sophos.security_group_id ] + name = "nic_sync_sophos2" +} + +# ----------------------------------------------------------------------------- +# Interface Attachements 2 +# ----------------------------------------------------------------------------- + +resource "stackit_server_network_interface_attach" "nic-attachment-mgmt2" { + project_id = var.project_id + server_id = stackit_server.sophos_appliance2.server_id + network_interface_id = stackit_network_interface.nic_mgmt_sophos2.network_interface_id +} + +resource "stackit_server_network_interface_attach" "nic-attachment-wan2" { + project_id = var.project_id + server_id = stackit_server.sophos_appliance2.server_id + network_interface_id = stackit_network_interface.nic_wan_sophos2.network_interface_id + depends_on = [stackit_server_network_interface_attach.nic-attachment-mgmt2] +} + +resource "stackit_server_network_interface_attach" "nic-attachment-lan2" { + project_id = var.project_id + server_id = stackit_server.sophos_appliance2.server_id + network_interface_id = stackit_network_interface.nic_lan_sophos2.network_interface_id + depends_on = [stackit_server_network_interface_attach.nic-attachment-wan2] +} + +resource "stackit_server_network_interface_attach" "nic-attachment-sync2" { + project_id = var.project_id + server_id = stackit_server.sophos_appliance2.server_id + network_interface_id = stackit_network_interface.nic_sync_sophos2.network_interface_id + depends_on = [stackit_server_network_interface_attach.nic-attachment-lan2] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..ce9669c --- /dev/null +++ b/README.md @@ -0,0 +1,199 @@ +# Sophos HA on STACKIT + +This directory contains the **Terraform configuration** for deploying a **High Availability (HA) cluster** of two **Sophos Firewalls** on the **STACKIT** cloud platform. The configuration includes all necessary resources such as networks, virtual machines (appliances), volumes, interfaces, and security groups. + +## Content Readme +* [Directory Structure](#directory-structure) +* [Prerequisites](#prerequisites) +* [Infrastructure Guide](#infrastructure-guide) +* [Application Guide](#application-guide) +--- +## Directory Structure + +#### [`01-provider.tf`](./01-provider.tf) +This file initializes the **STACKIT Terraform Provider**. It defines which cloud platform is being managed and specifies the version to be used. The **latest version** is always selected; in the specific deployment, **Version 0.69.0** was used. + +#### [`02-config.tf`](./02-config.tf) +This is where the most important **configuration variables** are defined, determining the target project and hardware specifications. Parameters include `project_id`, the path to the `service_account_key_path`, and default settings for `default_region`, `default_az`, and the VM `flavor` (e.g., `m2i.2`). + +#### [`03-sophos-image.tf`](./03-sophos-image.tf) +This file configures the creation of the necessary STACKIT images. The local **QCOW2 files** (`PRIMARY-DISK.qcow2` and `AUXILIARY-DISK.qcow2`), which contain the Sophos installation, are converted into usable cloud images. + +#### [`04-sophos-network.tf`](./04-sophos-network.tf) +Here, the four **Sophos-specific networks** (Management, LAN, Synchronization, WAN) and the associated components are configured: +* `sophos_mgmt_net` +* `sophos_lan_net` +* `sophos_sync_net` +* `sophos_wan_net` +* A **VIP (Virtual IP) Interface** for HA operation. The VIP should not be attached to any VM. +* A **Public IP address** for external access (e.g., WAN). +* The necessary **Security Groups and Rules** to control traffic. + +#### [`05-sophos-appliance1.tf`](./05-sophos-appliance1.tf) and [`06-sophos-appliance2.tf`](./06-sophos-appliance2.tf) +These files each define one of the two Sophos VMs that form the HA cluster. The configuration includes: +* Creation of the two **Volumes** (boot and auxiliary disk) for the VM. +* Creation of the **VM** itself. +* Creation and correct sequential attachment of the **four network interfaces**: + 1. Management (`mgmt`) + 2. LAN (`lan`) + 3. Synchronization (`sync`) + 4. WAN (`wan`) + +--- + +## Prerequisites + +Before deploying the Sophos HA construct, ensure the following tools and assets are available: + +### 1. Software Tools + +* **Terraform CLI:** You need the **Terraform Command Line Interface** installed and configured to execute the Infrastructure-as-Code files (`*.tf`). +* **STACKIT CLI (Optional):** The **STACKIT Command Line Interface** is not strictly required for the Terraform deployment itself but can be useful for managing your STACKIT Project and is *recommended* for mapping the MAC addresses. + +### 2. Sophos Assets + +* **Sophos Images (QCOW2 Format):** The Sophos appliance images must be available as **two QCOW2 files**. + * Place these files directly in the root directory and ensure they are named exactly: + * `PRIMARY-DISK.qcow2` + * `AUXILIARY-DISK.qcow2` +* **Sophos Serial Number/License:** A valid **Sophos Serial Number** or **License** is required to activate the appliances and enable HA functionality after they have been successfully deployed. +--- +## Infrastructure Guide + +### Step 1: Prepare the Environment + +1. **Clone the Repository:** + ```bash + git clone + cd Sophos-HA + ``` +2. **Provide Sophos Images:** + * Place the two Sophos QCOW2 image files directly into the root directory of the cloned repository. + * Ensure they are named correctly or adjust the path as a variable: `PRIMARY-DISK.qcow2` and `AUXILIARY-DISK.qcow2`. + +### Step 2: Configure Terraform Variables + +1. **Create Variables File:** + * The required variables are defined in `02-config.tf`. To provide the values, create a new file named **`00-variables.auto.tfvars`** in the root directory. + * Fill in the values based on your project and environment: +2. **Configure STACKIT Service Account:** + * **Generate** a STACKIT Service Account Key (JSON format) and place the path to this key in the `service_account_key_path` variable. + +3. **Configure Terraform Backend:** + * **Recommendation:** For production environments, it is highly recommended to configure a remote backend (e.g., a **STACKIT Object Storage Bucket**) in `01-provider.tf` to store the `tfstate` securely. Alternatively, you can use the default local backend configuration for testing purposes. + +### Step 3: Execute Terraform + +1. **Initialize Terraform:** + * Ensure that you are in the project folder (`cd Sophos-HA`). + * Initialize the working directory and download the necessary providers (including the STACKIT provider). + ```bash + terraform init + ``` +2. **Review the Plan:** + * Check the infrastructure changes Terraform intends to make. + ```bash + terraform plan + ``` +3. **Apply the Configuration:** + * Execute the plan to deploy all resources (Networks, Images, Volumes, VMs/Appliances). + ```bash + terraform apply + ``` + * Wait until the process is complete and the VMs are fully provisioned and booted. + +### Step 4: Initial Sophos Appliance Configuration + +After successful deployment, the two Sophos Appliances need an initial configuration via the console to enable management access. + +1. **Access the Console:** + * In the STACKIT Portal, access the **Console** of **Appliance 1** (`sophos-appliance1`). +2. **Initial Login:** + * The Sophos appliance should boot into the main menu. + * The standard password for Sophos appliances is **`admin`** (case sensitive). +3. **Configure Management Interface:** + * From the main menu, select **`1. Network Configuration`**. + * Select **`1. Interface Configuration`**. + * Identify the interface corresponding to the **Management Network** (e.g., Port 1) and configure it with the pre-defined ipv4 IP and CIDR block from the Terraform configuration (specifically the **`sophos_mgmt_net`** ). + +4. **Repeat for Appliance 2:** + * Perform the same initial console configuration for **Appliance 2** (`sophos-appliance2`), assigning it the pre-defined IP and CIDR within the same `sophos_mgmt_net` subnet. + +5. **Access Web Interface:** + * Use a jump host VM within the same subnet `sophos_mgmt_net` or your local device with appropriate routing to access the Sophos WebAdmin console. (`https://:4444`) + +## Application Guide + +This section outlines the configuration steps required within the Sophos WebAdmin interface to establish the High Availability (HA) cluster and configure public connectivity. + +### Step 1: Initial Wizard and Registration + +1. **Run the Setup Wizard:** + * Log in to the WebAdmin of both appliances (`https://:4444`). + * Complete the basic setup wizard on **both** appliances. + * **Firmware Check:** Ensure both appliances are running the **exact same firmware version**. + * *Tip:* If firmware versions match immediately, you can configure the second appliance as an "HA Spare" directly during the first wizard step. Otherwise, configure both as standalone first and update firmware. +2. **Registration:** + * After the reboot, log in with the admin credentials. + * Register both firewalls. A valid license (minimum **Home License**) is required to enable HA functionality. + +### Step 2: Configure Sync Interface + +Perform these steps on **both** appliances: + +1. **Network Configuration:** + * Navigate to **Network > Interfaces**. + * Edit the Port identified as the **Sync Interface**. + * Set the **Network Zone** to **DMZ**. + * Assign the IP address allocated by Terraform for the Sync network. +2. **Device Access:** + * Navigate to **Administration > Device Access**. + * Enable **SSH** on the **DMZ** zone (required for HA communication). + +### Step 3: Configure High Availability (HA) + +Configure the **Auxiliary (Sophos 2)** appliance first, then the **Primary (Sophos 1)**. + +#### 1. Configure Sophos 2 (Auxiliary) +* Navigate to **System Services > High Availability**. +* **Initial Device Role:** Select **Auxiliary (Interactive Mode)**. +* **Node Name:** Assign a name (e.g., `Sophos-Node2`). +* **Passphrase:** Set a secure passphrase (note this down, it must match on the Primary). +* **Dedicated HA Link:** Select the **DMZ Port** configured in Step 3. +* Click **Save** or **Enable HA**. + +#### 2. Configure Sophos 1 (Primary) +* Navigate to **System Services > High Availability**. +* **Initial Device Role:** Select **Primary (Interactive Mode)**. +* **Cluster ID:** Select an ID (0-63). +* **Node Name:** Assign a name (e.g., `Sophos-Node1`). +* **Passphrase:** Enter the same passphrase used on the Auxiliary. +* **Dedicated HA Link:** Select the **DMZ Port**. +* **Peer HA Link IPv4:** Enter the IP address of the **Sophos 2 Sync Interface**. +* **Monitored Ports:** Select the interfaces to monitor (usually LAN and WAN). +* **Peer Administration Settings:** Enter the **Management IP** of Sophos 2. +* **Hypervisor MAC:** Set **Use host or hypervisor-assigned MAC address** to **True**. + * *Important:* This setting is critical for STACKIT/OpenStack environments to ensure traffic routing works correctly during failover. +* Click **Enable HA**. + +### Step 4: Post-HA Network Configuration (VIP) + +Once the HA cluster is built, the primary appliance handles traffic. You must now configure the public-facing interface to use the Virtual IP (VIP). + +1. **Assign VIP Address:** + * On the active (Primary) appliance, navigate to **Network > Interfaces**. + * Edit the **WAN Port**. + * Manually change the IP address to the **local VIP Address**. +2. **Enable WAN Services:** + * Navigate to **Administration > Device Access**. + * Enable necessary services on the **WAN** zone (e.g., User Portal, VPN). + * **Testing:** Temporarily enable **Ping** on WAN to verify connectivity. + +### Step 5: Verification and Failover Test + +1. **Ping Test:** + * Ping the **Public IP** output by the Terraform script. It should be reachable. +2. **Failover Test:** + * Shut down the **Primary VM** via the STACKIT Portal or Sophos WebUI. + * The **Auxiliary VM** should take over the role of Primary after a short interruption. + * Verify that the Public IP remains pingable. \ No newline at end of file