diff --git a/examples/iaas-cross-az-loadbalancer/.terraform.lock.hcl b/examples/iaas-cross-az-layer4-loadbalancer/.terraform.lock.hcl similarity index 100% rename from examples/iaas-cross-az-loadbalancer/.terraform.lock.hcl rename to examples/iaas-cross-az-layer4-loadbalancer/.terraform.lock.hcl diff --git a/examples/iaas-cross-az-loadbalancer/00-provider.tf b/examples/iaas-cross-az-layer4-loadbalancer/00-provider.tf similarity index 100% rename from examples/iaas-cross-az-loadbalancer/00-provider.tf rename to examples/iaas-cross-az-layer4-loadbalancer/00-provider.tf diff --git a/examples/iaas-cross-az-loadbalancer/01-variables.tf b/examples/iaas-cross-az-layer4-loadbalancer/01-variables.tf similarity index 100% rename from examples/iaas-cross-az-loadbalancer/01-variables.tf rename to examples/iaas-cross-az-layer4-loadbalancer/01-variables.tf diff --git a/examples/iaas-cross-az-loadbalancer/02-network.tf b/examples/iaas-cross-az-layer4-loadbalancer/02-network.tf similarity index 100% rename from examples/iaas-cross-az-loadbalancer/02-network.tf rename to examples/iaas-cross-az-layer4-loadbalancer/02-network.tf diff --git a/examples/iaas-cross-az-loadbalancer/03-machine01.tf b/examples/iaas-cross-az-layer4-loadbalancer/03-machine01.tf similarity index 97% rename from examples/iaas-cross-az-loadbalancer/03-machine01.tf rename to examples/iaas-cross-az-layer4-loadbalancer/03-machine01.tf index f6a13ad..cd16c5a 100644 --- a/examples/iaas-cross-az-loadbalancer/03-machine01.tf +++ b/examples/iaas-cross-az-layer4-loadbalancer/03-machine01.tf @@ -21,7 +21,7 @@ module "test-machine01" { name = "machine01" machine_type = var.jumphost_flavor - disk_size = 500 + disk_size = 48 user_data = templatefile("${path.module}/apache-debug-user.yaml", {}) } diff --git a/examples/iaas-cross-az-loadbalancer/04-machine02.tf b/examples/iaas-cross-az-layer4-loadbalancer/04-machine02.tf similarity index 97% rename from examples/iaas-cross-az-loadbalancer/04-machine02.tf rename to examples/iaas-cross-az-layer4-loadbalancer/04-machine02.tf index ab626ed..956ccd2 100644 --- a/examples/iaas-cross-az-loadbalancer/04-machine02.tf +++ b/examples/iaas-cross-az-layer4-loadbalancer/04-machine02.tf @@ -21,7 +21,7 @@ module "test-machine02" { name = "machine02" machine_type = var.jumphost_flavor - disk_size = 500 + disk_size = 48 user_data = templatefile("${path.module}/apache-debug-user.yaml", {}) } diff --git a/examples/iaas-cross-az-loadbalancer/05-loadbalancer.tf b/examples/iaas-cross-az-layer4-loadbalancer/05-l4-loadbalancer.tf similarity index 100% rename from examples/iaas-cross-az-loadbalancer/05-loadbalancer.tf rename to examples/iaas-cross-az-layer4-loadbalancer/05-l4-loadbalancer.tf diff --git a/examples/iaas-cross-az-loadbalancer/MAINTAINERS.md b/examples/iaas-cross-az-layer4-loadbalancer/MAINTAINERS.md similarity index 100% rename from examples/iaas-cross-az-loadbalancer/MAINTAINERS.md rename to examples/iaas-cross-az-layer4-loadbalancer/MAINTAINERS.md diff --git a/examples/iaas-cross-az-loadbalancer/README.md b/examples/iaas-cross-az-layer4-loadbalancer/README.md similarity index 67% rename from examples/iaas-cross-az-loadbalancer/README.md rename to examples/iaas-cross-az-layer4-loadbalancer/README.md index 352342c..e07830c 100644 --- a/examples/iaas-cross-az-loadbalancer/README.md +++ b/examples/iaas-cross-az-layer4-loadbalancer/README.md @@ -1,5 +1,5 @@ -# IaaS cross AZ Loadbalancer +# IaaS cross AZ Layer4 Loadbalancer ## Overview -A classic highly-available architecture: provisioning multiple VMs across different Availability Zones (AZs) and putting them behind a STACKIT Load Balancer. +A classic highly-available architecture: provisioning multiple VMs across different Availability Zones (AZs) and putting them behind a STACKIT L4 Load Balancer. diff --git a/examples/iaas-cross-az-loadbalancer/apache-debug-user.yaml b/examples/iaas-cross-az-layer4-loadbalancer/apache-debug-user.yaml similarity index 100% rename from examples/iaas-cross-az-loadbalancer/apache-debug-user.yaml rename to examples/iaas-cross-az-layer4-loadbalancer/apache-debug-user.yaml diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/.terraform-version b/examples/iaas-cross-az-layer7-loadbalancer-waf/.terraform-version new file mode 100644 index 0000000..79f9beb --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/.terraform-version @@ -0,0 +1 @@ +v1.14.0 diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/.terraform.lock.hcl b/examples/iaas-cross-az-layer7-loadbalancer-waf/.terraform.lock.hcl new file mode 100644 index 0000000..5e195e5 --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/.terraform.lock.hcl @@ -0,0 +1,86 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/random" { + version = "3.8.1" + constraints = ">= 3.6.3" + hashes = [ + "h1:u8AKlWVDTH5r9YLSeswoVEjiY72Rt4/ch7U+61ZDkiQ=", + "zh:08dd03b918c7b55713026037c5400c48af5b9f468f483463321bd18e17b907b4", + "zh:0eee654a5542dc1d41920bbf2419032d6f0d5625b03bd81339e5b33394a3e0ae", + "zh:229665ddf060aa0ed315597908483eee5b818a17d09b6417a0f52fd9405c4f57", + "zh:2469d2e48f28076254a2a3fc327f184914566d9e40c5780b8d96ebf7205f8bc0", + "zh:37d7eb334d9561f335e748280f5535a384a88675af9a9eac439d4cfd663bcb66", + "zh:741101426a2f2c52dee37122f0f4a2f2d6af6d852cb1db634480a86398fa3511", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:a902473f08ef8df62cfe6116bd6c157070a93f66622384300de235a533e9d4a9", + "zh:b85c511a23e57a2147355932b3b6dce2a11e856b941165793a0c3d7578d94d05", + "zh:c5172226d18eaac95b1daac80172287b69d4ce32750c82ad77fa0768be4ea4b8", + "zh:dab4434dba34aad569b0bc243c2d3f3ff86dd7740def373f2a49816bd2ff819b", + "zh:f49fd62aa8c5525a5c17abd51e27ca5e213881d58882fd42fec4a545b53c9699", + ] +} + +provider "registry.terraform.io/hashicorp/tls" { + version = "4.2.1" + hashes = [ + "h1:akFNuHwvrtnYMBofieoeXhPJDhYZzJVu/Q/BgZK2fgg=", + "zh:0d1e7d07ac973b97fa228f46596c800de830820506ee145626f079dd6bbf8d8a", + "zh:5c7e3d4348cb4861ab812973ef493814a4b224bdd3e9d534a7c8a7c992382b86", + "zh:7c6d4a86cd7a4e9c1025c6b3a3a6a45dea202af85d870cddbab455fb1bd568ad", + "zh:7d0864755ba093664c4b2c07c045d3f5e3d7c799dda1a3ef33d17ed1ac563191", + "zh:83734f57950ab67c0d6a87babdb3f13c908cbe0a48949333f489698532e1391b", + "zh:951e3c285218ebca0cf20eaa4265020b4ef042fea9c6ade115ad1558cfe459e5", + "zh:b9543955b4297e1d93b85900854891c0e645d936d8285a190030475379c5c635", + "zh:bb1bd9e86c003d08c30c1b00d44118ed5bbbf6b1d2d6f7eaac4fa5c6ebea5933", + "zh:c9477bfe00653629cd77ddac3968475f7ad93ac3ca8bc45b56d1d9efb25e4a6e", + "zh:d4cfda8687f736d0cba664c22ec49dae1188289e214ef57f5afe6a7217854fed", + "zh:dc77ee066cf96532a48f0578c35b1eaf6dc4d8ddd0e3ae8e029a3b10676dd5d3", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/mastercard/restapi" { + version = "3.0.0" + constraints = "3.0.0" + hashes = [ + "h1:y1I3azDHOqRySTyDHsb3Xh1waP/99KfykZRagbRx1qI=", + "zh:0b63bd3c25a31f090a41933f90b7dd6e984add1c4261d8f5caa73f4d5aa065a4", + "zh:1c3e89cf19118fc07d7b04257251fc9897e722c16e0a0df7b07fcd261f8c12e7", + "zh:2d31f322454d271eb328c2d3b3d41f426df98503982788be347799ddf68bf9bf", + "zh:47dd97e3f43bb89ae4254bba90ffbc6d521338554a1f94961e21214dd801b81b", + "zh:49636b072b9a30d15916468857bce91d39bc87bbba1c99fb3894fafa9409b8b4", + "zh:5566605a8e16478bc66c1fec8dea0890586c084221161dc82b73d162d44c08a7", + "zh:5859e0ad05aa6b3b108f0b718986e237a18d5176efea62d1ac1ef352561b4713", + "zh:76129b89e2b56d8d2af8f6e10cc748bea4ee6ec1105e916f1254cd124f4dcf9c", + "zh:bfc20b5fd03cb3243917e8cf360e5208284e757ab82f83c992da471ef16a0eab", + "zh:d1d2363009253cdfe5795a48b6412bff11104fe6a52fb0a57e5a95fc765a161e", + "zh:d1f0b981089ad709b73c4f989a9cd9118c4e3cb8fc0a2b303aa4d77cc5102a53", + "zh:dbfddb2f407481a4e88fdc17739c805d9d9fff2451efcb9226572d59ed2e9128", + "zh:df04a8c777d05896684171807b27c41befbf5f217f50b0e9b2b27164d4aacca5", + "zh:e68b450c66efe55d1132585477fa71207680806edafb3792ca44d9695d0a1d75", + "zh:f894e7e9913347e25e67d5d3bf91659c06877dd5fa11acf75820fa03fa34b8bd", + ] +} + +provider "registry.terraform.io/stackitcloud/stackit" { + version = "0.91.0" + constraints = ">= 0.87.0" + hashes = [ + "h1:8de9n+Roq6Z2Ltp9poBBBN9a4zSpx73VLpgFS5mTyoI=", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:0ed12db90276ccd2d6f87135b7dd078657823c3ca33121c6a157d0bdf08f801e", + "zh:160b32bcf1d01666784cf8469e10e0a38d4c3d24c80c0c5be470cc63ef27ea62", + "zh:32e1909037235c24138b74131c6fb12ac99003f79750f1768ca5468cc05da6b0", + "zh:4376f1cdafbb35ad5f220e28153741908390b23161d9eae3828f7830039ce8ef", + "zh:458b054781ef6165d9136fc3d667f9bf37319e37d0f19300bbb63b703de2599d", + "zh:54a1864cf1315a118c043f834e02f2a1ca0ecbc8c2a246460589a95847da6c80", + "zh:83424712926ccef3c60cc011dfa298721bdbaee3598a0c8459da46bc6b7424cc", + "zh:a3c38ebffdbca21dd177b06acf891bed1a903907ba252d0219d91ff0ecf9d861", + "zh:c6325e583b77aa1e9df94e3b4b12479d7bf12c66a2ace71c1b8f64e46ac5c37e", + "zh:de6db8deeee895af5670df2449c8b8c34df051277f8a6e2f19c5c9ec1f0ddb12", + "zh:e18b05e7d8356caa6103c5c80b5ea373be3ff255b453cf577c68798ffe1b93ce", + "zh:f4d9215f7a2888c882892642539b2edd3ea97cb25904e4fa358db4f001c3ccd0", + "zh:f94d0c0c2bf843867122ababc8d8066d52257e68bbcb5c62a603f77c581e9668", + ] +} diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/00-provider.tf b/examples/iaas-cross-az-layer7-loadbalancer-waf/00-provider.tf new file mode 100644 index 0000000..8673fee --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/00-provider.tf @@ -0,0 +1,48 @@ +# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Define required providers +terraform { + required_version = ">= 0.14.0" + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">= 0.87.0" + } + random = { + source = "hashicorp/random" + version = ">= 3.6.3" + } + restapi = { + source = "Mastercard/restapi" + version = ">= 3.0.0" + } + } +} + +ephemeral "stackit_access_token" "alb" {} + +provider "restapi" { + uri = "https://alb-waf.api.stackit.cloud" + bearer_token = ephemeral.stackit_access_token.alb.access_token + + id_attribute = "name" + write_returns_object = true +} + +provider "stackit" { + default_region = var.stackit_region + service_account_key_path = var.stackit_service_account_key_path + enable_beta_resources = true +} diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/01-variables.tf b/examples/iaas-cross-az-layer7-loadbalancer-waf/01-variables.tf new file mode 100644 index 0000000..efb773e --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/01-variables.tf @@ -0,0 +1,37 @@ +# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +variable "stackit_project_id" { + type = string + default = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" +} + +variable "stackit_region" { + type = string + default = "eu01" +} + +variable "stackit_service_account_key_path" { + type = string + default = "../../keys/stackit-sa.json" +} + +resource "stackit_key_pair" "admin_keypair" { + name = "admin-keypair-12345" + public_key = chomp(file("~/.ssh/id_rsa.pub")) +} + +variable "jumphost_flavor" { + default = "c2i.1" +} diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/02-network.tf b/examples/iaas-cross-az-layer7-loadbalancer-waf/02-network.tf new file mode 100644 index 0000000..29222d3 --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/02-network.tf @@ -0,0 +1,20 @@ +# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +resource "stackit_network" "network" { + project_id = var.stackit_project_id + name = "network01" + ipv4_nameservers = ["1.1.1.1", "9.9.9.9"] + ipv4_prefix = "172.17.1.0/24" +} diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/03-machine01.tf b/examples/iaas-cross-az-layer7-loadbalancer-waf/03-machine01.tf new file mode 100644 index 0000000..1972d38 --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/03-machine01.tf @@ -0,0 +1,28 @@ +# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module "test-machine01" { + source = "../../modules/test-machine" + + project_id = var.stackit_project_id + network_id = stackit_network.network.network_id + availability_zone = "eu01-1" + security_enabled = true + + name = "machine01" + machine_type = var.jumphost_flavor + disk_size = 48 + + user_data = templatefile("${path.module}/apache-debug-user.yaml", {}) +} diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/04-machine02.tf b/examples/iaas-cross-az-layer7-loadbalancer-waf/04-machine02.tf new file mode 100644 index 0000000..a197447 --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/04-machine02.tf @@ -0,0 +1,28 @@ +# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module "test-machine02" { + source = "../../modules/test-machine" + + project_id = var.stackit_project_id + network_id = stackit_network.network.network_id + availability_zone = "eu01-2" + security_enabled = true + + name = "machine02" + machine_type = var.jumphost_flavor + disk_size = 48 + + user_data = templatefile("${path.module}/apache-debug-user.yaml", {}) +} diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/05-l7-loadbalancer.tf b/examples/iaas-cross-az-layer7-loadbalancer-waf/05-l7-loadbalancer.tf new file mode 100644 index 0000000..969dfc7 --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/05-l7-loadbalancer.tf @@ -0,0 +1,117 @@ +# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +resource "tls_private_key" "example" { + algorithm = "RSA" + rsa_bits = 2048 +} + +resource "tls_self_signed_cert" "example" { + private_key_pem = tls_private_key.example.private_key_pem + + subject { + common_name = "localhost" + organization = "STACKIT Test" + } + + validity_period_hours = 12 + + allowed_uses = [ + "key_encipherment", + "digital_signature", + "server_auth", + ] +} + +resource "stackit_public_ip" "public_ip" { + project_id = var.stackit_project_id + + lifecycle { + ignore_changes = [network_interface_id] + } +} + +resource "stackit_alb_certificate" "this" { + project_id = var.stackit_project_id + name = "example-certificate" + private_key = tls_private_key.example.private_key_pem + public_key = tls_self_signed_cert.example.cert_pem +} + +resource "stackit_application_load_balancer" "this" { + project_id = var.stackit_project_id + region = var.stackit_region + name = "example-load-balancer" + plan_id = "p10" + external_address = stackit_public_ip.public_ip.ip + + listeners = [ + { + name = "listener01" + port = 443 + http = { + hosts = [{ + host = "*" + rules = [{ + target_pool = "target-pool-01" + /*path = { + prefix = "/path" + }*/ + }] + }] + } + https = { + certificate_config = { + certificate_ids = [ + stackit_alb_certificate.this.cert_id + ] + } + } + waf_config_name = restapi_object.waf.api_data.name + protocol = "PROTOCOL_HTTPS" + } + ] + networks = [ + { + network_id = stackit_network.network.network_id + role = "ROLE_LISTENERS_AND_TARGETS" + } + ] + target_pools = [ + { + name = "target-pool-01" + target_port = 80 + targets = [ + { + display_name = "server01" + ip = module.test-machine01.primary_ip + }, + { + display_name = "server02" + ip = module.test-machine02.primary_ip + } + ] + } + ] +} + + +output "alb_external_address" { + value = stackit_application_load_balancer.this.external_address +} + +/*output "alb_private_ip_address" { + // for private alb loadbalancer usage + value = stackit_application_load_balancer.this.private_address +}*/ diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/06-waf.tf b/examples/iaas-cross-az-layer7-loadbalancer-waf/06-waf.tf new file mode 100644 index 0000000..405898e --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/06-waf.tf @@ -0,0 +1,46 @@ +# Copyright 2026 Schwarz Digits Cloud GmbH & Co. KG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +resource "restapi_object" "waf_crs" { + path = "/v1alpha/projects/${var.stackit_project_id}/regions/${var.stackit_region}/core-rule-sets" + data = jsonencode({ + name = "example-crs" + active = true + }) + + ignore_server_additions = true +} + +resource "restapi_object" "waf_rules" { + path = "/v1alpha/projects/${var.stackit_project_id}/regions/${var.stackit_region}/rules" + data = jsonencode({ + name = "example-rules" + rules = file("${path.module}/example-waf.conf") + }) + + ignore_server_additions = true + depends_on = [restapi_object.waf_crs] +} + +resource "restapi_object" "waf" { + path = "/v1alpha/projects/${var.stackit_project_id}/regions/${var.stackit_region}/wafs" + data = jsonencode({ + name = "example-waf" + coreRuleSetName = restapi_object.waf_crs.api_data.name + rulesConfigName = restapi_object.waf_rules.api_data.name + }) + + ignore_server_additions = true + depends_on = [restapi_object.waf_rules] +} diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/MAINTAINERS.md b/examples/iaas-cross-az-layer7-loadbalancer-waf/MAINTAINERS.md new file mode 100644 index 0000000..6457701 --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/MAINTAINERS.md @@ -0,0 +1,9 @@ +# Maintainers + +General maintainers: + +- Mauritz Uphoff (Mauritz.Uphoff@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. +Please include the BP name and version in your request. We will track your request as an issue. diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/README.md b/examples/iaas-cross-az-layer7-loadbalancer-waf/README.md new file mode 100644 index 0000000..895244b --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/README.md @@ -0,0 +1,36 @@ +# IaaS cross AZ Layer 7 Loadbalancer + +## Overview + +A classic highly-available architecture: provisioning multiple VMs across different Availability Zones (AZs) and putting them behind a STACKIT L7 Load Balancer. This example also includes a Web Application Firewall (WAF) configuration to secure the backend workloads against malicious traffic. + +## ⚠️ Important Note: [WAF Implementation](06-waf.tf) + +Currently, the official STACKIT Terraform provider does not natively support Web Application Firewall (WAF) resources. + +To bridge this gap and fully automate the deployment, this example utilizes a `restapi` provider as a workaround. This allows Terraform to interact directly with the STACKIT WAF REST API (`/v1alpha/projects/...`) to create and attach the Core Rule Sets and custom SecLang rules until native support is released. + +## Testing the WAF + +This deployment includes rules written in SecLang. These rules are specifically designed to safely verify that the WAF is successfully deployed, actively intercepting traffic, and applying your configurations. + +Once `terraform apply` completes successfully, extract the public IP of your Load Balancer from the Terraform outputs: + +```bash +# Export the Load Balancer IP to an environment variable +export ALB_IP=$(terraform output -raw alb_external_address) +``` + +Now, use curl to trigger the custom rules. Because the WAF is configured to block these specific signatures, both of the following commands should return an HTTP 403 Forbidden status code. + +Test 1: Trigger via Query Parameter + +```Bash +curl -k -I -X GET "https://${ALB_IP}/?waf_test=trigger" +``` + +Test 2: Trigger via Custom HTTP Header + +```Bash +curl -k -I -H "X-WAF-Test: trigger" "https://${ALB_IP}/" +``` diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/apache-debug-user.yaml b/examples/iaas-cross-az-layer7-loadbalancer-waf/apache-debug-user.yaml new file mode 100644 index 0000000..c44cda9 --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/apache-debug-user.yaml @@ -0,0 +1,22 @@ +#cloud-config +users: + - name: debug + groups: sudo + shell: /bin/bash + sudo: ["ALL=(ALL) NOPASSWD:ALL"] + lock_passwd: false + passwd: "$6$JZBVJ2zsw/o4C1UJ$FskGQWf.nqwj.o9bHbxkSGvSilQcHt03KdPYlgsiE3L77tNqFj0/vnlCXSf.SRb4jR2xsHk/.OlEyT16Txj4J." # hashed version of 'House123!' + +chpasswd: + expire: false + +ssh_pwauth: true + +packages: + - apache2 + +runcmd: + - systemctl enable apache2 + - systemctl start apache2 + - echo "
Hostname $(hostname)
" > /var/www/html/index.html + - chown www-data:www-data /var/www/html/index.html diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/example-waf.conf b/examples/iaas-cross-az-layer7-loadbalancer-waf/example-waf.conf new file mode 100644 index 0000000..31067e4 --- /dev/null +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/example-waf.conf @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------------ +# WAF TEST RULES +# Custom rule IDs should generally start at 1000000 to avoid conflicting +# with the OWASP Core Rule Set (which uses the 900000 - 999999 range). +# ------------------------------------------------------------------------ + +# Test Rule 1: Block based on a specific query parameter (?waf_test=trigger) +SecRule ARGS:waf_test "@streq trigger" \ + "id:1000001,\ + phase:1,\ + deny,\ + status:403,\ + log,\ + msg:'WAF Test Rule Triggered via Query Parameter'" + +# Test Rule 2: Block based on a specific custom header (X-WAF-Test: trigger) +SecRule REQUEST_HEADERS:X-WAF-Test "@streq trigger" \ + "id:1000002,\ + phase:1,\ + deny,\ + status:403,\ + log,\ + msg:'WAF Test Rule Triggered via Custom Header'"