From 0f423eff6f0462ed5608f83cf2482699979d9bab Mon Sep 17 00:00:00 2001 From: Michael Sodan Date: Wed, 15 Apr 2026 11:58:19 +0000 Subject: [PATCH 1/2] palo-alto-ha tf examples --- examples/iaas-paloalto-ha/00-provider.tf | 23 +++ examples/iaas-paloalto-ha/01-network.tf | 158 ++++++++++++++++++ .../iaas-paloalto-ha/02-paloalto-image.tf | 13 ++ .../iaas-paloalto-ha/03-paloalto_appliance.tf | 48 ++++++ examples/iaas-paloalto-ha/04-attachment.tf | 25 +++ .../iaas-paloalto-ha/05-security-group.tf | 33 ++++ examples/iaas-paloalto-ha/99-variables.tf | 35 ++++ examples/iaas-paloalto-ha/README.md | 56 +++++++ .../iaas-paloalto-ha/project/00-provider.tf | 18 ++ examples/iaas-paloalto-ha/project/01-sna.tf | 15 ++ .../iaas-paloalto-ha/project/02-project.tf | 21 +++ .../iaas-paloalto-ha/project/99-variables.tf | 35 ++++ 12 files changed, 480 insertions(+) create mode 100644 examples/iaas-paloalto-ha/00-provider.tf create mode 100644 examples/iaas-paloalto-ha/01-network.tf create mode 100644 examples/iaas-paloalto-ha/02-paloalto-image.tf create mode 100644 examples/iaas-paloalto-ha/03-paloalto_appliance.tf create mode 100644 examples/iaas-paloalto-ha/04-attachment.tf create mode 100644 examples/iaas-paloalto-ha/05-security-group.tf create mode 100644 examples/iaas-paloalto-ha/99-variables.tf create mode 100644 examples/iaas-paloalto-ha/README.md create mode 100644 examples/iaas-paloalto-ha/project/00-provider.tf create mode 100644 examples/iaas-paloalto-ha/project/01-sna.tf create mode 100644 examples/iaas-paloalto-ha/project/02-project.tf create mode 100644 examples/iaas-paloalto-ha/project/99-variables.tf diff --git a/examples/iaas-paloalto-ha/00-provider.tf b/examples/iaas-paloalto-ha/00-provider.tf new file mode 100644 index 0000000..0745928 --- /dev/null +++ b/examples/iaas-paloalto-ha/00-provider.tf @@ -0,0 +1,23 @@ + +terraform { + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">=0.50.0" + } + } +} + +# Authentication +# Key flow (using path) + + +provider "stackit" { + default_region = var.default_region + service_account_key_path = var.service_account_key_path + enable_beta_resources = true +} + +module "project" { + source = "./project" # Der Pfad zum Modul-Verzeichnis +} diff --git a/examples/iaas-paloalto-ha/01-network.tf b/examples/iaas-paloalto-ha/01-network.tf new file mode 100644 index 0000000..c4a121c --- /dev/null +++ b/examples/iaas-paloalto-ha/01-network.tf @@ -0,0 +1,158 @@ +resource "stackit_network" "mgmt_network" { + project_id = module.project.project_info["project_id"] + name = "mgmt_network" + ipv4_nameservers = ["1.1.1.1", "8.8.8.8"] + ipv4_prefix = "10.220.129.0/24" + routed = true +} + +resource "stackit_network" "ha_network" { + project_id = module.project.project_info["project_id"] + name = "ha_network" + ipv4_prefix = "10.220.254.0/24" + routed = false +} + +resource "stackit_network" "wan_network" { + project_id = module.project.project_info["project_id"] + name = "wan_network" + ipv4_nameservers = ["1.1.1.1", "8.8.8.8"] + ipv4_prefix = "10.220.131.0/24" + routed = true +} + + +resource "stackit_network" "lan_network1" { + project_id = module.project.project_info["project_id"] + name = "lan_network1" + ipv4_prefix = "10.220.1.0/24" + routed = false +} + +resource "stackit_network" "lan_network2" { + project_id = module.project.project_info["project_id"] + name = "lan_network2" + ipv4_prefix = "10.220.2.0/24" + routed = false +} + +resource "stackit_network_interface" "mgmt" { + project_id = module.project.project_info["project_id"] + network_id = stackit_network.mgmt_network.network_id + security = false + name = "MGMT" + ipv4 = "10.220.129.17" +} + +resource "stackit_network_interface" "ha" { + project_id = module.project.project_info["project_id"] + network_id = stackit_network.ha_network.network_id + security = false + name = "HA" + ipv4 = "10.220.254.100" +} +resource "stackit_network_interface" "wan" { + project_id = module.project.project_info["project_id"] + network_id = stackit_network.wan_network.network_id + security = true + name = "MGMT" + ipv4 = "10.220.131.10" + allowed_addresses = ["10.220.131.30/32", "0.0.0.0/0"] + security_group_ids = [stackit_security_group.paloalto.security_group_id] + +} + +resource "stackit_network_interface" "mgmt2" { + project_id = module.project.project_info["project_id"] + network_id = stackit_network.mgmt_network.network_id + security = false + name = "MGMT2" + ipv4 = "10.220.129.18" +} + +resource "stackit_network_interface" "ha2" { + project_id = module.project.project_info["project_id"] + network_id = stackit_network.ha_network.network_id + security = false + name = "HA2" + ipv4 = "10.220.254.200" +} +resource "stackit_network_interface" "wan2" { + project_id = module.project.project_info["project_id"] + network_id = stackit_network.wan_network.network_id + security = true + name = "WAN2" + allowed_addresses = ["10.220.131.30/32", "0.0.0.0/0"] + security_group_ids = [stackit_security_group.paloalto.security_group_id] +} + +resource "stackit_network_interface" "vip" { + project_id = module.project.project_info["project_id"] + network_id = stackit_network.wan_network.network_id + security = false + name = "VIP" + ipv4 = "10.220.131.30" +} + +resource "stackit_network_interface" "lan1" { + project_id = module.project.project_info["project_id"] + network_id = stackit_network.lan_network1.network_id + security = false + name = "LAN1" +} +resource "stackit_network_interface" "lan1_2" { + project_id = module.project.project_info["project_id"] + network_id = stackit_network.lan_network1.network_id + security = false + name = "LAN1" +} + +resource "stackit_network_interface" "lan2" { + project_id = module.project.project_info["project_id"] + network_id = stackit_network.lan_network2.network_id + security = false + name = "LAN2" +} +resource "stackit_network_interface" "lan2_2" { + project_id = module.project.project_info["project_id"] + network_id = stackit_network.lan_network2.network_id + security = false + name = "LAN2" +} + +resource "stackit_public_ip" "mgmt_ip" { + project_id = module.project.project_info["project_id"] + network_interface_id = stackit_network_interface.mgmt.network_interface_id +} + +resource "stackit_public_ip" "wan_ip" { + project_id = module.project.project_info["project_id"] + network_interface_id = stackit_network_interface.wan.network_interface_id +} + + +resource "stackit_public_ip" "mgmt2_ip" { + project_id = module.project.project_info["project_id"] + network_interface_id = stackit_network_interface.mgmt2.network_interface_id +} + +resource "stackit_public_ip" "wan2_ip" { + project_id = module.project.project_info["project_id"] + network_interface_id = stackit_network_interface.wan2.network_interface_id +} + +resource "stackit_public_ip" "vip_ip" { + project_id = module.project.project_info["project_id"] + network_interface_id = stackit_network_interface.vip.network_interface_id +} + +output "public_ips" { + value = { + "mgmt_ip" = stackit_public_ip.mgmt_ip.ip + "wan_ip" = stackit_public_ip.wan_ip.ip + "mgmt2_ip" = stackit_public_ip.mgmt2_ip.ip + "wan2_ip" = stackit_public_ip.wan2_ip.ip + "VIP" = stackit_public_ip.vip_ip.ip + } +} + diff --git a/examples/iaas-paloalto-ha/02-paloalto-image.tf b/examples/iaas-paloalto-ha/02-paloalto-image.tf new file mode 100644 index 0000000..5abfc2c --- /dev/null +++ b/examples/iaas-paloalto-ha/02-paloalto-image.tf @@ -0,0 +1,13 @@ +// Upload VPN Appliance Image to STACKIT +resource "stackit_image" "paloalto" { + project_id = module.project.project_info["project_id"] + name = "PA-VM-KVM-11.2.5-root" + local_file_path = "./PA-VM-KVM-11.2.5.qcow2" + disk_format = "qcow2" + min_disk_size = 80 + min_ram = 8 + config = { + uefi = false + } +} + diff --git a/examples/iaas-paloalto-ha/03-paloalto_appliance.tf b/examples/iaas-paloalto-ha/03-paloalto_appliance.tf new file mode 100644 index 0000000..276ccf1 --- /dev/null +++ b/examples/iaas-paloalto-ha/03-paloalto_appliance.tf @@ -0,0 +1,48 @@ +resource "stackit_volume" "paloalto_vol" { + project_id = module.project.project_info["project_id"] + name = "PA-VM-KVM-11.2.5-root" + availability_zone = var.region_az1 + size = 100 + performance_class = "storage_premium_perf2" + source = { + id = stackit_image.paloalto.image_id + type = "image" + } +} + +resource "stackit_server" "paloalto_server" { + project_id = module.project.project_info["project_id"] + name = "paloAlto" + boot_volume = { + source_type = "volume" + source_id = stackit_volume.paloalto_vol.volume_id + } + availability_zone = var.region_az1 + machine_type = var.flavor + network_interfaces = [stackit_network_interface.mgmt.network_interface_id, stackit_network_interface.ha.network_interface_id, stackit_network_interface.wan.network_interface_id] +} + +resource "stackit_volume" "paloalto_vol_2" { + project_id = module.project.project_info["project_id"] + name = "PA-VM-KVM-11.2.5-root2" + availability_zone = var.region_az2 + size = 100 + performance_class = "storage_premium_perf2" + source = { + id = stackit_image.paloalto.image_id + type = "image" + } +} + +resource "stackit_server" "paloalto_server_2" { + project_id = module.project.project_info["project_id"] + name = "paloAlto2" + boot_volume = { + source_type = "volume" + source_id = stackit_volume.paloalto_vol_2.volume_id + } + availability_zone = var.region_az2 + machine_type = var.flavor + network_interfaces = [stackit_network_interface.mgmt2.network_interface_id, stackit_network_interface.ha2.network_interface_id, stackit_network_interface.wan2.network_interface_id] +} + diff --git a/examples/iaas-paloalto-ha/04-attachment.tf b/examples/iaas-paloalto-ha/04-attachment.tf new file mode 100644 index 0000000..7645e62 --- /dev/null +++ b/examples/iaas-paloalto-ha/04-attachment.tf @@ -0,0 +1,25 @@ +resource "stackit_server_network_interface_attach" "nic-attachment-lan1" { + project_id = module.project.project_info.project_id + server_id = stackit_server.paloalto_server.server_id + network_interface_id = stackit_network_interface.lan1.network_interface_id + depends_on = [ stackit_server_network_interface_attach.nic-attachment-lan1 ] +} +resource "stackit_server_network_interface_attach" "nic-attachment-lan2" { + project_id = module.project.project_info.project_id + server_id = stackit_server.paloalto_server.server_id + network_interface_id = stackit_network_interface.lan2.network_interface_id + depends_on = [ stackit_server_network_interface_attach.nic-attachment-lan1 ] +} + +resource "stackit_server_network_interface_attach" "nic-attachment-lan1_2" { + project_id = module.project.project_info.project_id + server_id = stackit_server.paloalto_server_2.server_id + network_interface_id = stackit_network_interface.lan1_2.network_interface_id + depends_on = [ stackit_server_network_interface_attach.nic-attachment-lan2 ] +} +resource "stackit_server_network_interface_attach" "nic-attachment-lan2_2" { + project_id = module.project.project_info.project_id + server_id = stackit_server.paloalto_server_2.server_id + network_interface_id = stackit_network_interface.lan2_2.network_interface_id + depends_on = [ stackit_server_network_interface_attach.nic-attachment-lan1_2 ] +} diff --git a/examples/iaas-paloalto-ha/05-security-group.tf b/examples/iaas-paloalto-ha/05-security-group.tf new file mode 100644 index 0000000..d3befeb --- /dev/null +++ b/examples/iaas-paloalto-ha/05-security-group.tf @@ -0,0 +1,33 @@ +resource "stackit_security_group" "paloalto" { + project_id = module.project.project_info["project_id"] + name = "test" + labels = { + "key" = "example" + } +} + +resource "stackit_security_group_rule" "icmp_ingress" { + project_id = module.project.project_info["project_id"] + security_group_id = stackit_security_group.paloalto.security_group_id + direction = "ingress" + icmp_parameters = { + code = 0 + type = 8 + } + protocol = { + name = "icmp" + } +} +resource "stackit_security_group_rule" "icmp_egress" { + project_id = module.project.project_info["project_id"] + security_group_id = stackit_security_group.paloalto.security_group_id + direction = "egress" + icmp_parameters = { + code = 0 + type = 8 + } + protocol = { + name = "icmp" + } +} + diff --git a/examples/iaas-paloalto-ha/99-variables.tf b/examples/iaas-paloalto-ha/99-variables.tf new file mode 100644 index 0000000..45225a5 --- /dev/null +++ b/examples/iaas-paloalto-ha/99-variables.tf @@ -0,0 +1,35 @@ +# -- network variables +variable "organization_id" { + default = "03a34540-3c1a-4794-b2c6-7111ecf824ef" +} + +variable "service_account_key_path" { + default = "/Users/sodan/.stackit/credentials.json" +} + +variable "default_region" { + default ="eu01" +} + +variable "region_az1" { + default = "eu01-1" +} + +variable "region_az2" { + default = "eu01-2" +} + +variable "region_az3" { + default = "eu01-3" +} + +variable "region_metro" { + default = "eu01-m" +} + +variable "flavor" { + type = string + description = "" + default = "m1.2" +} + diff --git a/examples/iaas-paloalto-ha/README.md b/examples/iaas-paloalto-ha/README.md new file mode 100644 index 0000000..fbc4905 --- /dev/null +++ b/examples/iaas-paloalto-ha/README.md @@ -0,0 +1,56 @@ +# Palo Alto HA Setup with Terraform (STACKIT Cloud) + +This Terraform configuration sets up a new project inside your organisation with an SNA as described in the .tf file. +Then two **Palo Alto Firewalls** in a **High Availability (HA)** setup on the **STACKIT Cloud IaaS** layer will be deployed. +It includes proper configuration for floating IPs (VIPs), port security, and network interface rules. +This is only example code, so please change for your needs ! + +--- + +## ๐Ÿ› ๏ธ Key Concepts + +### ๐Ÿ” High Availability (HA) +Two firewalls are deployed with identical network interfaces. A virtual IP (VIP) is configured for failover between the two units. + +### ๐Ÿงท Port Security & VIPs +- `port_security` **must be enabled** on interfaces where the **VIP** is active. +- **Do not attach** the VIP interface to any server or instance! +- VIP must be added as an `allowed_address_pair` on **both firewalls'** relevant interfaces. + +--- + +## โœ… Requirements + +- Terraform โ‰ฅ 1.3.x +- [STACKIT Terraform Provider](https://registry.terraform.io/providers/stackitcloud/stackit/latest) +- Palo Alto VM-Series Images (pre-imported into the STACKIT project) + +--- + +## ๐Ÿšง Limitations & Notes + +- **VIP must not be attached to any instance** + The floating IP (VIP) is managed entirely by the Palo Alto HA configuration. Do **not** associate this IP statically with any compute instance via Terraform. + +- **Setting CIDRs in `allowed_addresses`** + You **must** specify the VIP as a `/32` IP (e.g., `10.220.131.30/32`) โ€” CIDR blocks (e.g., `/24`) are not supported and will be rejected or silently ignored. + You **must** specify the CIDR `0.0.0.0/0` as a second string, this is necessary for a working failover scenario. + +- **Routing issues if `allowed_addresses` are missing** + If the VIP is not explicitly added to `allowed_addresses` on each port where it might be active, network traffic will fail silently due to missing neighbor/ARP entries. + +- **Security groups must explicitly allow VIP traffic** + When using `port_security = true`, ensure that the correct **security group rules** allow inbound/outbound traffic for the VIP address. If omitted, traffic will be blocked. + +- **Interface networks must match on both firewalls** + For a successful HA sync and failover, interfaces on both firewalls must be connected to the **same virtual networks** with matching roles (e.g., both `wan`, both `lan1`, etc.). + +- **No dynamic interface switching in Terraform** + VIP failover happens on the firewall level. Terraform is **not** responsible for enabling/disabling interfaces โ€” make sure the Palo Alto HA config is correctly set up within the OS. + +- **HA Sync and Preemption is not handled by Terraform** + The logic for state sync, failover, and preemption priorities must be configured manually in the firewall GUI or CLI. This project only provisions the infrastructure. + +- **floating IP switch only possible with GARP** + Important: The Floating IP will only work correctly after the move if a Gratuitous ARP (GARP) is sent out โ€” this ensures that the IP-to-MAC binding is updated on neighboring network devices. + diff --git a/examples/iaas-paloalto-ha/project/00-provider.tf b/examples/iaas-paloalto-ha/project/00-provider.tf new file mode 100644 index 0000000..c4d763b --- /dev/null +++ b/examples/iaas-paloalto-ha/project/00-provider.tf @@ -0,0 +1,18 @@ + +terraform { + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">=0.50.0" + } + } +} + +# Authentication +# Key flow (using path) + +provider "stackit" { + default_region = var.default_region + service_account_key_path = var.service_account_key_path + enable_beta_resources = true +} diff --git a/examples/iaas-paloalto-ha/project/01-sna.tf b/examples/iaas-paloalto-ha/project/01-sna.tf new file mode 100644 index 0000000..b6af233 --- /dev/null +++ b/examples/iaas-paloalto-ha/project/01-sna.tf @@ -0,0 +1,15 @@ +resource "time_sleep" "wait_before_destroy" { + destroy_duration = "60s" +} + +resource "stackit_network_area" "sna" { + organization_id = var.organization_id + name = "connectivity" + network_ranges = [ + { + prefix = "10.0.0.0/8" + } + ] + transfer_network = "192.168.254.0/24" + depends_on = [time_sleep.wait_before_destroy] +} diff --git a/examples/iaas-paloalto-ha/project/02-project.tf b/examples/iaas-paloalto-ha/project/02-project.tf new file mode 100644 index 0000000..08adbeb --- /dev/null +++ b/examples/iaas-paloalto-ha/project/02-project.tf @@ -0,0 +1,21 @@ +resource "stackit_resourcemanager_project" "paloalto" { + parent_container_id = var.organization_id + name = "paloalto_ha" + owner_email = "michael.sodan@stackit.cloud" + labels = { + "networkArea" = stackit_network_area.sna.network_area_id + } +} + +data "stackit_resourcemanager_project" "paloalto" { + project_id = stackit_resourcemanager_project.paloalto.project_id + container_id = stackit_resourcemanager_project.paloalto.container_id +} + +output "project_info" { + value = { + project_id = data.stackit_resourcemanager_project.paloalto.project_id + container_id = data.stackit_resourcemanager_project.paloalto.container_id + } +} + diff --git a/examples/iaas-paloalto-ha/project/99-variables.tf b/examples/iaas-paloalto-ha/project/99-variables.tf new file mode 100644 index 0000000..b0e3412 --- /dev/null +++ b/examples/iaas-paloalto-ha/project/99-variables.tf @@ -0,0 +1,35 @@ +# -- network variables +variable "organization_id" { + default = "03a34540-3c1a-4794-b2c6-7111ecf824ef" +} + +variable "service_account_key_path" { + default = "/Users/sodan/.stackit/credentials.json" +} + +variable "default_region" { + default ="eu01" +} + +variable "region_az1" { + default = "eu01-1" +} + +variable "region_az2" { + default = "eu01-2" +} + +variable "region_az3" { + default = "eu01-3" +} + +variable "region_metro" { + default = "eu01-m" +} + +variable "flavor" { + type = string + description = "" + default = "c1.2" +} + -- 2.49.1 From cf6181cf5d4e05f02fbe8a9ef3bca1968c38d9b4 Mon Sep 17 00:00:00 2001 From: Michael Sodan Date: Wed, 15 Apr 2026 12:05:38 +0000 Subject: [PATCH 2/2] add me --- examples/secretsmanager-vault-terraform-provider/MAINTAINERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/secretsmanager-vault-terraform-provider/MAINTAINERS.md b/examples/secretsmanager-vault-terraform-provider/MAINTAINERS.md index 1aaefce..8252d30 100644 --- a/examples/secretsmanager-vault-terraform-provider/MAINTAINERS.md +++ b/examples/secretsmanager-vault-terraform-provider/MAINTAINERS.md @@ -3,6 +3,7 @@ General maintainers: - Mauritz Uphoff (mauritz.uphoff@digits.schwarz) +- Michael Sodan (michael.sodan@digits.schwarz) This example is actively maintained. The owner is responsible for reviewing and updating dependencies and functionalities on a monthly basis. For questions, issues, or feature requests, please email general maintainers. -- 2.49.1