From 8da063d3ee908454a9a37d1256e264106f72b0d4 Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Thu, 23 Apr 2026 10:04:51 +0200 Subject: [PATCH 01/14] example(dbaas): add example on how to ship dbaas metrics to obs instance Signed-off-by: Mauritz Uphoff --- .../.terraform.lock.hcl | 101 ++++++++++++++++++ .../dbaas-otel-collect-metrics/00-provider.tf | 55 ++++++++++ .../01-variables.tf | 33 ++++++ examples/dbaas-otel-collect-metrics/02-ske.tf | 67 ++++++++++++ .../03-observability.tf | 20 ++++ .../dbaas-otel-collect-metrics/04-postgres.tf | 44 ++++++++ .../04-service-account.tf | 38 +++++++ .../05-otel-helm.tf | 65 +++++++++++ .../dbaas-otel-collect-metrics/MAINTAINERS.md | 9 ++ examples/dbaas-otel-collect-metrics/README.md | 39 +++++++ .../helm-values/otel-collector-values.tftpl | 76 +++++++++++++ 11 files changed, 547 insertions(+) create mode 100644 examples/dbaas-otel-collect-metrics/.terraform.lock.hcl create mode 100644 examples/dbaas-otel-collect-metrics/00-provider.tf create mode 100644 examples/dbaas-otel-collect-metrics/01-variables.tf create mode 100644 examples/dbaas-otel-collect-metrics/02-ske.tf create mode 100644 examples/dbaas-otel-collect-metrics/03-observability.tf create mode 100644 examples/dbaas-otel-collect-metrics/04-postgres.tf create mode 100644 examples/dbaas-otel-collect-metrics/04-service-account.tf create mode 100644 examples/dbaas-otel-collect-metrics/05-otel-helm.tf create mode 100644 examples/dbaas-otel-collect-metrics/MAINTAINERS.md create mode 100644 examples/dbaas-otel-collect-metrics/README.md create mode 100644 examples/dbaas-otel-collect-metrics/helm-values/otel-collector-values.tftpl diff --git a/examples/dbaas-otel-collect-metrics/.terraform.lock.hcl b/examples/dbaas-otel-collect-metrics/.terraform.lock.hcl new file mode 100644 index 0000000..db8eb36 --- /dev/null +++ b/examples/dbaas-otel-collect-metrics/.terraform.lock.hcl @@ -0,0 +1,101 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/helm" { + version = "3.1.1" + hashes = [ + "h1:47CqNwkxctJtL/N/JuEj+8QMg8mRNI/NWeKO5/ydfZU=", + "zh:1a6d5ce931708aec29d1f3d9e360c2a0c35ba5a54d03eeaff0ce3ca597cd0275", + "zh:3411919ba2a5941801e677f0fea08bdd0ae22ba3c9ce3309f55554699e06524a", + "zh:81b36138b8f2320dc7f877b50f9e38f4bc614affe68de885d322629dd0d16a29", + "zh:95a2a0a497a6082ee06f95b38bd0f0d6924a65722892a856cfd914c0d117f104", + "zh:9d3e78c2d1bb46508b972210ad706dd8c8b106f8b206ecf096cd211c54f46990", + "zh:a79139abf687387a6efdbbb04289a0a8e7eaca2bd91cdc0ce68ea4f3286c2c34", + "zh:aaa8784be125fbd50c48d84d6e171d3fb6ef84a221dbc5165c067ce05faab4c8", + "zh:afecd301f469975c9d8f350cc482fe656e082b6ab0f677d1a816c3c615837cc1", + "zh:c54c22b18d48ff9053d899d178d9ffef7d9d19785d9bf310a07d648b7aac075b", + "zh:db2eefd55aea48e73384a555c72bac3f7d428e24147bedb64e1a039398e5b903", + "zh:ee61666a233533fd2be971091cecc01650561f1585783c381b6f6e8a390198a4", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/kubernetes" { + version = "3.1.0" + hashes = [ + "h1:G9QqKNpcztBRqrywtlNylFJSpGzDfRFtO8hcWLdkvRY=", + "zh:0215c5c60be62028c09a2f22458e89cda3ef5830a632299f1d401eb3538874b0", + "zh:09ebb9f442431e278a310a9423f32caf467cb4b3cad3fe59573ca71fa7b14e20", + "zh:0c4e5912f83bb35846ae0a9ae54fc320706ee61894cd21cc6b4181b1c5a2fa5c", + "zh:1678c982853ad461e65ccb5e79d585e13ed109dd47dab2a66d3a7a304faeef65", + "zh:1c050a5c15e330457a9c18caacf61a923c59d663e13f2962e4b32f04fef523a0", + "zh:2c55bcec83be58ec132c7cb0a1ac644758b800d794fdc636d53a0eada0358a3a", + "zh:a062bb0aa316c08d8460c66a5d68da71da40de5d3bc3b31abcf3a1a9a19650f1", + "zh:a26fdea0afaa9b247c73c0b42843ca51ba7db0ac2571f9d3d50dcabd20ca1b98", + "zh:c872c9385a78d502bf5823d61cd3bb0f9a0585030e025eb12585c83451beeaa1", + "zh:f180879af931182beee4c8c0d9dab62b81d86f17ddcbe3786ef4c7cec9163a4e", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + "zh:f70f5789264069e0eef06f9b5d5fde955ef7206f7d446d1ce51a4c37a3f3e02f", + ] +} + +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/time" { + version = "0.13.1" + hashes = [ + "h1:ZT5ppCNIModqk3iOkVt5my8b8yBHmDpl663JtXAIRqM=", + "zh:02cb9aab1002f0f2a94a4f85acec8893297dc75915f7404c165983f720a54b74", + "zh:04429b2b31a492d19e5ecf999b116d396dac0b24bba0d0fb19ecaefe193fdb8f", + "zh:26f8e51bb7c275c404ba6028c1b530312066009194db721a8427a7bc5cdbc83a", + "zh:772ff8dbdbef968651ab3ae76d04afd355c32f8a868d03244db3f8496e462690", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:898db5d2b6bd6ca5457dccb52eedbc7c5b1a71e4a4658381bcbb38cedbbda328", + "zh:8de913bf09a3fa7bedc29fec18c47c571d0c7a3d0644322c46f3aa648cf30cd8", + "zh:9402102c86a87bdfe7e501ffbb9c685c32bbcefcfcf897fd7d53df414c36877b", + "zh:b18b9bb1726bb8cfbefc0a29cf3657c82578001f514bcf4c079839b6776c47f0", + "zh:b9d31fdc4faecb909d7c5ce41d2479dd0536862a963df434be4b16e8e4edc94d", + "zh:c951e9f39cca3446c060bd63933ebb89cedde9523904813973fbc3d11863ba75", + "zh:e5b773c0d07e962291be0e9b413c7a22c044b8c7b58c76e8aa91d1659990dfb5", + ] +} + +provider "registry.terraform.io/stackitcloud/stackit" { + version = "0.92.0" + constraints = ">= 0.87.0" + hashes = [ + "h1:j26ncxqlAp4q0/NHFoiATuVdIg7KH0zZhWoSAd+4Yj0=", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:5eaa713f68a004ec33697f510ca4c7722940e2bab8080c025822ca547325ef98", + "zh:60ed4496492b9781f7cc581e346222a6356538a527e4ac67dce6815a64fc5c66", + "zh:6834a7819429e3482a5fdd547c442cc032d7047c3fb0dee30e8babb2438598e1", + "zh:6de632db0cbb42b429a9e752078df37716b0f335e5c39e883be5c55f7f1da553", + "zh:ac8b1bc8212236aaab789cef1dce718e6b8394bcf4b5f6c6f8dabf8c8a213573", + "zh:af4b1e805d6082a3ec94d2f5b68e8a62f04205af3f75a4a7d1b167e0f027d9ec", + "zh:b709258a4cd3acd0a9426809c1d7c1ed25859010b566c1b29481b132a7e2af13", + "zh:c7e8c5e8f2ca8c14c1bf5c92716a761b67792b38046b99653bdbf9ca423fc675", + "zh:c7f47c6b7e33d1f28bdc8d1aa5fda2734d74d6b1b0c6ef8b258489d9405af231", + "zh:d57dc6ad6b3a2879aa47012faf82f597a2ca1c3de1561bb96c6191e65072ea95", + "zh:d5b18390104164477913ced864e7a1cd5a678490f9412be887e5d8e3961d242e", + "zh:ead616306ab18c30a4c1110ad7fa8aee7d8a99e4410ceecbe5875beac5724f8a", + "zh:f73ad70183a35e5d04e4b48c44654c76fec48a8f4c913dd31a5befc2a1c2e4dc", + ] +} diff --git a/examples/dbaas-otel-collect-metrics/00-provider.tf b/examples/dbaas-otel-collect-metrics/00-provider.tf new file mode 100644 index 0000000..8bf8bc1 --- /dev/null +++ b/examples/dbaas-otel-collect-metrics/00-provider.tf @@ -0,0 +1,55 @@ +# 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. + +# This file defines the required Terraform providers and their configurations. +# It sets up the STACKIT, Kubernetes, and Helm providers to manage resources in the project and the SKE cluster. +terraform { + required_version = ">= 0.14.0" + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">= 0.87.0" + } + random = { + source = "hashicorp/random" + version = ">= 3.6.3" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = ">=2.14.0" + } + } +} + +provider "stackit" { + default_region = var.stackit_region + service_account_key_path = var.stackit_service_account_key_path + experiments = ["iam"] +} + +provider "kubernetes" { + host = yamldecode(stackit_ske_kubeconfig.this.kube_config).clusters.0.cluster.server + client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.this.kube_config).users.0.user.client-certificate-data) + client_key = base64decode(yamldecode(stackit_ske_kubeconfig.this.kube_config).users.0.user.client-key-data) + cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.this.kube_config).clusters.0.cluster.certificate-authority-data) +} + +provider "helm" { + kubernetes = { + host = yamldecode(stackit_ske_kubeconfig.this.kube_config).clusters.0.cluster.server + client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.this.kube_config).users.0.user.client-certificate-data) + client_key = base64decode(yamldecode(stackit_ske_kubeconfig.this.kube_config).users.0.user.client-key-data) + cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.this.kube_config).clusters.0.cluster.certificate-authority-data) + } +} diff --git a/examples/dbaas-otel-collect-metrics/01-variables.tf b/examples/dbaas-otel-collect-metrics/01-variables.tf new file mode 100644 index 0000000..35ec61c --- /dev/null +++ b/examples/dbaas-otel-collect-metrics/01-variables.tf @@ -0,0 +1,33 @@ +# 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 = "d75e6aab-b616-4b42-ae3b-aaf161ad626d" +} + +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")) +} diff --git a/examples/dbaas-otel-collect-metrics/02-ske.tf b/examples/dbaas-otel-collect-metrics/02-ske.tf new file mode 100644 index 0000000..173ccbb --- /dev/null +++ b/examples/dbaas-otel-collect-metrics/02-ske.tf @@ -0,0 +1,67 @@ +# 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_ske_kubeconfig" "this" { + project_id = var.stackit_project_id + cluster_name = stackit_ske_cluster.this.name + refresh = true + + depends_on = [stackit_ske_cluster.this] +} + +data "stackit_ske_kubernetes_versions" "this" { + version_state = "SUPPORTED" +} + +data "stackit_ske_machine_image_versions" "this" { + version_state = "SUPPORTED" +} + +locals { + flatcar_supported_version = one(flatten([ + for mi in data.stackit_ske_machine_image_versions.this.machine_images : [ + for v in mi.versions : + v.version + if mi.name == "flatcar" + ] + ])) +} + +resource "stackit_ske_cluster" "this" { + project_id = var.stackit_project_id + name = "dbaas-otel" + kubernetes_version_min = data.stackit_ske_kubernetes_versions.this.kubernetes_versions.0.version + + maintenance = { + enable_kubernetes_version_updates = true + enable_machine_image_version_updates = true + start = "01:00:00Z" + end = "02:00:00Z" + } + + node_pools = [ + { + name = "standard" + machine_type = "g2i.4" + minimum = "3" + maximum = "9" + max_surge = "3" + availability_zones = ["eu01-1", "eu01-2", "eu01-3"] + os_version_min = local.flatcar_supported_version + os_name = "flatcar" + volume_size = 150 + volume_type = "storage_premium_perf6" + }, + ] +} diff --git a/examples/dbaas-otel-collect-metrics/03-observability.tf b/examples/dbaas-otel-collect-metrics/03-observability.tf new file mode 100644 index 0000000..916d7db --- /dev/null +++ b/examples/dbaas-otel-collect-metrics/03-observability.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_observability_instance" "example" { + project_id = var.stackit_project_id + name = "example-obs" + plan_name = "Observability-Large-EU01" + alert_config = null +} diff --git a/examples/dbaas-otel-collect-metrics/04-postgres.tf b/examples/dbaas-otel-collect-metrics/04-postgres.tf new file mode 100644 index 0000000..6247083 --- /dev/null +++ b/examples/dbaas-otel-collect-metrics/04-postgres.tf @@ -0,0 +1,44 @@ +# 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_postgresflex_instance" "this" { + project_id = var.stackit_project_id + name = "example-instance" + backup_schedule = "00 00 * * *" + flavor = { + cpu = 2 + ram = 4 + } + replicas = 3 + storage = { + class = "premium-perf2-stackit" + size = 15 + } + version = 15 + acl = ["0.0.0.0/0"] +} + +resource "stackit_postgresflex_user" "this" { + project_id = var.stackit_project_id + instance_id = stackit_postgresflex_instance.this.instance_id + username = "test" + roles = ["createdb", "login"] +} + +resource "stackit_postgresflex_database" "this" { + project_id = var.stackit_project_id + instance_id = stackit_postgresflex_instance.this.instance_id + name = "test" + owner = stackit_postgresflex_user.this.username +} diff --git a/examples/dbaas-otel-collect-metrics/04-service-account.tf b/examples/dbaas-otel-collect-metrics/04-service-account.tf new file mode 100644 index 0000000..eb25d4c --- /dev/null +++ b/examples/dbaas-otel-collect-metrics/04-service-account.tf @@ -0,0 +1,38 @@ +# 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_service_account" "this" { + name = "prom-proxy" + project_id = var.stackit_project_id +} + +resource "time_rotating" "rotate" { + rotation_days = 150 +} + +resource "stackit_service_account_key" "this" { + project_id = var.stackit_project_id + service_account_email = stackit_service_account.this.email + ttl_days = 180 + + rotate_when_changed = { + rotation = time_rotating.rotate.id + } +} + +resource "stackit_authorization_project_role_assignment" "this" { + resource_id = var.stackit_project_id + role = "prometheus-proxy.reader" + subject = stackit_service_account.this.email +} diff --git a/examples/dbaas-otel-collect-metrics/05-otel-helm.tf b/examples/dbaas-otel-collect-metrics/05-otel-helm.tf new file mode 100644 index 0000000..acc8ee6 --- /dev/null +++ b/examples/dbaas-otel-collect-metrics/05-otel-helm.tf @@ -0,0 +1,65 @@ +# 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. + +locals { + sa_json = jsondecode(stackit_service_account_key.this.json) + otel_helm_values = templatefile("${path.module}/helm-values/otel-collector-values.tftpl", { + stackit_project_id = var.stackit_project_id + stackit_region = var.stackit_region + stackit_postgres_instance_id = stackit_postgresflex_instance.this.instance_id + observability_metrics_endpoint = stackit_observability_instance.example.metrics_push_url + secret_name = kubernetes_secret.otel_secret.metadata[0].name + sa_client_id = local.sa_json.credentials.sub + sa_issuer = local.sa_json.credentials.iss + sa_key_id = local.sa_json.credentials.kid + }) +} + + +resource "stackit_observability_credential" "otel" { + project_id = var.stackit_project_id + instance_id = stackit_observability_instance.example.instance_id +} + +resource "kubernetes_namespace" "monitoring" { + metadata { + name = "monitoring" + } +} + +resource "kubernetes_secret" "otel_secret" { + metadata { + name = "otel-secrets" + namespace = kubernetes_namespace.monitoring.metadata[0].name + } + + data = { + OBSERVABILITY_AUTHORIZATION_HEADER = "Basic ${base64encode("${stackit_observability_credential.otel.username}:${stackit_observability_credential.otel.password}")}" + JSON = stackit_service_account_key.this.json + PRIVATE_KEY = jsondecode(stackit_service_account_key.this.json).credentials.privateKey + } +} + +resource "helm_release" "opentelemetry_collector" { + name = "opentelemetry-collector" + repository = "https://open-telemetry.github.io/opentelemetry-helm-charts" + chart = "opentelemetry-collector" + version = "0.152.0" + namespace = kubernetes_namespace.monitoring.metadata[0].name + timeout = 30 + + values = [ + local.otel_helm_values + ] +} diff --git a/examples/dbaas-otel-collect-metrics/MAINTAINERS.md b/examples/dbaas-otel-collect-metrics/MAINTAINERS.md new file mode 100644 index 0000000..6457701 --- /dev/null +++ b/examples/dbaas-otel-collect-metrics/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/dbaas-otel-collect-metrics/README.md b/examples/dbaas-otel-collect-metrics/README.md new file mode 100644 index 0000000..965b11b --- /dev/null +++ b/examples/dbaas-otel-collect-metrics/README.md @@ -0,0 +1,39 @@ +# DBaaS OpenTelemetry Metrics Collection + +Collect metrics from STACKIT PostgreSQL Flex and MongoDB instances using OpenTelemetry (OTel) and export them to STACKIT Observability. + +## Prerequisites + +- STACKIT Project ID and Service Account key. +- Terraform, `kubectl`, and `helm` installed. + +## Usage + +1. **Configure**: Update `stackit_project_id` and `stackit_service_account_key_path` in `01-variables.tf`. +2. **Deploy**: + ```bash + terraform init + terraform apply + ``` + +## Scrape Configuration + +The OTel Collector scrapes metrics from: + +- **PostgreSQL**: `https://postgres-prom-proxy.api.stackit.cloud/v2/...` +- **MongoDB**: `https://mongodb-prom-proxy.api.stackit.cloud/v2/...` + +_Note: MSSQL is not supported._ + +## Debugging + +View live scrape data in the collector logs: + +```bash +kubectl logs -l app.kubernetes.io/name=otel-collector -n monitoring -f +``` + +## Documentation + +- [PostgreSQL Flex Metrics](https://docs.stackit.cloud/products/databases/postgresql-flex/reference/observability-metrics-in-postgresql-flex/) +- [MongoDB Flex Metrics](https://docs.stackit.cloud/products/databases/mongodb-flex/reference/observability-metrics/) diff --git a/examples/dbaas-otel-collect-metrics/helm-values/otel-collector-values.tftpl b/examples/dbaas-otel-collect-metrics/helm-values/otel-collector-values.tftpl new file mode 100644 index 0000000..4bbcdff --- /dev/null +++ b/examples/dbaas-otel-collect-metrics/helm-values/otel-collector-values.tftpl @@ -0,0 +1,76 @@ +fullnameOverride: otel-collector +mode: deployment + +image: + repository: "otel/opentelemetry-collector-contrib" + +config: + receivers: + prometheus: + config: + scrape_configs: + - job_name: stackit-postgres + metrics_path: /v2/projects/$${STACKIT_PROJECT_ID}/regions/$${STACKIT_REGION}/instances/$${STACKIT_POSTGRES_INSTANCE_ID}/metrics + oauth2: + audience: $${SA_TOKEN_REQUEST_AUDIENCE} + client_certificate_key_file: /mnt/secrets-store/private-key + client_certificate_key_id: $${SA_TOKEN_REQUEST_CLIENT_CERTIFICATE_KEY_ID} + client_id: $${SA_TOKEN_REQUEST_CLIENT_ID} + grant_type: urn:ietf:params:oauth:grant-type:jwt-bearer + iss: $${SA_TOKEN_REQUEST_ISSUER} + signature_algorithm: RS512 + token_url: https://service-account.api.stackit.cloud/token + scheme: https + scrape_interval: 1m + static_configs: + - targets: + - postgres-prom-proxy.api.stackit.cloud:443 + exporters: + debug: + verbosity: normal + prometheusremotewrite: + endpoint: $${OBSERVABILITY_METRICS_ENDPOINT} + headers: + Authorization: $${OBSERVABILITY_AUTHORIZATION_HEADER} + + service: + pipelines: + metrics: + receivers: [prometheus] + exporters: [prometheusremotewrite, debug] + +extraEnvs: + - name: STACKIT_PROJECT_ID + value: "${stackit_project_id}" + - name: STACKIT_REGION + value: "${stackit_region}" + - name: STACKIT_POSTGRES_INSTANCE_ID + value: "${stackit_postgres_instance_id}" + - name: OBSERVABILITY_METRICS_ENDPOINT + value: "${observability_metrics_endpoint}" + - name: OBSERVABILITY_AUTHORIZATION_HEADER + valueFrom: + secretKeyRef: + name: ${secret_name} + key: OBSERVABILITY_AUTHORIZATION_HEADER + - name: SA_TOKEN_REQUEST_CLIENT_ID + value: "${sa_client_id}" + - name: SA_TOKEN_REQUEST_ISSUER + value: "${sa_issuer}" + - name: SA_TOKEN_REQUEST_CLIENT_CERTIFICATE_KEY_ID + value: "${sa_key_id}" + - name: SA_TOKEN_REQUEST_AUDIENCE + value: "https://service-account.api.stackit.cloud/token" + +extraVolumes: + - name: otel-secrets + secret: + secretName: ${secret_name} + items: + - key: PRIVATE_KEY + path: private-key + +extraVolumeMounts: + - name: otel-secrets + mountPath: /mnt/secrets-store + readOnly: true From cc4120dc63c6ec3db7ea81cde8f2612003aaf014 Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Thu, 23 Apr 2026 10:47:11 +0200 Subject: [PATCH 02/14] example(dbaas): add key id annotation for rotation Signed-off-by: Mauritz Uphoff --- .../helm-values/otel-collector-values.tftpl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/dbaas-otel-collect-metrics/helm-values/otel-collector-values.tftpl b/examples/dbaas-otel-collect-metrics/helm-values/otel-collector-values.tftpl index 4bbcdff..2f34dd0 100644 --- a/examples/dbaas-otel-collect-metrics/helm-values/otel-collector-values.tftpl +++ b/examples/dbaas-otel-collect-metrics/helm-values/otel-collector-values.tftpl @@ -1,6 +1,9 @@ fullnameOverride: otel-collector mode: deployment +podAnnotations: + stackit-sa-key-id: "${sa_key_id}" + image: repository: "otel/opentelemetry-collector-contrib" From 295c1c5b8912a5f3a34e94adc088368b580e4d4e Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Fri, 24 Apr 2026 09:25:14 +0200 Subject: [PATCH 03/14] docs: rename repository Signed-off-by: Mauritz Uphoff --- .github/workflows/default-ci.yaml | 2 +- .github/workflows/github-mirror-ci.yaml | 6 ++-- GOVERNANCE.md | 41 +++++++++++++++++++++++++ README.md | 4 +-- 4 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 GOVERNANCE.md diff --git a/.github/workflows/default-ci.yaml b/.github/workflows/default-ci.yaml index 75355ad..d455023 100644 --- a/.github/workflows/default-ci.yaml +++ b/.github/workflows/default-ci.yaml @@ -1,4 +1,4 @@ -name: "Professional Services CI" +name: "Default CI" on: push: diff --git a/.github/workflows/github-mirror-ci.yaml b/.github/workflows/github-mirror-ci.yaml index c596648..5b71600 100644 --- a/.github/workflows/github-mirror-ci.yaml +++ b/.github/workflows/github-mirror-ci.yaml @@ -28,11 +28,11 @@ jobs: - name: Push to Public Repo run: | echo "Setting up remote..." - git config --global user.name "prof-service-sync-bot" - git config --global user.email "prof-service-sync-bot@digits.schwarz" + git config --global user.name "ps-sync-bot" + git config --global user.email "ps-sync-bot@digits.schwarz" # Add the GitHub remote using the SSH protocol - git remote add public git@github.com:stackitcloud/professional-services.git + git remote add public git@github.com:stackitcloud/stackit-ps-solutions.git echo "Pushing main branch to GitHub..." git push public main --force diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 0000000..4b1be95 --- /dev/null +++ b/GOVERNANCE.md @@ -0,0 +1,41 @@ +# Project Governance: STACKIT PS Solutions + +This document defines the management, ownership, and maintenance processes for the STACKIT PS Solutions repository. + +## 1. Strategy & "The Story" + +This repository serves as a bridge between internal excellence and public visibility. + +- **Internal Git (Source of Truth):** The primary repository is hosted on our internal STACKIT Git instance. All internal communication, documentation, and chat links MUST point to the internal instance to promote our own infrastructure and tools. +- **GitHub (Public Mirror):** The GitHub repository is a mirror intended for external visibility, SEO, and accessibility for AI models (LLMs). It helps customers find our solutions and establishes STACKIT as a thought leader in cloud automation. + +## 2. Ownership + +### 2.1 Organizational Ownership + +The repository is owned by the **STACKIT Professional Services** organization. High-level decisions regarding repository structure, licensing, and global policies are managed by the Core Maintainers team. + +### 2.2 Example & Module Ownership + +Individual examples or modules within the repository have specific owners, documented in their respective `MAINTAINERS.md` files. + +- **Responsibility:** Owners are responsible for the technical health, periodic updates (e.g., dependency bumps), and community feedback for their specific content. +- **Handover:** If an owner leaves the project or company, ownership reverts to the Core Maintainers until a new owner is assigned. + +## 3. Review & Quality Assurance + +To ensure high standards and security, we follow a strict contribution process: + +- **4-Eyes Principle:** No code enters the `main` branch without at least one successful Peer Review. +- **Automated Validation:** Every Pull Request must pass the CI pipeline, which includes: + - Linting and formatting checks. + - License header verification (Apache 2.0). + - Secret scanning (Trufflehog). +- **Best Effort Policy:** While we strive for quality, the content is provided "as-is." Use in production environments requires independent validation by the user. + +## 4. Mirroring Process + +The synchronization between the internal Git and GitHub is fully automated: + +1. Changes are merged into the internal `main` branch. +2. A GitHub Action triggers on every push to `main`. diff --git a/README.md b/README.md index 46e3b56..68b4d37 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# STACKIT Professional Services +# STACKIT PS Solutions -Welcome to the central repository for STACKIT Professional Services examples, scripts, and boilerplate code! +Welcome to the central repository for STACKIT examples, scripts, and boilerplate code! > **⚠️ REPOSITORY MIRROR NOTICE** > From 2f6cb3a1e27c2ef70ad928343f33aa836a8ef739 Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Fri, 24 Apr 2026 09:36:05 +0200 Subject: [PATCH 04/14] docs: change url in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 68b4d37..132d692 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Welcome to the central repository for STACKIT examples, scripts, and boilerplate > > This GitHub repository is a **mirror**. > The primary, internal source of truth for this codebase lives at: -> `https://professional-service.git.onstackit.cloud/professional-service-best-practices/professional-services` +> `https://professional-service.git.onstackit.cloud/professional-service-best-practices/stackit-ps-solutions` > > We automatically sync changes from our STACKIT managed GIT instance to this public GitHub repository. > From e27a25209deb17f4fa277998e7ced7a4f93dfc7b Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Mon, 27 Apr 2026 16:01:27 +0200 Subject: [PATCH 05/14] example(hub-spoke): replace python crypt func --- examples/pfsense-hub-and-spoke/cloud-init/user-init-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/pfsense-hub-and-spoke/cloud-init/user-init-linux.yml b/examples/pfsense-hub-and-spoke/cloud-init/user-init-linux.yml index 6850de0..be6e579 100644 --- a/examples/pfsense-hub-and-spoke/cloud-init/user-init-linux.yml +++ b/examples/pfsense-hub-and-spoke/cloud-init/user-init-linux.yml @@ -8,7 +8,7 @@ # default password in production. # # Generate a SHA-512 hash on Linux/macOS: -# python3 -c "import crypt; print(crypt.crypt('YourPassword', crypt.mksalt(crypt.METHOD_SHA512)))" +# openssl passwd -6 "YourPassword" # --------------------------------------------------------------------------- users: - name: admin-user From 879abdd0e847f6387257d962ccd2ec45443def00 Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Tue, 5 May 2026 09:22:14 +0200 Subject: [PATCH 06/14] chore: rename project --- .github/workflows/github-mirror-ci.yaml | 2 +- GOVERNANCE.md | 4 ++-- README.md | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/github-mirror-ci.yaml b/.github/workflows/github-mirror-ci.yaml index 5b71600..de61ea9 100644 --- a/.github/workflows/github-mirror-ci.yaml +++ b/.github/workflows/github-mirror-ci.yaml @@ -32,7 +32,7 @@ jobs: git config --global user.email "ps-sync-bot@digits.schwarz" # Add the GitHub remote using the SSH protocol - git remote add public git@github.com:stackitcloud/stackit-ps-solutions.git + git remote add public git@github.com:stackitcloud/professional-service.git echo "Pushing main branch to GitHub..." git push public main --force diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 4b1be95..8b1c7fc 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -1,6 +1,6 @@ -# Project Governance: STACKIT PS Solutions +# Project Governance: STACKIT Professional Service -This document defines the management, ownership, and maintenance processes for the STACKIT PS Solutions repository. +This document defines the management, ownership, and maintenance processes for the STACKIT Professional Service repository. ## 1. Strategy & "The Story" diff --git a/README.md b/README.md index 132d692..d2b4225 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# STACKIT PS Solutions +# STACKIT Professional Service Welcome to the central repository for STACKIT examples, scripts, and boilerplate code! @@ -6,7 +6,7 @@ Welcome to the central repository for STACKIT examples, scripts, and boilerplate > > This GitHub repository is a **mirror**. > The primary, internal source of truth for this codebase lives at: -> `https://professional-service.git.onstackit.cloud/professional-service-best-practices/stackit-ps-solutions` +> `https://professional-service.git.onstackit.cloud/professional-service-best-practices/professional-service` > > We automatically sync changes from our STACKIT managed GIT instance to this public GitHub repository. > From 23cf4370447653edadd9145660b5ed165a312d8d Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Tue, 5 May 2026 10:06:46 +0200 Subject: [PATCH 07/14] chore: readme typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d2b4225..9fce77a 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Let's be upfront about how this repository is maintained: - **Strictly Best Effort:** Everything you find in this repository is provided on a "best effort" basis. - **No Guarantees on Freshness:** We try our best to keep the examples, Terraform modules, and scripts up to date with the latest provider releases and API changes. However, **we cannot guarantee it**. Things move fast in the cloud, and some examples might become outdated over time. -- **Use Your Brain:** Do not blindly copy-paste code from here directly into a production environment. +- **Review Before Deploying:** Do not blindly copy-paste code from here directly into a production environment. ## Contents From e3c8d518462b9517755f7b7b34a0411c9a922f7a Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Tue, 5 May 2026 10:09:14 +0200 Subject: [PATCH 08/14] chore(test-machine module): add validation for variables --- modules/test-machine/variables.tf | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/modules/test-machine/variables.tf b/modules/test-machine/variables.tf index a85ae88..f32d00e 100644 --- a/modules/test-machine/variables.tf +++ b/modules/test-machine/variables.tf @@ -15,22 +15,42 @@ variable "project_id" { description = "The STACKIT Project ID" type = string + + validation { + condition = can(regex("^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$", var.project_id)) + error_message = "The project_id must be a valid UUID." + } } variable "network_id" { description = "The Network ID (UUID) where the machine should be spawned" type = string + + validation { + condition = can(regex("^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$", var.network_id)) + error_message = "The network_id must be a valid UUID." + } } variable "name" { description = "Hostname of the server" type = string default = "test-machine" + + validation { + condition = can(regex("^[a-z0-9-]+$", var.name)) + error_message = "The machine name must contain only lowercase letters, numbers, and hyphens." + } } variable "availability_zone" { description = "The availability zone (e.g. eu01-1)" type = string + + validation { + condition = can(regex("^[a-z]{2}[0-9]{2}-[a-zA-Z0-9]+$", var.availability_zone)) + error_message = "The availability zone must follow the STACKIT pattern (e.g., eu01-1, eu01-m)." + } } variable "machine_type" { @@ -43,12 +63,22 @@ variable "image_id" { description = "Image UUID (Default: Debian 12)" type = string default = "c751cde7-e648-4f81-9722-ce9c7848bed0" + + validation { + condition = can(regex("^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$", var.image_id)) + error_message = "The image_id must be a valid UUID." + } } variable "disk_size" { description = "Boot volume size in GB" type = number default = 50 + + validation { + condition = var.disk_size >= 1 + error_message = "The disk_size must be at least 1 GB." + } } variable "disk_performance_class" { From 6f29d02c651c999a8acb18d5aad76f21ce84ad6b Mon Sep 17 00:00:00 2001 From: Mouhsen Ibrahim Date: Wed, 6 May 2026 12:05:08 +0200 Subject: [PATCH 09/14] terraform: Add provider blocks to all examples --- .../.terraform.lock.hcl | 8 ++- .../.terraform.lock.hcl | 2 + .../.terraform.lock.hcl | 6 +- examples/iaas-ha-vrrp/.terraform.lock.hcl | 2 + .../.terraform.lock.hcl | 1 + .../.terraform.lock.hcl | 2 + .../.terraform.lock.hcl | 47 ++++++++++++++ .../.terraform.lock.hcl | 44 +++++++++++++ .../main.tf | 15 ----- .../provider.tf | 41 ++++++++++++ .../ske-encrypted-volumes/.terraform.lock.hcl | 44 +++++++++++++ examples/ske-encrypted-volumes/main.tf | 12 ---- examples/ske-encrypted-volumes/provider.tf | 38 +++++++++++ .../.terraform.lock.hcl | 5 ++ examples/ske-gpu-operator/.terraform.lock.hcl | 5 +- .../.terraform.lock.hcl | 44 +++++++++++++ .../ske-nginx-rate-limit/.terraform.lock.hcl | 4 ++ .../.terraform.lock.hcl | 64 +++++++++++++++++++ .../main.tf | 21 ------ .../provider.tf | 51 +++++++++++++++ .../.terraform.lock.hcl | 64 +++++++++++++++++++ examples/ske-observability-log-alerts/main.tf | 21 ------ .../ske-observability-log-alerts/provider.tf | 51 +++++++++++++++ .../.terraform.lock.hcl | 1 + 24 files changed, 521 insertions(+), 72 deletions(-) create mode 100644 examples/s3-aws-terraform-provider/.terraform.lock.hcl create mode 100644 examples/secretsmanager-vault-terraform-provider/.terraform.lock.hcl create mode 100644 examples/secretsmanager-vault-terraform-provider/provider.tf create mode 100644 examples/ske-encrypted-volumes/.terraform.lock.hcl create mode 100644 examples/ske-encrypted-volumes/provider.tf create mode 100644 examples/ske-kubernetes-terraform-provider/.terraform.lock.hcl create mode 100644 examples/ske-observability-alerting-kube-state-metrics/.terraform.lock.hcl create mode 100644 examples/ske-observability-alerting-kube-state-metrics/provider.tf create mode 100644 examples/ske-observability-log-alerts/.terraform.lock.hcl create mode 100644 examples/ske-observability-log-alerts/provider.tf diff --git a/examples/dbaas-otel-collect-metrics/.terraform.lock.hcl b/examples/dbaas-otel-collect-metrics/.terraform.lock.hcl index db8eb36..810732d 100644 --- a/examples/dbaas-otel-collect-metrics/.terraform.lock.hcl +++ b/examples/dbaas-otel-collect-metrics/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/helm" { version = "3.1.1" hashes = [ "h1:47CqNwkxctJtL/N/JuEj+8QMg8mRNI/NWeKO5/ydfZU=", + "h1:5b2ojWKT0noujHiweCds37ZreRFRQLNaErdJLusJN88=", "zh:1a6d5ce931708aec29d1f3d9e360c2a0c35ba5a54d03eeaff0ce3ca597cd0275", "zh:3411919ba2a5941801e677f0fea08bdd0ae22ba3c9ce3309f55554699e06524a", "zh:81b36138b8f2320dc7f877b50f9e38f4bc614affe68de885d322629dd0d16a29", @@ -21,9 +22,11 @@ provider "registry.terraform.io/hashicorp/helm" { } provider "registry.terraform.io/hashicorp/kubernetes" { - version = "3.1.0" + version = "3.1.0" + constraints = ">= 2.14.0" hashes = [ "h1:G9QqKNpcztBRqrywtlNylFJSpGzDfRFtO8hcWLdkvRY=", + "h1:oodIAuFMikXNmEtil5MQgP4dfSctUBYQiGJfjbsF3NY=", "zh:0215c5c60be62028c09a2f22458e89cda3ef5830a632299f1d401eb3538874b0", "zh:09ebb9f442431e278a310a9423f32caf467cb4b3cad3fe59573ca71fa7b14e20", "zh:0c4e5912f83bb35846ae0a9ae54fc320706ee61894cd21cc6b4181b1c5a2fa5c", @@ -43,6 +46,7 @@ provider "registry.terraform.io/hashicorp/random" { version = "3.8.1" constraints = ">= 3.6.3" hashes = [ + "h1:Eexl06+6J+s75uD46+WnZtpJZYRVUMB0AiuPBifK6Jc=", "h1:u8AKlWVDTH5r9YLSeswoVEjiY72Rt4/ch7U+61ZDkiQ=", "zh:08dd03b918c7b55713026037c5400c48af5b9f468f483463321bd18e17b907b4", "zh:0eee654a5542dc1d41920bbf2419032d6f0d5625b03bd81339e5b33394a3e0ae", @@ -62,6 +66,7 @@ provider "registry.terraform.io/hashicorp/random" { provider "registry.terraform.io/hashicorp/time" { version = "0.13.1" hashes = [ + "h1:+W+DMrVoVnoXo3f3M4W+OpZbkCrUn6PnqDF33D2Cuf0=", "h1:ZT5ppCNIModqk3iOkVt5my8b8yBHmDpl663JtXAIRqM=", "zh:02cb9aab1002f0f2a94a4f85acec8893297dc75915f7404c165983f720a54b74", "zh:04429b2b31a492d19e5ecf999b116d396dac0b24bba0d0fb19ecaefe193fdb8f", @@ -82,6 +87,7 @@ provider "registry.terraform.io/stackitcloud/stackit" { version = "0.92.0" constraints = ">= 0.87.0" hashes = [ + "h1:dE5sdzUaHkzVL8AW3+GXD2EEWX2PlS+sHT7F25SXcZ0=", "h1:j26ncxqlAp4q0/NHFoiATuVdIg7KH0zZhWoSAd+4Yj0=", "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", "zh:5eaa713f68a004ec33697f510ca4c7722940e2bab8080c025822ca547325ef98", diff --git a/examples/iaas-cross-az-layer4-loadbalancer/.terraform.lock.hcl b/examples/iaas-cross-az-layer4-loadbalancer/.terraform.lock.hcl index bd80b22..eeb1632 100644 --- a/examples/iaas-cross-az-layer4-loadbalancer/.terraform.lock.hcl +++ b/examples/iaas-cross-az-layer4-loadbalancer/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/random" { version = "3.8.1" constraints = ">= 3.6.3" hashes = [ + "h1:Eexl06+6J+s75uD46+WnZtpJZYRVUMB0AiuPBifK6Jc=", "h1:u8AKlWVDTH5r9YLSeswoVEjiY72Rt4/ch7U+61ZDkiQ=", "zh:08dd03b918c7b55713026037c5400c48af5b9f468f483463321bd18e17b907b4", "zh:0eee654a5542dc1d41920bbf2419032d6f0d5625b03bd81339e5b33394a3e0ae", @@ -26,6 +27,7 @@ provider "registry.terraform.io/stackitcloud/stackit" { constraints = ">= 0.87.0" hashes = [ "h1:8de9n+Roq6Z2Ltp9poBBBN9a4zSpx73VLpgFS5mTyoI=", + "h1:RStdHSDwbtonYfg7mR5Y92v6fxIVX9FEz0UN+tm9kHI=", "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", "zh:0ed12db90276ccd2d6f87135b7dd078657823c3ca33121c6a157d0bdf08f801e", "zh:160b32bcf1d01666784cf8469e10e0a38d4c3d24c80c0c5be470cc63ef27ea62", diff --git a/examples/iaas-cross-az-layer7-loadbalancer-waf/.terraform.lock.hcl b/examples/iaas-cross-az-layer7-loadbalancer-waf/.terraform.lock.hcl index 5e195e5..25ece83 100644 --- a/examples/iaas-cross-az-layer7-loadbalancer-waf/.terraform.lock.hcl +++ b/examples/iaas-cross-az-layer7-loadbalancer-waf/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/random" { version = "3.8.1" constraints = ">= 3.6.3" hashes = [ + "h1:Eexl06+6J+s75uD46+WnZtpJZYRVUMB0AiuPBifK6Jc=", "h1:u8AKlWVDTH5r9YLSeswoVEjiY72Rt4/ch7U+61ZDkiQ=", "zh:08dd03b918c7b55713026037c5400c48af5b9f468f483463321bd18e17b907b4", "zh:0eee654a5542dc1d41920bbf2419032d6f0d5625b03bd81339e5b33394a3e0ae", @@ -24,6 +25,7 @@ provider "registry.terraform.io/hashicorp/random" { provider "registry.terraform.io/hashicorp/tls" { version = "4.2.1" hashes = [ + "h1:F5d6bQY8UlBo0D71Sv7CsV+3aZOFz0yeNF+vufog7h4=", "h1:akFNuHwvrtnYMBofieoeXhPJDhYZzJVu/Q/BgZK2fgg=", "zh:0d1e7d07ac973b97fa228f46596c800de830820506ee145626f079dd6bbf8d8a", "zh:5c7e3d4348cb4861ab812973ef493814a4b224bdd3e9d534a7c8a7c992382b86", @@ -42,8 +44,9 @@ provider "registry.terraform.io/hashicorp/tls" { provider "registry.terraform.io/mastercard/restapi" { version = "3.0.0" - constraints = "3.0.0" + constraints = ">= 3.0.0" hashes = [ + "h1:Fqxoc6bsydl6iWGx6ZvyqUDdGt7Cb4sW/BSHhBeHGgw=", "h1:y1I3azDHOqRySTyDHsb3Xh1waP/99KfykZRagbRx1qI=", "zh:0b63bd3c25a31f090a41933f90b7dd6e984add1c4261d8f5caa73f4d5aa065a4", "zh:1c3e89cf19118fc07d7b04257251fc9897e722c16e0a0df7b07fcd261f8c12e7", @@ -68,6 +71,7 @@ provider "registry.terraform.io/stackitcloud/stackit" { constraints = ">= 0.87.0" hashes = [ "h1:8de9n+Roq6Z2Ltp9poBBBN9a4zSpx73VLpgFS5mTyoI=", + "h1:RStdHSDwbtonYfg7mR5Y92v6fxIVX9FEz0UN+tm9kHI=", "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", "zh:0ed12db90276ccd2d6f87135b7dd078657823c3ca33121c6a157d0bdf08f801e", "zh:160b32bcf1d01666784cf8469e10e0a38d4c3d24c80c0c5be470cc63ef27ea62", diff --git a/examples/iaas-ha-vrrp/.terraform.lock.hcl b/examples/iaas-ha-vrrp/.terraform.lock.hcl index 22969f3..c8e7f0a 100644 --- a/examples/iaas-ha-vrrp/.terraform.lock.hcl +++ b/examples/iaas-ha-vrrp/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/random" { version = "3.8.1" constraints = ">= 3.6.3" hashes = [ + "h1:Eexl06+6J+s75uD46+WnZtpJZYRVUMB0AiuPBifK6Jc=", "h1:u8AKlWVDTH5r9YLSeswoVEjiY72Rt4/ch7U+61ZDkiQ=", "zh:08dd03b918c7b55713026037c5400c48af5b9f468f483463321bd18e17b907b4", "zh:0eee654a5542dc1d41920bbf2419032d6f0d5625b03bd81339e5b33394a3e0ae", @@ -25,6 +26,7 @@ provider "registry.terraform.io/stackitcloud/stackit" { version = "0.90.0" constraints = ">= 0.87.0" hashes = [ + "h1:QgP6TOtucJ3A6fA51rdUvxhYGjl9RrWvXQZpjHTOuiU=", "h1:W29Kv6XUxYssF2Gy8KcmTx3EFstt6k8sKgPRIBbq+qs=", "zh:003af58a84884558bbb2fc40fcbefa6774ec20aa9e4b97cf3f950190a600afd2", "zh:026ee9cef4670cf33369f8654c6b9b1d8c0e116ceb0b353c882be222951ecdd4", diff --git a/examples/iaas-volume-encryption/.terraform.lock.hcl b/examples/iaas-volume-encryption/.terraform.lock.hcl index 7c3993a..f4f00c9 100644 --- a/examples/iaas-volume-encryption/.terraform.lock.hcl +++ b/examples/iaas-volume-encryption/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/stackitcloud/stackit" { version = "0.80.0" constraints = "0.80.0" hashes = [ + "h1:VqmLlSV9sMOX7aq5Bnsj18KNKCUPFahZzf0SA5fTkVk=", "h1:wz7uGwzVoo1NO18CDLcfjLraTSiWQ5EzJnDeCKcFi60=", "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", "zh:3a0e6cb125ef76a24b2b5ff9c786c57058f385571d283bd68f633225fcca695a", diff --git a/examples/resourcemanager-nested-folders/.terraform.lock.hcl b/examples/resourcemanager-nested-folders/.terraform.lock.hcl index c9888a0..0fdab96 100644 --- a/examples/resourcemanager-nested-folders/.terraform.lock.hcl +++ b/examples/resourcemanager-nested-folders/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/random" { version = "3.6.3" constraints = "3.6.3" hashes = [ + "h1:Fnaec9vA8sZ8BXVlN3Xn9Jz3zghSETIKg7ch8oXhxno=", "h1:zG9uFP8l9u+yGZZvi5Te7PV62j50azpgwPunq2vTm1E=", "zh:04ceb65210251339f07cd4611885d242cd4d0c7306e86dda9785396807c00451", "zh:448f56199f3e99ff75d5c0afacae867ee795e4dfda6cb5f8e3b2a72ec3583dd8", @@ -25,6 +26,7 @@ provider "registry.terraform.io/stackitcloud/stackit" { version = "0.90.0" constraints = ">= 0.66.0" hashes = [ + "h1:QgP6TOtucJ3A6fA51rdUvxhYGjl9RrWvXQZpjHTOuiU=", "h1:W29Kv6XUxYssF2Gy8KcmTx3EFstt6k8sKgPRIBbq+qs=", "zh:003af58a84884558bbb2fc40fcbefa6774ec20aa9e4b97cf3f950190a600afd2", "zh:026ee9cef4670cf33369f8654c6b9b1d8c0e116ceb0b353c882be222951ecdd4", diff --git a/examples/s3-aws-terraform-provider/.terraform.lock.hcl b/examples/s3-aws-terraform-provider/.terraform.lock.hcl new file mode 100644 index 0000000..8873576 --- /dev/null +++ b/examples/s3-aws-terraform-provider/.terraform.lock.hcl @@ -0,0 +1,47 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.100.0" + constraints = "~> 5.0" + hashes = [ + "h1:edXOJWE4ORX8Fm+dpVpICzMZJat4AX0VRCAy/xkcOc0=", + "zh:054b8dd49f0549c9a7cc27d159e45327b7b65cf404da5e5a20da154b90b8a644", + "zh:0b97bf8d5e03d15d83cc40b0530a1f84b459354939ba6f135a0086c20ebbe6b2", + "zh:1589a2266af699cbd5d80737a0fe02e54ec9cf2ca54e7e00ac51c7359056f274", + "zh:6330766f1d85f01ae6ea90d1b214b8b74cc8c1badc4696b165b36ddd4cc15f7b", + "zh:7c8c2e30d8e55291b86fcb64bdf6c25489d538688545eb48fd74ad622e5d3862", + "zh:99b1003bd9bd32ee323544da897148f46a527f622dc3971af63ea3e251596342", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9f8b909d3ec50ade83c8062290378b1ec553edef6a447c56dadc01a99f4eaa93", + "zh:aaef921ff9aabaf8b1869a86d692ebd24fbd4e12c21205034bb679b9caf883a2", + "zh:ac882313207aba00dd5a76dbd572a0ddc818bb9cbf5c9d61b28fe30efaec951e", + "zh:bb64e8aff37becab373a1a0cc1080990785304141af42ed6aa3dd4913b000421", + "zh:dfe495f6621df5540d9c92ad40b8067376350b005c637ea6efac5dc15028add4", + "zh:f0ddf0eaf052766cfe09dea8200a946519f653c384ab4336e2a4a64fdd6310e9", + "zh:f1b7e684f4c7ae1eed272b6de7d2049bb87a0275cb04dbb7cda6636f600699c9", + "zh:ff461571e3f233699bf690db319dfe46aec75e58726636a0d97dd9ac6e32fb70", + ] +} + +provider "registry.terraform.io/stackitcloud/stackit" { + version = "0.94.0" + constraints = "> 0.90.0" + hashes = [ + "h1:ikFzd4yeJ1LR8ojP2PsZwiK2ZLhxBjRXkEg2HJrI07U=", + "zh:06c8da7d8a048216e825fa7d1e45949c1bda2a5f53f9bb0556b83b6610703fe6", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:19e82636cfd52a65105e0cf030bc8a0c815082818ef953b84f9b1e349a87318c", + "zh:24af9b7d2f1bb38f480b1aa8cf5e4ecf483bd4403642a9e8a5accbe1ae212feb", + "zh:3b10850e9242bcd00c519ff4140130e8443002fd60b6dff90983e7cb1973b2c3", + "zh:54837a0fa4ddbcf0b8407718f8823b831322deba3bd7ec8492e4578928f50633", + "zh:5cfd6a6b1ca73826a03f8746ef84a5c4059648bc49abf8056c8e0f9b87800a23", + "zh:6ab3bcfef6ff65b4ce76d333b4ad99e5f91991fcf5bddbe1958aadde6ee05eab", + "zh:81b96dc29b055f15e475d8bc32482617a582785949b3c02f44ef15d19951f69c", + "zh:85f478c2fcf10219263462d0f06b5cc41603b1edad813c336e100b3e0a55bfe8", + "zh:9adbb7655fddfe4d4081746d0d7e39c3e8fbf8aa3d8b7d3b5164f30c16a6bd93", + "zh:9c24b39e788283ead8a8ce1f013a47562ff0dc1ccb642a8e18644cbdcda0f1c4", + "zh:a425f28d6a5f6f024cab56c848c55025e84a09db946f1b00a2655d9567251cea", + "zh:f28aa62d2f06e08fe6d18ef9103a8164aa9278540779bebd61120f810c603c6b", + ] +} diff --git a/examples/secretsmanager-vault-terraform-provider/.terraform.lock.hcl b/examples/secretsmanager-vault-terraform-provider/.terraform.lock.hcl new file mode 100644 index 0000000..474bc20 --- /dev/null +++ b/examples/secretsmanager-vault-terraform-provider/.terraform.lock.hcl @@ -0,0 +1,44 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/vault" { + version = "5.9.0" + constraints = "5.9.0" + hashes = [ + "h1:8wcXxEMo7XvCnrtZHSpAuWmRfYiZkWn2tssshB1BDzo=", + "zh:16e23a37c0965938544af282a7bc13dabca445f462ab27829f98e936ace4d263", + "zh:249fcf9da1a690fe9aa44a7421fad89a425afb0c2ce7eaf306d75daddd691af5", + "zh:3d92af386049a229a428f21b938a22df61703447c8ceed65c73f111a64e627d2", + "zh:4033fedf9d4f54f0aacf7c4a79e20978bcd67c0a8ab9411acd447db1469108a4", + "zh:51c78d0dc378037bbaf3cd26ff29fae7c40d7b134b40d059b982257987c15f9f", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:86e414b7327343de676ec506d30c557a514dbd992b27a2670466adaf9ed69718", + "zh:879c3a61ed8d183a68ddb590e63a7e0d6aab8d8044fd4a13658e7b1661395a9d", + "zh:8d548617543ee2ce0340972a5df93e7ac37b7895d4bf506bd587f8daac58e6d6", + "zh:8d75b3bbfd9a536c8c1d84504cb3d1c8e1a3fd30e377a51a6311476632363103", + "zh:922f625a36642c49daa432e07c12e72ff75025e0b9afda8d7240f38c6789fe46", + "zh:fbceae685b395acaff6c820ed7d7eaa6250ef4769e04481145dc50e09b89db2f", + ] +} + +provider "registry.terraform.io/stackitcloud/stackit" { + version = "0.94.0" + constraints = ">= 0.94.0" + hashes = [ + "h1:ikFzd4yeJ1LR8ojP2PsZwiK2ZLhxBjRXkEg2HJrI07U=", + "zh:06c8da7d8a048216e825fa7d1e45949c1bda2a5f53f9bb0556b83b6610703fe6", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:19e82636cfd52a65105e0cf030bc8a0c815082818ef953b84f9b1e349a87318c", + "zh:24af9b7d2f1bb38f480b1aa8cf5e4ecf483bd4403642a9e8a5accbe1ae212feb", + "zh:3b10850e9242bcd00c519ff4140130e8443002fd60b6dff90983e7cb1973b2c3", + "zh:54837a0fa4ddbcf0b8407718f8823b831322deba3bd7ec8492e4578928f50633", + "zh:5cfd6a6b1ca73826a03f8746ef84a5c4059648bc49abf8056c8e0f9b87800a23", + "zh:6ab3bcfef6ff65b4ce76d333b4ad99e5f91991fcf5bddbe1958aadde6ee05eab", + "zh:81b96dc29b055f15e475d8bc32482617a582785949b3c02f44ef15d19951f69c", + "zh:85f478c2fcf10219263462d0f06b5cc41603b1edad813c336e100b3e0a55bfe8", + "zh:9adbb7655fddfe4d4081746d0d7e39c3e8fbf8aa3d8b7d3b5164f30c16a6bd93", + "zh:9c24b39e788283ead8a8ce1f013a47562ff0dc1ccb642a8e18644cbdcda0f1c4", + "zh:a425f28d6a5f6f024cab56c848c55025e84a09db946f1b00a2655d9567251cea", + "zh:f28aa62d2f06e08fe6d18ef9103a8164aa9278540779bebd61120f810c603c6b", + ] +} diff --git a/examples/secretsmanager-vault-terraform-provider/main.tf b/examples/secretsmanager-vault-terraform-provider/main.tf index ddd4b6e..bea426c 100644 --- a/examples/secretsmanager-vault-terraform-provider/main.tf +++ b/examples/secretsmanager-vault-terraform-provider/main.tf @@ -12,11 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -provider "stackit" { - default_region = "eu01" - service_account_key_path = "" -} - resource "stackit_secretsmanager_instance" "example" { project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" name = "example-instance" @@ -29,16 +24,6 @@ resource "stackit_secretsmanager_user" "example" { write_enabled = true } -provider "vault" { - address = "https://prod.sm.eu01.stackit.cloud" - skip_child_token = true - - auth_login_userpass { - username = stackit_secretsmanager_user.example.username - password = stackit_secretsmanager_user.example.password - } -} - resource "stackit_observability_instance" "example" { project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" name = "example-instance" diff --git a/examples/secretsmanager-vault-terraform-provider/provider.tf b/examples/secretsmanager-vault-terraform-provider/provider.tf new file mode 100644 index 0000000..cf73ad6 --- /dev/null +++ b/examples/secretsmanager-vault-terraform-provider/provider.tf @@ -0,0 +1,41 @@ +# 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. + +terraform { + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">= 0.94.0" + } + vault = { + source = "hashicorp/vault" + version = "5.9.0" + } + } +} + +provider "stackit" { + default_region = "eu01" + service_account_key_path = "" +} + +provider "vault" { + address = "https://prod.sm.eu01.stackit.cloud" + skip_child_token = true + + auth_login_userpass { + username = stackit_secretsmanager_user.example.username + password = stackit_secretsmanager_user.example.password + } +} diff --git a/examples/ske-encrypted-volumes/.terraform.lock.hcl b/examples/ske-encrypted-volumes/.terraform.lock.hcl new file mode 100644 index 0000000..39718fe --- /dev/null +++ b/examples/ske-encrypted-volumes/.terraform.lock.hcl @@ -0,0 +1,44 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/kubernetes" { + version = "3.1.0" + constraints = ">= 3.1.0" + hashes = [ + "h1:oodIAuFMikXNmEtil5MQgP4dfSctUBYQiGJfjbsF3NY=", + "zh:0215c5c60be62028c09a2f22458e89cda3ef5830a632299f1d401eb3538874b0", + "zh:09ebb9f442431e278a310a9423f32caf467cb4b3cad3fe59573ca71fa7b14e20", + "zh:0c4e5912f83bb35846ae0a9ae54fc320706ee61894cd21cc6b4181b1c5a2fa5c", + "zh:1678c982853ad461e65ccb5e79d585e13ed109dd47dab2a66d3a7a304faeef65", + "zh:1c050a5c15e330457a9c18caacf61a923c59d663e13f2962e4b32f04fef523a0", + "zh:2c55bcec83be58ec132c7cb0a1ac644758b800d794fdc636d53a0eada0358a3a", + "zh:a062bb0aa316c08d8460c66a5d68da71da40de5d3bc3b31abcf3a1a9a19650f1", + "zh:a26fdea0afaa9b247c73c0b42843ca51ba7db0ac2571f9d3d50dcabd20ca1b98", + "zh:c872c9385a78d502bf5823d61cd3bb0f9a0585030e025eb12585c83451beeaa1", + "zh:f180879af931182beee4c8c0d9dab62b81d86f17ddcbe3786ef4c7cec9163a4e", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + "zh:f70f5789264069e0eef06f9b5d5fde955ef7206f7d446d1ce51a4c37a3f3e02f", + ] +} + +provider "registry.terraform.io/stackitcloud/stackit" { + version = "0.94.0" + constraints = ">= 0.94.0" + hashes = [ + "h1:ikFzd4yeJ1LR8ojP2PsZwiK2ZLhxBjRXkEg2HJrI07U=", + "zh:06c8da7d8a048216e825fa7d1e45949c1bda2a5f53f9bb0556b83b6610703fe6", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:19e82636cfd52a65105e0cf030bc8a0c815082818ef953b84f9b1e349a87318c", + "zh:24af9b7d2f1bb38f480b1aa8cf5e4ecf483bd4403642a9e8a5accbe1ae212feb", + "zh:3b10850e9242bcd00c519ff4140130e8443002fd60b6dff90983e7cb1973b2c3", + "zh:54837a0fa4ddbcf0b8407718f8823b831322deba3bd7ec8492e4578928f50633", + "zh:5cfd6a6b1ca73826a03f8746ef84a5c4059648bc49abf8056c8e0f9b87800a23", + "zh:6ab3bcfef6ff65b4ce76d333b4ad99e5f91991fcf5bddbe1958aadde6ee05eab", + "zh:81b96dc29b055f15e475d8bc32482617a582785949b3c02f44ef15d19951f69c", + "zh:85f478c2fcf10219263462d0f06b5cc41603b1edad813c336e100b3e0a55bfe8", + "zh:9adbb7655fddfe4d4081746d0d7e39c3e8fbf8aa3d8b7d3b5164f30c16a6bd93", + "zh:9c24b39e788283ead8a8ce1f013a47562ff0dc1ccb642a8e18644cbdcda0f1c4", + "zh:a425f28d6a5f6f024cab56c848c55025e84a09db946f1b00a2655d9567251cea", + "zh:f28aa62d2f06e08fe6d18ef9103a8164aa9278540779bebd61120f810c603c6b", + ] +} diff --git a/examples/ske-encrypted-volumes/main.tf b/examples/ske-encrypted-volumes/main.tf index 8e2d010..55d2826 100644 --- a/examples/ske-encrypted-volumes/main.tf +++ b/examples/ske-encrypted-volumes/main.tf @@ -12,18 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -provider "stackit" { - default_region = "eu01" - service_account_key_path = "" -} - -provider "kubernetes" { - host = yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.server - client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-certificate-data) - client_key = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-key-data) - cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.certificate-authority-data) -} - resource "stackit_ske_cluster" "default" { project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" name = "ske-enc-vol" diff --git a/examples/ske-encrypted-volumes/provider.tf b/examples/ske-encrypted-volumes/provider.tf new file mode 100644 index 0000000..7c46d2b --- /dev/null +++ b/examples/ske-encrypted-volumes/provider.tf @@ -0,0 +1,38 @@ +# 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. + +terraform { + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">= 0.94.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 3.1.0" + } + } +} + +provider "stackit" { + default_region = "eu01" + service_account_key_path = "" +} + +provider "kubernetes" { + host = yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.server + client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-certificate-data) + client_key = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-key-data) + cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.certificate-authority-data) +} diff --git a/examples/ske-external-secrets-sync/.terraform.lock.hcl b/examples/ske-external-secrets-sync/.terraform.lock.hcl index fbb7035..f7f082b 100644 --- a/examples/ske-external-secrets-sync/.terraform.lock.hcl +++ b/examples/ske-external-secrets-sync/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/helm" { version = "2.17.0" constraints = "2.17.0" hashes = [ + "h1:K5FEjxvDnxb1JF1kG1xr8J3pNGxoaR3Z0IBG9Csm/Is=", "h1:kQMkcPVvHOguOqnxoEU2sm1ND9vCHiT8TvZ2x6v/Rsw=", "zh:06fb4e9932f0afc1904d2279e6e99353c2ddac0d765305ce90519af410706bd4", "zh:104eccfc781fc868da3c7fec4385ad14ed183eb985c96331a1a937ac79c2d1a7", @@ -26,6 +27,7 @@ provider "registry.terraform.io/hashicorp/kubernetes" { constraints = ">= 2.25.2" hashes = [ "h1:P0c8knzZnouTNFIRij8IS7+pqd0OKaFDYX0j4GRsiqo=", + "h1:vyHdH0p6bf9xp1NPePObAJkXTJb/I09FQQmmevTzZe0=", "zh:02d55b0b2238fd17ffa12d5464593864e80f402b90b31f6e1bd02249b9727281", "zh:20b93a51bfeed82682b3c12f09bac3031f5bdb4977c47c97a042e4df4fb2f9ba", "zh:6e14486ecfaee38c09ccf33d4fdaf791409f90795c1b66e026c226fad8bc03c7", @@ -45,6 +47,7 @@ provider "registry.terraform.io/hashicorp/random" { version = "3.7.2" constraints = "3.7.2" hashes = [ + "h1:356j/3XnXEKr9nyicLUufzoF4Yr6hRy481KIxRVpK0c=", "h1:KG4NuIBl1mRWU0KD/BGfCi1YN/j3F7H4YgeeM7iSdNs=", "zh:14829603a32e4bc4d05062f059e545a91e27ff033756b48afbae6b3c835f508f", "zh:1527fb07d9fea400d70e9e6eb4a2b918d5060d604749b6f1c361518e7da546dc", @@ -64,6 +67,7 @@ provider "registry.terraform.io/hashicorp/random" { provider "registry.terraform.io/hashicorp/vault" { version = "5.8.0" hashes = [ + "h1:eSJgYoJoVMce2xjJJCeAZnJELsC4RoqaotD0fgfn6dw=", "h1:gk1cR+x1D+TEz05MKWmpp0p06+Trob5cN0eYU1vZGJs=", "zh:18e79b42c8c155a5c541a45d54a6ccdeab23c404c239acdeed336a17cbfc2fd4", "zh:241f50d1ea40030578034b4440e41676f1c9b5e8a2be5cd3afdb6e387914e0bf", @@ -84,6 +88,7 @@ provider "registry.terraform.io/stackitcloud/stackit" { version = "0.90.0" constraints = ">= 0.66.0" hashes = [ + "h1:QgP6TOtucJ3A6fA51rdUvxhYGjl9RrWvXQZpjHTOuiU=", "h1:W29Kv6XUxYssF2Gy8KcmTx3EFstt6k8sKgPRIBbq+qs=", "zh:003af58a84884558bbb2fc40fcbefa6774ec20aa9e4b97cf3f950190a600afd2", "zh:026ee9cef4670cf33369f8654c6b9b1d8c0e116ceb0b353c882be222951ecdd4", diff --git a/examples/ske-gpu-operator/.terraform.lock.hcl b/examples/ske-gpu-operator/.terraform.lock.hcl index 2cebd8e..9772a39 100644 --- a/examples/ske-gpu-operator/.terraform.lock.hcl +++ b/examples/ske-gpu-operator/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/helm" { version = "3.1.1" hashes = [ "h1:47CqNwkxctJtL/N/JuEj+8QMg8mRNI/NWeKO5/ydfZU=", + "h1:5b2ojWKT0noujHiweCds37ZreRFRQLNaErdJLusJN88=", "zh:1a6d5ce931708aec29d1f3d9e360c2a0c35ba5a54d03eeaff0ce3ca597cd0275", "zh:3411919ba2a5941801e677f0fea08bdd0ae22ba3c9ce3309f55554699e06524a", "zh:81b36138b8f2320dc7f877b50f9e38f4bc614affe68de885d322629dd0d16a29", @@ -25,6 +26,7 @@ provider "registry.terraform.io/hashicorp/kubernetes" { constraints = ">= 2.14.0" hashes = [ "h1:P0c8knzZnouTNFIRij8IS7+pqd0OKaFDYX0j4GRsiqo=", + "h1:vyHdH0p6bf9xp1NPePObAJkXTJb/I09FQQmmevTzZe0=", "zh:02d55b0b2238fd17ffa12d5464593864e80f402b90b31f6e1bd02249b9727281", "zh:20b93a51bfeed82682b3c12f09bac3031f5bdb4977c47c97a042e4df4fb2f9ba", "zh:6e14486ecfaee38c09ccf33d4fdaf791409f90795c1b66e026c226fad8bc03c7", @@ -42,9 +44,10 @@ provider "registry.terraform.io/hashicorp/kubernetes" { provider "registry.terraform.io/stackitcloud/stackit" { version = "0.91.0" - constraints = "> 0.60.0" + constraints = ">= 0.60.0" hashes = [ "h1:8de9n+Roq6Z2Ltp9poBBBN9a4zSpx73VLpgFS5mTyoI=", + "h1:RStdHSDwbtonYfg7mR5Y92v6fxIVX9FEz0UN+tm9kHI=", "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", "zh:0ed12db90276ccd2d6f87135b7dd078657823c3ca33121c6a157d0bdf08f801e", "zh:160b32bcf1d01666784cf8469e10e0a38d4c3d24c80c0c5be470cc63ef27ea62", diff --git a/examples/ske-kubernetes-terraform-provider/.terraform.lock.hcl b/examples/ske-kubernetes-terraform-provider/.terraform.lock.hcl new file mode 100644 index 0000000..de5a520 --- /dev/null +++ b/examples/ske-kubernetes-terraform-provider/.terraform.lock.hcl @@ -0,0 +1,44 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/kubernetes" { + version = "2.38.0" + constraints = "~> 2.24" + hashes = [ + "h1:5CkveFo5ynsLdzKk+Kv+r7+U9rMrNjfZPT3a0N/fhgE=", + "zh:0af928d776eb269b192dc0ea0f8a3f0f5ec117224cd644bdacdc682300f84ba0", + "zh:1be998e67206f7cfc4ffe77c01a09ac91ce725de0abaec9030b22c0a832af44f", + "zh:326803fe5946023687d603f6f1bab24de7af3d426b01d20e51d4e6fbe4e7ec1b", + "zh:4a99ec8d91193af961de1abb1f824be73df07489301d62e6141a656b3ebfff12", + "zh:5136e51765d6a0b9e4dbcc3b38821e9736bd2136cf15e9aac11668f22db117d2", + "zh:63fab47349852d7802fb032e4f2b6a101ee1ce34b62557a9ad0f0f0f5b6ecfdc", + "zh:924fb0257e2d03e03e2bfe9c7b99aa73c195b1f19412ca09960001bee3c50d15", + "zh:b63a0be5e233f8f6727c56bed3b61eb9456ca7a8bb29539fba0837f1badf1396", + "zh:d39861aa21077f1bc899bc53e7233262e530ba8a3a2d737449b100daeb303e4d", + "zh:de0805e10ebe4c83ce3b728a67f6b0f9d18be32b25146aa89116634df5145ad4", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + "zh:faf23e45f0090eef8ba28a8aac7ec5d4fdf11a36c40a8d286304567d71c1e7db", + ] +} + +provider "registry.terraform.io/stackitcloud/stackit" { + version = "0.94.0" + constraints = "~> 0.35" + hashes = [ + "h1:ikFzd4yeJ1LR8ojP2PsZwiK2ZLhxBjRXkEg2HJrI07U=", + "zh:06c8da7d8a048216e825fa7d1e45949c1bda2a5f53f9bb0556b83b6610703fe6", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:19e82636cfd52a65105e0cf030bc8a0c815082818ef953b84f9b1e349a87318c", + "zh:24af9b7d2f1bb38f480b1aa8cf5e4ecf483bd4403642a9e8a5accbe1ae212feb", + "zh:3b10850e9242bcd00c519ff4140130e8443002fd60b6dff90983e7cb1973b2c3", + "zh:54837a0fa4ddbcf0b8407718f8823b831322deba3bd7ec8492e4578928f50633", + "zh:5cfd6a6b1ca73826a03f8746ef84a5c4059648bc49abf8056c8e0f9b87800a23", + "zh:6ab3bcfef6ff65b4ce76d333b4ad99e5f91991fcf5bddbe1958aadde6ee05eab", + "zh:81b96dc29b055f15e475d8bc32482617a582785949b3c02f44ef15d19951f69c", + "zh:85f478c2fcf10219263462d0f06b5cc41603b1edad813c336e100b3e0a55bfe8", + "zh:9adbb7655fddfe4d4081746d0d7e39c3e8fbf8aa3d8b7d3b5164f30c16a6bd93", + "zh:9c24b39e788283ead8a8ce1f013a47562ff0dc1ccb642a8e18644cbdcda0f1c4", + "zh:a425f28d6a5f6f024cab56c848c55025e84a09db946f1b00a2655d9567251cea", + "zh:f28aa62d2f06e08fe6d18ef9103a8164aa9278540779bebd61120f810c603c6b", + ] +} diff --git a/examples/ske-nginx-rate-limit/.terraform.lock.hcl b/examples/ske-nginx-rate-limit/.terraform.lock.hcl index 1adc572..1c27261 100644 --- a/examples/ske-nginx-rate-limit/.terraform.lock.hcl +++ b/examples/ske-nginx-rate-limit/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/hashicorp/helm" { version = "3.1.1" hashes = [ "h1:47CqNwkxctJtL/N/JuEj+8QMg8mRNI/NWeKO5/ydfZU=", + "h1:5b2ojWKT0noujHiweCds37ZreRFRQLNaErdJLusJN88=", "zh:1a6d5ce931708aec29d1f3d9e360c2a0c35ba5a54d03eeaff0ce3ca597cd0275", "zh:3411919ba2a5941801e677f0fea08bdd0ae22ba3c9ce3309f55554699e06524a", "zh:81b36138b8f2320dc7f877b50f9e38f4bc614affe68de885d322629dd0d16a29", @@ -25,6 +26,7 @@ provider "registry.terraform.io/hashicorp/kubernetes" { constraints = ">= 2.14.0" hashes = [ "h1:P0c8knzZnouTNFIRij8IS7+pqd0OKaFDYX0j4GRsiqo=", + "h1:vyHdH0p6bf9xp1NPePObAJkXTJb/I09FQQmmevTzZe0=", "zh:02d55b0b2238fd17ffa12d5464593864e80f402b90b31f6e1bd02249b9727281", "zh:20b93a51bfeed82682b3c12f09bac3031f5bdb4977c47c97a042e4df4fb2f9ba", "zh:6e14486ecfaee38c09ccf33d4fdaf791409f90795c1b66e026c226fad8bc03c7", @@ -43,6 +45,7 @@ provider "registry.terraform.io/hashicorp/kubernetes" { provider "registry.terraform.io/hashicorp/random" { version = "3.8.1" hashes = [ + "h1:Eexl06+6J+s75uD46+WnZtpJZYRVUMB0AiuPBifK6Jc=", "h1:u8AKlWVDTH5r9YLSeswoVEjiY72Rt4/ch7U+61ZDkiQ=", "zh:08dd03b918c7b55713026037c5400c48af5b9f468f483463321bd18e17b907b4", "zh:0eee654a5542dc1d41920bbf2419032d6f0d5625b03bd81339e5b33394a3e0ae", @@ -63,6 +66,7 @@ provider "registry.terraform.io/stackitcloud/stackit" { version = "0.90.0" constraints = ">= 0.66.0" hashes = [ + "h1:QgP6TOtucJ3A6fA51rdUvxhYGjl9RrWvXQZpjHTOuiU=", "h1:W29Kv6XUxYssF2Gy8KcmTx3EFstt6k8sKgPRIBbq+qs=", "zh:003af58a84884558bbb2fc40fcbefa6774ec20aa9e4b97cf3f950190a600afd2", "zh:026ee9cef4670cf33369f8654c6b9b1d8c0e116ceb0b353c882be222951ecdd4", diff --git a/examples/ske-observability-alerting-kube-state-metrics/.terraform.lock.hcl b/examples/ske-observability-alerting-kube-state-metrics/.terraform.lock.hcl new file mode 100644 index 0000000..3e3b5bf --- /dev/null +++ b/examples/ske-observability-alerting-kube-state-metrics/.terraform.lock.hcl @@ -0,0 +1,64 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/helm" { + version = "3.1.1" + constraints = ">= 3.1.1" + hashes = [ + "h1:5b2ojWKT0noujHiweCds37ZreRFRQLNaErdJLusJN88=", + "zh:1a6d5ce931708aec29d1f3d9e360c2a0c35ba5a54d03eeaff0ce3ca597cd0275", + "zh:3411919ba2a5941801e677f0fea08bdd0ae22ba3c9ce3309f55554699e06524a", + "zh:81b36138b8f2320dc7f877b50f9e38f4bc614affe68de885d322629dd0d16a29", + "zh:95a2a0a497a6082ee06f95b38bd0f0d6924a65722892a856cfd914c0d117f104", + "zh:9d3e78c2d1bb46508b972210ad706dd8c8b106f8b206ecf096cd211c54f46990", + "zh:a79139abf687387a6efdbbb04289a0a8e7eaca2bd91cdc0ce68ea4f3286c2c34", + "zh:aaa8784be125fbd50c48d84d6e171d3fb6ef84a221dbc5165c067ce05faab4c8", + "zh:afecd301f469975c9d8f350cc482fe656e082b6ab0f677d1a816c3c615837cc1", + "zh:c54c22b18d48ff9053d899d178d9ffef7d9d19785d9bf310a07d648b7aac075b", + "zh:db2eefd55aea48e73384a555c72bac3f7d428e24147bedb64e1a039398e5b903", + "zh:ee61666a233533fd2be971091cecc01650561f1585783c381b6f6e8a390198a4", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/kubernetes" { + version = "3.1.0" + constraints = ">= 3.1.0" + hashes = [ + "h1:oodIAuFMikXNmEtil5MQgP4dfSctUBYQiGJfjbsF3NY=", + "zh:0215c5c60be62028c09a2f22458e89cda3ef5830a632299f1d401eb3538874b0", + "zh:09ebb9f442431e278a310a9423f32caf467cb4b3cad3fe59573ca71fa7b14e20", + "zh:0c4e5912f83bb35846ae0a9ae54fc320706ee61894cd21cc6b4181b1c5a2fa5c", + "zh:1678c982853ad461e65ccb5e79d585e13ed109dd47dab2a66d3a7a304faeef65", + "zh:1c050a5c15e330457a9c18caacf61a923c59d663e13f2962e4b32f04fef523a0", + "zh:2c55bcec83be58ec132c7cb0a1ac644758b800d794fdc636d53a0eada0358a3a", + "zh:a062bb0aa316c08d8460c66a5d68da71da40de5d3bc3b31abcf3a1a9a19650f1", + "zh:a26fdea0afaa9b247c73c0b42843ca51ba7db0ac2571f9d3d50dcabd20ca1b98", + "zh:c872c9385a78d502bf5823d61cd3bb0f9a0585030e025eb12585c83451beeaa1", + "zh:f180879af931182beee4c8c0d9dab62b81d86f17ddcbe3786ef4c7cec9163a4e", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + "zh:f70f5789264069e0eef06f9b5d5fde955ef7206f7d446d1ce51a4c37a3f3e02f", + ] +} + +provider "registry.terraform.io/stackitcloud/stackit" { + version = "0.94.0" + constraints = ">= 0.94.0" + hashes = [ + "h1:ikFzd4yeJ1LR8ojP2PsZwiK2ZLhxBjRXkEg2HJrI07U=", + "zh:06c8da7d8a048216e825fa7d1e45949c1bda2a5f53f9bb0556b83b6610703fe6", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:19e82636cfd52a65105e0cf030bc8a0c815082818ef953b84f9b1e349a87318c", + "zh:24af9b7d2f1bb38f480b1aa8cf5e4ecf483bd4403642a9e8a5accbe1ae212feb", + "zh:3b10850e9242bcd00c519ff4140130e8443002fd60b6dff90983e7cb1973b2c3", + "zh:54837a0fa4ddbcf0b8407718f8823b831322deba3bd7ec8492e4578928f50633", + "zh:5cfd6a6b1ca73826a03f8746ef84a5c4059648bc49abf8056c8e0f9b87800a23", + "zh:6ab3bcfef6ff65b4ce76d333b4ad99e5f91991fcf5bddbe1958aadde6ee05eab", + "zh:81b96dc29b055f15e475d8bc32482617a582785949b3c02f44ef15d19951f69c", + "zh:85f478c2fcf10219263462d0f06b5cc41603b1edad813c336e100b3e0a55bfe8", + "zh:9adbb7655fddfe4d4081746d0d7e39c3e8fbf8aa3d8b7d3b5164f30c16a6bd93", + "zh:9c24b39e788283ead8a8ce1f013a47562ff0dc1ccb642a8e18644cbdcda0f1c4", + "zh:a425f28d6a5f6f024cab56c848c55025e84a09db946f1b00a2655d9567251cea", + "zh:f28aa62d2f06e08fe6d18ef9103a8164aa9278540779bebd61120f810c603c6b", + ] +} diff --git a/examples/ske-observability-alerting-kube-state-metrics/main.tf b/examples/ske-observability-alerting-kube-state-metrics/main.tf index 17520b1..0194bc1 100644 --- a/examples/ske-observability-alerting-kube-state-metrics/main.tf +++ b/examples/ske-observability-alerting-kube-state-metrics/main.tf @@ -12,27 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -provider "stackit" { - default_region = "eu01" - service_account_key_path = "" -} - -provider "kubernetes" { - host = yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.server - client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-certificate-data) - client_key = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-key-data) - cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.certificate-authority-data) -} - -provider "helm" { - kubernetes { - host = yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.server - client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-certificate-data) - client_key = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-key-data) - cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.certificate-authority-data) - } -} - resource "stackit_ske_cluster" "example" { project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" name = "example" diff --git a/examples/ske-observability-alerting-kube-state-metrics/provider.tf b/examples/ske-observability-alerting-kube-state-metrics/provider.tf new file mode 100644 index 0000000..430bb85 --- /dev/null +++ b/examples/ske-observability-alerting-kube-state-metrics/provider.tf @@ -0,0 +1,51 @@ +# 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. + +terraform { + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">= 0.94.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 3.1.0" + } + helm = { + source = "hashicorp/helm" + version = ">= 3.1.1" + } + } +} + +provider "stackit" { + default_region = "eu01" + service_account_key_path = "" +} + +provider "kubernetes" { + host = yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.server + client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-certificate-data) + client_key = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-key-data) + cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.certificate-authority-data) +} + +provider "helm" { + kubernetes = { + host = yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.server + client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-certificate-data) + client_key = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-key-data) + cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.certificate-authority-data) + } +} diff --git a/examples/ske-observability-log-alerts/.terraform.lock.hcl b/examples/ske-observability-log-alerts/.terraform.lock.hcl new file mode 100644 index 0000000..3e3b5bf --- /dev/null +++ b/examples/ske-observability-log-alerts/.terraform.lock.hcl @@ -0,0 +1,64 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/helm" { + version = "3.1.1" + constraints = ">= 3.1.1" + hashes = [ + "h1:5b2ojWKT0noujHiweCds37ZreRFRQLNaErdJLusJN88=", + "zh:1a6d5ce931708aec29d1f3d9e360c2a0c35ba5a54d03eeaff0ce3ca597cd0275", + "zh:3411919ba2a5941801e677f0fea08bdd0ae22ba3c9ce3309f55554699e06524a", + "zh:81b36138b8f2320dc7f877b50f9e38f4bc614affe68de885d322629dd0d16a29", + "zh:95a2a0a497a6082ee06f95b38bd0f0d6924a65722892a856cfd914c0d117f104", + "zh:9d3e78c2d1bb46508b972210ad706dd8c8b106f8b206ecf096cd211c54f46990", + "zh:a79139abf687387a6efdbbb04289a0a8e7eaca2bd91cdc0ce68ea4f3286c2c34", + "zh:aaa8784be125fbd50c48d84d6e171d3fb6ef84a221dbc5165c067ce05faab4c8", + "zh:afecd301f469975c9d8f350cc482fe656e082b6ab0f677d1a816c3c615837cc1", + "zh:c54c22b18d48ff9053d899d178d9ffef7d9d19785d9bf310a07d648b7aac075b", + "zh:db2eefd55aea48e73384a555c72bac3f7d428e24147bedb64e1a039398e5b903", + "zh:ee61666a233533fd2be971091cecc01650561f1585783c381b6f6e8a390198a4", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/kubernetes" { + version = "3.1.0" + constraints = ">= 3.1.0" + hashes = [ + "h1:oodIAuFMikXNmEtil5MQgP4dfSctUBYQiGJfjbsF3NY=", + "zh:0215c5c60be62028c09a2f22458e89cda3ef5830a632299f1d401eb3538874b0", + "zh:09ebb9f442431e278a310a9423f32caf467cb4b3cad3fe59573ca71fa7b14e20", + "zh:0c4e5912f83bb35846ae0a9ae54fc320706ee61894cd21cc6b4181b1c5a2fa5c", + "zh:1678c982853ad461e65ccb5e79d585e13ed109dd47dab2a66d3a7a304faeef65", + "zh:1c050a5c15e330457a9c18caacf61a923c59d663e13f2962e4b32f04fef523a0", + "zh:2c55bcec83be58ec132c7cb0a1ac644758b800d794fdc636d53a0eada0358a3a", + "zh:a062bb0aa316c08d8460c66a5d68da71da40de5d3bc3b31abcf3a1a9a19650f1", + "zh:a26fdea0afaa9b247c73c0b42843ca51ba7db0ac2571f9d3d50dcabd20ca1b98", + "zh:c872c9385a78d502bf5823d61cd3bb0f9a0585030e025eb12585c83451beeaa1", + "zh:f180879af931182beee4c8c0d9dab62b81d86f17ddcbe3786ef4c7cec9163a4e", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + "zh:f70f5789264069e0eef06f9b5d5fde955ef7206f7d446d1ce51a4c37a3f3e02f", + ] +} + +provider "registry.terraform.io/stackitcloud/stackit" { + version = "0.94.0" + constraints = ">= 0.94.0" + hashes = [ + "h1:ikFzd4yeJ1LR8ojP2PsZwiK2ZLhxBjRXkEg2HJrI07U=", + "zh:06c8da7d8a048216e825fa7d1e45949c1bda2a5f53f9bb0556b83b6610703fe6", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:19e82636cfd52a65105e0cf030bc8a0c815082818ef953b84f9b1e349a87318c", + "zh:24af9b7d2f1bb38f480b1aa8cf5e4ecf483bd4403642a9e8a5accbe1ae212feb", + "zh:3b10850e9242bcd00c519ff4140130e8443002fd60b6dff90983e7cb1973b2c3", + "zh:54837a0fa4ddbcf0b8407718f8823b831322deba3bd7ec8492e4578928f50633", + "zh:5cfd6a6b1ca73826a03f8746ef84a5c4059648bc49abf8056c8e0f9b87800a23", + "zh:6ab3bcfef6ff65b4ce76d333b4ad99e5f91991fcf5bddbe1958aadde6ee05eab", + "zh:81b96dc29b055f15e475d8bc32482617a582785949b3c02f44ef15d19951f69c", + "zh:85f478c2fcf10219263462d0f06b5cc41603b1edad813c336e100b3e0a55bfe8", + "zh:9adbb7655fddfe4d4081746d0d7e39c3e8fbf8aa3d8b7d3b5164f30c16a6bd93", + "zh:9c24b39e788283ead8a8ce1f013a47562ff0dc1ccb642a8e18644cbdcda0f1c4", + "zh:a425f28d6a5f6f024cab56c848c55025e84a09db946f1b00a2655d9567251cea", + "zh:f28aa62d2f06e08fe6d18ef9103a8164aa9278540779bebd61120f810c603c6b", + ] +} diff --git a/examples/ske-observability-log-alerts/main.tf b/examples/ske-observability-log-alerts/main.tf index 21b3e6a..1be4fc0 100644 --- a/examples/ske-observability-log-alerts/main.tf +++ b/examples/ske-observability-log-alerts/main.tf @@ -12,27 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -provider "stackit" { - default_region = "eu01" - service_account_key_path = "" -} - -provider "kubernetes" { - host = yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.server - client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-certificate-data) - client_key = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-key-data) - cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.certificate-authority-data) -} - -provider "helm" { - kubernetes { - host = yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.server - client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-certificate-data) - client_key = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-key-data) - cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.certificate-authority-data) - } -} - resource "stackit_ske_cluster" "example" { project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" name = "example" diff --git a/examples/ske-observability-log-alerts/provider.tf b/examples/ske-observability-log-alerts/provider.tf new file mode 100644 index 0000000..430bb85 --- /dev/null +++ b/examples/ske-observability-log-alerts/provider.tf @@ -0,0 +1,51 @@ +# 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. + +terraform { + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">= 0.94.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 3.1.0" + } + helm = { + source = "hashicorp/helm" + version = ">= 3.1.1" + } + } +} + +provider "stackit" { + default_region = "eu01" + service_account_key_path = "" +} + +provider "kubernetes" { + host = yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.server + client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-certificate-data) + client_key = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-key-data) + cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.certificate-authority-data) +} + +provider "helm" { + kubernetes = { + host = yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.server + client_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-certificate-data) + client_key = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).users.0.user.client-key-data) + cluster_ca_certificate = base64decode(yamldecode(stackit_ske_kubeconfig.example.kube_config).clusters.0.cluster.certificate-authority-data) + } +} diff --git a/examples/ske-stackit-sfs-integration/.terraform.lock.hcl b/examples/ske-stackit-sfs-integration/.terraform.lock.hcl index 75c9e75..d3f19c1 100644 --- a/examples/ske-stackit-sfs-integration/.terraform.lock.hcl +++ b/examples/ske-stackit-sfs-integration/.terraform.lock.hcl @@ -5,6 +5,7 @@ provider "registry.terraform.io/stackitcloud/stackit" { version = "0.79.0" constraints = "0.79.0" hashes = [ + "h1:AB51ok4llxeTmkVadjYpsafPbzSU5xEHLzcVBuVHxqc=", "h1:l7AeT3WWi/u7QB7E1SaksYc5VjU9JS2LYc4OnavI3kw=", "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", "zh:1eb8276c0d8a4b5b92534020df0cb270ed7c4d91dfed6db089ee775b50a8f5e3", From 50584780cfef4dc7314e5f86bda1b55f9096bbba Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Wed, 6 May 2026 14:09:03 +0200 Subject: [PATCH 10/14] example(nested-folder): add warning to readme --- examples/resourcemanager-nested-folders/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/resourcemanager-nested-folders/README.md b/examples/resourcemanager-nested-folders/README.md index 1e99e45..b3d356d 100644 --- a/examples/resourcemanager-nested-folders/README.md +++ b/examples/resourcemanager-nested-folders/README.md @@ -2,4 +2,6 @@ ## Overview +> ⚠️ Two levels of folders must be enabled via a support ticket. By default, only one level is possible. + This repository demonstrates code to generate nested folders within a project. From 08d09f311919456d2ebc7e82ffe9f54853dcac69 Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Tue, 12 May 2026 10:16:48 +0200 Subject: [PATCH 11/14] ci: add step to resolve todos --- .github/workflows/default-ci.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/default-ci.yaml b/.github/workflows/default-ci.yaml index d455023..7f9f84d 100644 --- a/.github/workflows/default-ci.yaml +++ b/.github/workflows/default-ci.yaml @@ -17,6 +17,23 @@ jobs: - name: TruffleHog Scan uses: edplato/trufflehog-actions-scan@master + todo-check: + name: "Check for Open TODOs" + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'stackit-ubuntu-22' }} + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Search codebase + run: | + # Searches recursively (-r), showing line numbers (-n), ignoring binary files (-I) + # Excludes the .git directory to prevent false positives + if grep -rnIE "# ?TODO" --exclude-dir=.git --exclude-dir=.github .; then + echo "Error: TODOs found in the codebase. Please resolve them before merging." + exit 1 + fi + echo "No TODOs found. Proceeding." + pre-commit-checks: name: "Pre-Commit Hooks" runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'stackit-ubuntu-22' }} From 41762cf7dc1f3c726400fdf46f45f27b0fd5bc86 Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Tue, 12 May 2026 11:11:13 +0200 Subject: [PATCH 12/14] example(vpn): implement usecases --- examples/vpn-usecases/README.md | 7 + .../stackit-sna-with-debug-machine/README.md | 70 ++++ .../debug-user.yml | 25 ++ .../stackit-sna-with-debug-machine/main.tf | 96 +++++ .../stackit-sna-with-debug-machine/outputs.tf | 43 ++ .../provider.tf | 22 + .../variables.tf | 138 +++++++ .../stackit-azure/.terraform.lock.hcl | 105 +++++ .../stackit-azure/010-provider.tf | 54 +++ .../stackit-azure/020-variables.tf | 30 ++ .../stackit-azure/030-stackit-azure-vpn.tf | 376 ++++++++++++++++++ .../vpn-usecases/stackit-azure/MAINTAINERS.md | 9 + examples/vpn-usecases/stackit-azure/README.md | 48 +++ .../stackit-gcp/.terraform.lock.hcl | 83 ++++ .../vpn-usecases/stackit-gcp/010-provider.tf | 56 +++ .../vpn-usecases/stackit-gcp/020-variables.tf | 36 ++ .../stackit-gcp/030-stackit-gcp-vpn.tf | 305 ++++++++++++++ .../vpn-usecases/stackit-gcp/MAINTAINERS.md | 9 + examples/vpn-usecases/stackit-gcp/README.md | 48 +++ .../stackit-stackit/.terraform.lock.hcl | 87 ++++ .../stackit-stackit/010-provider.tf | 50 +++ .../stackit-stackit/020-variables.tf | 28 ++ .../030-stackit-stackit-vpn.tf | 255 ++++++++++++ .../stackit-stackit/MAINTAINERS.md | 9 + .../vpn-usecases/stackit-stackit/README.md | 21 + .../stackit-stackit/docs/architecture.png | Bin 0 -> 198838 bytes modules/test-machine/variables.tf | 2 +- 27 files changed, 2011 insertions(+), 1 deletion(-) create mode 100644 examples/vpn-usecases/README.md create mode 100644 examples/vpn-usecases/module/stackit-sna-with-debug-machine/README.md create mode 100644 examples/vpn-usecases/module/stackit-sna-with-debug-machine/debug-user.yml create mode 100644 examples/vpn-usecases/module/stackit-sna-with-debug-machine/main.tf create mode 100644 examples/vpn-usecases/module/stackit-sna-with-debug-machine/outputs.tf create mode 100644 examples/vpn-usecases/module/stackit-sna-with-debug-machine/provider.tf create mode 100644 examples/vpn-usecases/module/stackit-sna-with-debug-machine/variables.tf create mode 100644 examples/vpn-usecases/stackit-azure/.terraform.lock.hcl create mode 100644 examples/vpn-usecases/stackit-azure/010-provider.tf create mode 100644 examples/vpn-usecases/stackit-azure/020-variables.tf create mode 100644 examples/vpn-usecases/stackit-azure/030-stackit-azure-vpn.tf create mode 100644 examples/vpn-usecases/stackit-azure/MAINTAINERS.md create mode 100644 examples/vpn-usecases/stackit-azure/README.md create mode 100644 examples/vpn-usecases/stackit-gcp/.terraform.lock.hcl create mode 100644 examples/vpn-usecases/stackit-gcp/010-provider.tf create mode 100644 examples/vpn-usecases/stackit-gcp/020-variables.tf create mode 100644 examples/vpn-usecases/stackit-gcp/030-stackit-gcp-vpn.tf create mode 100644 examples/vpn-usecases/stackit-gcp/MAINTAINERS.md create mode 100644 examples/vpn-usecases/stackit-gcp/README.md create mode 100644 examples/vpn-usecases/stackit-stackit/.terraform.lock.hcl create mode 100644 examples/vpn-usecases/stackit-stackit/010-provider.tf create mode 100644 examples/vpn-usecases/stackit-stackit/020-variables.tf create mode 100644 examples/vpn-usecases/stackit-stackit/030-stackit-stackit-vpn.tf create mode 100644 examples/vpn-usecases/stackit-stackit/MAINTAINERS.md create mode 100644 examples/vpn-usecases/stackit-stackit/README.md create mode 100644 examples/vpn-usecases/stackit-stackit/docs/architecture.png diff --git a/examples/vpn-usecases/README.md b/examples/vpn-usecases/README.md new file mode 100644 index 0000000..27e0755 --- /dev/null +++ b/examples/vpn-usecases/README.md @@ -0,0 +1,7 @@ +# VPN Usecases + +> ⚠️ Note: Currently, we are still leveraging the restful provider to roll out managed VPN resources. Native integration for the STACKIT Terraform provider is a work in progress. We will update these examples once it is released. + +- [`STACKIT-STACKIT`](stackit-stackit) +- [`STACKIT-GCP`](stackit-gcp) +- [`STACKIT-AZURE`](stackit-azure) diff --git a/examples/vpn-usecases/module/stackit-sna-with-debug-machine/README.md b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/README.md new file mode 100644 index 0000000..509f3de --- /dev/null +++ b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/README.md @@ -0,0 +1,70 @@ +# SNA with test-machine module + +This module is used to quickly spin up a sna with a test virtual machine. We use this module to debug vpn connectivity. + +> ⚠️ **SECURITY WARNING** +> Be careful: By default, **port security is disabled** on the network interface to allow unrestricted traffic for debugging purposes. **Do not use this module in a production environment**. + + + +## Requirements + +| Name | Version | +| ------------------------------------------------------------------ | -------- | +| [stackit](#requirement_stackit) | >=0.95.0 | + +## Providers + +| Name | Version | +| ------------------------------------------------------------ | -------- | +| [stackit](#provider_stackit) | >=0.95.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +| -------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| [stackit_network.this](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/network) | resource | +| [stackit_network_area.this](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/network_area) | resource | +| [stackit_network_area_region.this](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/network_area_region) | resource | +| [stackit_network_interface.this](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/network_interface) | resource | +| [stackit_public_ip.this](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/public_ip) | resource | +| [stackit_resourcemanager_project.this](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/resourcemanager_project) | resource | +| [stackit_server.this](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/server) | resource | +| [stackit_volume.this](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/volume) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -------------- | ---------------------------------------- | :------: | +| [machine_availability_zone](#input_machine_availability_zone) | The availability zone (e.g. eu01-1) | `string` | n/a | yes | +| [machine_disk_performance_class](#input_machine_disk_performance_class) | Storage performance class | `string` | `"storage_premium_perf4"` | no | +| [machine_disk_size](#input_machine_disk_size) | Boot volume size in GB | `number` | `20` | no | +| [machine_image_id](#input_machine_image_id) | Image UUID (Default: Debian 12) | `string` | `"c751cde7-e648-4f81-9722-ce9c7848bed0"` | no | +| [machine_ipv4_prefix](#input_machine_ipv4_prefix) | The IPv4 prefix for the test machine's network (CIDR notation). This must be a subnet within the defined SNA network ranges. | `string` | n/a | yes | +| [machine_name](#input_machine_name) | name of the stackit test machine | `string` | n/a | yes | +| [machine_network_name](#input_machine_network_name) | The name of the network where the test machine will be connected. | `string` | n/a | yes | +| [machine_type](#input_machine_type) | Flavor of the machine | `string` | `"c2i.1"` | no | +| [sna_default_nameserver](#input_sna_default_nameserver) | A list of STACKIT SNA default nameservers (IP addresses). | `list(string)` |
[
"1.1.1.1"
]
| no | +| [sna_name](#input_sna_name) | The name of the STACKIT Network Area (SNA). | `string` | n/a | yes | +| [sna_network_range_prefix](#input_sna_network_range_prefix) | A list of STACKIT SNA network range prefixes in CIDR notation. | `list(string)` |
[
"10.28.0.0/16"
]
| no | +| [sna_transfer_range](#input_sna_transfer_range) | The STACKIT SNA transfer range in CIDR notation. | `string` | `"172.16.0.0/16"` | no | +| [stackit_admin_email](#input_stackit_admin_email) | The email address of the project administrator. | `string` | n/a | yes | +| [stackit_org_id](#input_stackit_org_id) | The STACKIT Organization ID (UUID). | `string` | n/a | yes | +| [stackit_project_name](#input_stackit_project_name) | The name of the STACKIT project where the managed VPN and test machine will be deployed. | `string` | n/a | yes | + +## Outputs + +| Name | Description | +| ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | +| [machine_network_ipv4](#output_machine_network_ipv4) | The IPv4 prefix of the machine's network. | +| [machine_private_ipv4](#output_machine_private_ipv4) | The private IP address of the test machine. | +| [machine_public_ip](#output_machine_public_ip) | The public IP address of the test machine. | +| [project_id](#output_project_id) | The ID of the STACKIT project. | +| [sna_id](#output_sna_id) | The ID of the STACKIT Network Area. | +| [sna_network_range](#output_sna_network_range) | The network ranges (sna-ipv4) of the STACKIT Network Area. | + + diff --git a/examples/vpn-usecases/module/stackit-sna-with-debug-machine/debug-user.yml b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/debug-user.yml new file mode 100644 index 0000000..865ffb5 --- /dev/null +++ b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/debug-user.yml @@ -0,0 +1,25 @@ +#cloud-config +# --------------------------------------------------------------------------- +# Example cloud-init for Linux instances (RHEL / Debian). +# Creates a local admin user for initial access. +# +# IMPORTANT: Replace the password hash below with a hash of your own +# secure password before deploying. Never use a shared or well-known +# default password in production. +# +# Generate a SHA-512 hash on Linux/macOS: +# openssl passwd -6 "YourPassword" +# --------------------------------------------------------------------------- +users: + - name: debug + groups: sudo + shell: /bin/bash + sudo: ["ALL=(ALL) NOPASSWD:ALL"] + lock_passwd: false + # debug123 + passwd: "$6$dIIA5b1oK7qi89.P$MH9SSMtnzCo8QvvUnVoCE5e1c7FY0NUgB4dpsv5JDq9zpRDiTpfiYtM5DitiJIuQWvZ7T1emTTgKaBufayaIW." + +chpasswd: + expire: false + +ssh_pwauth: true diff --git a/examples/vpn-usecases/module/stackit-sna-with-debug-machine/main.tf b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/main.tf new file mode 100644 index 0000000..a8f09c4 --- /dev/null +++ b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/main.tf @@ -0,0 +1,96 @@ +# 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_area" "this" { + name = var.sna_name + organization_id = var.stackit_org_id + labels = { + "preview/routingtables" = "true" + } +} + +resource "stackit_network_area_region" "this" { + organization_id = var.stackit_org_id + network_area_id = stackit_network_area.this.network_area_id + ipv4 = { + transfer_network = var.sna_transfer_range + network_ranges = [ + for prefix in var.sna_network_range_prefix : { + prefix = prefix + } + ] + default_nameservers = var.sna_default_nameserver + } +} + +resource "stackit_resourcemanager_project" "this" { + parent_container_id = var.stackit_org_id + name = var.stackit_project_name + owner_email = var.stackit_admin_email + labels = { + "networkArea" = stackit_network_area.this.network_area_id + } +} + +resource "stackit_volume" "this" { + project_id = stackit_resourcemanager_project.this.project_id + name = "${var.machine_name}-volume" + availability_zone = var.machine_availability_zone + size = var.machine_disk_size + performance_class = var.machine_disk_performance_class + source = { + type = "image" + id = var.machine_image_id + } +} + +resource "stackit_network" "this" { + name = var.machine_network_name + project_id = stackit_resourcemanager_project.this.project_id + ipv4_prefix = var.machine_ipv4_prefix + ipv4_nameservers = var.sna_default_nameserver +} + +resource "stackit_network_interface" "this" { + project_id = stackit_resourcemanager_project.this.project_id + network_id = stackit_network.this.network_id + security = false +} + +resource "stackit_server" "this" { + project_id = stackit_resourcemanager_project.this.project_id + name = var.machine_name + availability_zone = var.machine_availability_zone + machine_type = var.machine_type + + boot_volume = { + source_type = "volume" + source_id = stackit_volume.this.volume_id + } + + agent = { + provisioning_policy = "ALWAYS" + } + + network_interfaces = [ + stackit_network_interface.this.network_interface_id + ] + + user_data = file("${path.module}/debug-user.yml") +} + +resource "stackit_public_ip" "this" { + project_id = stackit_resourcemanager_project.this.project_id + network_interface_id = stackit_network_interface.this.network_interface_id +} diff --git a/examples/vpn-usecases/module/stackit-sna-with-debug-machine/outputs.tf b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/outputs.tf new file mode 100644 index 0000000..ec2f79d --- /dev/null +++ b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/outputs.tf @@ -0,0 +1,43 @@ +# 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. + +output "sna_id" { + description = "The ID of the STACKIT Network Area." + value = stackit_network_area.this.network_area_id +} + +output "project_id" { + description = "The ID of the STACKIT project." + value = stackit_resourcemanager_project.this.project_id +} + +output "machine_public_ip" { + description = "The public IP address of the test machine." + value = stackit_public_ip.this.ip +} + +output "machine_private_ipv4" { + description = "The private IP address of the test machine." + value = stackit_network_interface.this.ipv4 +} + +output "machine_network_ipv4" { + description = "The IPv4 prefix of the machine's network." + value = stackit_network.this.ipv4_prefix +} + +output "sna_network_range" { + description = "The network ranges (sna-ipv4) of the STACKIT Network Area." + value = stackit_network_area_region.this.ipv4.network_ranges +} diff --git a/examples/vpn-usecases/module/stackit-sna-with-debug-machine/provider.tf b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/provider.tf new file mode 100644 index 0000000..edbbfce --- /dev/null +++ b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/provider.tf @@ -0,0 +1,22 @@ +# 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. + +terraform { + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">=0.95.0" + } + } +} diff --git a/examples/vpn-usecases/module/stackit-sna-with-debug-machine/variables.tf b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/variables.tf new file mode 100644 index 0000000..a3fce06 --- /dev/null +++ b/examples/vpn-usecases/module/stackit-sna-with-debug-machine/variables.tf @@ -0,0 +1,138 @@ +# 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_org_id" { + description = "The STACKIT Organization ID (UUID)." + type = string + validation { + condition = can(regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", var.stackit_org_id)) + error_message = "The stackit_org_id must be a valid UUID." + } +} + +variable "stackit_project_name" { + description = "The name of the STACKIT project where the managed VPN and test machine will be deployed." + type = string + validation { + condition = length(var.stackit_project_name) >= 1 && length(var.stackit_project_name) <= 63 + error_message = "The project name must be between 1 and 63 characters long." + } +} + +variable "stackit_admin_email" { + description = "The email address of the project administrator." + type = string + validation { + condition = can(regex("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", var.stackit_admin_email)) + error_message = "The stackit_admin_email must be a valid email address." + } +} + +variable "sna_name" { + description = "The name of the STACKIT Network Area (SNA)." + type = string +} + +variable "sna_transfer_range" { + description = "The STACKIT SNA transfer range in CIDR notation." + type = string + default = "172.16.0.0/16" + validation { + condition = can(cidrnetmask(var.sna_transfer_range)) + error_message = "The sna_transfer_range must be a valid CIDR notation." + } +} + +variable "sna_network_range_prefix" { + description = "A list of STACKIT SNA network range prefixes in CIDR notation." + type = list(string) + default = ["10.28.0.0/16"] + validation { + condition = alltrue([for r in var.sna_network_range_prefix : can(cidrnetmask(r))]) + error_message = "All elements in sna_network_range_prefix must be valid CIDR notations." + } +} + +variable "sna_default_nameserver" { + description = "A list of STACKIT SNA default nameservers (IP addresses)." + type = list(string) + default = ["1.1.1.1"] + validation { + condition = alltrue([for ns in var.sna_default_nameserver : can(regex("^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$", ns))]) + error_message = "All elements in sna_default_nameserver must be valid IP addresses." + } +} + +variable "machine_network_name" { + description = "The name of the network where the test machine will be connected." + type = string +} + +variable "machine_ipv4_prefix" { + description = "The IPv4 prefix for the test machine's network (CIDR notation). This must be a subnet within the defined SNA network ranges." + type = string + validation { + condition = can(cidrnetmask(var.machine_ipv4_prefix)) + error_message = "The machine_ipv4_prefix must be a valid CIDR notation." + } +} + +variable "machine_name" { + type = string + description = "name of the stackit test machine" +} + +variable "machine_availability_zone" { + description = "The availability zone (e.g. eu01-1)" + type = string + + validation { + condition = can(regex("^[a-z]{2}[0-9]{2}-[a-zA-Z0-9]+$", var.machine_availability_zone)) + error_message = "The availability zone must follow the STACKIT pattern (e.g., eu01-1, eu01-m)." + } +} + +variable "machine_type" { + description = "Flavor of the machine" + type = string + default = "c2i.1" +} + +variable "machine_image_id" { + description = "Image UUID (Default: Debian 12)" + type = string + default = "c751cde7-e648-4f81-9722-ce9c7848bed0" + + validation { + condition = can(regex("^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$", var.machine_image_id)) + error_message = "The image_id must be a valid UUID." + } +} + +variable "machine_disk_size" { + description = "Boot volume size in GB" + type = number + default = 20 + + validation { + condition = var.machine_disk_size >= 1 + error_message = "The disk_size must be at least 1 GB." + } +} + +variable "machine_disk_performance_class" { + description = "Storage performance class" + type = string + default = "storage_premium_perf4" +} diff --git a/examples/vpn-usecases/stackit-azure/.terraform.lock.hcl b/examples/vpn-usecases/stackit-azure/.terraform.lock.hcl new file mode 100644 index 0000000..e793dcf --- /dev/null +++ b/examples/vpn-usecases/stackit-azure/.terraform.lock.hcl @@ -0,0 +1,105 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/azurerm" { + version = "4.72.0" + constraints = "4.72.0" + hashes = [ + "h1:QYnPAHT/PYheOOZz52ucHqw/ZO9PxWyPLtO7UD/jSMg=", + "zh:073472587c3752e89738522814d2b4eb2fd69eb2cb19c5a5ead3c7d2eabdc279", + "zh:1950effc0c315b6002c8cb6327b94fe59bda210e699367d9727bc66490d651d2", + "zh:47c990db75658525de57c8955a05b4752b88f3a900fffac0e7661d4a749e94f2", + "zh:610f2cbd6fab76750d8b093f03beabbb7162dc8c6affe0109f534ce240b3ff0f", + "zh:6739d645fe548c5a489d711f7748f32368cf68d723d2c59d3f2e21456304d692", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:a277ab095cc8aff3aede9e43eca2a699936472ef90abb272adf3daa609eb9141", + "zh:b1fdcdaf926c86de0d884beda90d78cb94a42ddede03a1f0b92c36b321d4f07e", + "zh:c003f1f15e52c54e189301ae2c7d8dd65acb2e5a7527d201355f2757b5465ba9", + "zh:c45f2d2206c0f8f71f207cd39eec73da9619d35932bbe1a5b8be7679c50a151e", + "zh:d7040d8ec295481bc1d30346ed7f3075c40ede87c0fedf1db34dd91c1c367a10", + "zh:e595f0b870cd5fd5debdc926fc1740201d2b66188b9b132dc598bdd6444e7348", + ] +} + +provider "registry.terraform.io/hashicorp/random" { + version = "3.9.0" + hashes = [ + "h1:OO+IuvQJSPmWdN8AyyIEvPJbLvDQpgX/zbktoa9KsJE=", + "zh:161ad0bd9a75768c82f53fb6e7172a9d8be2d4889b012645a34795031aaf1bf1", + "zh:19dc9a5b17729725ccfc4f45b0500af0ee5bc6b6b160c7adb8f2bf617d2c80ea", + "zh:269eda8fe42daa7974d5a34d166c3ba9defe80cde86c01e4dadcfdf2e1f05e5f", + "zh:373f7c65566f8f2cc7f45d698654feb9d988996957e1266a69ca00c52d6d16d0", + "zh:5599d16804c41c83009ec621b6d6b6f74e102f5827678a4750f8809055546b61", + "zh:583be0440469a22bff70dcfa56593b01566860b29607437264adb51060cf46fc", + "zh:5f211d8ec3f2e1f414870d9584bfe26e6995560ef81c748f8447a48164767398", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7b547fd16216761ef86efc3ed516ac5ac0c5c42b7c7eb24a08cef2d93f69ed5e", + "zh:7e7c0679daf2a382151d05068c8c3f0dae6b7b7dccf818827b73dd08638df2ef", + "zh:8089dec888a8038b9b4fb23b3df7e1057293dbc5b60b42cc47ff690d69d4b61b", + "zh:c51f15a031edfd6f23ce8ced3446ca7f8d8d647e2499890d7d5d10d5016d7257", + "zh:c94784f005708890dc6895afd53636ec00ec1e430b15d41e5aebfb1d4b39bd04", + ] +} + +provider "registry.terraform.io/hashicorp/time" { + version = "0.14.0" + hashes = [ + "h1:/hlxsUpuN/lvPTNL9+NyVGsOyRsK5NsxwFMsj5CdOp4=", + "zh:12abfd6b800e4d7fa6db7310dec8ffd440b31993861ef188c7ed5260b3073937", + "zh:23005521e800bb19e1597bf755c5f70d675d30b685d4255001ed5fa47d9df3f1", + "zh:2fea249b582ae97cd1cc10385187ea50993bb47c28cc5df0305e57ceaabf0a10", + "zh:322018d3b987b7aad08697178029a2bb667bed699e88328f0c89c52a2fd41341", + "zh:32a08e98fce2d273cb9b2c89d6c54727cc9f0a32e15bfd896be4e02cc6b48f95", + "zh:3db89aabd0e619616bd4b0f8b373a7586dfe60feffcea12a84a0bdbc445714b3", + "zh:7488f56c81d742dc020f29063626c8f07ca188aa97be61e7307e8d62397020a2", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:7cb4067f2e7559b13f7562ef722f948950901eb37834873e98360ab28f66e9d7", + "zh:9d552c8345f61e1b7db8e725144981345f18ac1014d58d6f5ddf0928a195fffb", + "zh:a8e69fb6b97fc9d86fb19a9f4d42abe33c4a68e700b15387ce2e17d2b9934bed", + "zh:aeeb900eb8dd0f790c60ea5c0e0c8d42bd6e4a54f391681d4decca15b544394b", + "zh:c239c619101a8c95e1f14061eb973c57a8d15fa0e68878ced5bbd76858ee5b79", + ] +} + +provider "registry.terraform.io/magodo/restful" { + version = "0.25.2" + hashes = [ + "h1:gvoDTFfxp7n1B4Wsnx9IC7Ku8g8tdVR4mCC6TDX0Mws=", + "zh:0513ff62fce41a59462f39e1c4636f3c87e6f8d24ee579075900d3e0f57f6992", + "zh:1a3e39e6b8c7fd0f3983730944a029db8f00557922e337cff0567a07c5e74b45", + "zh:2527c96fcc45458efc9eca1c66cee98269d80693b571c57baee783402bfbaa28", + "zh:50cec9afe8b55629d1c94d477b26ff95de8cc8e3304f6c2bfc5dad3bccc6decc", + "zh:89e94c0f312d0ef4213b46ee776a27f6a5d114520c08a4716f4fee4c26c16f91", + "zh:9a9762ebaf9567a4aa34a1911f051527696241679e087137fcc7821e52b66483", + "zh:a065be3488e24928199904f4a496974c03fdcf2b06fccf016e405b3068d5ef76", + "zh:c62a1a6fb3c5135451f68ea4ed1f66d999ab654323d10526756e83f6f77d6bdf", + "zh:cf01364f89b713dc10eb87098839317e6f2de222bec2597923cddbb07bdd9c13", + "zh:dc0ac6a1e5e3199e1d35fb49f9de1d9325caa3c0d3e87ea8128295e19ac941c3", + "zh:e55cf6e8230f081b7c8ade592c14f1b8b45ee0aaa14c2bde2da9531d819a4392", + "zh:f333748916e68050c8935d760d6b9b469dd76eb94363af93562cbd076dba6ff5", + "zh:f809ab383cca0a5f83072981c64208cbd7fa67e986a86ee02dd2c82333221e32", + "zh:fdfdca8b7976c1a8b1b6a3589b4bfec277beb6dfb40c5568271d42f0b2f88a9d", + ] +} + +provider "registry.terraform.io/stackitcloud/stackit" { + version = "0.95.0" + constraints = ">= 0.87.0, >= 0.95.0" + hashes = [ + "h1:sKmc6SGKEFglXKLMtOluJkFm7tzQZKQV3/QxUbHug1E=", + "zh:023edbb8ca984233bb51605a9005d4f7cb3365f0b11ddd68d911a1e30ccf64be", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:1fc43ed3055c4912e5b3ae2eba49dd5407beaa9ba6617612f317543f7d26ccd7", + "zh:31e587a9f279661b74b139e2a964a7d1c54a4073d27d21c2f948e0e7ba4c0d04", + "zh:37427a23800dff84c1b89d4985cb935c0112c59acd716d8920c160221c459061", + "zh:3a575f5c7d1252d99aea9187923087e1d483b2b34e42c9f058f557ec28c45d84", + "zh:44c7ee340e1a09d6f9a9873959f8283f0d73aee4a8c884f7b36985f943874b65", + "zh:4fab8fe953a0d4c21589cd36d23afe072c6403e37620c82839f9f829139cbbbf", + "zh:69fc061b3c7ea82d9e9a31d3665a535f6bb9dc3d6ff5b466f940d3d04a105e19", + "zh:85ee00442eff70ea103a96276efb5e1485b661b0a1db08bcdbd28b11b1f966e6", + "zh:9761ef1321c93cb3e4bc2499995b3e7ae910e2ae68b3228164dea73e9687ddb5", + "zh:b158a4e4726a4d4c9f61c5dc71abb4ca3a621269e1d7af88ab36d34c3bcec66f", + "zh:da37df9a426d83da8f6c1340104a6b9a7eef4a7e2589d0b70a89c574a1b3cc78", + "zh:e6421b9a351b2c9b2ab2341f2c07d863eb2ed055b847ea839de96b0fd62baf97", + ] +} diff --git a/examples/vpn-usecases/stackit-azure/010-provider.tf b/examples/vpn-usecases/stackit-azure/010-provider.tf new file mode 100644 index 0000000..88f7674 --- /dev/null +++ b/examples/vpn-usecases/stackit-azure/010-provider.tf @@ -0,0 +1,54 @@ +# 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. + +terraform { + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">=0.95.0" + } + restful = { + source = "magodo/restful" + } + azurerm = { + source = "hashicorp/azurerm" + version = "4.72.0" + } + } +} + +provider "stackit" { + default_region = var.stackit_region + service_account_key_path = var.stackit_service_account_key_path + enable_beta_resources = true +} + +provider "azurerm" { + features {} + subscription_id = var.azure_subscription_id +} + +ephemeral "stackit_access_token" "this" {} + +provider "restful" { + alias = "stackit" + base_url = "https://vpn.api.eu01.stackit.cloud" + security = { + http = { + token = { + token = ephemeral.stackit_access_token.this.access_token + } + } + } +} diff --git a/examples/vpn-usecases/stackit-azure/020-variables.tf b/examples/vpn-usecases/stackit-azure/020-variables.tf new file mode 100644 index 0000000..d3bc60b --- /dev/null +++ b/examples/vpn-usecases/stackit-azure/020-variables.tf @@ -0,0 +1,30 @@ +# 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_org_id" { + type = string +} + +variable "stackit_region" { + type = string + default = "eu01" +} + +variable "stackit_service_account_key_path" { + type = string +} + +variable "azure_subscription_id" { + type = string +} diff --git a/examples/vpn-usecases/stackit-azure/030-stackit-azure-vpn.tf b/examples/vpn-usecases/stackit-azure/030-stackit-azure-vpn.tf new file mode 100644 index 0000000..bad5cd7 --- /dev/null +++ b/examples/vpn-usecases/stackit-azure/030-stackit-azure-vpn.tf @@ -0,0 +1,376 @@ +# 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. + +# STACKIT Side (vpn-sna-01) +module "vpn_sna_01" { + source = "../module/stackit-sna-with-debug-machine" + machine_availability_zone = "eu01-1" + machine_ipv4_prefix = "10.10.10.0/24" + machine_network_name = "vpn-sna-01" + sna_name = "vpn-sna-01" + machine_name = "vpn-sna-01" + stackit_admin_email = "mauritz.uphoff@digits.schwarz" + stackit_org_id = var.stackit_org_id + stackit_project_name = "vpn-sna-01" + sna_network_range_prefix = [ + "10.10.0.0/16" + ] +} + +resource "restful_resource" "vpn_01_gateway" { + provider = restful.stackit + path = "/v1/projects/${module.vpn_sna_01.project_id}/regions/eu01/gateways" + body = { + availabilityZones = { + tunnel1 = "eu01-1" + tunnel2 = "eu01-2" + } + bgp = { + localAsn = 64512 + overrideAdvertisedRoutes = ["10.10.0.0/16"] + } + displayName = "vpn01" + labels = null + planId = "p500" + routingType = "BGP_ROUTE_BASED" + } + + read_path = "$(path)/$(body.id)" + update_path = "$(path)/$(body.id)" + update_method = "PUT" + delete_path = "$(path)/$(body.id)" + delete_method = "DELETE" +} + +data "restful_resource" "vpn_01_gateway_status" { + provider = restful.stackit + id = "${restful_resource.vpn_01_gateway.id}/status" +} + +resource "random_password" "vpn_psk" { + length = 32 + special = false +} + +# Azure Side +resource "azurerm_resource_group" "rg" { + name = "rg-vpn-test" + location = "West Europe" +} + +# 1. Azure VNet and Subnets +resource "azurerm_virtual_network" "azure_vnet" { + name = "azure-vpn-network" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + address_space = ["10.11.0.0/16"] +} + +resource "azurerm_subnet" "azure_gateway_subnet" { + name = "GatewaySubnet" # MUST be exactly named GatewaySubnet + resource_group_name = azurerm_resource_group.rg.name + virtual_network_name = azurerm_virtual_network.azure_vnet.name + address_prefixes = ["10.11.0.0/24"] +} + +resource "azurerm_subnet" "azure_vm_subnet" { + name = "vm-subnet" + resource_group_name = azurerm_resource_group.rg.name + virtual_network_name = azurerm_virtual_network.azure_vnet.name + address_prefixes = ["10.11.1.0/24"] +} + +# 2. Azure Public IPs (2 required for Active-Active HA VPN) +resource "azurerm_public_ip" "azure_gw_pip1" { + name = "azure-gw-pip1" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + allocation_method = "Static" + sku = "Standard" + zones = ["1", "2", "3"] + + lifecycle { + ignore_changes = [domain_name_label] + } +} + +resource "azurerm_public_ip" "azure_gw_pip2" { + name = "azure-gw-pip2" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + allocation_method = "Static" + sku = "Standard" + zones = ["1", "2", "3"] + + lifecycle { + ignore_changes = [domain_name_label] + } +} + +# 3. Azure HA VPN Gateway +resource "azurerm_virtual_network_gateway" "azure_gateway" { + name = "azure-ha-vpn" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + + type = "Vpn" + vpn_type = "RouteBased" + active_active = true + bgp_enabled = true + sku = "VpnGw1AZ" + + bgp_settings { + asn = 64513 # Azure's local ASN + peering_addresses { + ip_configuration_name = "vnetGatewayConfig1" + apipa_addresses = ["169.254.21.2"] + } + peering_addresses { + ip_configuration_name = "vnetGatewayConfig2" + apipa_addresses = ["169.254.21.6"] + } + } + + ip_configuration { + name = "vnetGatewayConfig1" + public_ip_address_id = azurerm_public_ip.azure_gw_pip1.id + private_ip_address_allocation = "Dynamic" + subnet_id = azurerm_subnet.azure_gateway_subnet.id + } + + ip_configuration { + name = "vnetGatewayConfig2" + public_ip_address_id = azurerm_public_ip.azure_gw_pip2.id + private_ip_address_allocation = "Dynamic" + subnet_id = azurerm_subnet.azure_gateway_subnet.id + } +} + +# 4. Azure Local Network Gateways (Represents the 2 STACKIT Tunnels) +resource "azurerm_local_network_gateway" "stackit_tunnel1" { + name = "stackit-tunnel-1" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + gateway_address = data.restful_resource.vpn_01_gateway_status.output.tunnels[0].publicIP + + bgp_settings { + asn = 64512 + bgp_peering_address = "169.254.21.1" + } +} + +resource "azurerm_local_network_gateway" "stackit_tunnel2" { + name = "stackit-tunnel-2" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + gateway_address = data.restful_resource.vpn_01_gateway_status.output.tunnels[1].publicIP + + bgp_settings { + asn = 64512 + bgp_peering_address = "169.254.21.5" + } +} + +# 5. Azure VPN Connections +resource "azurerm_virtual_network_gateway_connection" "azure_tunnel1" { + name = "conn-to-stackit-tunnel1" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + + type = "IPsec" + virtual_network_gateway_id = azurerm_virtual_network_gateway.azure_gateway.id + local_network_gateway_id = azurerm_local_network_gateway.stackit_tunnel1.id + shared_key = random_password.vpn_psk.result + enable_bgp = true + + ipsec_policy { + ike_encryption = "GCMAES256" + ike_integrity = "SHA256" + ipsec_encryption = "GCMAES256" + ipsec_integrity = "GCMAES256" + dh_group = "DHGroup14" + pfs_group = "PFS14" + sa_lifetime = 3600 + sa_datasize = 102400000 + } +} + +resource "azurerm_virtual_network_gateway_connection" "azure_tunnel2" { + name = "conn-to-stackit-tunnel2" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + + type = "IPsec" + virtual_network_gateway_id = azurerm_virtual_network_gateway.azure_gateway.id + local_network_gateway_id = azurerm_local_network_gateway.stackit_tunnel2.id + shared_key = random_password.vpn_psk.result + enable_bgp = true + + ipsec_policy { + ike_encryption = "GCMAES256" + ike_integrity = "SHA256" + ipsec_encryption = "GCMAES256" + ipsec_integrity = "GCMAES256" + dh_group = "DHGroup14" + pfs_group = "PFS14" + sa_lifetime = 3600 + sa_datasize = 102400000 + } +} + +# Connection from STACKIT to Azure +resource "restful_resource" "vpn_01_connection" { + provider = restful.stackit + path = "${restful_resource.vpn_01_gateway.id}/connections" + body = { + displayName = "conn-to-azure" + tunnel1 = { + bgp = { + remoteAsn = 64513 + } + peering = { + localAddress = "169.254.21.1" + remoteAddress = "169.254.21.2" + } + phase1 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + phase2 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + preSharedKey = random_password.vpn_psk.result + remoteAddress = azurerm_public_ip.azure_gw_pip1.ip_address + } + tunnel2 = { + bgp = { + remoteAsn = 64513 + } + peering = { + localAddress = "169.254.21.5" + remoteAddress = "169.254.21.6" + } + phase1 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + phase2 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + preSharedKey = random_password.vpn_psk.result + remoteAddress = azurerm_public_ip.azure_gw_pip2.ip_address + } + } + + lifecycle { + ignore_changes = [ + body.tunnel1.preSharedKey, + body.tunnel2.preSharedKey + ] + } + + read_path = "$(path)/$(body.id)" + update_path = "$(path)/$(body.id)" + update_method = "PUT" + delete_path = "$(path)/$(body.id)" + delete_method = "DELETE" +} + +# Azure Test VM & NSG +resource "azurerm_network_security_group" "vm_nsg" { + name = "test-vm-nsg" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + + security_rule { + name = "Allow-STACKIT" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "*" + source_port_range = "*" + destination_port_range = "*" + source_address_prefix = "10.10.0.0/16" + destination_address_prefix = "*" + } +} + +resource "azurerm_network_interface" "vm_nic" { + name = "test-vm-nic" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + + ip_configuration { + name = "internal" + subnet_id = azurerm_subnet.azure_vm_subnet.id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_network_interface_security_group_association" "vm_nsg_assoc" { + network_interface_id = azurerm_network_interface.vm_nic.id + network_security_group_id = azurerm_network_security_group.vm_nsg.id +} + +resource "azurerm_linux_virtual_machine" "azure_test_vm" { + name = "azure-vpn-test-vm" + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + size = "Standard_B1s" + admin_username = "azureuser" + admin_password = "VpnTestPassw0rd!" + disable_password_authentication = false + + network_interface_ids = [ + azurerm_network_interface.vm_nic.id, + ] + + os_disk { + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = "Canonical" + offer = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts" + version = "latest" + } +} + +# Outputs +output "vpn01_public_ip" { + value = module.vpn_sna_01.machine_public_ip + description = "Connect here via SSH to ping Azure" +} + +output "vpn01_private_ip" { + value = module.vpn_sna_01.machine_private_ipv4 +} + +output "azure_test_vm_private_ip" { + value = azurerm_linux_virtual_machine.azure_test_vm.private_ip_address +} + +# Command to run a ping test without SSHing +output "azure_run_command_ping_test" { + value = "az vm run-command invoke --resource-group ${azurerm_resource_group.rg.name} --name ${azurerm_linux_virtual_machine.azure_test_vm.name} --command-id RunShellScript --scripts 'ping -c 4 ${module.vpn_sna_01.machine_private_ipv4}'" + description = "Copy and paste this in your terminal to securely ping from the Azure VM to the STACKIT VM." +} diff --git a/examples/vpn-usecases/stackit-azure/MAINTAINERS.md b/examples/vpn-usecases/stackit-azure/MAINTAINERS.md new file mode 100644 index 0000000..1aaefce --- /dev/null +++ b/examples/vpn-usecases/stackit-azure/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/vpn-usecases/stackit-azure/README.md b/examples/vpn-usecases/stackit-azure/README.md new file mode 100644 index 0000000..626bac6 --- /dev/null +++ b/examples/vpn-usecases/stackit-azure/README.md @@ -0,0 +1,48 @@ +# STACKIT-to-Azure HA VPN Gateway + +> ⚠️ azurerm_virtual_network_gateway.azure_gateway takes between 30-90mins + +This example demonstrates how to establish a secure, Highly Available (HA) IPsec VPN connection between a STACKIT Network Area (SNA) and Microsoft Azure. + +The connection uses **BGP (Border Gateway Protocol)** via an Azure Virtual Network Gateway (Active-Active mode) to automatically exchange and propagate routes dynamically between the two cloud environments. + +## Architecture + +This Terraform configuration provisions the following resources: + +- **STACKIT:** An SNA, a debug machine, and an HA VPN Gateway (`ASN 64512`). +- **Azure:** A Resource Group, VNet, dedicated `GatewaySubnet`, an Active-Active Virtual Network Gateway (`ASN 64513`), two Local Network Gateways (representing STACKIT), and a private Ubuntu test VM. +- **VPN Connection:** Two redundant IPsec tunnels using dynamically generated PSKs and Link-Local BGP peering (`169.254.x.x/30`). +- **Security:** Azure Network Security Group (NSG) rules configured to allow inbound ICMP/SSH traffic specifically from the STACKIT network range. + +## Prerequisites + +- Configured STACKIT and Azure provider credentials. +- Azure CLI (`az`) installed and authenticated for testing from the Azure side. + +## Outputs + +Once the deployment is complete, Terraform will output the following information to help you verify connectivity: + +- `vpn01_public_ip`: The public IP of the debug machine in STACKIT. +- `vpn01_private_ip`: The private IP of the debug machine in STACKIT. +- `azure_test_vm_private_ip`: The private IP of the test VM in Azure. +- `azure_run_command_ping_test`: A pre-formatted Azure CLI command to test the connection. + +## How to Test the Connection + +You can verify the bi-directional tunnel is fully operational by following these steps: + +### 1. Test from Azure to STACKIT (Zero-Config) + +We utilize the Azure "Run Command" feature to execute a ping test directly inside the private Azure VM without needing SSH access or a Bastion host. + +Copy the command generated by the `azure_run_command_ping_test` output and run it in your terminal: + +```bash +az vm run-command invoke \ + --resource-group rg-vpn-test \ + --name azure-vpn-test-vm \ + --command-id RunShellScript \ + --scripts 'ping -c 4 ' +``` diff --git a/examples/vpn-usecases/stackit-gcp/.terraform.lock.hcl b/examples/vpn-usecases/stackit-gcp/.terraform.lock.hcl new file mode 100644 index 0000000..a510f99 --- /dev/null +++ b/examples/vpn-usecases/stackit-gcp/.terraform.lock.hcl @@ -0,0 +1,83 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/google" { + version = "7.32.0" + hashes = [ + "h1:hDMENgq6nxoM6ttxN1HNrqbYiyRV8avLmUuUe4QWvKY=", + "zh:091afeeeb58035f26ebaec34755a15d56e3229c4ce6db2745c52ba2593204a30", + "zh:15d6a375c49d023dd21e612610b12bf79fbc6459bc5ad64b989d2180e9931f7d", + "zh:2c70ee949b01c0c7925618e36417ac5b9c1de91c66bb0bd956b2b2bd1d38a2b6", + "zh:2e531cf6f3af847104df65675ebd9c9a7450ba91d8d21ff6ed04eeab6a5684e2", + "zh:42fece780ef909136213762731c945d59c58dbaf92f64a46989102da9ebfa998", + "zh:9008b13bec8c588ef41ec813c3d67d26acb22ada241d9dd9ed408687607726cc", + "zh:a62e09bd551de8ea74b68c1eb44f9d7d0dc56957811915d46ec0a28254a30e0b", + "zh:ad3d4419561d19e88b72ad4bedbbc73ee77f20acb594261be8f716bf1a89f947", + "zh:af0c23df89e5fb815751c64c9a438527d6e0609df52fa7e281dbd90aa238270b", + "zh:b4d1157559d04792441550ae79f13d16bd7cc3f80a9616cd9ef3f83466564ce4", + "zh:db32528838dc9641981769012bdabf21e658756f1581ccbcd239aab0eb4aed11", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/random" { + version = "3.8.1" + 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/magodo/restful" { + version = "0.25.2" + hashes = [ + "h1:gvoDTFfxp7n1B4Wsnx9IC7Ku8g8tdVR4mCC6TDX0Mws=", + "zh:0513ff62fce41a59462f39e1c4636f3c87e6f8d24ee579075900d3e0f57f6992", + "zh:1a3e39e6b8c7fd0f3983730944a029db8f00557922e337cff0567a07c5e74b45", + "zh:2527c96fcc45458efc9eca1c66cee98269d80693b571c57baee783402bfbaa28", + "zh:50cec9afe8b55629d1c94d477b26ff95de8cc8e3304f6c2bfc5dad3bccc6decc", + "zh:89e94c0f312d0ef4213b46ee776a27f6a5d114520c08a4716f4fee4c26c16f91", + "zh:9a9762ebaf9567a4aa34a1911f051527696241679e087137fcc7821e52b66483", + "zh:a065be3488e24928199904f4a496974c03fdcf2b06fccf016e405b3068d5ef76", + "zh:c62a1a6fb3c5135451f68ea4ed1f66d999ab654323d10526756e83f6f77d6bdf", + "zh:cf01364f89b713dc10eb87098839317e6f2de222bec2597923cddbb07bdd9c13", + "zh:dc0ac6a1e5e3199e1d35fb49f9de1d9325caa3c0d3e87ea8128295e19ac941c3", + "zh:e55cf6e8230f081b7c8ade592c14f1b8b45ee0aaa14c2bde2da9531d819a4392", + "zh:f333748916e68050c8935d760d6b9b469dd76eb94363af93562cbd076dba6ff5", + "zh:f809ab383cca0a5f83072981c64208cbd7fa67e986a86ee02dd2c82333221e32", + "zh:fdfdca8b7976c1a8b1b6a3589b4bfec277beb6dfb40c5568271d42f0b2f88a9d", + ] +} + +provider "registry.terraform.io/stackitcloud/stackit" { + version = "0.95.0" + constraints = ">= 0.66.0, >= 0.87.0" + hashes = [ + "h1:sKmc6SGKEFglXKLMtOluJkFm7tzQZKQV3/QxUbHug1E=", + "zh:023edbb8ca984233bb51605a9005d4f7cb3365f0b11ddd68d911a1e30ccf64be", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:1fc43ed3055c4912e5b3ae2eba49dd5407beaa9ba6617612f317543f7d26ccd7", + "zh:31e587a9f279661b74b139e2a964a7d1c54a4073d27d21c2f948e0e7ba4c0d04", + "zh:37427a23800dff84c1b89d4985cb935c0112c59acd716d8920c160221c459061", + "zh:3a575f5c7d1252d99aea9187923087e1d483b2b34e42c9f058f557ec28c45d84", + "zh:44c7ee340e1a09d6f9a9873959f8283f0d73aee4a8c884f7b36985f943874b65", + "zh:4fab8fe953a0d4c21589cd36d23afe072c6403e37620c82839f9f829139cbbbf", + "zh:69fc061b3c7ea82d9e9a31d3665a535f6bb9dc3d6ff5b466f940d3d04a105e19", + "zh:85ee00442eff70ea103a96276efb5e1485b661b0a1db08bcdbd28b11b1f966e6", + "zh:9761ef1321c93cb3e4bc2499995b3e7ae910e2ae68b3228164dea73e9687ddb5", + "zh:b158a4e4726a4d4c9f61c5dc71abb4ca3a621269e1d7af88ab36d34c3bcec66f", + "zh:da37df9a426d83da8f6c1340104a6b9a7eef4a7e2589d0b70a89c574a1b3cc78", + "zh:e6421b9a351b2c9b2ab2341f2c07d863eb2ed055b847ea839de96b0fd62baf97", + ] +} diff --git a/examples/vpn-usecases/stackit-gcp/010-provider.tf b/examples/vpn-usecases/stackit-gcp/010-provider.tf new file mode 100644 index 0000000..eb7fb81 --- /dev/null +++ b/examples/vpn-usecases/stackit-gcp/010-provider.tf @@ -0,0 +1,56 @@ +# 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. + +terraform { + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">=0.95.0" + } + restful = { + source = "magodo/restful" + } + google = { + source = "hashicorp/google" + version = "7.32.0" + } + } +} + +provider "stackit" { + default_region = var.stackit_region + service_account_key_path = var.stackit_service_account_key_path + enable_beta_resources = true +} + +provider "google" { + project = var.gcp_project + region = "europe-west4" + zone = "europe-west4-a" + credentials = file(var.gcp_service_account_key_path) +} + +ephemeral "stackit_access_token" "this" {} + +provider "restful" { + alias = "stackit" + base_url = "https://vpn.api.eu01.stackit.cloud" + security = { + http = { + token = { + token = ephemeral.stackit_access_token.this.access_token + } + } + } +} diff --git a/examples/vpn-usecases/stackit-gcp/020-variables.tf b/examples/vpn-usecases/stackit-gcp/020-variables.tf new file mode 100644 index 0000000..0288fbb --- /dev/null +++ b/examples/vpn-usecases/stackit-gcp/020-variables.tf @@ -0,0 +1,36 @@ +# 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. + +# load via *.auto.tfvars + +variable "stackit_org_id" { + type = string +} + +variable "stackit_region" { + type = string + default = "eu01" +} + +variable "stackit_service_account_key_path" { + type = string +} + +variable "gcp_service_account_key_path" { + type = string +} + +variable "gcp_project" { + type = string +} diff --git a/examples/vpn-usecases/stackit-gcp/030-stackit-gcp-vpn.tf b/examples/vpn-usecases/stackit-gcp/030-stackit-gcp-vpn.tf new file mode 100644 index 0000000..8f0c906 --- /dev/null +++ b/examples/vpn-usecases/stackit-gcp/030-stackit-gcp-vpn.tf @@ -0,0 +1,305 @@ +# 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. + +# STACKIT Side (vpn-sna-01) +module "vpn_sna_01" { + source = "../module/stackit-sna-with-debug-machine" + machine_availability_zone = "eu01-1" + machine_ipv4_prefix = "10.10.10.0/24" + machine_network_name = "vpn-sna-01" + sna_name = "vpn-sna-01" + machine_name = "vpn-sna-01" + stackit_admin_email = "mauritz.uphoff@digits.schwarz" + stackit_org_id = var.stackit_org_id + stackit_project_name = "vpn-sna-01" + sna_network_range_prefix = [ + "10.10.0.0/16" + ] +} + +resource "restful_resource" "vpn_01_gateway" { + provider = restful.stackit + path = "/v1/projects/${module.vpn_sna_01.project_id}/regions/eu01/gateways" + body = { + availabilityZones = { + tunnel1 = "eu01-1" + tunnel2 = "eu01-2" + } + bgp = { + localAsn = 64512 + overrideAdvertisedRoutes = ["10.10.0.0/16"] + } + displayName = "vpn01" + labels = null + planId = "p500" + routingType = "BGP_ROUTE_BASED" + } + + read_path = "$(path)/$(body.id)" + update_path = "$(path)/$(body.id)" + update_method = "PUT" + delete_path = "$(path)/$(body.id)" + delete_method = "DELETE" +} + +data "restful_resource" "vpn_01_gateway_status" { + provider = restful.stackit + id = "${restful_resource.vpn_01_gateway.id}/status" +} + +resource "random_password" "vpn_psk" { + length = 32 + special = false +} + +# GCP VPC and Subnet +resource "google_compute_network" "gcp_vpc" { + name = "gcp-vpn-network" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "gcp_subnet" { + name = "gcp-vpn-subnet" + ip_cidr_range = "10.11.0.0/16" + region = "europe-west4" + network = google_compute_network.gcp_vpc.id +} + +# GCP HA VPN Gateway +resource "google_compute_ha_vpn_gateway" "gcp_gateway" { + name = "gcp-ha-vpn" + network = google_compute_network.gcp_vpc.id + region = "europe-west4" +} + +# GCP Cloud Router (for BGP) +resource "google_compute_router" "gcp_router" { + name = "gcp-router" + network = google_compute_network.gcp_vpc.name + region = "europe-west4" + bgp { + asn = 64513 # GCP's local ASN + } +} + +# GCP External VPN Gateway (Represents STACKIT in GCP) +resource "google_compute_external_vpn_gateway" "stackit_gateway" { + name = "stackit-external-gw" + redundancy_type = "TWO_IPS_REDUNDANCY" + description = "STACKIT VPN Gateway" + + # Fetching the public IPs from STACKIT + interface { + id = 0 + ip_address = data.restful_resource.vpn_01_gateway_status.output.tunnels[0].publicIP + } + interface { + id = 1 + ip_address = data.restful_resource.vpn_01_gateway_status.output.tunnels[1].publicIP + } +} + +# GCP VPN Tunnels +resource "google_compute_vpn_tunnel" "gcp_tunnel1" { + name = "gcp-tunnel-1" + region = "europe-west4" + vpn_gateway = google_compute_ha_vpn_gateway.gcp_gateway.id + peer_external_gateway = google_compute_external_vpn_gateway.stackit_gateway.id + peer_external_gateway_interface = 0 + shared_secret = random_password.vpn_psk.result + router = google_compute_router.gcp_router.id + vpn_gateway_interface = 0 +} + +resource "google_compute_vpn_tunnel" "gcp_tunnel2" { + name = "gcp-tunnel-2" + region = "europe-west4" + vpn_gateway = google_compute_ha_vpn_gateway.gcp_gateway.id + peer_external_gateway = google_compute_external_vpn_gateway.stackit_gateway.id + peer_external_gateway_interface = 1 + shared_secret = random_password.vpn_psk.result + router = google_compute_router.gcp_router.id + vpn_gateway_interface = 1 +} + +# GCP Cloud Router Interfaces & BGP Peers +resource "google_compute_router_interface" "gcp_router_interface1" { + name = "gcp-interface-1" + router = google_compute_router.gcp_router.name + region = "europe-west4" + ip_range = "169.254.0.2/30" # GCP's local BGP IP + vpn_tunnel = google_compute_vpn_tunnel.gcp_tunnel1.name +} + +resource "google_compute_router_peer" "gcp_router_peer1" { + name = "gcp-peer-1" + router = google_compute_router.gcp_router.name + region = "europe-west4" + peer_ip_address = "169.254.0.1" # STACKIT's local BGP IP + peer_asn = 64512 # STACKIT's ASN + advertised_route_priority = 100 + interface = google_compute_router_interface.gcp_router_interface1.name +} + +resource "google_compute_router_interface" "gcp_router_interface2" { + name = "gcp-interface-2" + router = google_compute_router.gcp_router.name + region = "europe-west4" + ip_range = "169.254.1.2/30" + vpn_tunnel = google_compute_vpn_tunnel.gcp_tunnel2.name +} + +resource "google_compute_router_peer" "gcp_router_peer2" { + name = "gcp-peer-2" + router = google_compute_router.gcp_router.name + region = "europe-west4" + peer_ip_address = "169.254.1.1" + peer_asn = 64512 + advertised_route_priority = 100 + interface = google_compute_router_interface.gcp_router_interface2.name +} + +# Connection from STACKIT to GCP +resource "restful_resource" "vpn_01_connection" { + provider = restful.stackit + path = "${restful_resource.vpn_01_gateway.id}/connections" + body = { + displayName = "conn-to-gcp" + tunnel1 = { + bgp = { + remoteAsn = 64513 + } + peering = { + localAddress = "169.254.0.1" + remoteAddress = "169.254.0.2" + } + phase1 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + phase2 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + preSharedKey = random_password.vpn_psk.result + remoteAddress = google_compute_ha_vpn_gateway.gcp_gateway.vpn_interfaces[0].ip_address + } + tunnel2 = { + bgp = { + remoteAsn = 64513 + } + peering = { + localAddress = "169.254.1.1" + remoteAddress = "169.254.1.2" + } + phase1 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + phase2 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + preSharedKey = random_password.vpn_psk.result + remoteAddress = google_compute_ha_vpn_gateway.gcp_gateway.vpn_interfaces[1].ip_address + } + } + + lifecycle { + ignore_changes = [ + body.tunnel1.preSharedKey, + body.tunnel2.preSharedKey + ] + } + + read_path = "$(path)/$(body.id)" + update_path = "$(path)/$(body.id)" + update_method = "PUT" + delete_path = "$(path)/$(body.id)" + delete_method = "DELETE" +} + +# GCP Test VM & Firewall Rules +# Firewall: Allow Identity-Aware Proxy (IAP) to SSH into the VM +resource "google_compute_firewall" "allow_iap_ssh" { + name = "allow-iap-ssh" + network = google_compute_network.gcp_vpc.name + + allow { + protocol = "tcp" + ports = ["22"] + } + + source_ranges = ["35.235.240.0/20"] + target_tags = ["test-vm"] +} + +# Firewall: Allow STACKIT to ping/SSH into the GCP VM over the VPN +resource "google_compute_firewall" "allow_stackit_vpn_traffic" { + name = "allow-stackit-vpn-traffic" + network = google_compute_network.gcp_vpc.name + + allow { + protocol = "icmp" + } + allow { + protocol = "tcp" + ports = ["22"] + } + + # Your STACKIT SNA range + source_ranges = ["10.10.0.0/16"] + target_tags = ["test-vm"] +} + +# GCP Virtual Machine +resource "google_compute_instance" "gcp_test_vm" { + name = "gcp-vpn-test-vm" + machine_type = "e2-micro" + zone = "europe-west4-a" + + tags = ["test-vm"] + + boot_disk { + initialize_params { + image = "debian-cloud/debian-12" + } + } + + network_interface { + subnetwork = google_compute_subnetwork.gcp_subnet.id + # Omitting the 'access_config' block ensures this VM gets NO public IP address. + } +} + +# Outputs +output "vpn01_public_ip" { + value = module.vpn_sna_01.machine_public_ip +} + +output "vpn01_private_ip" { + value = module.vpn_sna_01.machine_private_ipv4 +} + +output "gcp_test_vm_private_ip" { + value = google_compute_instance.gcp_test_vm.network_interface[0].network_ip +} + +output "gcp_iap_command" { + value = "gcloud compute ssh ${google_compute_instance.gcp_test_vm.name} --tunnel-through-iap" +} diff --git a/examples/vpn-usecases/stackit-gcp/MAINTAINERS.md b/examples/vpn-usecases/stackit-gcp/MAINTAINERS.md new file mode 100644 index 0000000..1aaefce --- /dev/null +++ b/examples/vpn-usecases/stackit-gcp/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/vpn-usecases/stackit-gcp/README.md b/examples/vpn-usecases/stackit-gcp/README.md new file mode 100644 index 0000000..d0c9f44 --- /dev/null +++ b/examples/vpn-usecases/stackit-gcp/README.md @@ -0,0 +1,48 @@ +# STACKIT-to-GCP HA VPN Gateway + +This example demonstrates how to establish a secure, Highly Available (HA) IPsec VPN connection between a STACKIT Network Area (SNA) and Google Cloud Platform (GCP). + +The connection uses **BGP (Border Gateway Protocol)** via a GCP Cloud Router to automatically exchange and propagate routes dynamically between the two cloud environments. + +## Architecture + +This Terraform configuration provisions the following resources: + +- **STACKIT:** An SNA, a debug machine, and an HA VPN Gateway (`ASN 64512`). +- **GCP:** A VPC, a Subnet (`europe-west4`), an HA VPN Gateway, a Cloud Router (`ASN 64513`), and a private Debian test VM. +- **VPN Connection:** Two redundant IPsec tunnels using dynamically generated PSKs and Link-Local BGP peering (`169.254.x.x/30`). +- **Security:** GCP Firewall rules configured to allow Identity-Aware Proxy (IAP) SSH access and inbound ICMP/SSH traffic from the STACKIT network. + +## Prerequisites + +- Configured STACKIT and GCP provider credentials. +- Google Cloud SDK (`gcloud` CLI) installed and authenticated for IAP testing. + +## How to Test the Connection + +Once `terraform apply` is complete, check the generated outputs. You can verify the bi-directional tunnel is fully operational by following these steps: + +### 1. Test from GCP to STACKIT + +Connect to the private GCP VM using Google's Identity-Aware Proxy (IAP) and ping the STACKIT debug machine. + +```bash +# 1. SSH into the GCP test VM (copy this from the `gcp_iap_command` output) +gcloud compute ssh gcp-vpn-test-vm --zone=europe-west4-a --tunnel-through-iap + +# 2. Ping the STACKIT private IP (copy from the `vpn01_private_ip` output) +ping +``` + +### 2. Test from STACKIT to GCP + +Connect to the STACKIT debug machine using its public IP, then ping the private GCP VM across the VPN tunnel. + +```Bash +# 1. SSH into the STACKIT debug machine +ssh debug@ +# password debug123 + +# 2. Ping the GCP private IP (copy from the `gcp_test_vm_private_ip` output) +ping +``` diff --git a/examples/vpn-usecases/stackit-stackit/.terraform.lock.hcl b/examples/vpn-usecases/stackit-stackit/.terraform.lock.hcl new file mode 100644 index 0000000..489e1ef --- /dev/null +++ b/examples/vpn-usecases/stackit-stackit/.terraform.lock.hcl @@ -0,0 +1,87 @@ +# 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" + 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/magodo/restful" { + version = "0.25.2" + hashes = [ + "h1:gvoDTFfxp7n1B4Wsnx9IC7Ku8g8tdVR4mCC6TDX0Mws=", + "zh:0513ff62fce41a59462f39e1c4636f3c87e6f8d24ee579075900d3e0f57f6992", + "zh:1a3e39e6b8c7fd0f3983730944a029db8f00557922e337cff0567a07c5e74b45", + "zh:2527c96fcc45458efc9eca1c66cee98269d80693b571c57baee783402bfbaa28", + "zh:50cec9afe8b55629d1c94d477b26ff95de8cc8e3304f6c2bfc5dad3bccc6decc", + "zh:89e94c0f312d0ef4213b46ee776a27f6a5d114520c08a4716f4fee4c26c16f91", + "zh:9a9762ebaf9567a4aa34a1911f051527696241679e087137fcc7821e52b66483", + "zh:a065be3488e24928199904f4a496974c03fdcf2b06fccf016e405b3068d5ef76", + "zh:c62a1a6fb3c5135451f68ea4ed1f66d999ab654323d10526756e83f6f77d6bdf", + "zh:cf01364f89b713dc10eb87098839317e6f2de222bec2597923cddbb07bdd9c13", + "zh:dc0ac6a1e5e3199e1d35fb49f9de1d9325caa3c0d3e87ea8128295e19ac941c3", + "zh:e55cf6e8230f081b7c8ade592c14f1b8b45ee0aaa14c2bde2da9531d819a4392", + "zh:f333748916e68050c8935d760d6b9b469dd76eb94363af93562cbd076dba6ff5", + "zh:f809ab383cca0a5f83072981c64208cbd7fa67e986a86ee02dd2c82333221e32", + "zh:fdfdca8b7976c1a8b1b6a3589b4bfec277beb6dfb40c5568271d42f0b2f88a9d", + ] +} + +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.95.0" + constraints = ">= 0.66.0" + hashes = [ + "h1:sKmc6SGKEFglXKLMtOluJkFm7tzQZKQV3/QxUbHug1E=", + "zh:023edbb8ca984233bb51605a9005d4f7cb3365f0b11ddd68d911a1e30ccf64be", + "zh:0dde99e7b343fa01f8eefc378171fb8621bedb20f59157d6cc8e3d46c738105f", + "zh:1fc43ed3055c4912e5b3ae2eba49dd5407beaa9ba6617612f317543f7d26ccd7", + "zh:31e587a9f279661b74b139e2a964a7d1c54a4073d27d21c2f948e0e7ba4c0d04", + "zh:37427a23800dff84c1b89d4985cb935c0112c59acd716d8920c160221c459061", + "zh:3a575f5c7d1252d99aea9187923087e1d483b2b34e42c9f058f557ec28c45d84", + "zh:44c7ee340e1a09d6f9a9873959f8283f0d73aee4a8c884f7b36985f943874b65", + "zh:4fab8fe953a0d4c21589cd36d23afe072c6403e37620c82839f9f829139cbbbf", + "zh:69fc061b3c7ea82d9e9a31d3665a535f6bb9dc3d6ff5b466f940d3d04a105e19", + "zh:85ee00442eff70ea103a96276efb5e1485b661b0a1db08bcdbd28b11b1f966e6", + "zh:9761ef1321c93cb3e4bc2499995b3e7ae910e2ae68b3228164dea73e9687ddb5", + "zh:b158a4e4726a4d4c9f61c5dc71abb4ca3a621269e1d7af88ab36d34c3bcec66f", + "zh:da37df9a426d83da8f6c1340104a6b9a7eef4a7e2589d0b70a89c574a1b3cc78", + "zh:e6421b9a351b2c9b2ab2341f2c07d863eb2ed055b847ea839de96b0fd62baf97", + ] +} diff --git a/examples/vpn-usecases/stackit-stackit/010-provider.tf b/examples/vpn-usecases/stackit-stackit/010-provider.tf new file mode 100644 index 0000000..6e6d261 --- /dev/null +++ b/examples/vpn-usecases/stackit-stackit/010-provider.tf @@ -0,0 +1,50 @@ +# 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. + +terraform { + required_providers { + stackit = { + source = "stackitcloud/stackit" + version = ">=0.95.0" + } + restapi = { + source = "Mastercard/restapi" + version = ">= 3.0.0" + } + restful = { + source = "magodo/restful" + } + } +} + +provider "stackit" { + default_region = var.stackit_region + service_account_key_path = var.stackit_service_account_key_path + enable_beta_resources = true + experiments = ["iam"] +} + +ephemeral "stackit_access_token" "this" {} + +provider "restful" { + alias = "stackit" + base_url = "https://vpn.api.eu01.stackit.cloud" + security = { + http = { + token = { + token = ephemeral.stackit_access_token.this.access_token + } + } + } +} diff --git a/examples/vpn-usecases/stackit-stackit/020-variables.tf b/examples/vpn-usecases/stackit-stackit/020-variables.tf new file mode 100644 index 0000000..2606c07 --- /dev/null +++ b/examples/vpn-usecases/stackit-stackit/020-variables.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. + +# load via *.auto.tfvars + +variable "stackit_org_id" { + type = string +} + +variable "stackit_region" { + type = string + default = "eu01" +} + +variable "stackit_service_account_key_path" { + type = string +} diff --git a/examples/vpn-usecases/stackit-stackit/030-stackit-stackit-vpn.tf b/examples/vpn-usecases/stackit-stackit/030-stackit-stackit-vpn.tf new file mode 100644 index 0000000..234356c --- /dev/null +++ b/examples/vpn-usecases/stackit-stackit/030-stackit-stackit-vpn.tf @@ -0,0 +1,255 @@ +# 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 "vpn_sna_01" { + source = "../module/stackit-sna-with-debug-machine" + machine_availability_zone = "eu01-1" + machine_ipv4_prefix = "10.10.10.0/24" + machine_network_name = "vpn-sna-01" + sna_name = "vpn-sna-01" + machine_name = "vpn-sna-01" + stackit_admin_email = "mauritz.uphoff@digits.schwarz" + stackit_org_id = var.stackit_org_id + stackit_project_name = "vpn-sna-01" + sna_network_range_prefix = [ + "10.10.0.0/16" + ] +} + +module "vpn_sna_02" { + source = "../module/stackit-sna-with-debug-machine" + machine_availability_zone = "eu01-2" + machine_ipv4_prefix = "10.11.11.0/24" + machine_network_name = "vpn-sna-02" + machine_name = "vpn-sna-02" + sna_name = "vpn-sna-02" + stackit_admin_email = "mauritz.uphoff@digits.schwarz" + stackit_org_id = var.stackit_org_id + stackit_project_name = "vpn-sna-02" + sna_network_range_prefix = [ + "10.11.0.0/16" + ] +} + +# Gateway 1 (vpn-sna-01) +resource "restful_resource" "vpn_01_gateway" { + provider = restful.stackit + path = "/v1/projects/${module.vpn_sna_01.project_id}/regions/eu01/gateways" + body = { + availabilityZones = { + tunnel1 = "eu01-1" + tunnel2 = "eu01-2" + } + bgp = { + localAsn = 64512 + overrideAdvertisedRoutes = ["10.10.0.0/16"] + } + displayName = "vpn01" + labels = null + planId = "p500" + routingType = "BGP_ROUTE_BASED" + } + + read_path = "$(path)/$(body.id)" + update_path = "$(path)/$(body.id)" + update_method = "PUT" + delete_path = "$(path)/$(body.id)" + delete_method = "DELETE" +} + +data "restful_resource" "vpn_01_gateway_status" { + provider = restful.stackit + id = "${restful_resource.vpn_01_gateway.id}/status" +} + +# Gateway 2 (vpn-sna-02) +resource "restful_resource" "vpn_02_gateway" { + provider = restful.stackit + path = "/v1/projects/${module.vpn_sna_02.project_id}/regions/eu01/gateways" + body = { + availabilityZones = { + tunnel1 = "eu01-1" + tunnel2 = "eu01-2" + } + bgp = { + localAsn = 64513 + overrideAdvertisedRoutes = ["10.11.0.0/16"] + } + displayName = "vpn02" + labels = null + planId = "p500" + routingType = "BGP_ROUTE_BASED" + } + + read_path = "$(path)/$(body.id)" + update_path = "$(path)/$(body.id)" + update_method = "PUT" + delete_path = "$(path)/$(body.id)" + delete_method = "DELETE" +} + +data "restful_resource" "vpn_02_gateway_status" { + provider = restful.stackit + id = "${restful_resource.vpn_02_gateway.id}/status" +} + +# Shared VPN Credentials +resource "random_password" "vpn_psk" { + length = 32 + special = false +} + +# Connection from Gateway 1 to Gateway 2 +resource "restful_resource" "vpn_01_connection" { + provider = restful.stackit + path = "${restful_resource.vpn_01_gateway.id}/connections" + body = { + displayName = "conn-to-vpn02" + tunnel1 = { + bgp = { + remoteAsn = 64513 + } + peering = { + localAddress = "169.254.0.1" + remoteAddress = "169.254.0.2" + } + phase1 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + phase2 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + preSharedKey = random_password.vpn_psk.result + remoteAddress = data.restful_resource.vpn_02_gateway_status.output.tunnels[0].publicIP + } + tunnel2 = { + bgp = { + remoteAsn = 64513 + } + peering = { + localAddress = "169.254.1.1" + remoteAddress = "169.254.1.2" + } + phase1 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + phase2 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + preSharedKey = random_password.vpn_psk.result + remoteAddress = data.restful_resource.vpn_02_gateway_status.output.tunnels[1].publicIP + } + } + + lifecycle { + ignore_changes = [ + body.tunnel1.preSharedKey, + body.tunnel2.preSharedKey + ] + } + + read_path = "$(path)/$(body.id)" + update_path = "$(path)/$(body.id)" + update_method = "PUT" + delete_path = "$(path)/$(body.id)" + delete_method = "DELETE" +} + +# Connection from Gateway 2 to Gateway 1 +resource "restful_resource" "vpn_02_connection" { + provider = restful.stackit + path = "${restful_resource.vpn_02_gateway.id}/connections" + body = { + displayName = "conn-to-vpn01" + tunnel1 = { + bgp = { + remoteAsn = 64512 + } + peering = { + localAddress = "169.254.0.2" + remoteAddress = "169.254.0.1" + } + phase1 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + phase2 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + preSharedKey = random_password.vpn_psk.result + remoteAddress = data.restful_resource.vpn_01_gateway_status.output.tunnels[0].publicIP + } + tunnel2 = { + bgp = { + remoteAsn = 64512 + } + peering = { + localAddress = "169.254.1.2" + remoteAddress = "169.254.1.1" + } + phase1 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + phase2 = { + dhGroups = ["modp2048"] + encryptionAlgorithms = ["aes256gcm16"] + integrityAlgorithms = ["sha2_256"] + } + preSharedKey = random_password.vpn_psk.result + remoteAddress = data.restful_resource.vpn_01_gateway_status.output.tunnels[1].publicIP + } + } + + read_path = "$(path)/$(body.id)" + update_path = "$(path)/$(body.id)" + update_method = "PUT" + delete_path = "$(path)/$(body.id)" + delete_method = "DELETE" + + lifecycle { + ignore_changes = [ + body.tunnel1.preSharedKey, + body.tunnel2.preSharedKey + ] + } +} + +output "vpn01_public_ip" { + value = module.vpn_sna_01.machine_public_ip +} + +output "vpn01_private_ip" { + value = module.vpn_sna_01.machine_private_ipv4 +} + +output "vpn02_public_ip" { + value = module.vpn_sna_02.machine_public_ip +} + +output "vpn02_private_ip" { + value = module.vpn_sna_02.machine_private_ipv4 +} diff --git a/examples/vpn-usecases/stackit-stackit/MAINTAINERS.md b/examples/vpn-usecases/stackit-stackit/MAINTAINERS.md new file mode 100644 index 0000000..1aaefce --- /dev/null +++ b/examples/vpn-usecases/stackit-stackit/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/vpn-usecases/stackit-stackit/README.md b/examples/vpn-usecases/stackit-stackit/README.md new file mode 100644 index 0000000..c091147 --- /dev/null +++ b/examples/vpn-usecases/stackit-stackit/README.md @@ -0,0 +1,21 @@ +# STACKIT-to-STACKIT VPN Gateway + +This example leverages the STACKIT VPN service to establish a secure, Highly Available (HA) connection between two separate STACKIT Network Areas (SNAs). + +The connection utilizes **BGP (Border Gateway Protocol)** to automatically propagate and learn routing information between the two networks. + +> **Note:** Currently, native SNA peering is not available in STACKIT. Therefore, provisioning a VPN connection is the required method to interconnect two SNAs. This will change in the future once native SNA peering is released. + +![Architecture Diagram](docs/architecture.png) + +## How to Test the Connection + +Once the deployment is complete, you can verify the VPN tunnel using the provisioned debug machines: + +1. **SSH** into the first debug machine using its public IP (`vpn01_public_ip`). +2. **Ping** the private IP of the second debug machine (`vpn02_private_ip`) across the tunnel. + +```bash +# Example test command once connected to the vpn01 machine via SSH +ping +``` diff --git a/examples/vpn-usecases/stackit-stackit/docs/architecture.png b/examples/vpn-usecases/stackit-stackit/docs/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..fe965d1ff56c6568346dd461433bef474ccb490b GIT binary patch literal 198838 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 pUPt8U0Dbt-XrxpvB_WcT>e&dQN+D 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�}7*fi@@UQIR!?c#?3~ z67zZVS9|*o5IO|Lj74Q+Oz1Nd9MCW<+g$8ivxfDJkDsH389qUSv3OZrU!m+<>vSG1 zQORZ7w~2~1bjtC`I83o4f)Gdf{F!LfzynC6IqeZTQNai5mi0{Mn}F)d9(rP&MsZM7 z$L?=D!ww*nVAG{JqFR?#bhMT}u%20TrpaIH9L5gd4_`123y<=(5DcE!#fMKY1?q`n za7HPTB>0yK3copzW7=8|uTA=j2>t3@Ewcy2MDgb*e{KNo-eHLq+}r5Wbd6Fp=Y9S; zUkgeWs90*@s4@vneQXo2@z#ju(|;=(Qpiz^uR~Vy=-4;nu*GL_^4`%-Qt#bO)GQut zU!mZkNuREu-aEqlO!NfUCLRXYATZv^nn{}#D#e*fIKegkJ;aYRen95QZrk6zWB+n- z>S1MIj0v-S+~8Bna=(RxXVRq=UDiAy=^h;ZHn^Ff?kvZ}?o!h*B!U4Y7d(1dz!6Nw z1>>B`No#d{9d^3FmmJHOZnYLm+#9h&dgYoKSR!W^DJdobJ1L5hzEyw`RzW)bFX_v@Xkc`30SY!fPM`8HPzsk;{? zHWQ&8k5LA?4s1P$REu_PD%deI%taHXlUYK`0t2>dbVrvsRkZ~`7w)~ZMywk#9Tu^G zX0u$`H@|8&p^dY%G=i3;9)9DpK_`e*6)&vUV$I=g6u+8R5-mtW9Qk3$pSLs!mE`L+ zF`B4o^TX_h0_FxO)y_K+BI{X&df01Sw1@PfD=Koo{K*hY$QzOgOyn!gTxm~wfoPGS z0hR(mDoRT|X(#4CL13P$L&}p>+d3@4f)fGP?lTd@J3+jCJ{Q(1PyTsHwhF9R_mSB z<3dS-9+w=gV`nN?Nh>)IwMFF#iuE0qQ7aYEPEI63>+a1#r>deo9--pnAKSuft$J=@ z-{1Saa5UnJ{KtVWgSf?fu8((6@EpPcFnjnq(tLD2=}4m47u?6Ky{jB56SH6# zL@=V^Q8Jo(XAQIk+^^nXf`!74Q)qo5b5DV#Qda8T1@S9&JRujGIZNjrzfRuD!vIjj zy^zWwxIy5PZGu)%AHo%eKW65u5t);!HKbT&w@pbZ3adddfz>nz+=)KL;zIPt%vs>o z=8MdQ!u7qJu;=UyST?ex=vvcSm&JtEV4x-N7mXmBNtv`&x zqmuB1w|-sKPT`)AKK}EFovPl24d%vl(TKmD3pX%s4YXr-0poX?+zFi`bNVxFve3vb z$(yihr%9ZLG}nsr=%%w>memS~EO!`AVtf~F7jVeR{P{!h!The9$jBeNoFL4E(K@7$ zZ}F7ZboNgYkv53Y3xTls$}Vz!oI~?JIv7dDu=lBO!7XCN7GrhAYg91}1a8 zg?bHk?fpD5$(yz;Bju#1XsNvO_Bj&Oe%ii$E43C)bDnOTw*CA@or`OB`(E4_!aFjS zU38-V+#zm-mkPQD(m%$n>Wh27#cVn6tPpQsXYGfGA}BgiIC>3DI&(t79RBSG2xrP? zLyy>Eqz2%1we!PI=bm-|k?x`yE{77X*8*TSgkk`&YDILF6s8wnDMcovm{O9zRGOElxI0f<2z7I zVYXU?emZF;0Yu#EjZt{tUPPLLiULjGz_fLX&mf~f2c5Vxoz$H{RY(WxIzy(#OX>=Z zsny;#1r~oA6GOHMV`!WKOK=C(3k)oWDHjEq#LO{g=hn}T(v~?YYpMcT|M@Z1e>3#F z>U#_qf}IX=g7fIqVp(~4vj%;d5pA$G!tAK`AZ6i2uQ9lG(Yp+Yvpm@YOOLov$ChB=>DC8^+z%F>z9f=Fcm*RboBLP9t7QkC429uOxRRE3SK z`Es(00&crqlKVEw=kli-(g|#O=93H!J)D6u((SeCMuin-8 ze^X3iDpyN?*-=&+9Ys!pN7#@4C}pMKFrt%r{Yl!p>7TIQ%(m_xc8^h}?gIK- znPZ)#_sp`weA>?8^Q4RVVjocNsax<6a`VhqUqG}Jt`JWC_^cfHpU=Q8&GeLV{|zbA zP}*1AFBa~~!BM?-mn}P&OX)_DSm(~InJ=_hG`DEUOQEet)acVTf5RUWQ4iu&A3rA` z@K`62qh!4bYiw09&^v#VmpX!hrN*~vDEsy3eik4kWZ8WugBL7pN#e-*J?KHC;6&6p zl?HJjKhcEE@|4;(a{FHvYC_%y68vSj=*=B32k*CfN24J+>7og&WQBDT$yl}a1>L-r{>?Mo3E5_0R89S3SSgKjk!STA1Dh}+2*OVK zpOOaXfqofaa<3o#(na-{W%oFL4<1UbJzYP3e~TqtjWv9bQJM}9)AzKhlK*HeWn?jl zMHxD*@j#XXf)mZG;W!$JK1+co;7D_bPlQvbQPg!#Cvh(t(j@*BpPI zj2-?l@I|lmCY`Xp zDZPuy$~S``?hfWYbRa3SLW*FKxGr!xf36EQ3wo*cjC@r>Hd8eb$%E=vBA{-$z}!d5 zI`D#7UJJ0yJcS+1)QUBjeoVsemK9#-(ax~ld-!`4p>}+GM4ZGM#L1#hwDs3ed_#Nj zl&3y8h7RDL+GX23%C7m$f|EXp!H$U{g6}OLN);B~N}}k)uYm&Z8WhxDu@^!Pgb^A1 zOnJaovXIZ&Ohja1EZz^JUb&lryZQ?=KO`?tQ19`Hc2M+vu$nbX{&B`A<+6%@u|dDm zuL+U9XP~QILB2cgw*mTLP8J1jJrADz(`kzmweB8YkDD8;;H2qF6s5&Uf^gvmKbF8u zFx0CBM{#^w{R_2Q6C}K9QbVr~l@1YwIJhc|YUgLm|I{Wu=pQ!lf(c*w2^?zjbHnpl zghWW#SpX)t087t{JZ%ZBc&i-gjquVpwt{M*X^JpU0K35uT^at;R{N;MtG9Qw=-)#Q zWX`;F6S4!W*YyDr>YapcA6!O7+bsT&P3R&aB^RPAmM*Y*JJz>UI(k~}7Bokhg`j_p zumjKhg0^j#*1G}I!$m_|t*$e%4pR?IJ~(>Jkl@GYJV6l6@;mhFu-XPfXee&|AcUc` zyoyO}A^)_Rl&|QA8Q9+a&37LRhdj8mZ^;9w@XImg^addKwMopRZ z9Q@~UROYy)e&q;DZ(v_<;F1%(bnB-{9E}r-N;`jzmse-n4nlAn*VEH6eLnctt5XD? z7eUVO!98m!Lcbc!P7iGs@AA@P{1E>c^>885Axz!2;&;D6U`cQ#BMJ$<&!jaB0kxL{ zJ#p@_OWTaXXFN6p&3z|+d%{2#J^)J&IPq1ojb~`HZt+v6_-ck>dsvCeY&3wUQXyfJ zxt)H89z`W;br&v)e5wkC-@^%$u%eFqUFX}VL;~=x{mcEO2GYU2uJk#iObLm?t2aw3 z3Jj^s6hOye3kIlj>ypZ25Eo0YW(;7$>`=?%0KeAY$tAo@=7;7YPw+hOzc2XnC1$9I z>tFsLTXD-MHTd3mRU|f>P)^TVWQjJ;oygJ!pGaRWTH4tywU0ioqIcKwMF&cT&V1Q( z+iht8b~3rRG~rp0#t?36-R7UTC2Zy!FSw57#RYNuorRa;@$GRTxeKPXp*d0KoDnPI zXmF_IC7*F^3z$Ei;G33)x&L+IqXeGqboRgyy5sNyiL?t(+c4R48P_=;3imHMSFIlr z26IQ2>^nMfUksPD;zZ>&g}j$>l2>2Gh@E|Tas8z{eQ!FR-X$FN?GO|SV!DRF~qcd}1|tJsxaNYV@ia8FDYfv0L?Lb}pppOy?1?8lV1 z?>{_ZBvGoE*7h7Ha`O8M3XOr=Nt#Kl+o@N-TGbf=z-vL;5DSK2EWjp#;sQYofg)t3 z0DVUgpX@*#13%V$z>}JsGX_ie-IJs)>ikQ=AnHN4c5c_ek8mi%p2C zv69dC$G{F%eJ>_fL#zT}?1WB%jQ_-q8RoKS-XhzM=!`rEXOE&a%h)~_*P2jCz9}az zAnC`UBvy(uiWCRnuPI%8%ddxGBmTasV)HtESGqzr^p5q}$f}8&Vy{C?N=O`j;}x_s zFN1&kZ^>2P?IJBLaC(Qy;=*#l`>2(F00+8^_}BG@Nrg>22JPx=;ni$fB3Q3l;70tWmjcg&IOo482W zINe};06!5DDB`~77e`u(Tl~}}q^=)QGm=ub&0g8zrMR@wG98H0Oem5vrbgi zpVYK?>BZakq|NV#dNY4kusaOJa!H`y}(VD#jc+F4De)@U3{w%mgCic#!naC z{qVP5e+S|75^Zk!WlC$B-u+hU&$G0)ns1L#K~f~&k@`4Gb&E(JziQ?7FMIgj48B2( zvAGFf$QvJS9~X{Bi^bUa#-E6oLwcGQ7f{~iNF?}w6mn}5L1XMjjp)*z6es>ol9kji zR}e6=N&P|4iyGZ=MBvdcF=@>X<`zUihUCm2kWcwymK?tfm5pSL(yw#0xo=;5K>v3t zrER7ZF65Wiq>C&tcDg2i*qZ6HMuU(*4W^x>y=X!1U4-G%*3z5Nc4;wpxx~@9Yo`Q9mYExG8-|I@h zsU=?0>w^ObU}{Ex@~k;KkVlN#ksop+eG>)yYYh5-fZyCP&~1XyQ2mP(i7b;O92d&} zA?nNHsa)6hmy{wRG$@1!m1K%!3W*FA$`l$zlA&4}%#DVmg_1GFG8L(iQpOZAhNzS& zVOdET62k9#w7=(f{yFD!&fcB9-uHd(=f1D$UT0vja?Tt0!+H4CO$|1A*E#oPCE>*i z^6>|ZIjoBV>}6e{Xtfp{j@ODNqvAK9$*CM__dyG_Oe8{*WO9uofBTwuLAVcNaUz(v zNBIBU8V;L6XAlivgIwl=u4h%cehVq8^h}w*tUSAPdXj{2IRD&yzUY4T1xRZcxk1m> zD?-KPkG^%lcG4f5;yB;Wvz>B(@#POao(ssCdkxxt4;sdsi0xz!dN_7|bDyN=K=b3U z3q~vEBzf}iOXmN`Lb^$26VCz&`V_H&lB#-t5Fvk=*!{~ek!b4lgW9+*{V2l-?tV$9 zsCZKOabMZ=Nw$lA=}0oj*4%&PvA&vH$G7CY)Ss%ucN()-ERvQ-bjY;~Y^@q|?|MV- z;N`M*nf6;4|7*}6V!x@$?z8eaM&V*RGF^?O>8Bt13@ycHo;RbeLVsbV258T|Ws5^y zyj5ChGI0R6*45#PXvoOuZkbk=376b0+yrz-!E5wb4z#bQ5t=+5p??bR4kO}!xDtUt ziJfO+SL0mM_8KEi<;@B|Q;6G{D}R#5MB&+*&k_yGMWeI+9{j~}&_--V3$L_cf97U1 z6=#dK?awfM?NEQ`i)wyGFj-Jhd?L1gtTlbFPFhLw+b9{Agjqth=B5Mm2p@~RK-+Wz zkMysyh3dloc>N^&Z@ob6wrAgo|KBI-4|#y9x-C`-y(h^wEx%LvQM;$>FKwBqGsR`M zL6%3}(m3R1(pqx<32U@P^8r@SJ9=V#@aturzqPW9%)B__>QPqCXbaP zEQnP9v>Nsf{WsmA)ykT3=13ka>&Gc#qEk2zmTo6gvQcLHnoGDJ{+T(X`#(R=!DNL- zG2yECx*dy#6ZR(dd30Y_Zucm#*%|4_#r{VJkZjiJH8+NaHK#`-#|lbCzqBbaHtxZK z)(y&^X}-1)6xw0q#s6KJ33o0nL|h8(evFI57OwoM`)JcGpO=b`3p1()KgQJzvksk( zQ`eiZ$*ugZ;x+wikpOLd&Lv-LiRlH}>Xkz)K{H$o%<$h&xdK^whf~&=E*M$W-+YXy zyEjTviT-PEs1VlRddHpx6CK|3h`<`@+_*|8`N%z-mXqg&#G?R^S@)^Cx4%@CaYQ=n zk@e>32VHeU=0qbCMEY!1t;=f~P1~5TP#O{>5i-m}NNt-|aZ`;S9AjLbkn|3SEo*Ub zM+au0l~-|z=_IhQo%j#>>Idzce)zuJ&2e??{OvhSi*Y1wX;KbiL6*gl5FD?5 zkQ+n^AV$5ZYMMw06v9P7TOCc%oFJP((c3|L3P=F32p}mc;X(@1s%~7IT=}`s+u~nm zz8!r*rnd`6a%4T4Xk&c0nWtku1${HmYTRK`Z1;peRBVheGYRAPlNq_u5sZ&EdB=~s z?i9g?lDy)igl%*6tqo2xYuqZSt!`iV`S4^%|Icns&^-CmJ2DNFZDK_AiqGsKnV9@e zx57(f@BMfI4OismS~n6X;JT(GxG)nS@o>Jrq2`V`+WtgiT%sfg{h z(LztSFg#cB)}T*~XC#h3H*^6<^9q5N+QkRV4OlMweVJpT&xP`@>>tq}O!)E@c<%X6 zC3qkwYi5W7c74kUNY8q=_%GaTakx@#vQ@wQ53d7PaNlINLQLrqgzmJsT;U_emyrND zLBhvFHUFe#>7tn6weR{}Zw8#L8Yu_rV%?_(A+xGd@BU27L#{i$b|6T?820`Ifpns*L_Kq4^PECQgnb$b zICbuO8)YQHd&zgb6jfD}BiZ$iRH$2Xdbr7WE}Ax*ihvAa1PQ3D z;(k2YUSMDBr^?0X1WIMH)7IBdjD6w<+1z7Bf=4u1F&Sdt1%=SHWH@^NRe|H39wwE%E4L1zdaNL49OV{CP*iFCNTww&&--n;J8QdgTKU=)(w(%Mw zGD}M_FvpUVNwLCv7k=8DC7C1E6`lXFNchkjuxE?e4tM6LC^!GNE^o}NnWuRTK(hSm z(C#BCwv*$Xw7T7lLkPTWdHR`nqDyr~C!+M{H?r?35FKz`Tn;jGOf2ImP(3pOP$`vN z$8U+l<<5MsmtZ5hj4%hJ-Rs9!#~7tKJiUg-*oMh2Nq`sP;k6J5$0TFToSPqO(Or#- zvA-Vlj#LZ0IBtYBQL3%HnD6w;)SPa9j352IU?*1c)PS_F!N3qd?`X_E6|_(L?Ot}j z;?|_L_u+ZxZKd|p&W{b;YL~d2f!nm@*R3HZN<=+I+PNO5FzpqWa}>S?F`YxXwZI|3 zE4MQ4tg~G_Dn~OhA~is4ZGsknf3b{xC$Icq4z=jLgO^^yYC-40t8vQ- z*!Fa1>h;TK86z@gSJv?|YBKZXcp7iXe4^W&NslQl3nqHe_j+?VgylP}7ZY>1D~a8d zS#8pc?b+*v;*Zj-u!SdcY@v1tLNTK@T4fI2{!#Wb3{b$!r#4imNIbm?B3z9#?z#by zp0(;lsDR1%X#wO(kGQ=QgFr78)wWLSJL*S!yr%z*W?OJ8wBR$)h)`Dr%s+#nx(OOd zW?}p%vQg5H9XZ>p@Eu{-dBZPV5VwI{%8bbDredCz1?1~^%@`2H3Qy4BY2iIeXi^-*(&z6;8z3#5G zlou$9mTdxpkHwqLRP&EaD!t;8R#PDc57+ysQ3@W2ZRlT&dAGprH2~k!sg|u1U6*Ur zR@Hhxf;`7Ed#NBCzpdBAbBQ@-N@Pds&oHQEE&Eh>=E9QL58>}>dCC?@E$|aM?>32H zbK8}?MBm?5v5wgWE|q761fpey9;P(qQJ)8*a=W!W9`P1kNHfA6IsS=7#hG1T5#~Ts zy?8l;9Ig5W{Z6`M7E`hQK#W$bLj|@3BAJ8Be!!mJ~k;nBQ6KoYvHGVyX6RM z9A%}z3j4GJ%lOoxyyk1=Tr`LHFF|-Xcxe{LBY1Im++SvEj7B97nBuUoW$KSZ5wy~y9*FiNg zWaiIWbr|Sp%hb51=(y+bSy?i=I+B1-JCDkZKm$b-fm#*Umka~#v#Jnha3q6Xe9)wx z1?sOwj&^abiw&OuvjoTvEV&*BH$C|@LDG(_cI&B2Xk%=Y;g)$t3}PCmXXIiNK6!qWvNjpXBn zZI_?@KzI)Niiu74hO*|Y4m@SJ8WJ*izdd6d5ilTYy1+s8Bdqy7bzQYtrFi;f>qv+zrJ=uhifBUq=z9NS1Ea zC2D5diw$6Zrc>b=5oFcSng)b!FJ#vE5QiWc@FTI!kEztX3|$Z6Uk{b*G;x8Uf}?Qd)!J)q38Kw+vs}q&~m{HO1=jK6y#C^O_h=@e2;RGT#kCRorc%0qDEnMg1fv~TAvJvLm%W4e}?_nj& zyG;HADRd^`rNm+x!Y_Te@XSjw;Cd#kkI`kM`QHs$ z2o0Z=&gwb4s<2%P&O;kS40O8Sfl1fiWq9J>-`#ny)C=r8?(GBU>|5l>2f_0kt$_7- z3j%)XasFzspV(-wfbhG)`1|2J&x37GQehZR&TQo4{9H$fxOH6lVlkcl(2>}Q+Zu#lY=6_tMw$?MEqqUh$#zKJH&^+96&tj68yBjV z{=y#uRYb#-^vThF!stp0sp`}|lt1_LV4=P#$;QlcFBQF{_O%Q6mm?rxM-Zv_^i|gZ zVrzL?zM&^S8k3o-g0Df>!6$#SkO~GcStATZ2;gZ{EtKo*&`MXWS?FoNk>fhj|QJ!wn>dGK{#|2>29@3DL3$*18e2p3}U} zzYzzg!u@B|g-ttTUBq?H(f3nx0o7N<6)=i0U+$vs419IW3#T=2x9Z{dw`63{YW4C< z_PcT^(-*gaD;Yb^f<4!b#`_$nniC&%>5>5xebCtYue%(dziV3-gl-9sC45S_upZ~D z*;(HMd|rOt5fQLzT{WEFB-|7(E~p?*YcV-V1!kp@w!HWLT{%C?Ro?<`B_cbLfPjH5 zLs?1m+535w0lt)Aosb8kQ;I6<_h%kMIli~TP$6GCTTA~m?4_ME=M4_!g2+Jme%Pd5 zo5e#u4y_(CE`I@v+S+6}NmwrWd9=FPyj~lN@wV3G}K2Gr)?9^{rQ~D)j2|^!m zV03%B@-@v1}}l8#o=l0Ud@F|<6DFg`>jG%z4pD0czL76P68@2G5LjHV1_r9|GaFu2!^ek(pn zqp%}f7rEo{YhI;zpHK@G+Sc;vYA4O4v1-6Gp`U(@FQN(G%87*C?Ae}zB#|iZhAOB8 z`U*o8`E+fz&rDZtWqPz|tXcUy3he}a@q@PU`?;!&FF3^esr3;f_s8wK zadW6HV9(!n{_p{LzI$F~`z+7yDOSF?o6gqi|X6$<|2iSvUx@x>Xxr z5FF=>9TANviCMmpo7(j?Ftz2^rCc^rC!3&|)ZL5HrcOQKUsA2LfDxOTuNgtRur}Yl zqvZjdU}oU2q6EAg@!x&Km`Cq))k!kk}`q={JCtw*%|-_w2D zknYqs+N*cVMkb)<6q|_emqPDWFLyTW89h`RLs?$4;kawMsFl z5NwvXQCj+JRYVn>5bX3*lgYVnrOb}jU(1h+WLPYGmePZ%r{yv2r&-^3hqafI#wIwz zh~Q?2nlYP3!SoM4L898aCLuUs>j<@|BmCy65ZtW;a^2!rPNrV>SViZ<0QMWH_ zde^;wvB(ss$aLj&qMtpRwx4%c>xql8FCVtw(W<2I;i2d|`o2rNCcio~k?3)YM(fjCDb_DZxLM{1zaVC=)@y&>U_#0IdT;Ggzs14j0O;a}q@kLk)@8LPp3?&W zl+e)#DA5I+!+m9?6C_BxMW)!3MSsn3QOi)3mJj6cs_H)ohVAlV-u9DG;x75p>DOT+nwNWk_{Nspx_&!2_OG-o^4;=(7aWaVcy3>154; z)VRe$tsz$WsB&gTORD{K6S2)%#(Ub1VX<@bWJYz1=0;7zarX8*!h zfI}C~Ih0_7*3G{E>Q9~P`hHygF!eqHjEEU}CAmIa;$B_H9{6a$L~)42Q4w_Aw(kH)C>-UP#RvyQ?sDwCNS8ab1VXUyOkmQ*QGcy=OZ&=sS4*`}6 ztDxz~Sq*DIu7{eQ95qxxFksrYas1Vzy|I`bY^tkj94XzBDNCjxsBXMQe?g?BZPKEw zx(*GC5Qj`wDp@85^6Pou-TcYDNwZ4d=D+7!koGQ_&vR}!+(r= z#YyyxOEChtC;?bE;yMCM9W4Pqr3Gg7%+^Cy#9e|F)6_tLS=7kTO){Pv<0Ss=4mGNwjI* zyOBsPW@kFwgtDZ+FFd@vpc<@8gV*c=?Ez{;DU;*HxAEuX0;EzXYRG={LWI*lUe*>q zM$E~j_Png5;}tp87;MpDQ<1ZI5(mf;vu`TGy_~)Nh;t`_b?fIpzV6zb{9&n}pYZFA zP1OTmMN3&r%THpx!3Y$mR((<`z(Pn8<>CrS{UZ{hITX<%GHf!{=2u82`XsGjDLaKEy&O0QM+kNg z-HK)Fe#KXVF=sspsFAUh#+-&DsTZ%y>og1f0@a%A1R85!e3{z1d)@GhqV|QsXwPB+ z#1D{P{|#|oElwg=-U&;EMy=`pt21O6Xj81K{Q{*TPqtLFuLpJxFFE`0dCSlLNxN~q9POB=YPXTSqm*lF`Fj_tpGoK4WEfhd@a?-25W|;cZ$E%;Ar{$u~6Q zF-MoXmDUnqE@Aj2c27b(;`nU!+)knao9Qw;krp!&ewtU(v>F0(pUHw&Gm@ODV?m1 zUrwX(XmQd}A&`3xaZkLBPTs8g{5>+cRo!{fLn$Lrwt*2O#`uwO!`q{hb1i4QPUaT` z$({K8>|H1pQZiO1Zm`(Iv<|f(VPUD{rsTT_XLbx+&dk~cJUtk+vZn>Pb>(Mgd>{lJ z=?Yw9JtZ#c|Df?}(F#hyIhqseWX_E_CaSu5gS^K8s{(e)n{+yszNhu z*3$;U*=0Ih7t~zBMHa?n?*gLg%e%pgDRK*Xr+17Z$tyo6Ef;7DUtL=SA$~vq62|GJ zf;&R^PYUy_J)h!qh`Rawo(bgtTea~TRGN?TzorD7B?<#hVYLsFQ)^80m)dx(cuBBG z@AcwEWGwI7#A9T!W_4qs*%~IMigzS@?HbF;lMv|SK&+o8r-chLlW7)M6O=h?ldB!O znCyUwncn$yamj4uP_TQ^MC#Zb_RIYI-d*aaVfJW^5n~O{{PKu}vgjL5P>a)@j@70R z-V_k$(U+#t8NhkAb75bLbkIX*PB9Vq!^q_~D9tw7N?78)sbD*&XQEBvxR+W_e9Eng zx!-)PfXWz7^fkG0@s$Jb{mrIOj{A^!Q)&5zKCKFpFO#G%A8d*vQLxDmG;iIIrdM0p zb!ai7-5M#KET%o89VTnn1GyPaU?b8e>q5FCHvyJ+X0dvZwy-50HCr%h^Dd!quJiDRI{e6Lc83#>Acaz}usc0D>Gi2(5cih=HSb3J4L#Ruw|_H?e0|8id~Nc$~aMBe=I zcCQsDCQBj9G6tiVc_dqhV;Su)@8iwZk!wci&y3xj#6_nJP#pA^5Y`c2Zr)5(ARjS+ zlT8c{j26M#fM|KRPD`}8dT)y9(!XF9$~>}K5M7SqTra@F-Uo59Nm|RHS65?Dx?XJA z7-T^-_^Dv!dQsEPu!Ro`U$m&w3IG^sIdq|u=0A)7dNj#k_o|qFU#>91I`4q+(;5xW zQw=7%)5Xcj>OtE86yXqpnMobDPu)f?3dkic_M&t*9x@jG4ifa8^`_62iJHX>u)`!( zh|s-$>?NnL@p5jcx8|6y*4OZH&tPVR^vx(c$P-D;aRva z@UO|>(Z+b4q0=5XewMQHC|agT{|e(hzxg+pCXi}CR0ID?;%H&sW$M1gw2RH~p{i)| z7;eu&KTW3*Zx*|fr&2^UIJbm_)X7gAmyI&Q`XfpgPpZ6ljk^Nh{^6?qE3*vtBB6>a z(|3`w!@331=E-r2l=4I$i(~CCpO58ljVFr4t;hqjJE~217-Vz8$aTTFDb=b^UWLA4 zgIE(3noJe83ba|HVp@&IzZB$oUN6Qd*b9x*lNs-q+H3=rMkj~IT>*>Mm6(fI(G}YQ zbit#K9lnFse4R_jrDP;m6NWY-j5DG&@uVL-o7+E4MvL1XqJjiNcf^>!J&(BaDdFb< zhkClph%PufT#}5AyQO#suW7T0ko#P${VM%i7`m>;Pd>rqSeKit{{qHb>xxzxaqf08 zP5yzAc%v)tN*z4viCJMfSlq$-HzJ+-_pwrvbVD*tx7|I8__SV_WxQ?~5V?X=8)v0c`KD5OT35sTr8oA7tT_<}U&j0c6s}m|bPSKkG)V;$E zQ{2(%1TIP95Cv}fz#`@*2CtEtwa>}YtvcUJ8rh|Cm~KF%&Gzs3HB0g$JYQZ+2C~9` z`&A@tH*jg_q;19HKT5<0)TG-c**LEGQP(X+Pyp~BRX##=u2+)fP%HBsMo zp1Ki1ScP-*wb?XClsEbDrnHaZV@|8*nxjqDx#=e3iiNXA8;C4ZSFb>&`W2tAyO47; zu4TrXn3{x7wD`{<%9nIP9C-v7f@@i`#~xF!;p%0)?po?LB$Lgrw-7Z}??b{n`xR(0 z((s*MHelOLgjAC@t4xfdHrBsd-jBcg^$P>2pi7pl-7nngM8?1MQh>v*(;~u4 zgw^_Mavx^z6q4`!SdXwk;o))3nCH42=~!2_g9dnrm*_%&|Jcy)<=Y{ zj?i!nLR!>4pNVq!e=EIe)G+}|(KN5tfvRSv{GR>xX{DkT=>1GI@dgq4{|9AtL|Cc4y(xWUx|UPY;paCfT1MBaUnx809}O3T zr=MqYrd5-)aKa?tvvB4d zVXEUlid|hIH1IdIbFBVcc?V3(oqruuvekwDrjBV23v((RlOvjJxdjxF7!sB?X@vgD zfMYHh!S$F(JGwG_=YAdjc+(<+L<30d|BzOl5zb^z^?T@WWTf1+=6G;HcLc3q6V@#- z3%J7Ywe`RLIjeuWpP+mdH8KQLNSj*nvKAu-&arB36SS_;hx5yBYICe4#{eJw&s@l` zRJkq67|nglPxscyk)-(tW0|;2Ohq_`Xaehq9wEU=2pIU;ANA9EY})-tmI}g?w;2MP zrfV#BkP1#T>IqTnNSf`)R6C|{xF}rXtun@3-fRF#(*1n|X%}78G+z)@?FU3Qx)mSk zue_uFVglyk(WIhv#TfwQnpO9g%6b1jQ3y7S-OzDIL*mg>9ZV-6zfrPFQ1k7Ja>-S< z85SOey4!%<2CT+wyRK3%|3O|`?aT8cHNb_&3;`|`L^EBiDgb0=uNWcG9jTUkgawE1 z_7JIv(od26g&}?$LYJ)D;Rm8Z4u4aAnBga2YB(qPc(*bFS;R zSKWhOOYzIY-e?7IE<|q6wA-rm4lo41dsEsb238H^K6DmBhw}c~3@hNW>xBxFX2ed|3ud`)3XJH$QVHke|G$Df&M2rN>Bb-pdAMN zZtxG{k#k!4Zzgo(B(L7>7ZN!gop=N%Sd(|3dl@5w`# zeA*JGpXdU@MV<^fF?#ZxZKXRGvC=-cSb^zZLz?pdaz><~!|<#rGgo@%)z| zp3+|cpBS$x_9W@Q;oc<^!xhl1o}6*3I>_amE@Ip^`t;2P=$;2_0wi)w^ewdh+^G59 zOr$5D8c1xO(;LOhPCzVMFl|7^Fv-`^>yjiQ$3qugnLYExFgE9wx_kPyEKN(0~gzc zst`8n1pYFoIr4#K&kb`DA$%7?XYZ~6;w}p0$PoH0g5|^S_I&Fvj0Qk?8l~}wv>MwW zL1BPxQSg0Ov~Y0w?4NaFtFDzy2Q|gM_T`q zCDMl@O8I^w#v@rLgdNI6?>QKyLgBL%Y}ZY4zYr4OHAdl4zzwp6a9=a)uJ8>j@8+Nb zseEX$cm==S+7I|^jEP3bMbw-Klwr?#n1Mg)h27DDHnh2UwQi!9RKWIRuUO~<^v8Nt znnWbpzd4hLP{Jz#o}~|@09u-vYoHpQ{@J;G1n!l>41MiWiL2^rSc(3H?VE@vYWXoJ z&E14rwJJGJbM~`Q#FK~>Ez!o#>&NX?q;4*}O%6|pIvz@ZgXERn06NYHUv{X9cwI2W zrQCDq{@#nnJ92f`U^tG4WHM}SF*MQ>> z2GPT|d|j7)IvAhw9$3MaFruZRE~w$7k~D9KtQXivDUv9zV2lSfFBDf`{CGji9)v(6 zxFS?@4l;d1cRJKWzavpmL_A8;J13^+SM9+17_h1dHbU~Os~Syy41Tj5__}(|e~;t9 ze2wYJf>fEY7(^j~LtV@-b+<{~c*vh%jwE87#!rt7Q4^%C=^OKPdnRhTivHm^*d^jp znUt_I&y5$VPeZP#^Ah{`O_;G1}e`GJD+$+5;gV zFdPQ;PYpPr8jKP(fouGZ*{?go*W~UdPH5DZ9n1Iyr%aM zZ&0CX$vEWMkZ@%+Mch$5Zi(#e5$|f41AF)_2d2YzR=Vq)s=;tTbJzgu+tnGQ2Ly};wB$*#=${+5Sr8+Zq{l%hP zmpOarG`Rva<$X0VW{9r#n`B5ffhtt2-MCEfiLmsusM1?_g$i)!dHC7W<~cpzbadSY zfdGlwZCK3OS6p3OJ+#u4F0JsL1hZMY4~ zMdi>&(*p=hH0?WUM%NUO5;qLCDv(((UA#i? zg;3<>jQ}-Qk6vXH10VVC+1=*HvlH1{#rQ0ytEP)51m8Q z$pQ$2@lRlK|JrqNGRdGB<$WJUqeNiQLSGH|p{(L%UFCpsyE!YhPY^)Mq&NWIgTe>` zO18a@9A15)$cUnv)5UQ6rrO#{_3kX;*NYzMg&FY#&T!gv>V21+Q&DqQg%Cm zz=M8H)AMtedpS+e-FZn;{k1UI5Bqm4JqomB^BSL@7fAL4$izZ$A}9M=c(8lu#bz&r zRjJAtAGTYW0K3uLVE64RkwWQ<113D1T6jxZbZpw?nW#|8(YI|FnYP&;P97x9fy*vv zyNV;`IZXQni4#K+QH~gJSHGin&&DUuN=?)%}D+G zt}68B2B9_4<7`Wyci@s_uG)3EQR8hBKXsx5?lqR&1XW0TtI2hwVq8+PlPyQN# zgR-?y#Oy17gL-8QP%86lHW9dc?Jch)UT}!)917!b?WL)RU+VuZax zqx&$t9h$HCu}Ei z7;j0piMWDsPK+VjHzFcjm-WJ;t%JbUYe_llWm$9yUIoPe+;76@(UnPke5-gHrc3UR zwOgXX@g?@TXV;8Mu>L@a$x>dHAyT}Xc|=H1KKT>0XQPLMSkKSgtKTWoqpT0&^BO0; zDbaY2EVEAiIfgqOF2=dN0a`T%w=V+_hd1z(<#>A6Rip6FK-+Tw$75a}`wWpGE>)fB*d4EL-DY&q9YnSCnGbIj%cxwK3{# z*0`}(pi!dCB}E60cVH5k#tX|ZDx8Wi$>v*Uw0SPy#var1EXgngnf?C3LYh|3bUR|3 znCgNigv&=#z^-gwhBz=H5E`DUv~|$fdxngFY;k*YV~slmVh(8KnEb|lFsln}mT0|G zbemTCnYcL=em(*HMdAhUCCc=I$e)y;(8FOT;=HW;Nnb8V@o7IcW@TUz3Ig1hHdfg? zvJ=A1>ctrug+G@?b_`-z2vn?zT*s#Ge@gRi{ce$-qHdh^#%sVr%}lxJnvqhWzqJlg zF@^mD&t!SAC8K#I#%?(P^G`H3%-f4tx4uJ~6kTmq>9^di=pLWUJiNS`Xp<(eK|Y~u zK$jR|T((K{>#<(m8L}7)%$aHjB3Y^@3;7?A*arnIOFIj;iv$w%Y6>vN3_nrTTsz!p z|3iKBIj1sx(Q#;Mi4P1dV`C`_s@e1%vOr=h%)@pPyd@wDvqqLJlD<2y+n6KTVSflw zOp&t-$6r4`MGon!2*Ep&a8+>v_anvT}kYpzU}4xx`h3a)v`aPwj7KCdpu}$R3DM-= z%$6S<1M@eVFs&_o^IZ(rW5~b^Mf~}mQy(8TO1PT`3whQKx8L%fH|@tM ziQ(v*8mIPQ;IP=h;YfBMsbI*!f6Y)VFTo8_3rSgmH;Em5?fKIiRi&SZGEfRsiY2E8 z?S6O`n=RBI*Y**UD^CQou|^0;~B zm6RzZ@M!X*MtW zMjR<5oKUfh>nl0|H(%k(p_}?^(2<;SWDEd}CIKCuZrw}C?p(9YvaG#F8{%sY^zLY! zuQh}pJ(0*Cvi4V1Xx!xA1=@}&Xg6Aj`OKGXq7acP;Z1XD^_-*CsiYAuHd?!g@^i)W zjPNq`=@{B4GQ-0Oq2YnKBdtxBEPyFq4956wH1?_x+mW4bSsRpGd77l81o&e@T_eBX z7lfYirAd?VJ9(klmd7$dkD_FjAe88~cq@rf?+x*PaHL|4#e#`meG#&8Y>WMT6RuLl zc2qTTenp$g0APO26yAC;Ul~hcSy}|eav-^ zY+~sAxHr~u!9xrODwR|sly3t~uFphKG#yFol0@nf(rtxfdgsmjYiD|5@fV`(>YO-BX`n-SgC7MKgW`AGlU?rP1-p z94Cy!|E_}sL~hOXN-=tiD1VQj!nE|2FtrPqr0kn#+kFw(F^eETtF3Ooh?MX40$Mq- zn&ay3rYbZKjeF>%8seJE{aEZ@Z0Bnld6Ba)``@bslxx_v{O=An|18@VE#QD(6$p#5 zKc9^#^C~c4eM7iik~`v+c$x6V2_$3OP9ov}CKu)Qb2?BotHC>A9pV~(020UmUVib( z;~=wI5bbl*wR!qtjlVo#vrGjH+%mQ8^D$&lOyEk5FJ5gY@mj#Em~{$e1j@lKazQ&H z(J2)}Nz2$$H*$3YvI8dg^EyD%SZHNS$w2R=N#_UEaN4mN(_iuE@h(xILl^%!G~RPSnh5y#g$#eWdL3`Ldm-=og>y51 zpPTI7b!ts9OoeGH4gD^0SHP1Ne>I3$3|1AAhzQkhngCOrmI$iQe)Nra(o1X-J32|i z(-=Ze>A^L<_cYxd_H$`MP?Jk7A4TuP??ws8uUa%kB0)f63qm5KL_!a*T@}|{)j#%g zVxD+56mu#G>j+L)nD~la;Dl6yn!~}%_8dG8_G2e$okMFVe_GM&Wz}PS>QW+{sk>Q0 z1&6~>-jW1ETZ_Q9%_#GA9be9_p>K%Y8Mz(Pe123f3*e^8v2>Ph#@TiK8Uyg zkN;pGr_OZ6-?Z%~CqGxH68s%oeSc8%HBfol%cE%@t;x=Ah)8)~qoODD1!l;o6oJ2# zw$APM|7{%Rxyxbm$)ECbZoi3El!lqz z7rMW?4x3&KxGL3zWtfIOFph}f0;K#w0ANrvc=TE#!(Uh&e%WYjBkSj$u1&NPh*s&Y zF-pm1dT6V%xqZqt$mZ1`Sh97it_L2=HzbhdX)LB6TR!7~y#syicQLt}yn9l#{IC!K zH=C-?WA&sXKH^^d`CfcYx*?@wE^NgA-N0bzsVY_ft|V@lYG5dqY4l^niKr1JwO2cB zI?zV+w&JO+$l5pY%yn&Rd3&2BHuyMM4E38W347KvHfb-!#$8Ug#zY1A#Yu@oSPg=K zMAe9W+4$yCyZ=NIE`>Wcg*U!^1;l$SIkX(#9zL|j3q}{#YVs(+8`^g&n{e_>)ev!q^Ur?(u1dF`r@si6)l&se7%s~3G!qYE zTep+&kxD7+znQulmGc@ZCyKG>Dj)41%Ft9e<09;)^6hrs|K3s;@pAFngE$iOj0dA+ zvdh}WL$sg_MlZ-XMRfVOVWp`0)B%^OyH&{RwVaYpc&-yZw9rd{T{_^5+2g}IHspht zQZRtruWMd{>`rMNlH8vrS%`*SWO_a0zoEAv{dv~t!e`6GnU!bjFHB;EN zjmSnG+sX3a4sT^px`|b`j=O}Ua*q{pDie7>ApwkBug?;d6w}f`(e1Nk+B^zLWY@jM zKZ^0KmJzk@(ZTJ^0uE*3rNbV{vV;5R+hTZa3TpaY6ys?ZZxEm8zOp{k^`T*O`0r?c zf$V5b_9Jm%O{Cr$dDgo=n&4%ksvw8+tSy(n_+l59Pf27xY{Z26xP>nW$6{cVI!4TC zZBnB3l4W_=FXu8r!jcuMnQXSZS_eozCAF`Z`5A2}Fxs#CA1xOg=3I!S+1SbuHuh0_ zu2Yo2V|YOgXQ7-6oY}TU5Ys^eW3QyD_Kg$06j)8@v$I za}Gh3B=!A~hDG;Y`VjNf$UT^DX1 z+u=)JAWJoZy&!Yk=Gi-pMSVLDGU6}%+-RL!sT%gbV{nefxPow=zM6rq7RLI|*rUVw zg}&4iN=2$_0+T5d{|8i2^t@Gv3^O)Qf)RlPARrL;u*HM@NSPN^$9CWeKSjWxeX+Z$ zzpG~iLqQ#f!CCdo-Lc{Y-MD^Q;u1E0zOx%)3)|D46Nt{Aar(1{la-#Iet4mYx&hYgaXl-Ifc0>t(7VcxmdkP?peO7O?X z>2bH;a=O`th1Wy=QILwon4Hgo&bUo=|Ahut@gDE&I!LYFNJb*}!)l5r2H+ZdmX63Vxmme903!9{+KjX_oR7b<-c_SO*clA zpfO5XCR6S+&8-nfWeX{R*^Zxd{y3z@>?z)PIRs5;94@o|ee;%*_+XwI+@BzHNzP=< zH(kHgQBDWQD#V9{mRG0|CRErjo<5zz-=sRI+2efzv-oU|(X*V+w@)U=E)r;QGxB-P zp29xXgM}s@mBo^A2=B6)S{elAhOAWnX+3;CL(>q0QyR%V#Ds7vH1!!i1!rre!XZ?v z_tKOAaS_{>WDnZ3EqD2xvx%{;x!HV9ghaXc{mYA1PUJ><4P9O>fBiGrw+Oo~-Qv1p zEY@y$zLX#dE3-)M3fB7}fxKd8!sOV-b?HII7O%~B{^xFGXaC5N#KxiT*^8xDbxm$p zyb`N%pc_a*3+8z>@&L#h5w0M1Y4M2dDI~!ncEK_%&MXj4UTWGL*H3gCu4i{G&~2=d zfa|^ZDih%OBfH%dIHd8PF%?+NE*F&Nb9>S_#Tx`TgJF&Yh$@Qc^j7&Z-z`z`k-hr` zU7Cx|rB}PZu#OhxlZ6>TbK{NLQfBWg+$mOfS;Y3u=oz*^qgs{{6>j&V9LpI=sU4DC zddPUI!N^?;`gLqz>5l9vQLU*KV|C`r&fiGlBL)EICD$#&?|zSa6o z{rQz#2~EWP--;X&RshrWl?ERjdX*clU^|1HSqaovU9X$0&v_{^F|l(B zz$kUFaE|tHt$yek{lmGt-n0IB($o-3p&VR;>w{MJ&FgYt;7D)O*NnGgAUn>Trbsk+ zIFWAs>c+l`D=~`}FXqEL<^_t{mvdEwL|Em@NJ*W9EV%h{`LRcfcO65nNDv{;rR;kW$pHLIT}HMS$_^*RO-|K^wNU8SQC&nSbvI%e+#X!=sQkOhESBc~CF- z-Oc&z2PGaqe*DQj4eix6blbb8GWYJ07yxh`geumS`k@0SB<8q4$O_rIxW9VU-#$In z4;M?_>7CY*2VuRj(lijA*EsPh^*4fp!&_vyB||-4-44E}`U3v&b0dr9x4 z*3M6uuC0BqI9xnv~QX14pafj$a5|T1~yKKp_r0dw2 zU}U{~z^BT0=C2ioJlTCO($l5dYqI+L`^}piD{0#woT-{kAPMIgGut4(v-WQFe{t@Y z*zBUVkAORJzk>_@iU2c;IMuedl?L`~#BtX>Z4sXY5xGy@f1ZpFyuYT5kMSCT5Xd?? z>XOzY091T-^Dw;>LdnutODIxL80EBsI zC~q>l+qZEnmSq@J%5i7tVs#9CdOyL2N2*S|k_tYCEX0>Fzuh0YrUw~mYtM7<-4C&= znelERb%R~ILiS6<`Y&v~yHsUj(mwC_vZ?t~_Z+;7G68jT&;91+(s+9v+Dc!0YssfZ zq5GXJm5RPAnlGkMEL#DL&`;;PeAxO9`lV%!!~Kt4+qSd|mPA3VBMty`?ci6(BY1Dt zS6Ckj58N!vU$KA}k(JF?%8z*@;YGNNt1n%;v~gz8@NR6b5;UfIWIw|v4abWS$`O%~ z6B}6?U*l(__%Qb>TR7fBpIzUQ*NPwx3c>6zMf(L>kcc z{McB0btQ4A=ecqi4~CM@1Rl07Ed`ONqK29i8rZ z?5Fv+FJ@4{*{pu^7lWiv%RxEC`9d9j{Q9^a_N?GdE@jvi`^f;{7l+Sl9j=?TgF}w2 z@98?kx}Ah|k&S0I^O@gTQ4)f;o1CIF`%&5<`vZ)nHOY2NUlkA;i*W z|5H8z0cn|5{6qN7`lA1A?7*(uPWgrP(4xv34_P1V#RVpYtwW}(L-7B2-1XeAR4_p^ zciJDCBx=aWxC4PYPs$nlGM&y=o>r5c>rWZ|Up?bli+ZMxN_ng9qgTV?T6|f<1}CbU zex|{A(^<>1u@4>5VLaW&8J8_6lxY%XO_xj`aj(({ayR7gYJisWxHViqR9l>D6@kKY zcd#xv-L9}8cW8;jI{Mk-=u?Bx zAINhY-C?VfGQi^VacYcN5eE`jHR*NC+f{kDXQzvdlU;~&6#`n z4;Z*(%_Jdct# z#fDDqF_w$9sNUcN|Et~x>6rTZYAF}H(aMmG_QD;56RQBGeO+^8!|21v8`e6>OMIs% z-+PGbP0Ac;fy0W1n7n8hySWczIP%^jo#g($%Z0 z<50f!)4wh)z8bnl^NzAv$PwP;efNb+ZWrR#dx?}7dL$%|!4Pfh_Z?T4`uGE*ppSfo zWuaGIZjD!ijzqwy-YXg$BD+3m*0OPN_o*Hb{LltzR*I|9h4Nz*il=~to>`Jq!14YC zqi{#&hFu1Qd@F3R{l)cx*P+`oLT2wsadYsHuu=Oi~jV%hIB2T=VEKu=G8rVIIH*mj!p{%F_F~Q}^DWj>Z6zGFFoHTIgT_(cZ0=vrz8+yTh9^g6((W7OjYr z{st1TQT6fB|2}^1m74=_QRN& zP_r!uzqA5VSa%NF!p&Zf4F5d>QMpwmA8`AVoTMH26zNCGZ#O(JXgaxrJ9S?kOqR}H zqJtszx<(GxN0tw~q$-x&+IyIa`|+GYfMW9T*MJmxaaG^`{ah>X%g(!}EJ~vnUYBxd zfqH_@0Gd)8mohv#<}x^)wAW-0Xc)8FYa#bOgumzr0>RQ_jO&PV?{*G9p~p;5xjllB zE3+DPl*VVdL=(U+=D|c{}idox{MmXFgt%4`R3_(n;?B&d)MqebY(3C+;Bp*PX%Dt(Opkxr+ZyAC?w)HljMe}g~#kN8!b)R*ZIzwN%aZrXJbq;nXn0zSp4{4OjO+vei=I`4jjLle44F^|@YWt(lZhR6Qj7ud1wB9ePc`8x)<^3og|7%PP zZ%UQMv7F-<63SY(hZrDoHB%(eMwerBuFR^c){mXN5?v4h~nuNCm3d5@XwHELCWp^vzDs`))VFsc5 z8KMIAzu{~Bxeh$(JoB;W#K~x$aetODK>nijQFc zZ{i*(nfSc#*Z+D@9!rwQ9T6v86|)8{n5P=iJ#LYIhf+9ELEo^8-=npw&IUR~Jpc#s z^}Jf_m`Ko4RsZiB?|V)msa$re*WFnkI^ruOvt4Kf7B+V`d1s<^2}b2N97*c`l()g% zZS@a5JABfb?gK5*-RT0%H#1H|0~pXV0aKO2d!INZmp5^iy!MG+2cCIcP{teIe8t|Z zf7L_zHgUbCOYSq|+6r{=`M9qmm<5|JP&86T9t)2?x-9HhGJE2~qwUta*W0}+Jqs20 z`-t#Aen+yw;bRS7t9T9}f35=g1T2rELgF5llH z+85V*|GGWom<*eyb)F*SJ<1$LP1JjAUcaf#+R$(;fsEOE<<*WSuYRqpP2|$9yBudH<5t3PCNQjUzL&j)OQYukNibAGHMTQI+Dv_C@fz%^oDNUwLlnR+8 z5u41ub?x5wd4I?8?SG%=(BAibUFWdYI@hUTEffO14E3`8?j`JkA8ttovz{FB2&{6t z*7aT!QcKcn1isms;pDBr`Wnsl`aC%eAnCQYf?i}FzF7X!d}lq|Jkb29lMJGWrO^{Y z|BGICwLiY-50?A(JnPBheUPB(A^cRKj(H+_>EP7J_n?U_vtu=S@WOdT^0Ev=Y!L<$ z2llvO7Z?J;HNr-tFTGF{NTpdvQ``|1*o68SSNEknx$!aQv;rpFm?WP#jR@6wm=K;AR3ajfv>nLP2E) zNbyyW%vGV=nW~-)lYT`^$*IQ@LU6;J9xsXn~zUP0?^rPID;3OPx8~A2XX{CHQlsmf3Q2pN`G3D3zxFbR5tR=8QA+sp(n3i zi2daxN<|>ZvaQ}_qTD+ZAPC8A7x}HTFCHMp(7v0-j>3l5Iq8!kx)E~0VG31A>e7HA z2r<vm+uD+pcXmD+KNxC@uol7j&E^6^uDVT)9@R9Vlv_qGZ?F5exn$f^hcEIf z-6%#6JVZuUV+$$Dd4Z4;nN@CGO8m@xtv}e%CKPL-u!2xnvg&!naN< z`)oL@vraJeV$7vhYh!o+wublLT-AEE4cp|O&4mA(r7BwcUrhi)Eu49V7iV03PfnY=H9J*l;ru3T?w^!(E+{SU z(P}YM6vml`<(k#EE(Q@ZR}5HNL+Yp3Ix)W_++xeAuc~hIvtILV1HVALM3+4f>^SLj zVNd~r$~Gt(*O^W}$wb9f5@K~ShS!C5_|0ZWP~J+o$&~$sxR+i}Z3D|LmUP~xWMc7q z%%r7{=T-wV^E&&GMNN6DM)w$*K3N4r_|5{RrC@(sjb?=YUcjTVye?1f?q=xFB597S zG~o`H1h4G=bBUUyGb3fuG03f`ZoPb-zm`x^R;TR`K=K@QJb0Fcg~b638L=UxPD}uh z&KAxzPu`e+p!A(q?HQEG8N&~lRXN*hy*u`z_*u+Y-Zl#vBz^>nK~oJ@o67j4Qz;lh z9dWuU>sR}canY5_^1Xw*+10nc30xorLc6Z{&K^S6jO|^t*bb$0`dri^)P9s7Iu1$! zz66It1ssYB#-#dDc>}CbGw!G}UW$HN<+Sz!IzWYYOmC9ZRa}=S$0j65;hOZ{pFzW%exH8mDt z*krIOE~Ej<^1c|=)%NE|CA#3EN(?#Z*5J3uL4W!3 zrPrp1^2SRt9Hgy1C7}wVPS7?x2^QL0WL2Za7>z8@FlP$Fz}g#JG0$8sQ;`R_o{Krl zCkR-oVo7?!r20+uIN#tldeJXbun)JF^8n+CsV(60r100v@_ESKy*m(*4`B3ZUxE;B$~_{7Un|ERah zcXte$+_*O%p5A(33EETvL#0RWiSEpBDKn#`SgKYE!o5q>MN31|XR_iJ zK&r(|@l+V1RCk2!f!Os@gLmu3!^lvMka^a^rQ^K ziiFF4;_vm4)0d86FvC6@4SM#_T?%=XU8}fvJ!1oM^oUW#c7qTt$Dm&|Bq|?cIk*Al z6HyZ`f6Kl1{qsxlZB61m7C@c&*ZG@V|XmR>|aI-bOJjeCQ*3#WaM!B4Pq5m&EW z>k?u-`Zi8Rf~a;MKcTQd4(BTXY4nvz<>!=8Z|8*CY+u76ShDtuez~nc063zGSJSa+uE~=<2 z=|KbRx9Ry0t^B+tC4&A|Pm@&_1GboCT++6D(NzPzL?!2FI{)*_H{{_%dD-~GaH6nf z)>*ooFYoe$6B^l*oasV*HF2(-8ib)Dk>S$v@{MpYiAVf);YcHxsjp=Vws2`CS3UY0 z`YLWCiktLVw0uGfk-S*O5fXjsxwGMD41XKN66~I6+MSaU2>f@I;GJmd44?6mOx^G}a-OxAa8I#x@yKooHSGA)z{YNoF06gSj=W zt#NjCfR8{)F#-BXs%|>1e))H;&d^XOruV4uBlmN@eft)-%UFt(TPH34Z4Q>+e)de& z5)#gV1Vv8hsobiDZxCn|cRmEo)-`NFF?>H@USIkHMer-qVpcPJ3jIHU!im-J`SbI` zp3BKOI4iR5YFnA_2A5?mz_Xc>7YAN482>(KA6ZqU*M{Y{>$)e$ zb8wMRr~&d4&*R)Dj?~_BT~3{VgkRHm9?g~v@B#PljR|1$0iy*a-~QG+-l`w*ThUIH zl{f}nKEN2TAccVIe)~T^3q->8{AK8TS+K>Ckp`v)CcVPb`0d$>&x5NWpDfJ5r)}2)}?uSR7tDXH??w{USF3)w8+v43d@Pmqxq^3` z0(7I67&LWGn&Je7y&6Y!6%s|C5Ys^xgwNH74jn2F8h!~ZhmJr##J_6NvWPXSIU@0lJrcqUe%ck$#jLF*Y?m?wp<^W`nuW}ME9VOM2%T1$d3t2xF(IRHQ4 zJ!*IU*Tg>C&K{n_D6M5s!Zeo&c2Oi*z;gr+xp|yQHfC7-cdO9Mm#y`b(gVEKYe4cw zA{h;NVtH%+*ns6MME@-C3jzWH6-f`HhH5Qcuko^b@O``!cIh@dNBz>MJU}Qi7xNbR zeTFPsy9R9{0SSx{ASSNj!Cs|z$?w8KWm**#rlA}3;i&$57AV4kTRqo7(!McC#O^S# zBcI3ax;JhT>8$UAk&)A+BX6s^_vVeE^O_u$XA&4HzMgsa`?+s6-^tKuQ(LZFVR-Z& zN&M0Gw`>>L{2<%qXudVCu^15$RK<39R$Pye{clxsha;pRMLM^3d%4||!Xa_kMoFC; zZo~8POKFc#%B=^hs1Jxd!(+%CP7gaTWMTpOnt3;haF;C51WO(84ZaREbOW9{$%KT_ z1(hz@V=s2rKVN5ChuA=69S$hf@SEM!`Z{01nJTKul0fTu&*SX-LtBJQYVF}JKh+@F zLwXzc{rlJcn_{f-7d4~Q&z~BY&1Pmhdn9A93a!GE_^SN&N07O6B1V@zYlx_qM; z%fa8@$~*&os52j{ae%UpoQW67EF+F_WSnkb#%fOwLp@IPSIv&ioV;iF);%N`vA{7d zP%FJaO17;+K>OI>YTDX2<#tdU1-agk%newy+RBtItI>bgT|3( zy%I?ZwY=>b_m!j-(4wsJ8KK3Mf@voF+gK{L@| zsvDSlkzXv~RtQ-35P;C=$F~K5J~UDL_3y0+3U!kF1v0~UrYw<25L7Qr$RvwhdV|35 zL|TGmJM`*tMUh%0u@MG?*y!OrF!X?|K!o^9Rv3b%;4%J84~|y0=huOOhbuT-`N@6Eauq%d@Wszazu}J!`cWdt5W` z+~e~(&x(nYvaYFLUqDNuc!>>r(fS`QYgexp_q8{EA%73_U`{6X6yH7Mut^2g_`un5 zRUj|9MGx%D<68RJtp^R=&=1D-0j_E zQ=o&edFa33*MREnY2AiWrf_35xF5P$T=f_6X zBLBf~VWCRLaFIdN`5_B{>Vm*@7`YCv0O}eP8Og9VIiPVfL6`lfEZ}nsdj7yV2B-~-rkDt&7qZwPK!Xy^0 z1!z{~&tBjx)vRCJ96*+!fLrN+gdZ1S`fml^p=9mm0jDRbpNqItdMYT|vAuz&gnlE& zA($$+Y;B&`gD1t4_9|4lPiC{N4w?esyD_n$g-!z564GnHcH5!x^|EDZknZzh`2)@G z%}H!R+kq}nZ;-b1U^lK-DjIoeSr;D|k)9Z-_utf!W|LrSQ!zF9BrH@c`-5^w11gal zW!Wd_(mKh06lDV42S3mwjrC`E=3MD|!H_m2TG+>=Gya#Pcfm6`2F`%w`wIUZ(U zzUwm}`wS0<_vo8*<42ArZ}n1iT}0{FgI@kdZIE~U%G>93KHi*EoP|afzZv+O(Z@1+ zy}J(#M6_mPHTa1qMKr~jg__MMl;8KBvcpd5*fOnGP=9&t)P*sTa{ut--#G9y)ZoMKiP zjcEuo>y?$`%zHi2iAFaE3xaB-$HS9B_AO3F7T*9r)~IoAU9hOaP3gPYfq&zH7(#Vi zZ4ei*lJDRJydCGj>&Z;izrX*EA{qp7I^*| zzvuJUyl`phk)tWk&h)Ul=H8uqYbUnXRr`<3xqVs`=~Q8+so(duBa=gcNawCA%}7ym zQ^|S#P=RCM^UZ0UUNr7 z-R27hEuBJq9cQP$=o5uXWAHZXSB!6Dt_Ll+brvm!F#mlNLOA{4GgOSbUM@x>(; zYJ1J=tE)t+fEwFruApJ>1R<|?T1+_(OvBNz}?`bC0V96Gg3q!oz3p>|neCZx!3~5+hO>c%$SkpwATB>%b zr;08s+u`QsR+6Y(C@b_!T3R|(HPnZC{o$D*cgwgC>`OoZ!RRN zzsc>CfN;3V>Z|3C|0S}+{LUigP&qv+(s>HGrLC_|m_m2y4{rJOv1J|c04= zo7n6hct@pP{x@kJ2w>S&@f~;NxXlO`+VTYj8cx{<8DcjC9mKKpLAO8H@*JTiaC z?5feJp%2EfQ2Gm{V>yVG=!ml#e}z}5#4zy+!G-pX*jQ1hr#FUAA66#jW*Ri6rJ0kH zo(#MOPV~0{`X8GHC@Vz`l z#)^KY3rx-yzRk@$w^sv}3?Y5S+mq1w?xQLeFTuNxIr2V^twoK8-ZLGN`p<8loQizG z0#k>iuTktzHZBrS6P+FPnehIjqmy-I5ZYq;&h%U^$zR=GPw1 zpFz!H_L}C}az~vdw^B~u0bDSU(1LRWJ|=ZV03DoO8ceiX_>$L<`;BH&5{Yc9=gJ!9 zzSM?2*^j3ngef^!rpymWhZCCTm6)e#@OvLLX2HC&?3*3^Zyk4wr!$;wN=G2Kmd45x zX&e7`qssPhm}|684)N{BF{RcJ%aWQ3GAc zhSR0AeH#et;nyeIukw}9B=8uefAR2Ns@Nx(*QL^ap3dTg0@6F7+Y+=1;=?lUap}L} zLpui=zPeXqN@{lqJpYW^U+w?`XpG&dHefiT>Q+}ohqY-HzXs4hC0bN@&FY^er9_u; zIu$|FutnpBrG!bDCcs5gT|Wf;=O;dzQz%*Z#!>F`Y1q~&<9b{j!?{s$CJ)}s0wK(? zRbq3~59xHAot@elD`~m@BMtClY-Scu+^o6zW}y*r>U#Nl@$Wfac6;r zl&qnsu4Q}qwvNgBzv$KFgK5IgpvMp$I_9{ZXqi)))XoGZ)h}CW+?jPGiM-TSOdT0!GPJ9{UlxHeR`bga*ioB7onnu`dkw#PHAo{# z3{=VueeteW-=PluaCBVd=3njQbtHG54qL>;YS^Ml&v|3n+jJb<1O5{A*&WF0)G6~w zNU++z?&`m|7nj#cmUFy&dV2g`0>G%kk}}cX2+-y?{ZQ7GBm$7Vl8u%z_Z&p)T=*po z^L|kCIcox2ICl2Y6|^(P?{!%E0qW!`zr+)O9_KQtKlSk_0);njGy?)|G!vJY5|OWd z{udYYIk>V9Gl26r+welvB|S7euLt1>UHm~%oA19WHM4ct+wbJl>xd`MOu{lPcLiQ- zV$vC6Gq@F(yq@0qqVgEDveE*GMtQnsb z6p4o=)0dYAD*kRliO(%a`MJfr*z?) z-%2IZ{jp!=esexR!u9k!(Z4B2Epe~}S$s(GiLWPLW-$sJQ!E4L=l<9?md{ashUPwLFtlk>XlQixu%}DWAV}`S z*+A%bK;vz7XJYkGhEvP~+8Rev@^)g{2ZeV;XHEeT$a}g8Tw#6?o%_Tcqi1>o{iTFL_Gr?#O~WZ+lX@C6t50HBp!B-L&49F= zyKZy>0 zhO%}%2>y-@!@&S(O=hkqro=ykJ5NW!Vv8kW(hb?WW5cv>P^T0+&Fe?*qQT%mRZ}pO zy_-n&_}(4^S^a%jh<18+|0@~kfX-8GZK>cL;>?#YEiDAUZd4s8h!oyc(`bh}lcr&J z7;&C7%#>=#ZDZYKtrIOBlr$n)(*r~ecAiD34$_O$1TAVpp(d5jy7CrB71|&f01t1p zI4Ck<5qtf14E|f``gp)zn{e;W8aKBzPHq2u|`!iFH| zjzk8zcgQNJiHl#RXZL1M&1iLgLr~b(bPxa1Re~3eDRQDIV{^K3oT8q3K4kV&eHVdl zyo$GYj-=4$_IIJFqCbJ{joYuDXS-q9pj)OXvsZyHq+#LZ-}4@dVhe9t5QnHI=JOI8 z`Of!Ue2$#u1D&U0>2k(3p)k@L_0sel2~a6W2TXL0D5Kl8_Gs(ITCCS9?Iz~;yQWwv z_k%AF^;YK#l17rQrC;tn)e6GI* ziCD>@|pDm$Rf1N055dKPXgpD01;>wCMxNno)6G|HVmm`cEGjFNb1lJ}b|e`pcCziGQHmU*dz2zuY1ym;CD zJxnGGcW}`<<)oxS%pKnJcbX|2t6kgHB+;~ND-hS5URahmw0(%iZZf$%c2;i|m?jvx zWVb;wY~s)E&LwSac;Po0ARKDzK|wovZ_&1^Xt8&z8H_u9DU!u4b3P5n>mhFw5t;oZ zo|d2j5>*%;F2@MTsvrH&z>DO)*wn7|fymhO(N8AJQYHsbjyudw{wBIU>hE52vg#cB z2oK!f{}0uDlsi2M)ek+Qp`EM5w67GZpRM6do-iS5059vzw@Ev=x_%35#iq3HedC65 zNMZ^*rm2T<+3APjC|Do;V&&YhQMbwIhesWVx|S|`pkI9sZ{eWMDQr%N8=chHXK#p~exL{Bf3>qFC-kzbR8sv-Q z;I1?~0g6!{aUk9I#SV+C1GoDqfsqD}Q&$!B&uL@QEd6jpGG^W{$H^RRiTHEwyR5=Z zwI*o7)h3@aYfNU}fT(dbR-4AQCWc@qUDiz=iYI1(HVo{ciZu1}_O@4U&Zcmq27Ct# z!;N-AHYkRmS+g2Fn)L&cMrkr81f6qC?Uj78D%ove-d8iHN8taLMG9>`&gI$}4-7r) zrkqWGrtpvZp_ePV2BTB)mP&G@O|zptHVCS_*_e%%3*A2`y?lhnirOf*-sBi%#P zl(N!x;|i@J$?U_OXuZ6~0-j?Hj8ki24s9y`H;8vli2Vc39B;{&wG**%jO8`0n_L9N z4a4idkpqWfZnv7yXiEI&U1qJDqoE!W<7{|eLOA(MLCcKSXazz5!#Ei=T;$`3IH1^z zZu#S%G@eVllo0WplT)0&K2vbL=@@&d94?`(q_xk%YssPdIL*bd;^(LO|WFdM+?@jCA75Gngw-i&Qw>&CULBV`>J^gxk{6(r@<-rBFhnBJ4T~$O^ka^d**O-;(kI z6Zt7C0JP3mp~0Q{$*?Y*s82K81N|f_e=%NaR zD;T!Hh=F@xvVpV*IU1Ohz8Cl|@`lA?51Q@6gBRoE=cdMv&3~jUs+CmW<4#NJL!oEu zaF|H@hg`&oEDoxXSI3r7R^!s~Kk^!LY$&~OK1#w|aNya51S|sXg-a59v)_X)a`RCg z!B6|V$!uf{PDl_?ThrpzlN?|#k;(%ofX2(*e_C2J1d(>D*I5S^C$xTH-?$URY5rjF zU8LmO71^o*biPr}=s$d8%42{}UcPtrb?<+6dDaNgs%%bkX#1_p@o>;Olj~6eFM~Fj zZ}r#A%GfRHgVyAxC$%BKq>4rFT(nheNBoA}X4CnVSBdJ2J1^(FhKFRD@A7R&l|E=_ znbFW}SNK~zi6_$n)mOP4Mmj1xkwIrSFs75LK-xf^(Z&OlCqgm=6ya`06zY@boD`V zOv%QfYxMSU9+b+yNdx*;MO5@B87dBeE=vjDsz1CgTV%18&?G1A_Hl%eRzeO|Wju7DEyY7QJ-2}H7qxS3M6u_9`YU_ovg@_|0;{z&$5AFSyZ(xSu*YbuyWxSo z7KtyE*>a*%XfeHk$)*FgLQoW`{>7qKwqDPm=_VwL*ackB&-Iz=Mb}K6m z=<%Db5d%Qmp5=V0PZ4OSqf8>%RByBoudoWc3a|P4%0&^na-XOC9w60d+hC5YMLMU}69m!Xk5mJ;!y>5wG49_m!vJ|GFE0Q~j&Lx5ogg-ZPHvWY}h z|GW2q<@Y;?+=gSF7rzp3$v?JFPs!S;(?hC&ETfbtP&%qEWVY2|YhFS*EP3s+Obxt- z-1D16wr*X^UcXineNt<)cfE8J%y!}+QMT(rxm0MJiaPGq z>CS`u+-FDT_OYYPIPNz;D}_WV!OA7MPJq2k4It+?&d#xTUo@7p2jNr8!(Xv7ysh$&h^WCn zA&+i;fFy;Od<}1UjQvi(kz_UZQ7A)YVt~gE{t@Q_KhH$~Z34&$WpSbZm#>#RPkVkC z)gYk%cy-nyLQ;5zQCXIFcX@0!|MBjw68=x;lsfqCgWxN_#9jD6(Bv7KUgff!A^^0 z`F@~k|B^lwt28}R?@u*#@%d4=Z-0xr7;~Zfr z#2h46r?JSQz6Sb9g} zQZw4=N+B{Q7tOQv?o1IH-K&s>WTNIY(B1R+NQmK%9o<3vfFT$kt z0G%L0L^;5p#6+o(`H=#Zo?`>N_UVE7Yp1zI-|}4VEUWK4s0p3;)-12Mh1xm<9m-Y9D(o}ZJwzyoTkG@knqg!+JD;I{c!Rrb%gr2+iqhp%s54_A;EtA zmCnMni%4f@wTykml;}EP{J*ekC2IbnnSg2pNKetHl;|Q5ngXmE>ui&5_ zsTBD~FvV~}CDGbt5LthAkm1r=wwmfcy9r__ozi^~iP&VO{CUbM#%xx1$nf=HH1R5c zfpJnsH{w8ULY`z7pDx*F#jYYldAuXJgQ`=UM6b_m_9?Ri`Uh#u%ytQ z@GPeljSF-3JW4HWf4=O8;TY^JMnCVN;@{WD_sTdr!iB`p5`B~6j<_3#*73xbbU?S% za|)cabqNNWw5zvLmMVMC>lq2s1Vt>$a|ZrlwrMzfT!$B<(mYDXWo+)U5%8URgFc21 zo>(3jNMsE6j=@v_4^zbi#54Ka?J1!@W_jf~0d3bCJn){KbjzJ828@R-Ai3u#2The8 zvugP@@+s*^;Z!ATPrLnlFy|d+ss}Wj*9j}ARZKqK$pO&Nvv+`bi_K%EnH1(sAO7Mc z()!FxY@Xjea@5#1v%3dXTky{wPO)QyFJrB!%9mBI93=j+g~J2n8Kk1F2qBuwndg{W zkZ@m7Bw`$}zrZovoTZ~_Zyx{^pIs^IL=CdaQLi}JbY1^l$E{c zl3Oj>VV1IDkNy{k4@1DY9e*2VhNgorsU<*d3>9>H){OT(vh1nQQVwpw_rC43>f0&p ztykXQWGy&7r|+M3AqASXGHD9+8x$>1x*j1HQs-UBdJA!Y+ae?%-S7eyC?$59}6LqltNeBbt!tYlL7{9Y_8!kAQ~BmeO*Lm=k)-+`;PC(B6}NP0W8(k%B_JI0ED3Bn+nAep;FrOJ;K8C{#^O~wc= zjI3x@!ho9dtpT$Cplz*AnDl6aF3RHb*FaPsH*z8a(M2}$fr1a&)+p-T%hlDrSLXRU z5KrbUndbI2BH5Lba9uFYG-@sX#x$4T{qmCt0cp;oV)AEF{+=d-?Kv9PhZoJX(tA{)a_?_>Y&)@?fu8X-Dqfg3LmJpjEU* zVS?FmwuOd+dfQ(9B&G=2aaU<=5mUU8Z&NSDzb|OQ#u;NvDOgYixLj|m@ zos{crz1jORS}JX4dnL|TJ<~svL|!qW>Go$|QX7sQJ^|+q%Jb;e9n-S^(=b!Y(nNXu zG(FgiuLjVbqE2%D^6WJP98;nPMQG8X(%Y~xdjADCy10^`S;XnncPLAb+bqpSqj)OF zn{=i_{NCz^@(&$tcU49^4aivohj#Rq~cEYM<6)#~MTs~0! z<@6t3tB?Nx-+R){!`B%reGK2qtaZMUwYV=m{*2Q8A8?wQ+|9`R+no&!-KSMzCEf7f zZ%qc9-Jr{_$TuI9E9K3XsKb8zESap^qPh~#AxJIxACr?KtI^_6XXG%&TirC}j zCeBN(jWxUajQz+EV^lTcM( zVVxV9alQe4laZ|uoLVyD6LUNG!*U_R4e;NUzh5e8HyWPnLG`Juay|=DnH{e~Ol9eN=Vh#@bO`j-d0HW{D~)AQ-H=7sfXF zVc%aUH0A_1GBgdnF)#gPF<(jmMO)Xc{cWpmvjO3lni#tE368JI(#-b$j$|K#10r=N zNKzk6=!`5#CVHXLA~IC!mZoIMy^qtC1DBTWHhR$hG$K+4!M zJC!N5O`OCRo`YD`Ox=e}lhHUAfhMhauPWxys8b(X2qe|KB{u(}wWX5vb>2L|*4{S1 z@{#PFSrN)=wK#v1Ki77_a)j*grarz93YF?Ll&&LtFS59^n+RON`s(cP<$7;lnsM;+ z-wQ9ZBBGLV1%B(Rsqhc9J^IJuj7nfP&>v!ZfRDU9Jo^4~&oYJX=PwBS5IQyx;woPf z%S17J4y!oBKEhT{cpehk-^S4-CB^r$_af>D?+hEmjJp^`6qysu#P^PuOWws05*^$h zOhlnmyMx?`F53AysihtUK`rmx-lKrYlHYSP=QX7~wfjz~MUIUR@X^9L@xXknP6vS6 zHu-W(daTkPn2i-#%ja!&OqqyU;x^hz!#d!_F~kNxx?~IT*=%^MySI%?fO0F8p0CXR zFo-({w7`esp+fG&ho_IS0Hx>hypqJB+nT<% z>aWSzvTX9_H_>9($ixa=9BO3rU1${tnC7T5o>wT+z5e^WAg?6PD>kjNWqZmsBYL&D z1d145Fa;DpUKkX+M|gyTPH^Vliup@b&9X8(Mx%z6P7ua+qEWWZIQD~=jPW{`FWUv> zmgT)Fl8NY3x7+(a`&v>Cow2l(a*>>B+&Av@Lv_2z>VSfE3bqp? z-*sIC$kJ?E7019k1D1-LJ@znC0y%yhxNC5))#yvL?i#?19Y!XxhIAapc!k*aZu$xD!J!j zO5qMi5gC~s>b=CVE@ZCS4q%2ZXmNaov(wbe|K2vZ9>@MDx8YL^b$tjhWmFtRm4sT> z=$H&J$a5oaE6jmR4vJWCQU9A#x6niWDB@mHT5; zUOl}iNV8g65$g2G-Bn-<3f`9zK}wi9N-T`9Bd$T(4>FhD4X)~6z=TtybYtVlxQ}l_ z2)b(0ET?kv!s=&wwCCEc8;Km^19yUx@A(q5I46PX{#n7R?e_sP`Omi45syx(Ao==@u2e6 zlg=n)sm09zaS!TSCw^)i>BkHW2VKCqlv2!-Ln@})@st^E_s%mbZXhVyXZ@f%_cUKj zOc73dk6`58zg6pO?+!Blm-KRu<;TPAa$gC)tM!fxvssndRzuf-6CEnV;|Dlg zXc|uP-#}Sj-YJ4wdY|P1o%&JjS*1VW)@--u9~z%&hPuD$>0JIORI5mw;CXniTX-TdD2kOt){l~0(XA@c`@BF5g`eftCn4jyySi1q@g)_&Wp ze9LshRb>6Qrc^+W1@}f{T9)2AHMz-KJGxK6|IM6VaSR!y6ZGHgiHkhw7vh_91g)9a zDvX^BX=J)*CRdPGUvknZyA$=e@!$b=zVC}}q$O!Tsp?06LS{WDzkR=lHqLf46~shFT^6F#Np&eL?a`3FmRrGbF*R+|l3t2*z8svWhc4g?Bm)c&P~wV}3ASS?gxxeJ*;7Lh7IkP2yM zhvf@lt-jIz&jk|6%S%#tTzxb~Nzw({B%aJwaW4DCAZ}!#v@Kfrn2GU&Ol%=WD&sUo zrZ8Cy%-gyWBI$lNFrZWj(W!p9%r=pM^@+gbksKv4sdKK4`NB?NdW5yT5{j`k=e;$H zHLe)f9odX&?yY=xols4sLeoL@YHvxYRVG9{cy2oBAvAu=hBGZkXT!oq+HKYk0}W|c z3g%>eCF5m27nL5NFk6z4#;WHf8=D#rcJ4j{c67FYRe^q!YpI~!HPSetrEvyQ^0;T0d zMMX!9DgzP^DM?LTlRmsi^)r-lg~uh7E*(XJ&*)kQhPuhhO2}jDOrrP(jf|Rlb{YWW71dwu8O~Ns~YCAY=;n|C5-N+jl3>z$NWn zWSKPsj`&RKyF&M&6Bt2pHyx3fM?pOF>MNk~oxWrQ^~aIhf;fuej~#2IeT8y0m)-He zOaU-*?HjKeH+=tQRO~*mK5t)|g+ih`syeFo>2N@SBSzF3@RP4VWiC=2-4CGbNuTfR z))Ois24UCZ!aGqTln`(PBgyi73W;i;bKez(G|X0Vl_pp-wI8%@K&=#5{b3{$ue^F> z-~e%AKy^oWI}%kSm>{m$(0Do-vu>+VcCNzOvFM1HgL>!&tB_@1K_7Kv%_(HAV5)b0 z7a*eE8U`v8+n1U@=Ak$RbTvZnN*$Cn4Yf%=Uo4QTVpW*=-HaV*2$HW*x99`f%;-@d zTk^Q@RCzGw-%)_-KDd7Tl3y~_*O{<%gTW8T#zrz0MTQ#OAkG~a&UXX$Jnx}HmOWGd zG%$vd&Ck^0GvTNfL&%*)qH(-a0C$pb^WHr`*SP5^=c3>)-f;z#;p)Q;>fex|joKSp zQhrd~^HXbO%)bB9SWeUf_Pw9SuvXH4dz%n#zN*m~?SK6oxZjHf?kjF0W&j--_!66(sM z^DM;#%1XQ~IM!_QMixmbbhWCNZ!`1$?R-p0$&GN)jCh0akigUX)zo=b`m?wu9w9KqDbqk zxzU?r<&F~fQ;`dQ^5R7Y0h?2&&ynRp(w1w&a<`2gJs*y+{o6>V7i~)Gym?*X<70Ij zeO2tqUSPteMhr;~ZB!uo*Z)Rquvl@wvTUS69WO<{n3~?^Q26RM8|2@kdYk0;xZ!v%+Insg>pjbCEKfG11{dZ@E}A>dr1SC=cN&D}>%rLdp3|bOj{Rz0 zein-&YDjh1(E!4raK#qd4hd*wsGG&}v~Son-g+*o5lRG$y~e4vO+MfH8y+6gT}5U} zFH#^5iz{ridpU699BLGC*@6@G?YiN$;k1$u`?x&{EHNBMnqXqDr}fT_Sa0-Xf!k9e zt_S!m!JyNIZ{|C%nA(7uH?ZFs`w8tPtgSglR}A_1AY58Ow_T(koisuHO^ z6gHM$`N!8MU8y|q^E$7oO;?VtHL_0n@NsdBqUXvs68a5o1!dNNR*2WZ(qf3e$P zOR}g_|M_-sV|3%uVMweDEzxqVCU;e+#|aHP)B$t@7&M{`Y3)YRk*%l5mASaBrwX<7 z1-g5Y9?Ax8GRIL{y_Gm*qHK62vHJy-7J3jmW_Y{^x;)PqP=8@=`U&PtAM(l{3~2d& zjgcFY98!VP2O#Yw>^yUG_4-@`XgYt^_#~&N#D6>pMgY{(fO1lW(GXvC0PZljk=hh{}sc2n#(_c;lYM8gTHjwci zYH>Yd-HcA%&gf~7CXn)__3ic9GR{l18iHITm`#l1#2B|%CQHKej91g=8R?LPGM2ZV z^C_jzvf@xwtd&l9J)FhK$?3J}sH(UEShH_`>%PmxHgcX2=}i`L|(jjp$E^%SD@$U z9#*?q`HVMqwd(^})b-A_eUe*fZe_FQp=KJh3|EuF;-4>#G5IBYifDs~p5eSAC(vf9 z;3d?(cj{mRwC+g%`8J?Jg{&{!?W-Q_h8J9U#w9~OqaJ9!XVU_um6dl*YkFHSZ@EEi zTy2@X$yyH#ZyRF1E`8`O^EXa4eGL1g_cW48_7bmc4Q1vxZWAWSw@8c3Qji&f_gt$C zT?NbAdQhdu-fUf|l90;{UWm$X zvk!<$Ub|CnyqY`zd)bRwsxJUWJthpBv&q5@`+>aa#c@-m~5IDFBlG2^Z*n6 zHeY{rOW(+ag`F0btMnOGEi)X}S6ja>brCCIxb;-^Kw76sI@Y%g>u+MGT`7(EdV14aQ^mS!+nFo(E{MmRz5Kz*v2F`iX_rj@xYw(i8iE(6j{Rh;TYoOb zHp^d8BC7}Cq-2KqlrIk%Q@yxf!FT@|@ zxO6{jIAh5buJKH@xjTWn;))^6Qv&-!<9jNX&)rO9nR3}L$OS+++)t`~nabEdKHJfn zQm#Xv(VO_2hCbWlrfd4iLxnzW%jdt;1vg;d%C_ccA%pQ_XR{MvPSB>5XL#4sz=SzY z+UDIB+{iYrZLBeSJ2NPQw_MBI4tVu&j}2=I3KuZGl~F{ISAT_bb0YV?;TE>nEpJ#y zd$!^&^!mhRxJTI{Jf4`gBou@iw~=I%)!E-0!wz7-XCrptjTJXs{&4$k&=pF6wTS-3 z>6@!fd}e=FV;9lk+b9SI<45;ryFKSWvwYw_itSzvlQ%(4Z@d+CpU=+c&TJ>6Ru`GK z>})_KQZwVG`-`U?3Od(l=f@8KmoM?-r^dJ+Rqp)kdb1e7&;%|F<{;f)-VbGOSMPO4Ok8*w0P(W_L^=VT^Hx~fJDoN zoHsfUMzTJieiLu+m(v(?Ae-Cn>-D`|rR&%qfg#*nuQ|P0kzcN4B(M=2`L?JhU&FS) zMu>80wR|CW&y5_FN6|AYytm47uAR2Qk|Y!~gM|rI8S>LG<@fA$)#5RD|I>#OaQ~^t z;I1s#AM~EJy~1@VV`o$&p8O(}+q9YG5$>`}nXhkA3~IsbQxaK0Q+LfX_=BK$unR)( zvbDMx>(~*&&t*_;{>)}|w@E)bsP9ZPgRr-1&Z~!Z8=4Uti@y0KYXCJJ|+?RwO~yp zPtmj!=^y0%$X=JdtuePA70ZfZG5g(}Q93WU-+e9iFv(gU;<=YsmVG5U|Ar~DI$kp^ z1Y&J1RNXJMtE zlJ<7%l&nR$*=hJf?Q)HdKC;Vcu1yqQFm-2?Xt(yhZ}z9KA7OWvM3MzN`*UITug5Nj z-8<@IhgCEMb$fKgbrO|b_}a%E^sr3`<;^V=akqZca2ZK(*@57avs}~Aj#pMIbSn7Q zL#XAj7;xL_m_w^i>#(7(<0ZMMAa>*e3EZ?X|v zxBWYW*Oz`9Be?yd@|roQ38%&G>@(Q3FBw_SHCi#>zWh{MWEC={yL9vpWIEGwBjOO0 zCC)bWG&NF1^-jFc0kUCI3QMp*@0Jl>=1wkgj)#hR8bgq1|s|7~c9LGX{$2MXiO|Ml`+=Q(v12ELG}EjS=!eRz22s zjsMKIvNJuQI7(Y33g$4vpxPP4ci@Uo(FKpOuMbj_l5&8I)nd$o(VUif@3hI@3+7;o9w(M z_u&Ez-U`fgIilAePL#6ylT7+X5AV2To1Z6=WrB?Zhu*#%M=5fKY!od>-jj-aesOro zW5wkq5EW=O_Hv+4Xvx6?qv()fr#0qTqd~2YSZ#P^@6CBiZ47R3Egf&(O&PZodapx=c1v%x&cDEZAQd45yOe6(5}9z{|!6nZ9w|GHNUHl#Md7L27?fOLfQ9 zB6+ohtrk)$3>i*;Ub1T`&4ej;GnghGI){30S}Zm7PnNFZLsM>4#>&-l7n>9S$2IzM zJSdw!ZdG&cDkJrK3kb7Y`HZTrp7TfWZOCzj~ezQTi(?i3YFWZ5fa>FD{V z%UEl#kvM<7udr|nb{tSBYhtdjj(Za3POU}-q0gaJM2wZlE$2S86JkDe;|{hGhG{MCjdMF*t<$8|3r zF-SjHiV&9x^RW-xHWb8XJU(3@Oq3K^>tFTM+-jkn{eNVAcRZDUANOgBhK7_f+bXh3 zwo<5!qO3wnqCs+`WVDrJv}_VN4Uv_|E=9IuG>FPNBs(iS@9(+P?|z==kGt1>|L%V0 zx~}i{Gv1%~XTb~7O-wlZryMwibl3sA+dSAkhcM&QpA_pzC~9p!2Tl0OHXe13J05%C zINM!DI#R5@hql~6@vR)X6=%d;xZ`(tdO15WR(;So>TGXtVDTBgEgY! z_ZQCA+k+ms;`2{o@^sXe_y(3ZnzvxsDC5yBgj_)bOZf}5+<2JpM-)YNIqh=qM9X$3 zqL--!ts+l>JKD4rlhKZ!efd~v@2O~S>{Y7;SGDsR_lcd7FTZZuY-!MpzPHxmgjzJl zTYFdO-r;!^jC!u%vAeC6PwwbwlZN=9!<=)R^2E+%tDeT2A3J?$wsD@iG6&cfhW8xf zEnG}Tp&h$Xu0W%0(=f=W{J}yn+$K}+yHA^K#FJ`ODMZ~9$ww3Jug!G*!ops@p#$9B zmH|6-z4e9sm!gWWnnm-S-xx7xG_d)axYryF+X`^7l{UZuy`PWA1&+R5ZfTVWY_}Qj zu(RFx>XGRkr*@5A;}YF=*TY-y2G60^0TGf*3-y!{=9X*Cyno#(NB5y=>gl|6*qGnF z8_OGeF%l;5;=ZSKm!eoOQdL#KWc6_c7Sfx@u ziKgdYG|TjvfmrX*uXm`c?q9{Z{C%{~`&(#=Xs6RO`EZ{b!;jm-`j{|O76pDghx+7; z#vV~dI-M$JBK3imFQrnSgo}e}`bL(Brq`Sj=?GoRU5u)SD*mi1;qDJKoe=L!kJbS> zhTczr%v*gmKegh^`s)cHgI72ggg_QP@*kJk^W0=3_AE%2pdhg?7IZp~)LJhyWI4XB z5NR9^(bk+EgI@^yl%lw8)%I|CmCeW@{=hu$Z-E^NTOS8M z=@FRzMBD0X)#zH0?fEz69{Zip;9H-s@~2C!xBf8c<(5O8${92VJmluwv7&N)|6gd} zcW*r`5^^9|no2((Wodyy;fejLY<4-p1@_aScGC)q!iS~5655W{_v%iryeq$L?Q17p zXx&afWB>l6!ApC_zc--@sANOdpWCdh=|xwHUaUy`m9G_zs;e50yYt65@zGBART}TH&{b$n zMaf#!(x7^M!5ZOy*P$l=XuEp1k&~g#sUV7iYi=D)$9hv8b{qn>u z?KMu9A6nB`4*>a_dy8+K#hNry<8ie6dtM2)tSt>N)e_QI{Qf-UD_2nn&bKZ5ja-4w z{U~g`d~#06kJJE`AYSf|O$gyJY(0F>cfg}>rEXKZvcG1dRJR!#neLxc$r0K9)>zx> z7{8RI<^zeXLgq;*Yn%ydt>BFDt-{m!7OGPar723n=$%UGNXClImhY@ZEAPfzVA4&| zIQN`$0bpD24NJ`5DpXjwAuC4T_hFQ#`9R#ZbOUow8NTZ^B3X`XOZ>X1cA4!!MzN4#L4xcUaK&7*eOia@0_nI}iuRYbiy;=;riAA4*3TbvIxn;T5 zYfcN|+Y&f}DOZyKHDo$P%tQ)BxtGYSdGV9%x$Co7S&1=Sp@wGX^7s$G@;!5V^`kpm zpgG0eJAT3kF_snQ-)>E-R~c-W5_-SVa=O*1;H605F6TQ}fVdCm|Gu?}?1@FyQx!N+ z?;&>*1T-k6o@qaBd#VTpDR#Fj5z@_DEPZ!_`PX!R>t)C+HD^uJ0R0&PQkms{>n5?i zHRI4C$0d3JJV9;B_sL{6onn~`ySPZygI+A3SQ6<5ZJxaY(nl6{kYZ7E z?gz|* z6x}2`UoLW>V>_k*Np>xL8FTg(JX5yO7_4atocm;MAKH%u^Lymg#U8j%jQ2qv5}bKKZ=ghF7!PTn$9(6 zs9e@S@A?AU=AE2F^Y~~Lx7H^oXqtvK3{Z# zj%KT@D@RH3hM66*_42cA4x(%}Iu79^gDJJWQ??4M3YwRk8qPZtf{6gClJ;tt6=3k0_{M9-FQKQi1~KRb{mo*1=TyK}>4%T+ow zO%1TH8^h1pMjf}HZw50zyC|j)u@#3PZ1}u5lAV@5n0+C8mM$u6D?ILro=()`66!yG zbtbEQTWN)&RncMx{`q>XobJ9y${fevC%#%~0NPaQ{ZjsJxBLbW9VIAH4M9>rpvHSu z(=K8*QRoWstn$jl!G57;BCop3uR_m?Gs%%RhggN7LMn@{~>C=WW>w zP)F`73MV3D&z@g~CL@WH3w_RF17=8P=17S#*5DjGQ&+TD*7iW<)#><0why|b_v98E zj3I(--5Vv!I$k#}CB91?fr`xgCHx6192N6t^=AF)xe0$L*c(*74bPr39(#muq-8r% zs~g{Ha;?kmyG zZ+}=!{UandKo8#a7X=H_tA4P+F}2E=mv?kyuPaoAk`0W`W!vCntYL8wnBncCJe<#m zbp#H-e;Q}lJSaOi+{fbM-G&O0+Eg@yV?JudhZ=MDlgi_@h*u925eJTILQhMf=z&)+ zY~FxB{Ik~FXv2Y554a031^{ithkwr#M_*J2koNx0cMjknq~pXy@@l(02-iL4j%dlz z+K9; z9z{_yWxR4TA4#GPcjO%Id2rp<>7Q-!)P-%~jvfiL<$l8G(L2BudBh;DA?s0DAsl!2 z8;qzggug6K7T%lB{Xt6FgJ&1)z)17B2if*E-LsA+T!%8ke3$8Iq|83lyG1xLtUxP{ zPwD!PBbxE{NEU{oelx<|xPGF`_bZ!Z$H4Qc zZY_TG(*PIvjJCuei+Hhqed8b|?sTA|KED7Zhsv#*X&Im+N}TFl7Y&ve0oZ1LI0n-t_1=H|w8RLCgu&j&hza%Ac96-Jo3RwO5!mu377(S!8+`TT*YoMPOH`C1(avL#1u zuCg>fZp=FZxZ+%6ufevpexO#hrZ*%L^Ovq8b(Ke<@Mi`_bDhD41pa^=lXoI$$~=YH zJFNw60)FX#dJ3BZe8+&;EQd`6b*9cg3BTTa;BJ1AlODb?+XrFA`?DtH9pCy#!>;hK z$ru;OoHjh9XC+ zfE`jZ6lbjJ5KdG^U5=@c?N+6;UD^C9cX|fjU<;B~{Vp=^f-%{CBlrym!JUH{z65<- zzpu6V(R=1;m8w$u`Lp&}vPLkPO;3gzvPKUqHpQHU(8;te$-t8@FtM-MS%jGAsay}6 zqG!?u1IOIv@xz#B=xA_#%5u*FrBZ4ZGEqibxzhT7m#YImvLSh$)e~eof`3E-Y|%PT0@@#NxU9B{ zcHINrqyfm=S#D}VfstIeOV16G>O2ZU?xJL9QRDh&sRhOFQF1n&%S*o;S-|4+w%~o> zL!6;I4I{C?+~u+^Zo55snycW>2_M@6Dr9E zrsJj)ALj<7>RM%fflK)CHDnTvj7To^dR7N#>R6Dh%e5X=qpg3s-f)+|uC|eozt7%E z%~Rk|H{5-Y>&|ox#zaIXUKw-ZM#%F_P<74yb-wN@ej&)9u&_h(llW)fWj_EJ+Ur)` z+AXbqUgf+>gs63ZLIO~XK9UZPH?0R_C*vg+da_?;W^A!5piUW^@7?#aBXJ;mFb3UbcQE!dZ z0#Zq(?IzOJ{wcfA*lt|(Ni>~lwa z=eT69Apucx-2ePX$LEdGVP>c#VcQqVe?aj8bI9wGB7Hu?*IO*;J$@T{kP@UL3A|{H z`2A%^>g>9?MB7dvCQy#jdV&&-Pg&a#6*;bTQ4QySudfjeyUkbHe|);f`gq5)PVa=FN#fL53) z)$1o{__~`QO!|tCsDGc5`0`9^S&k@5L0QY=)CAKfK0A!wQ7$T)Tk+tm@SKt@yZ z2Sn;PDm1z{h6bWX%(n{0PMzNbOtG=$!C&ziL+h+`7@CD**`ING!^d4b>gTnbjNtk} zNF#2WVOecKL((~sJG6(C2li<`to4q?zO0F`-RxB+y;63hHGEE1r$PH3^jyw zYEkQ5$A4!VCQQ@WS30c$nE6>=CE>sD}Aoo(FXF`eF_ zc(ykpk2dYO8WDnm%IF}~Q40bn4Q09CfZJ%>D{PDX5C==P{KbFBaKHCrps3?H@xkv= z!Aak#HD7PB609|w8~qJv+Rj5{YF_2jeT9?`OXB6eBaSOh$}$wGzoU%Ff~wybJo1<} zyjN&zF8H4J{0uVljQWBcY1#8f5aKmEg2T4@Ny79;71P;rk3S0@!8%2Ale`tvH=0zW zGRNols7m^-LH&!&e<%LyYsT?+Or(V>*$N9QMk(xl+(8z3$9>2GXfC-x-TW-nQ3N*m-*Wp5QOtPGtY~y>b!JEn)jTdKc zK)L#dbag8>%Y-o!ArSU9e@$HO6q@g1&}X^``Ry)kUW<||)@7t4+hn4iz+DH7`8N#A zTXDO#z2?7Hw!CVl6h>xpP%;wtc^9Xs*ZrjpZV?JU5x-C9s_#}4A}8PnkDV0^Bxy><#|E;pZ)cJnBpU)N(YbE@)qg3Ez@U#Z2gW--(3g6S+HI@x z(gkRGu>bw5?wM2jOk`vvI<~N>i#r@k`X`KwvAxDX4w}*sU{=D}9v(J-2yiLC@Om(a zl3<73mk0`^3CnW}DoXsY$%@N=^hM3Uq@M%^V2s}!9U~|G#V+ePb<%U6ScB%X!#vr_ zq?1V^^#f>!|K_!1;|F6f?+zHOkuh?Y=ZQ8T1sr*EpIjM|$Dy}Hk#dzD`MtJrzyqdT zuHL2h78CtM*%hciDm_E0DNlS(Dj4cWsSg3`IZe<+v&y(klZfG;RTZTV9})MR>Sf8!{|EZ#qDDjlhk^4IXSZvdxbsY+c~MuXjLX z0AV4@9O;9SR=|{2Sp{cNb3FbyTBI+>EV5WCw=P`lrNqDS%{OE_aTEu7XKu-@827!|XfA#&^L@SF|Yrju_htDoI3w}yR>w7IB% z$QZUs__mvVK7WOQnJ3I9y7a<^NaYk^6Od9xu44;ixaieqgbNw-j=htVwS4yrUGf}U zk4GCpj7N*rc8%y6xJ8vt3Urh+z^-bE5$%2y{Tm;=e|a1APGmMjYV&lCtK~OVawo8q zHU00MpUb8lL#B{w9i1uPtx%8K%zxL2AY68a<(i;w;fHXy=r2Fu(7VP^Y=A=?$ zphFzy6C%SeQc&-Q9UnJ*{LD@{$2-+-4S z?3IU=aYV~ZQxW#lb&Y%g1rv&D5am;5A1<$uy4-McL#DO2+@A7OhohssKh!^KWo6d8 zZ=OmM7PNGE7?+v@_kHN9^I4;JH@bXIaT`fFY@UAvkh=NL9n!w?@7O_EnJ@-DZMjp& zn~*bBidN9NpF+-jZU({)VhDNEmxn=OtxDv`Y=73?sCZOL1UWQ-YL*vc)xinK*?+&1 z2+BouOE)U9CQti>8Golxfj>HK<>j-Ii+6o1A)>OdB!wLwksDy_+j?gUX5VQG?e=OF zA_il$^P1thFEl==%YC`=!S&=F!h8gExv{H}ydWXQ#r2}{rQNY;$&9UkN6>76Pyw*| z0ZR3)4s=}O>7Ue{fJsRXC8=b0A7Z$D*b%}UXZ<8f36^Ba_DZSV26&MvPpx0~-b9HbJ?MpM6s7WvCv)@^*$DRj=; z?XPlMfgM?U$+ugycK2Zn2;DQT_4i_Qs8i2IJ#sJ$6dCHgMp`3%iUNp6&$A=7A99^5 zu5k;+>ibAx;du`>^yb9U$b zX*DgOq&x{g*H_UcV#E#0d+`pI$Tvm1lOQbnJiO(IjZ}!`DU9r9a)5}e!YN>+xa?@> zJD@d3`MHb021>Vtzl9-p#P}%M1&O}1X~YrcA>nvd>GCFA!Fgoov>E^Ifb@CMv-L?? zN=xV!ml`0(8@Pq?bq9A~3#%$aO7w6sPR%*61M%b?wxNd*hv$&&B$aS zy24Pzd#v-a1VNGu0li-IzZdcg;f+o=;S6dffxV1JopX>52|VX!XkINhQxWC5GT-)w zQI<+-=r2IKlf&sCs&Mkx|J^CYq@xLOY~rbJTOH=?B!Tk3ul|x` z6UqK+Fm)4Ojm@QS^Gxlh@I-+VPlh!PmP}rXVa{bN)dSeO`aZ-RmMjzUg*Br=EIZEB zp_`3tsk#x5S$F`VbGRZG*uh#w3*r1Dn7-GdXeI+0+W_BUKS9v#> zoft0A&61l$^IgN1KWHJLf|%Srb$qN2q^)E}f2o7~rpr?=F%j76`Y=W_k3E5j!XgV< z+mNp-PG*e${u0f^!PB`H!pPLrHXxKZj%H3~UmiBe0CDAm=F|>DY90>W7&X^m;HsC8Z)WCj+d5{8Et&kmm|~wusD?Q^Up&P) zb=q8*1>3R*7uiw>6`yeC;BCYHd-5o14sai~;Kh%WY`K9X9Nfxd=&l?p;qJ2z8}rR9 z@c1W^Nx);wMPyl)jpp*6gR#FHWasd2e!#r=iVPN#<5-E(*r!x-J>or6&!PQj8fk@i zqJLnfxh2V>WeL# zX1PKPRqA?otO5?(=qhrtkLT&!ueWfSEV^*){SD@}C2BYDQva+l9hH=h#0n$J>Y;OE z$5zmPn1ciDM*>u8Li^!N1M`1s3@hIKm}GNDXS*jE4$3m*%u+ysAIjqbpM($`T8XbB)(0JVkJ#dm{tW0L5r0_H{}F$XIjwZz zUx51uOY+bFint>HTZBLNJ$s9~V8^w$$#i}#_dRgW7X~n7&n}jYAF4_1JC@B4e*5 z^t$`Qy131_z_MVPJy7ae2l1UhYg6_A9Rrw(81^xMcbG6o36=%K9Qjy+#@jS;1%6zS zVEvymFJ76E?A48mb^yT1=nrm6?=4Y?R_SdlSTN|WX-0W}3}}{sGIlYQ!YyU6&Vjia z@mi&grbWcBjcMf(Y8+6YI(&0+>Y8|rv;C)wvAZKKu~h(p&*ceW@ZyVvFhqE6CTF#6 zLnYfM`|ZO_!s8_xH=yNhdsn2AR9Ro-TX-N`%Pe-BtB%@Lx3rc!US#77bM<^pZiJ4T zT$l1oMJo7Oqn!jtc_ror0n)0R~9xZX7+01#l=*-V0KknPMwrU8c&I!WoaM zbO+^~>UKWr%= zwK{Q>2|(~*CEo!ANZEnKkN~VHkAMW2pnzF!!%EDCkJI zd@!<|EX0DP*j8^o+Z$8>IYyX^gC#p|kP@%IIE>IxY#i1~3Wjg&K-|0Q-r9atLl67K zAS{SxVtGdl+bdjwySr_QGNPhXOqrh+dTm7o);%zf&gZF$=B2P8faDv15VB*{d4c6c zL}9_1ejbzjf*Q@9{wi(Q48!qts%8MFnIH$f?+DK1G0vB!y4YE9^w;aoHntKHXTerN z12ms9Z7_bO(uQ0_F4@}&L?(&pG@)}=)RHt^s%ShC8=;;nBuM#%;e0cdbKZmStbr^I zcE(KbYWWkjfm?6!B92RL*CMcKO7E-K6}_R3Y#zd^tTDFP5$-?#bOw3CTx2jxFkhOj z1Q?o7NdMe1(F@IQmd;9#u9= zhLGx5`RH=8a~&79@$kD@O!u64h-U_;?gn z$wV{Rbu8qPuHXio341M&uP1fhUs-o0+IQggg}+%P+-4(A4K6CE_vKS1ED%O2MaXX9 zeP;UlC5thC<<3@_6@d`!KsSd-6xHKrq(DhZw>*AJAo|~97)ExgQWQjaBvS5d@5g_7^5g^*-5iCTF-3o+wU#-cgi2NRBqVgZ?_o>lNWZw6pZs zo(i5)J1u-gb4lnkrtb=jmarQxoNXNFUuEs5MM^|U^w~`U)RAC7X|dOnQLU8ictyAe z5S1N_BUM|K>Rhq1f$|MrB)R4F1gVB41#MuEHnlus*B-C^9t98(Jz9rdP9ey@Pyn6u zc!KD74};dfN^>$X#I7s5!EdqlTE>&KireWQ1YQyXOLkI1B{E*cscY>q1dwtQUNG_i z#^J1&WI81kw~hQvEY)I|BBjKRT4pTQvyho~O4DlC#gUB5kzXkI3^TuNoMg`$$xRR% zyBCM1?YzI^uVm(i^n=6sw~#w&*S@em1-{84c4wCa@jY`hFgPTD zdN7t{PXwzcMaVRYiE|*0PPmTok@|7Eyf0QYzp^MXmIZVBkoj$1U3JdIzO8JH5IJlJ znB+}7i?;6ym{GgoT@TR+R6>k|{Cq90N*HYG;rC=%O`G<*0K3 zI6j&truR^SEQ=`pqlCB@^zkrSFK`l>F2>YJkP-y^&37caWL}J#|Kz$QG1LN*zE~i+ zl!K$96f&fxqR*C$Ww&gQ?9j1A;jxtKDv@U~Kr9-J(+|I^1Sz)l*XTJ^0{M_)3HlOqE_P+tzUL-Y5Y<7{z{8#1Mc=wz ziMcF@wFO4smy~v*Y&Kfy@?lgdI4_8rU>87827z6Gz%0pK_#NR+EvW#~(cr&oa`Ho*GnwAQEC$$x4q1s2>>bpwY-HUJSB`I-- zIj=VU{c!azYu1@r-Y7b3)AqIc=g$fF>szI{6_qlx&N26W$D2EW;Cdu`@jYBU z&r4O)Lug!cULY*mQJ+;Gk~N=D))cTLqkH)DQD_37V$ymyU`3RKGm-+x_Ee!Xk!b^> zy_&M+WF$UuZ0L1|V@t-h1oUp++{ij=z~^}a)Nyp(r5{%pnUw_#YZIWOdgu>A0peSD z)EVBW8=L;FFpay8j6eE1RWQ~5$F*MMhk`aa9R@dqSF;ho9-xpn^GSKu#H*PkJ*Hj_ zwzHjGUzdh_Z0Vm4Ms6$SYX#{jAk#vH!s@W?#W47!5|1v-8byAj`M@0SMdmK$nB96E z6JOLap2Q)jC{DWPO=8w!-*+gdvniSM*8{VTpa(RX`*I|pIZ?8HtLs~$+|{J^4}i(+ zTcxTubKvzmLeW#km)HeLgxtcr=7SKqGp8c-46#6z*(GJ;5F*kntHYs}3v01lJYqd* zbtYwaC8SifIWqy=1ZIOOM!V8ORNT$%JY}eg0DEjjB@pr4W9}zMzNVjx7P=gXX4VpP zIrLfOUm-s9w__v%rV?O$!q<*eniW zp+b@WCI$#4G}SECon+FAT%2PgdQJG`>5n^YCB%&rR(#iE+PgNQqeCR&# z1&`TFqXF1KW=e#fL9P76nW0{f&>0x%S3RwP>TeYT#@=UAg@BvjQXa}<`l*jd?W$wSDtzKYR}UI zF8@H*uqv1)+Ce%rN+)zs2&khPHU@=hV6wSoAs3;0s?P2H$NJpPJ z42_Z((ARs1r*2f45W}Lhw=NH^cTXBS@0_){WZY!YQF-26HOR4a#=;4xn z&2A{90`kPVsmoX>WZsMvwshxeJ1y@CbMl+Lb+VW=c4(%emH3&wv#_ z6#%=+wMctHnB_5w<`lsqPJvC>rQM1CiZ?b8m)_y_xZuOwix3n$!I;K4aj;|8OCg)> zb1C+)kM!ncbBU$-I1<{6k8ne^{*C9oZG{ASM(1d*hLmn>Nqq}TIiaxF(|w$+u-{>7 z!JX{TwCF=K0vactfnbkj8ucu~+g>*#bufq@16MB6G(4@gM{qsBMT*=&B^oS7yJqg?D%{O-8a1%e0wM$ilGZpRCbBALvR}^<-=K>yG73R>}~;I?z62Z zLDr&pgnJ>z2hz_F168sM3(vMu{yh>?94Y^f`E1~<2|tuMK6ajIg9`Bq%7M)2e^fSG z^zGC?maw$V3Mq@aOB6acgSDNZ82S|icec|f&=v|{Gfz#Qy`-_Py{43fVS7vzC^E2! zt>nFs`%jc|uYbx{@$d%H64N}Bk)DjLmzsN@XQ17IUD2DaVUgsHD=G!1^IT-C zzG{{{Ms9!Iw^IS#l9h?pg&$;9(-aWp$qghPDV!h^yWljDl!3wWT{3CI$|#9pk}wO7 zdM@NPm_z>zCqPFf54dp4Kz=2tKQeRj0$o>en(|N?+4>ZHQA-0Bgr!%2FObUp+qYGU zvdy^f9F{iMWz2fE8&=js)cGb*-tnme(kL0P?+QzQcY}p#cD;HNsFlNjIq8q8L3qXZ zbTenxO3E-^BF>KeYJ;S)j$*+v*&GCnz6BjNS&IRkqxgs!%PW})wnf;+z?hQh08gHs zP({*bdQjN)NV%1vIApB+dHGF8OOFiUL>ex_LuL$+;1!1!0LZ>-RqPm3wDRnuCkx&aUTjG(~RL zgVK{Nz^O>O!l09sz=VN9y=XKO+}ngf7m?n@g4@xfaS5k`VVQ2F)Lx&J)%)paxEwg6 z*deFJBl%-ZvKJA6%A+pp42fJ_H7^{cUJ`nI5~Lp4NSeXvVo4HRO(*-$bt|HB|M*cP z;x1k~vH`uP1)or=*^qJ>d31R&glXqGT5ge|5dTRot1BJ1jJZ+<73xC0ZzWbRFy6ks z1M@yb69t_V&kR$wF?5v*rnU6-5{OTL>`5Z#dF@mCaGjKNhgpz{~MH^Vbd&3uCy0o68`ztRgRDvx@;*)E3V zUz`{AJYazV>EA!yWtWvp&A852m)?np@DfS=QToOip1uwCV*0Gb2jx*I=Qu$oo&KTk z^Q6uz01j>+1CyHVP zMyqLm#t92JR+s;VlbqSZ8Vm%Wq?Jt2r>GMY8%c$(+Lb{(=XD(-F+h?CGu!F33%dVU zQ?UhaX@0}9QdYc}Tg{wAQ>HRC_%ro`ZB~w8$(|rZ99RmfT0M&B1|ibMhhqT z>Qr&^g%<|MF|o;Mne@|`gmDz`=Hk6b(zM9#lXtnvLz>JR!YoOZGx6i>Zf^{g;Ce90 zCsf7#>z|SH2C0$dcQeOxflDJ1#d1xDhjr48_C{)vz6uOeMUO6VD z2E%H_TNcbmKUf#LG)vP9<-dh&1Y%9=^2c)mk8gp-Pkc0zzqZszBlw~|`X`ndZwlQ+ zcr7X}KrcL@WALw5ksAOXg5owLB-4;8ab7@EUGf?$nNxZ1uHCnj{WaGQqH`Y!c*OC_ zV}pmO$axcnk~3`};Z>A{ZH2QV?@9_l|9e;b|AFkFbT(}aA^t)KF<)n*1GMs)8^6WE z(LFX!jHZw|DK{~{a%mj?qz}FB+6?Sn-v3ubk5ofMk(P=5Pef6&Oh;<6e-%1=c%Mq7 zp?qQDSR+=|_QMqbqn1%32sAGlx(SYV;s9VYNc=(e%=~u%o88CKDeOUO*nncyjWw4r zm7$fo_A5cBYGA<0v{mY!2(?Z}JkFf($c?&j&V4^#$rc z0*_y;*-kq8Rnvmud->QmkCZQq-HQ^Bm@iQ0j&T&R!P|~PPze=*UuZC=q>?R(wGHH) zF~ZLG9U1fyI}NE43fe3qJG80aMCeZSx5UH81?dEn_>Y|?eg`Qfc7^ap|JfCydo#{p zW`cv*58cqe6> zWA~d)>@<{RP(Y} zbrNliJy+%iv6;d~7(xV)G+`%DAdpMh38ZN#JHZaNc6`45D8rF)i%(je`fvi`aMRa# z@+Q&#P#t0Dv}i>IF-x09v-t^g*=$1a%>)kH?f8h8G*m`HyTf?YWlwzU3cTEh+B>BF zv=|s0JYm-lBWNc-?3MEGJ?+s|{O@|e6CaM923$>XE6Zj$`n-XNqrKCNx^6BJL(k4dNm4)zdZTHO8z8j z+$LNrMjgsRsT*f5r)7t4eO|$qps%knFy@~Yl5(0?}q68dJ*Fmh6%-><_LJrV0g>vqSo0?Ex+)?+shW;6} z$z#er%zN5ZdWU<`OAk`M(SfqB=e5-LMm* zjBY|IP^jD3swCDKer%61eEOuQlZd~HU5#}~uDZ|J{OmULPDXKepTH~{E`gp)}fRtH9rPz`NfnkME+ z@`CJ`3vI#{^3MTqCvGIdz``C-P~d+&EC>tPe=3Na2W%~(%)g(W#-U@;H@-doP#)e- zQPj(}@^QH|2dgEw6*ayAIzKcBLn-WxoDYL|94uA+ACH5A^Yf@Gk)1?~is#@K3^<;H zAsZ860!c?o$GZI)jMwR%UB`>W=LAL}I3^U4sO*G;06{@83W*#4a}cP0yY^2sk?KN! ztl@-G67JQ0)GAWO?OkKjFtJUw@KyWE=Y1P@W_0$(w0u4D`{MVg47oogYiR*K-qn@K&fl&s>iI@Xnvr8ovz~)L zKDVt|?22Z{mN&4oI;cN+Vq`c|ecS|eNTCP)=0SRBF}7}Pw$>1E+^dWnTYwLI=ECD` zCK;HbG<1q)a^;{5O-AGB25c%i`~AkyD%$$&WifuG(*|lCbjiQa`u478d zVS41_yK-kPYHxdtB)yyvm+H;AUehl$2PnHbOSZfe%dx&tT~VIpuF{jgocc+0=j@1& z<@Fj%Mgz+oZWeD&>-2o?&lvL&!VQZfAK!R;7cYJet^X_k{TzPt!E^6R<=q3)c&+wm zolujQXVW6xpH~^|7Za)wyHq~gS18H#_ovlDh&bqnkdNI^UA2e6Yh|7bydp3j#rQ*Y zKYB}cNiNa~kPs09c%*~M$Xruhh5B#@<(MOlBZuzoGbr$&?^3%|j;>m_*Wvq>7H7N{ zJm08BuJEn7OOK;tw<|6SXuJmnrbQA`)&l4EnklKoA!tRK&=M0H;j1}i5lX5mo+r8?**&F z*Edgt3_Vtv5TuU%b+CB@nEz%%ogT_^L;sx~INfmS^nRtalhXrDyZrwt6QqRMf2`D^0H^!o-qC&QFO;_N=j}LF{!({ z>QZ?Ywv%V{h}11xTt^$)vL7{A)DfPkwSRxeRG{g&{3H{9w&G|Aczv!$gG9L9T%!*Mv#p%?f4I&Y$*OZlHH?lUyq$d<+L;p2afLWi8eNcBccmQqw(=N}Ee@w0hBo4V6wx#gESEss&TQ|l1nGUe9Y-`z2nu)}4O&d60w%#rkRnlHWp0@Tlf_i5ktgdFe5xd8TN!cVk?YHP-LY0EyUq*M;eM)ScS&tw#5~{ZXDjCzi$gqx1srx!LJj@%(%ZrW5eER z`HJ?Ti!ftpztFz8zPfS`@&zRxlgpM(jhysA4u4p;!xD%$UjlC>&bAqcK&j`Y4M+MY zfAC25axq_@+IV}&*LI$l?FFFRg&cEmxM@)L1S5S7?LevjjM(5e521fL17ij=v7IvG zP&9n{{-OHJUf1}y^LI6>rEQl;n`E&6Wb*fH7)4X3H?w77v>(H(Nf1q0tm5V(xq%p< zQD|UUH8Qq0Q?paj5D#=Z{7P-%Z9gUe{m$dvzn+rF7tKM(d8t&cc67?tdvXT?**I=WOCAGz5v^i z8Za{qGm)sLn4bCc$jA`g&|*T>Qa!HSj9Kca!u;ByZ262MQnrrHq|QMWEcqdAfquwp zv)Ux1z6azr6eF!wp?Lnx{rfUE@ETkCxoD=$ zP?yc#^yP#;KZ2hJ?P2GCrQ+wRKA5kbTGob!vE4;8@sqpV@kb+m>e5Vc>ZgpXBd&Tn zI<6}m*#0xzc|NWhjSq{c^F-o{oToOXy#BMegLuKeR~_ae{t-IX3qzmn0?)80FUYy+ zo?(ec@?95qFcHfqPBXDYo;ppHv2LG<&qYRtd@fQME&o23dbfjU#UZxppmG?1<00*g zZ`YPKzcJaFsq(PxiD*u%!N}TB_(Mhn2b7DKE|9Tt>B4b=3)L%#E9^$M$zPR$`I(Cp zKD`*hv}b=`?CW1a+{Z=BMda&O_pgBRdGMdsRO1FnU*C#ivVFK*6x2TZr_O4?47HeL z=Q)HUZw-mow;x%Ds0JoFCtGc{V=(Qz2&0WFJ-bt!|sL~a$KQ5X#N@zs?-Y0RZhm`TtX;z4d@|=fn?-DP-$ssHL>f`GEz5WOLlt+Fte@%Jm zEHV6cf$oXcEg1G~PzISeWU2%{9O6aU9rlZ2jFRWjK{O$;eae*f*w?o4VMwZs^je4= z@!QTT`g?~GCqx8;ZI(EfK|~hDq_sVTwqsCefybl?tKbHBaj4|ve%!?K7Pi^E>>=p9 zhFAwnD^#GzJc|5!t|ipPdYAEu_&iTnJzb(L$<-$8`=$RmxAYwQx9NS&KcTt37PO@6 zum{L_lzL2})%ESqX>}iMHz$Cv0biGRNcj~IA^sXo)e6lAc_z-~+ZPpkB!{3@DgEPy z{>r-t`*0uub_uGl5z{TD-u%SNPgZzysCzMa^Ds!mA+s_`;5<9T$^^5(x|!%J3!T6; zMA%uT7 zH_|JS5ewlyDOb2YQ7hiOZ3nC{CLGt5UB=x$Z-9WUudeF$*Pxl)A%;^|c>?10RqwZ3 z=#Y!#C%L8UaU@R<#9uQb;KV}g3A#@6GM_Mr+c7$Pi|uxXflKTtSv>_=S=inNm<~(| z5Crp0fuJR%M=vjZ|2hJq@0D`y!TrB4Q5vW{G|FF`qiOT$h`-oxZKbM}i!+eeP9C}N zT+qv{Iq>L& zC_*yv<~kFB^FQNBtdkGCZ&oxLM{PkIugPb@^FQ~*1cy7fJ%MzZ0I1#^)n_X!Y+Q$1 zCPEQ{)ZwhoO`HI5b>sx*BUTG`)SPX#$`<3Ti%MZPJX0g8dT;_=`+GJz@MM|TJi50e z%^k1W0AV{$eRUU%27oVcb2IsBgbZ3nRb#Blxim=kc^1{G_t6Gg<4X62+Uxe&C- z>}*89B7%w}c}?l%hrT|)2Nme<93T4gf<#E{A8b0_gemDQY9?QwK8rQ^$#6cVDUpU0 zQ->P@K6e{pcwuN7WEtJZO|{K8F_^6yxAOr7Eexf41QwvGdk^1R+%C z@44IKWuGyikKpcH(0+;G@kbzOn$$>ShqlEOz>kp4lK%-dG2N74UpX3fE;?ZOL!^%% z!ST_Ou0Vh@jf6;_@Q}oq2G0Jb>ppTBEq0fib6NpAW$G<2`U@pFl*myL>33wl5x!s& z$A3nSD5EFA5xs8_O@+b0U6^K;E*ubdE3(xHTOO9A#SzcxSherV==#N@;}!4)ci2%L zMidvpy#WjnQU4A_rJ_Y^FX9mboQ^vdNxpAZ|j zFOAG$D)s1guZBH3ApLS9$I0vqlc?~=90LR6W8E74G+-PlLL+SDeWQo?WuPq8 z{V=c&l7`#zMKWgt?V9Ak*%`*%hz!WW<;&9DVUROEtbLX=GL%p#UMOqa(8TflD*;Qq zbfS9k(Qd5~9{+w>5D{+LF)Yf+J1}n}26K@UUVlmuk>4RPen-eaqngd(;*B-ye;X6u ztVzFa+X%#dVOkxWvT@84jI9B_oG|VLj8i6)b{am}TGD)59sC#j+Yf31qV*$uGvbJQ z`T5w;ZmHwXlMUkQiIv|XKU@edzRVFfw5GZeIQx|HtP8x|6}vVp?9FwoG4;pwv^_{X z*cbm^FqoU;L7wX{iy`3lMHSI#g@%ypU2YD%QZBKr8&6fjNZ;XJ2}IY_W6d39G+7KFfS6}I_<*HD^_%{ z=f-~IdAETRxmxOn@^#D8;*rW>$QiKmvQH+Jt5cZy416Ad^#M8%I+To^8ka`7F<|9NB=l z*2X)!;?*xtt{aqC!O?7}t{|iXpwL!SK^qm#M%?BK?Rz|he4l78oA8rlBt3Wk^FxRQ zPN5X5w=P7V101VB-KSa1zTVGP!6z$F2-Z_PB(MoF>7lG@;!GgAE?^2bE*9vyyr>`l zi}=C|o8~BXWgikyavAI*MtU1@!bek^?ymzLLCoHzL7GNv2=;2e_p%C5k6y6SzcCmq zD%D1zwyY$k&bn%bKou+s6OO#c{8GIQBz)cPlf(*sM4i_G{%l5=^I8&iB*n9Nzt#y0 zBEnWf{2@d3dof|`&5Oj&&0Z`aTnAGz)J&u8c7pn9q4Y(pI!a()%#kNPVlO{F{Fud7 z^s(%ps7or5wc%?CJ8x@GE0u4L!8g#l+>sD8h>3_~z|#?iJ9`B2iPH-hzEbguPNfMennk>d+P>&IGZjCrJoA?kMrL|;Sde2Tt74opdF)wntChU9LH*m&UXde}C4rCu- z+qk-HD(+ltd?lpD>84{V)Z8#esl~9nXOLLraVa_zoXWnR?QC2ESWX^)kPLgiIc4#q zFDUk<|GcZOBU)Vwz^FkC&vFtj;}2D7_I1^}4u~}e4ecXICtD`+@CELoAnxP9sYflf zOP4%J^lM3C;u1_H9wzE*?k)e(x&8UgQBwpx+Ao+o3JW>9ql0Zfu%UNkWR|ZPVj>bf zd69s^2Y(dH9IJes)bnB8A_twL$p}%S0lPOAqxXNj37}2N{`*^cF6ZhfqBlmmXAHWF zR}oX}F4txqeDbB}@AD)e$|#a5g#QgX9$O%5BkFJFY-2wcesF-CZ&Et2SCo;0h7w{+ z!XC08tqVssfp=tbA#fEtR)_8_Qpnne&32mLNscbTmVjYMX0JI?k-WVSDnsoQqVX{T zuk|2^$C5WaihqgoKU80%4@W@U?`!T?NHe6csY{IQu(F>UiC{CB4Wg39|Fo#&rOBD4 zPo=S~+Cswv@e>GRId)9!XI+>wXH9c>Y&Fy`tVFT5h_rUdpd0g#KL_pLBp&UTB|tD4wV!Q27QDd#|>v7zdt4q%hK zv~yq;$my4%g4Lvm%_l7mofbLXALrimX3~RSn6=SlJ1y#XGT`SUjM0;;b0}51Bn}Gp zI@n}M({oMts$@OZr_`R#Tk_&r6@cbbwLUPJ0pq+fAK_GY^ZO9G=r*9hv(3JK&LGLg zYVdFFi3yBExpg4O1PWv6X!j^&}~L5eK^p;_bk~bcUEPjT5iFUCSH(gu2oiQzz5R9fjvQl50Gt@GUf-20R@_@2@gk)ZX+MUCvEloVNTm zB!4~;w^j#Tw&`lf$;0d>6ZkJCXq|gHirsIYPO+c|ddD5{(IIn-VwB$#vqJ`w{m3CPA(%N}8%(VLMC|p;SqN%m$gDeGgWL*}LKCEEv$3CEKDm77jJP-Om*4njJJ9wvFDFm*tzDwwKJ5FLhXaLGKe`<0(D7d+OR-g zYa%GtCO*sgXZ-sLFup;8=NkR`FwTuZ2p?2EthyzrB(DU1n{|;xP!mLmc^WABXRdVo zR|fdeXHS8ZrR(h93$T!*(M_p4vmYx}_ohL-pB-K_TLL|5ezs5vI;fX@7Ev=8@9R5$ zER9%ZIA41pHnllO2JWNnTsN`_`}Xnstc!iM%oGyIg6!@hN`@t0-yTom;fCoU_io(C>(>lfMeyJeF8WO*7fDy znvnOi@;_g^dFr{o7^eO991#9b=g7A{paX>()Rjg4Mov5l;Pny0kd&t+P1k`-W0B0r zzV4Hr_B!gaMURz!e_THLLugzR;OG3l*BvkS52K^YtO|^ziR#1U+DAX?<+*4ou{lp))}8s1RJ`fS-i2G@AGf~D1dm~m4E{T+ShimAB&e``C(~Hb z`%WeltolD}T?trDY5UJIG>oMoMG~?`DoG0!W|U<}lqD&ZHPWP)XtfWm_M&wprBx_t zB`Rx4Qrf3zrL;-=|978r-g^1|uIu}*YdG&Y&vQTbb1%Pp(?@DnNGLFO6*36*m;Wtm zesaXZ5Shp*n2sAoOXDWRl-Sk?)%O;CK2FI1+vIC`<`edcQd^6!{JM z6nV`GLoq^T7`mqD#T1x_y$-{9#f0i_+!7Q@7Jn#mu(QH857$n65b_TF8I79F5q8?M zsWEkV#EpG>Bg#*^8!Xp;8yf?mJvN2}X4sxpA7ZDvD5V&fo|~=~0k5vhCePGG_WipT zPQ8guni~pVv}q?dG&y)TbjD@`eX%mP`>k+NVQfa?mxt>XX`5HA`C@2p=a`%Mut0V5 zqM3o_ReQe_xrO>>#aJgEF3F2L88^c`Z^f7Ex3~RawI(+*Ia| zDhk}{R6-AL%TO{(sI2Jluv=O*=0%lcd@@;;J%|G%JsLjWIoNR&{En zvzMZ2{n?|_Dld6$HFZbh*h(KSJJXTQs(Tj@FTEC-jdXjspz@uUv6-Kns&ZwC*FOZGm>apbt5(){-7~9qKf1WG z*(=Y?-Q%G~WtUg4ndInwCpJqxRr?QJQA6L4h(2>R=FjjsrVb+e+%{X&bh+FK)80!* z&pW5IDqP>R`1d-`%^6Rx&v?HuI`drX+HgD55o7EA-7J>YG3))R=v~gO07FgHMSIm9 zBfc+=K76)YEJHpsh0yHH!MTCudF~aWP78ZF)eQ0&9cm@Lw{w8m+r6D|JbRs=Pto*> zz5{b_ee2)TjpZ_)j1m%N1a#x5Z|w|DDAZFp)pg9{8^Q*knlG0KI@c)8E?JGU>d4=oXud>0sagjelunN^l0 ztCmrf!T4Y9QSy73l_L#qW3=Us8_R*@-@p4kKFr>CqVe=0LQ3rF+oJ7RG|6dKqketk zp{7RBw(Kc)kiMB_c#GXeylDH&>V@`*@dm*nnukO?4F}}ax8FUl`H);#l~~4uqAOCr zyLUxv7_?2YNjL})F zdnhy+X8T)=*D&aIXax?p3igIoZc+z4im>Y;B)V(hGDRj=s;e1jKX~#bws4*WRM1|S zMt@O6B=?hAWx43a%~NDyKkcQcNTpfO<@L2GTgVio==(KTr!y;l=74E;cMrl+1ohKvr2Kyckt<0pb;4uAqNcdd)ccIXMT-KM0(RuKCZ0G>^C=b$K6 z)R75O0}yF7*%cEO9o~OdGxzxaJ=epvZw^6h;yY zEO?26UJEd^%)WiOi*ucF%7b@g6SeZ-@epMLLGPfy8E&Nx{dM! zkps0Sli~#F^naS3!oM$nHf!Jtk+sfm)}OjI_2bz8f`$KBzC>nVfyhl;7z?3~^atOW zdRcTzgs{c(vvZbh6KQgOv+2~Msbder^w2vVEo`Cf^_lF30y7Ww&?ps;(FTLxPW6F) z_tt+LBOJXvKsMDvgy$0T$KbN5zde9Ly$RrQS-{rWxj`=m#ai{A^;}kNbQhTwwYgjEI5vtV*L!?=+hfa(ag`?%2@* zAA~c=bISG69iEmxasBWo=|1a+KTe-G=D$4QB&{-~)JPGY+xdNi4W)}@@`t^90z}#9 z)vt^@pZrMF^?=+ApRNF{w5`$*@T5p2m6JlI%TUW4m>XM zo9ov$T+FS%Jd$24J|$Intk&*KVexdulfo0VzRJfR)!LLLd`4SEVVSd-;onQuV6TTB z2*?&)aH2eWdds^FIuQfiMR=}{%mzyZUeM-=xykR~b-Rx~`ft_I1gaXHnkoI~ zL)eh|$6p9<)Oxho?|1|3GW|D;Pk4$9bRNBnr{=a~7f;>o?_InlZUMUnX9rS7kWAu3 zi0@5HGedwm#SS~Hwfvc)IWXmLnG^omCNUdDhPXLrhFQ!xalXRT9J>Ybtr*>6>I!rHHT|?mXEm6^=KY4z;caYW(0^n zeG+HCW}@gQ;Q^Cpa!3dQLQ4Xl4qx4_i0IBLd9{-Cz@#J13YvFx8!G`W%&jgDlgcyL z7h$SCvG@C=;(Wf%tmMt4D`>wv~ z`>>&_8V`xLKX!ADIthUHmo4@|hRGw{ouljq9dlE0HX0tvwUiU`Qt|7^$ z@zrgDk26=x+xGZjxUH$va$h(C6h!#`66FW$qrbV4nxn1{$oP~e)P{j>@CLWv*W@(q zUdv$da6No1mq{Rcv@1I62Dy$5#2y6IY?~IZY>wm)ymJpfK1bWp`T#4z1;3}vh6~!0 zw%9*IVoP@+gRDLXf$mx$g<^20l>|^lm$=0v`4U-W>zG(<4H7g3=u25A^eRdZK;lEw znrCQP5tMJ~rcwqhuk>#iFJtS9LXZo$81Iy{#qbm7ql8mVFoO(~15rjusx6R0+y)s) z?{ysm0Mz&XISIKPrlrf%Her<9Bja3>GvQW&-IU(X65t5Jv1lU{#izr6erIwYxPq5cvV`?Z?DdKN>V@?zi0$fU9Hek(kuAX>sej4QaM97O;PIA`Rqg z0>kz#a6AE!9YPLX)e}TsgaTf=!{RBwwt)s3|`dVu6*{leTBbk z3>6BvhS5}o_mN;Ut`1HrY~xDr0gt3+Fy<=dm9ge3-cs%EK0kwDT}m!wSa+Kg0HL|x zEQ~xBH?2q>FC_HtHSE~J8qM>0=1+_fQm(V|e8<(1w8muyP}o|2YGV69v9dxL$V0xN=@ z5XX}5oE-5}5T z%0HLtQT7|=lN@5;;G8Y;9jC^uefAGA`VvoM>h#L^L5^)Wkxj;5@~?-!!fiOD8gdsK zsF{ks9l=EYdU%@iq7?QinWUcT@*H?9ehjhtIm=tGs+foXUiL;3AqrV~7i40_MC-pA zrxae@&NCyMF-^nYSQbbRp`t5LrD_ML$1@ z!M5fTO!N?=`*Co3$V0k*01=r5m@T;g=}0mGql*g<06lGifjN`nb2agGkzw`vd4|?& zCTQ3np@(Pwvzm;`05)jZz&mTUR>D;9&pBBH0p~A z1!}D9i$G-!S|+XC?R#jWTJtN#9Hfhcs#UluzQsNDTMLAihYaXj!uEISmIdV#EzL`gaOy$Fn?`KX?epD!3-B4+Fm8ldK)|Wh-Z_-@* z=8sXnn~=NrEKv>UWEeR~mASwuH|rPnrUW{RZLQpd!VIT`7rku;pHg;xY5NjVZXMhG zIYv|GOV;L2>kN&vpXYk#vC{btC^)S1&my_<5|Os^7=#oZAN92R7qu}}D}1c2{3%(_<&epyeHdpEnW-MCC-*7Khsm%M9-TcA^`H^UjNvuzv6>ja9;U>~-tQTj zp^vtlnj~#F{_&ii#B#3(BMQS4qPWxAA(d@Z|=IQuQ6x@cHH zG3kfwgWdcW(DkDQ`|rID^&HGNL(mGh;1p|8a4`aaxBl+S$P`qJh)$nCo>Wxi15{M+p1WIB&9$6&8u(@a|= zu!bGed$m_&hKJY+(@Yo7)zBwKNxa{!&0bxKn0BIBB+*0Z$V5+-Z|x78v}N2!2z4p{ zU?^P}{))4LMI4`N?m$gIPs7<`wM>?>hvxd>viH}CPU^1G?A`KMeb2V}^9$@grBN9^6Xl*geL26e>91F%3Z5Cm7g9t(DX#&Vp!r0Z$UqOJW#M9`U)BwG z%21nqqBOeltk|g=!;kVNc|5XVK-hg=o3ox4%y_TbINu;KeC(8l>T#2NQ>Du!>q3QX zvaTrx8~j0ltZ`$V_GopD-Gj@THTS8@yr0n6Zk9Ae$Y}@*Oa6XHgGt20y(eeoQWhN( zlzg`C)n319aq*e!De=oJaKeUxF9Ee)?wGSNu}oCX8-26p7_T4r$cag=*V+BJ`p8mv zMu_}{>@n~rj|-+>McA8m>$CNl+1c{(Qz|o7&d&YrTwj+Ry&&EZy~xY=A{iiD&0*fX zSMw>)Ga~+^wpb1VqzZ&q>_z(c+OWuY^W5wOMhDKimuGLWM}ky%ytmeaMoQSJJvc$~ znR5R2leHZb2@A{onEmhK_$2KIP1Q0KdfMdsF>ts!Pq7rX=v(NW%V-EHyn(lYjJma|55) z@;0a=5*y}Tr?9CDR#9kt7&=+puT7s+yt7O z%Id~#n*#$o5v1C1$i~AtGMtJ@avQr*k`W%CqV4%U1YqOMT45(x1{;h23%pkgQt0aQ zTvKX8!$Q|a>LPVIsuscS+cIh|wE?Ca(hq(YQmx_yNK;Q#vN~|;F%ePU?SYC8@6gAj zN}m@VrO*57;p`r5F-NUXyBLyCKc>5PQE2s<(k;c%2F)_PrRG<9ug8=sM-}W2clZ|T zDzhn-v>srK)Uv>a0pKlt$;~}BQs(?FBfm!6cuNqEmnulCY3L>gudq>rwDcK9l8OKQCp=Pn&k-cxgq=tgdEt8O?^7qG z!^i*oI@Y8t_IO$BzhwsUDl#*U2@5|M@oUx6{|uIIkJ}hi_P6X}!!TiyJeg&;VwPAL zi7fLq&OMRQ93~uH+56>zOs{&u#=szDAB)~Di?-FDgYzvx-9S^P^klct zFLn71x>moLXH0X~(fe{FEjmmxL*~>(JD1 zB8gIP99un1vlV7VUJ|a#P|86bI=alH)J~{HCDI}FzYCYNF76rrx^)aE&DB4ICX zlmkcD%b!|voZzP+1x;IcZtr=EIq`2A^S&b3ufO!0@HDNz#U3%sI=*fbzFYHGYGx{BMye z<$LR|YwLdrF-F2e3t*31ln&gHf+WGeD6fMGvIq@%i^R!w7R~r=FiiY~a5Oj70M?F( zbpi+#8Xf%_3Df?RsD1hf6G>6bv#C-MXLW=;k7= z7N-^bzWT+4rS;Wu6Si#(3^eEIx<%g3mQ_-_skP}{^_dBh>jIni@)o(R4MyZ)O<4Hd zRk^AvYS*-e=2RO_C_de6y#)kWpAvOr&=KAskB3TXr{qYw!T|_VJFBhSXpqWYjfLeM-qUi|_aL6qt zfPnNKM6WGs5aJGhKR5cl+uBzI=h?PoYv*79TMpd1Yg8)L@=7sFZ=Wv$|F;bmC85D~ zuA0n=ms0j$m&VMa1c@-Ew+zbfNl0-EtV;dIl`wV{D4%REYChWE{w8GL{sUO0>edDH z;8(3DmS^SHpGw?~(#>D4kSn)RJlZ@sW9pJvpeuUE@4{z` zALh0E&D?>zMHagV84S*zdOj8&e-Oo)5RMO`7`*Q+>BMnUVo@caKcxw|k{g#cQOe7( zMA^H~rs@mLOBp&V=$+JUn3#HUx1T2MMEEJJUePM$_UU~Ulg17xjFU=pm|d@f)UrsU z!{-7liV`*=BU)y^MBBZ%sI+d`pUXsWkSml3^;LJ&J#qJwoEY z{^A@63t+D@P3KANAPG}#;Pv)@_HPv#@{7Uh!R1r+G?4KlGfm9oAqrhLO3I_k8H_N1Y>MA_HA0fQ!@J2K#^R`@mM^UD?Aw|EvAv?CfF}7g0yLspCbLO2@ z`#YNd=X5H}A^j49)=P;_bZd0`S@@HFb+|{Y#5_$TD z#v zV36hBv0VHKf5+2akivLGWNN?uogV9%#Uu!hSePFG{1YVz_`4-GK0wk&c@E^c^5dh)i=qSr_0cuO43Qe%^XB)Y_qFFxlafO9Ne?Q@>S@2KAR*!!X8w(eI zCHo>xb>`EVC$a%O9HjJZpa7p?SMeb~lGH$*@rQSfL~E9ogoWO#gcx>J0gL9rn&;p) zqF)vIs}O4VgA3?scyJ{jVg_zTi)CS10IDal(b1DCwGQ2Z02TwXxfY391QX+nAApn@ zaA2|&#TN+H2K0<1hLj_fRO{JiHW&g*X5u8M@geL19YsK=c?<|S9%XgF+iMYrd(EMm zlx9YcQ-U?5^el}Xg_HzGXfol>%(1a++;f?Voe5%P5$>)UW^enEX(a%hR3H(7Pcn*p z|3ES%#2SEPYG3Z>5S9)gbSK5!`6L0-$DE(Lq&NTkkot>5V$P4h3bb0g^}nm2BFKI_ zxdIUf244klkwGN53Ubt7tEh7U4}w9!BDJ^CQsdHEwcFp%TkJzxAkcVbeW=;O6trtp z6|x;bCPhoIZTcrkN-XChACADFnmLkTy0G42Yl?5ASI-r9NFTo&6*~Aqz)Qj$`7DAX z_$0_8s6rYixB&$J=W<{(fgf7}jYJ!1To0}-Z`qr8T{a>ltu(!x%hxOx5^ z6T~X;r}{2T5#oC)9{zRAjE{ng;Ky_t8y2x{27BQw(NQl=aVA|5SF)1@?q(4pr+oII zjA~*Z_<29DkJ@l8f8e_O??Xs4^v3rQrdwEwbW~h5>f1nZ8-~!p=ct^IPiV@f%yHO8Nu8c^5Jx7 zk4XOE!2+%nq}zTN130`e$k;`Ewt@-HKOAI(N8oVkaEV_CUPm~1*m{62Vb}auBMF2r zI*>1%3@0Ad8cQVig9d`^0kt;=>_OG3_~T^D95#C|7rdb2d=eJu*+5A!<$uIRAg_eK zVh3as@lO+=UouYf5Q1%dCY@ye^)Y`jNMHDW`GbN+9CK3Zl^=*q$4gp2smIg}&3<^<||z7imtj8g*p(YTUhaa&v?;w;4T zHvX__rqq@xj%8j>=~*}cx-t0E)57c&*T5M0y0`{qz4vVVvkb0OO?cFMIWQZJV79{h ze7E$F?2svq)zRBM^W9`)s}-*1FCQCyY_iOW1xrQFm)w+@I#p6+@4%@GpU&T1GOEGV zTGOuKsDGNlzVgO4?}sTnB5ig#*zJmR_yw`_t80)pUE}jY?}dB^SY@?FQ^te8|4aSO zsEs`z&}r{t=5r{%P%B*484U-Te`BJ9`I9K8NG*7N?tE9H`+Ib|7=3sD6`rik0f2=b zT?$N?SQecC&EKkCxqa271s(A!bZDOeJ1s^84jnmB+)QZ6uPBKN|5$9{M-v%@gbK~j zb8uyq-mUd#vMKSd>4IkR^wn3N`qMuyd5NzFXh@C-ltQ#yoC)_|MWaG>+Q3VBTeP-o zoJkM9ng0ZxaX_nW2^-OOl$PHX)Uus_DMCG$EI_8E0~})3Rr2n(6Qgq5l;1}jdvTu zJx>|EexHWs61}g?cXdRP`z4RAM&et+?Ru~j)ISP=!e2&&fvDgzeBfGR!HH-(n8Chx zKbq(fxed-_yJ;HIJz1iQ4s&bOW)cO{;oN!(P>@;#udHf8WbNr@lc3)MrBIghQQFDA z@26+bE5qOYOg8FCcDORp(3d^NzXj%nZyEE$I#6LINH|P}zLZ&m@RLV$s`+@WsBH-g zdl+eN@czBLE$Ryth6r5_2sELhH&d2|G@W^-Zw`_p#LP|;7d|+!O^^$%VYN*Y;8#rY zSfLi|lwd-u_p$%zVTrC=d>%kA-f6yIcD5@{!T#Qw!D z3K6@Dv?%m}|NqVuefo9Zs#1ch!p6;D8zkzb30?^bG&a>QY(OgiIV)nuJs)~qOj@Y>Xin@Fol5Ku50KcMf7NkWyIpXwZopip zfi3e;)WTgpSqw6$@ks{qAU-D?R~(I(%egB~tRThSjL^HhnzuKtJD!gSMBuoY6E4?4 z?{~py(n>^uYo5k&BaK$_4QR}DmZN@*lItYYQ@IWhnqIv}yc>zO z+;77pOj;109?x*ZyylZc{(1r7+^?dxm99I_C#D*i$#_-J-cx$Oa4|oBxlJYenE8C!QG6WBTYA|pRQOFzQ z1Yjo=6_|UbvTF&NRSUAH8SA#_}APMr8pXQkD^BT5B6PG(S~(q65$yPov`Z^lud9;*^2RD*!9gb*@VKdKN!bo2+H<= zd_(tCV{T1249kN1v(tx#*^76(7Dnpq3mxqz)c~wGp&TBO(vE!ODe1%J>=f@t zD&P#M4~fY9na-}|B^=L-Eo*@&xF`q(3?_6GESJSD?o0OjQhUesPpT30P-357y>&X> zHAc3f=8Y4e@A2G(-mP0?q_i54PR){POM%RDMin}B7M5NFBTynaN0|w|YP`=rnA9W1 z@IpN@n42!VE<{cRyT`lYS`dn?&nd_yqZ& zqZW+Y3mJN4R3I#=Ucn=v%2Xl?n2b*rl#8)skwO}vAX#7(VNSs$Zm&>?BtzI+2>WUc zxStaH1b8`%0)`)pTYJb-T6YG3;e1dh(hyP^hpU0S6P5#6exaKR^}#0#vVJZyY(p*L zI3~cb+}Sn03|pe{*9P#qB@)H>zd$Aj7!69@l~G=8pFb$JKdY2H_-qQd3*6{Vu{o@H zSBl^#w_}UqcqOb0h8nxBmN$P0G9A_6k)%aDfF}dJNb@h z(jKntTi?R?p`F6`DML7i)E8A3GPgQlCyIBsy;Vi`-nlGqKn+d@ZvZ});p7A?jq5FI z>C(AD;Zs&Le}VVHrNXl-c1z}gq=j%)UaQ_m5O zqJ(DQ=InTW5jW?u3AKlydjM4_A#e|xJ)F9viTO~w%kgBiwL#($E7!3k7*QzWAV4L) zQS0oRgXtxvH}AkNpsX6O9r_sAvrk^d_yY)kaJ2|2$pZ*V($S%}1$UxPGxz?NdRk%q z=1)(m$E;PE!qSJ4>A^7g(D9pNNj&)Y#4p@~I*Szq9;~8T4xGRm^n_vmdi7@?>Xj%y z8=GyRIF|j6=Cx`yH@RIA-N_b46^1i=p1&^&h5;?7MY@GXDGHLktD(2Yl2{uM3dgvn zRSPUj67hOSA@spu#m)Iozz$a1249fYPUkE+xMJL)-~(tOl)i%Orp|9)ys@C3mS9bm z$2cJalb((j!Q*ts;M#G{HwQHfW2EVJ)?@J6|4)5H{Xl)Nu~Yj?W5EmDgSZYkhCuUK z&*}X1!)sw7x?dn$G6ebpFitl(np+rFfDA%2=JnuNTY(j1L5-1y_D1_y z?y&P!(Ir<}i_wk1S4cMk0FdU+WGj2CIMVFwxj>V$j`;`Yt6ph0o=t>@Bg^famAVk7 zM3DKt_im8^(zQ4(6Z4VwvP^*B)ExHBm`T6&VhQUDBjiQC1#|@KDA1PCtjLYsG7Jye zGQ7i|?+RideJp<+IcW^b$0KKqJ8?!2fkhZbKwpb~MnI<|mJv{$BzT*kRjA!j|M>%{ zd&-`FYn>;~pDLNSZ$fh-A6}BKNDr*x>DU31thu*g2bh=U!R`Q7AngF%4$uB{XvkXY zXB&hf*+Zikh~S}7o+TZcvZYbqp;2u#%lS|>9Ot(q4ta^CDbij#fNpV20!E(STe;zd ze7sX{50(-IH{k~w5j23y($m%6Pa~u|votd9?a1rjGod!(gM?PS!50vR<|H=0Kv#$% z)lj6HgH&W(3*KGmwaE}v54Jx((RXUp^MDmpz~2Og|55VFA^a)$+P7y4$+CO|M0~!0 zFd?afahLt#3F8p(Anboid4>MkhDf>Kh6x#?4P%f;|At9@GtvPGcATm432xE~TgG|U zf`Y+74vy5gV~Bd-xFA3W4ITLx1Slo>a!Z9;2UK^C%t`8WL|=M-aeDuk$bMqJ1b>Hh zJXmXpj2fUW{SWSW6Tm)*E;geDr9QM8T^U@WektK5d2kD4g!0vbMrrRhNPhL7NJP4m zarf^+Fryh2OG{)Ns`lS@WJEH85WN5v&}m^zM&D`GmZmu2v|cb60&(=!tp|R(lihGp z`Z#(6nryLBj*w&lj@E(6NvDe;-JEU)|G?Lq&2lvQ4DdM`Y$3qWC_C(z{m77*!iX(( z>VQjy8pC*6S&Z6!8(I6!WpQz!_bZA zm^(ZQl^Wn9YVRV*N9cXN8cHl;%e@&K2|xRwakL~O{Q&?baP($udDvzI#q>YeS}V#v z2pJ{#Aob=VjT?Wcu1}FtS|-QRuxDv0z-qXqP{YuhHhedmiW2*NRzncRg;aPYgt~Fh z!(Q<~fiFR0=q)jZh%`cCAxArKHlj4x0UXpxXa@|ZgnAbVt`8frEQ;$_+bDq+VK##J z_&9nPB#Zd$&=WHBbyux$NYyM*bY}1244S00Y;Bw7Cx`p{{a(osUnS3 zn*+&C2LLphwbV%?VO}w(kx-~gLKKr71$jY7y;To4y#Z0}ex}x*baWcS)WzR7(I8i$ z?RGSFaAgC74*+f{{;oNPJh4aL&idxS?4HOH5>Ai6epReYX}^2AEM_Jryxy1ioZfUt z-L$F&2|ldQ#Z=8!T!J=4{sq-BU>Cwk`a~%8d1R@NybZwz(f&n|7=iFM{%y&D;t^x% z2{}!SfGCilu>wYL!e#9{u9hgL?m6ssk&)1^GiI*2K9=+(^++YU63oa-GtdvOGFz@sYm;WM~%LdRPT+g|I-)#?or;rj^vd3S^lS(5@P!1XY*`-mxT;7CD%l z{mVfn6Dtr2|6r+3eiGV#G9WQ>%E1+JgqCO#n@-;P+4le%eXv>y*aN427-t?SdHy)w zB6Jj)5J)RJFZ*pRI(nM1#|wv#NQ-d0pczCPMh;K^hDp^imw?LJID%3O9?oZ_=pwG! z0l@Mey7ZA}rLbvLwrB<#8Ot)J`} zcKzr+)qii$tbH8a8!A&L!V(73N7zk4JwZ1(OyDmY2(`J&k*2^6Y^`sww5j8vW0_j<;tXY4VwRT6wXrpWu_ ziY+2Aqwk6#Wz>bys9E01a_rq&z4b{o`d(&`oAm8WHudXqCAeluZ2qD{2tKi93XT>M zS{XxW1vwNw8ez#*P@!Sp4%DiAIQI~7mY*(*!#iE=erDUU+ZQ$jj@AzuqM+o~xW7&K zcLoWf+?^qg00NoLKeQZJ1>>1JW<*E<3C$%}!TfZD#QX$Pf=BBKpXlRJ@(LLqO~OQL z!5yGTknWgcTS967!jRm?s$wb@qJ?45>`!L^?Ypq=45&JbJz`K#yaFo{Vr^nY*uZqe zs4eVgPsVFzjBg5@;)pQ;k>gU5Ug)R5NH0h`RIo|)aka17A!p|3(2I@5eOM%VH)3KW z<}|zh8>K)VuFwb526+12Fi3$Jt0PwvC-(pYbOiT}lb-2!#I*0EeGk5v&FWU5=bXA? zeB$56&qts~qAf$SN1=bi=;4nI1M5J2AEB=38O7--d&stx4GZ?Y4`&>$68ZR7n(IjV zer*=D3r4aGYbPh6iJ0JeFl&jEUU$8cvT z$c_Umyt{L?z=35U7I2;PX0w0q#6E&Dpb-N!Q9Ox#JsrTe&mZ^)fcXEo{^ya4%8C`d zPEf3jCrc9?hlVWuQk`KCLU)p&g9UdA%J25E((0qUr1dKW);Pv3oCyS@--=-mKuTjV z2_eEN`tAUdv{*CZKvy<%=CK(7cKut{qWLf5y5ZIUi~ihCB2*`{B*Hx*xk8L`Cy9}{ zDAqBc^%F|bcViHRB&p65PwKZAm`L}1WmgSomwuT-&?n<(WT6dV`?K`!aNnQEYZM}4*FjIJ0a>VWj0H(V$;4#ayNWAJrClR*+b??2$OWQTU(K}y zTEUbRYK$5vkkF$3?tSdfgVCSC`191=-F`Yz#`!2M@c>P(xn(jma-FC;pH`3L=KeE7 zlv;{eeNS$bqbSQ(Um!46#Irs+6bDL1=k{GP^n^=cFBt$gT(TkxKd?W0O@_WAKn@Zv zD0dO*V^X+nmSEBvd0T&nZ`^_rIA?$%&NQH8;Xb~Qv9>gkA<@tiAjA6E~X~P6O^lg}W9WWd2KxZHq0k(r} zJ7*)335J?3l^=)v3MGci0?y~FE2+&E3a}@;2RE}A%{I7wPv~97`|S5(J@^zB zF8i0KpVl+@Yjz2fti&CBEQ(TR6mQr9p7Tem>K`9fAR7kM!Q~yzZq)*fq*lcT-@ObI zMAON!>A2e>RJOAW3F2%ByfjegMIOHJ??01RGCYgL3Cv`_(3{oUrSs!vF~@B-DN7(+ z981s`uZ#7!=iYl6~(SZz}XO~&njiVypku5Smx8@L_7#okRjcx%EV%ldzq zjIbGw@{kQ2<$C}FTpYE(2#JoY<3*dD(7W3Kyny3Iq${0z(Q>>%$=NsUWL86Q0IOKs z$2+73l%NLM;O26af%>}y%7ELFkjD0Lkc3UH{-!lw&)iZN7mkTZgN>>4sKP+R>EL~=!s;<>Qkh#4I{uvJmb54P1}zCi zh%Bez%=**-Qg}F9s}NQBUfl7bSHn-M$9x!)y2#n!`2U-CY1fPzTou5an3Mc`=)!t} zIe)ytP-cV>u%hxX7R&K-DWZKp?iUi#m2M0?yx-Y#`-0X1YrsN!YOXYBrSFJy2*DmK zG;1j&7UptrrZjRgo)GIG1m!t*%SCW>Jsgn#;UL05IS!)0D9b@qqQo*wAM>MG2ogck z0rzoAvJg#hu5r|XOUjCRK|;c}<=+!a=q5TX;OarEJ!e4n;F4+n$Ug|;Ai(4%LBKxi z0#UCxq9;TlvdUfmhmb&A*uQ-CEupk~9``74WR{&sYGQn^vk3eW#KGw5Qq-2?h6Xf; z;Fg35?j#N)w}Vvwk=^P06Dj^dAsGq>MX+e!`;injQ5vp%3EXVr2lVXVx^x_IG?g7m3>bs45DX;>OvK=X!B%RZHnT*=PIyApu!G3^2*na*1X*G`gn4zV} zu_r(txBuZ}a@IMKfZm7Gq2dsZaY8}>t%X8TKai!7^f%0aaq|qtIr77MSjjD=@BUz~ z2C@6MxC#OP1=Mt;ky9W0eHYoRDPI3zPc%YjGuEQtg4=|sd<1<8JOgKKH@lIfUjCy13 z1L8Bv^Ci}YYEkZ)#3Z5?)}g|Olox~`0R%s;e(vTwh!jdZprj$zilhP_PNpHG-oJDv z4+~4DND1r99IAOcojoI4biMwG;*dXNp3?L@{)>TgaW6(s_I_DRwBTehC5N)IgNA=y zVr4O+M84Q3fCd(j>$^{sg9;IXVc48URtVqX0xLq)(cY2$E@!>;=9M@cDb~N-IjDET zy3vEj-V~lX%vt!Ni{|KGX0Lj9c7@2zl^a5DEDhSEYuixyc0|BHXWrSf>z9q1efiY1 z!7Bzou@8m?T%=Ox2f^TyVRz>JL~g@tXIEftT>$wR5oi3Dc0@( zqU^viw`jvAwb`zIh$*xVk)~3i0}NY6e0(?)qow61QXC_56sMf8!o>1H zkN$Sm6IVx)cM)^M<7k$x;cN9nJ3~%0X}3SEpM)sZPq`%gAHeoB;C?V^Es^4lsI`vJ zojt$FxEi4sz(Ga&+MZAFe!?pK{%|6yc!7;z6HndL(aZ9A09EeQ^mS!g?Rz_!TMcsQG0asOhK9|6xrgN3Re z1*BGIIexqM5DmugF9)evd9%*8nw#<+kc1H>+jpS&um5MCfmu9hgtpP|uCLN)d&uAU zCpo7r+?p_M_W#*AT1;Hyc1~r>v~%!K3LJ+1mopr(7>Uo=FMMDAei3@AGw-=Q$9Jq& z3jR7*!j(GeW5x&~JR6&ea$xHEpms=7Tu(d+MG_x5GEv8WZb>u@=YPqRhpH3)`d?c* zZlH(voX+KJq zZovkAPE_W7V4x6hJI;KF#QyW#&S(1ky^Ptps8&>5xid%et5yEY&J)3f`YD}PqU@(D z4`Mb)NmBfsql7V6!VpaatXZDsuZ?z{ttIh^+cgT34fz{sf3>@RBT3*OhR3N0zSbrM znJs(*qZ_FK_Zw<7d4S@jLJ^@;T9Cj zej@E@+NfJ^LrKNl<{nbTJa^JSeEUzj@Ac%;a<6yl$nobtjCO;s``DuIVW>+V?qN8i zw>b?*O$L?Wv-HUKlL&2F{fIkB>1)O6oP5cI>SmK@~ETn;An9LLOBMU z{o>6qCL8-FuDIdxy1QP^vC)N3P_!fDXw(sKa^#Eur4gmPa}SS4&v5R%q>%R9e}`!* z6GI)1g>4ByZ1`(|vy#N!GHA8Xk}~+Nek{QuDptZq{VfCflV)r1Zy8RN^e5di5$%Z= z{`X-ZP6{mHHuf}mrjRJ2hoRK3^gT>zm3$#Ypdm-Jt}m8OWX8}PqX^3XM}Ks|;Hv^; zgp!@W(7)6%!S*C6-ah*G33pgkulUr&?csAATI}`{h|y0F>pk5KPW~LnG5z{jUha61 z(%pZ*g3-QJkxq8B!~S}k-mm{?@`WOphA$K;zV`pD1qrtNwNNVtR?&2$y^EgZS5!kk z|LJ^b{7s4-v@@UQkWRuVecX9UknQ_I@T`J?Lh;IAHDto_k9Vk){T+_gXiyjTVZH!@ z_%w!`;)u|MK+Y!atk7-iQr}szT!7hTp^j}dx{VXiFz;@1tV3{k>k#1gMg3pUz5k04 z&l1)Fq>e8~Q0mLUu_u+a{zQG6E?#Rxlf${U(4<`c<1ps>AHT6@xKMQo_!8I%pYq6` zVk}e8g&OMg(WQ?INU3ozZbyP4UlL+Q-X_bhki4AY;Y-2_NZ`;8nj@*oXJ&*C`OMtE zDO{7;&avnMH$sLfz2=J@m??ZoLh#^EoQz3)urHA{%YU5urE`qmzbV*R>&YBdz^Q^m z_>`xSqa5Xd`rIxlLo|yMse-HNp&nfv<&n@E#l0To{hamHr@P=HkUJjY8T#UqNG3gDrnO2$%P-han~OWN@vGF^qfu z@==1#e;h!?9a*ck8^uQ4Jp)U!G^h5a9mUimfHOvbM)S!CMtb>^ z9D^W$U&?yVj$d2#MWKerc*-i?u9+0JrEbE0oBAh`-GF zHNV-`k4gAWf3-vmunOPLa@Qj#Ct!7-BCXPByu$z%@uRbjG_kZ5c$ewgVM5{~yXVo1 zp3D!ak0XchpROU2x5-~w;t5l8pe#&H710H43FL(K(Rjhm7nh4}Uinv4Yti}R{vn$|~_!y=vOh4S#4y+t{mHIm4gx(y7M2)Pq0owDf z|9Vh&{sV8xUqJZYrgaF0t#UeS4%Ja8^|qjuI=Fbr&`5Zup{42=vBU8rJWaxCAFd>V zQye5$0x|bp+-{0cDVE!nL**x68cCX32v-G4re9anbg_>!BFJS#JMY>NYsraVJzPrA zGVj@oh7iok;U-Y0z6yvd~gDica=p3dpwf^}bJHmAr_g$FNHj zxh2!QG;_}QLq_Ae)`SZnu5$lxQUBz{{+3*dq{p+a5`!L_XJ5107{Z#r;3fMVFLf3_ zL&n_2KGcV@0$!{!0QzE!CJea})XkpV?&dutQY!tX(zN+C1Aq&m?oU5OLKU_%3(gUc zC293kggqzfA{SXwMnmP8Z9iH@lfRYP#y*4>1e1`G7 z!0rO1$+6CD)1pq~93J?BwAInzNWV^EHUNu&9I3}1|DWObh8_)mhV$~oJ0(9Lg();y zc|PJf{3j^8*u3O+Sd|7z7ijn9T<=5#f>{@6^LCuV7yrMmR{6e1^L6~F`VGyRXid3* zT!@7%51c-TYTJ#?Yq!;e%iGe#l#-7W+GLMmAbCiks=?2cQ`%oMzemgS&G-7clypF8q9-*%<+X64@foFyQ_9n3d_Qe1}*|f7KWFgT|Gg$k`s77dslYZ&@bO? z^s{v41>H-nrf%rAmo89CB1VwiSu#X6-NO|jHmp-^0V*Iudu3H?ZeBWQO+Vbc{b=%D zf*95q)P>7;AT)ZrWY0&MgUVve$HP&7nrpw|Bl=O{)Q`E-$X0!+i679gh=YeGqpM|j zr8m_F6@|xS4hy6S$+d1;j!l>R*)@Fqmoml8BX57CPFk<=7D-Hl)|WDDqDC{!*1!Hs zNhaozHH^7IYf%fw9IRY#D)nLc@%uUo8z|)=D?g#3vQlVC2KAK>9X0PE048f@H{aLM z^a-Ur+9uYrc6gxE*OO9umJ6HmQhJowgKB3+AsxN-jPQ^RLfeJ4)MOXjB?N(6NYmmC zH&^?P(?Yh;hg@&BiD=}*qLr`mWWvJNzgApM)4y?w;um3L#?`t=gQ4vk0LEv&W^nmG zspq3o)>!ZPHn($9tC7JHZu^A#ddDauVo<~+uMdewtT%LCh-3+QDm!*1sINVxUpj<MUpcMC+r zZy#28m;dR9V`LXAgFKD>N)N`?7*w6khGA^idTTY#AesGFjWQI-hgDu#g;4^&-h+hx zI1DYd$>HGh2BeU3FJLgx2Q=TZa+lN=yv2kXFqhcxU_>9Svuw~e0LUUdz1X=~|!(-e1K=#<{8=PPHsV`FQes*TPcsJ;;Z<+iwG8_Lc z~@kQ4#fR?eYG=*+=qK-0xDI1t2wO+ z{{A9{1GbO1f$6!adBt=}Si*1Sni4LMtL;h6;&9yf)3Oi+eCG4^Vj}0W*J_Hu2)?>m z+6Q)IT&8X|>@zR#Pg%J1~B;nnvcfPp5CrJxLeOyeDJ_jgZGtc|51#$E~^3fyvog z!sz5bN24lAb^}Z@A6c`(ze5kbBlbQ#y8DcQxFm)qxztMOqo;iWD*@)7Om4aorDv@@ zebcr>`q-`gU%RsWinn6=LugO@M+9?TVx$PpZagza&|3QfZqPjCFYn$A56p0v+}a&@ zU6mT*t)?YzKI4N{X_)@?oNl?bP?_0bbO_gTIIKwQ>&WzDdU>8<0!8P!7`2e}{L;*- zO5X{#CcJzoiZCaiU+2?{C?mb+!rr6FAs=ZBHC8Zg5Obj%6Lx^+)zrM4quwJ_RNGM> zU8UV)RgqD4usKuqVrn%qSE3)3JI~qJ`{*J~LG5*+_iq1i7ne%Udiiw9aiX)GK~ua# z8xHJ3_mC`Zr(b;=?1Qh*aV8<0gxclGO5d&1PG|o|jlO#>yxtEhC<%?2Dm{rXcP_^h z(5QN2R}ZetM^7Okmkas-&1@@u-PP#f^oo7u?8C_1*R%d}I(6MUpfT13g7!0flU&XF z*N`Kp!0sjJ4T`>P=`@uz^$rrcL~r{Sb761QW_S~##*%RLzf??`TeNPa&*b=!xo=ae zf$s&Th#u}4s(cS7M-{g)v}E5Fdi39mG#r6$CGJG49*u7f?P$J8BVXHq1#-I>s|qhH z3=h*R**5eqsPg>n^;B8ckyKdJ>M?H%G=E2L+drCJCXP(_YV|pq7TCOOy6$2n%slD( zU1+<)xQu{GjihTNFN~Lv_5bK?6-@`JJb8V~yP3|iO{vv?6GQZV^=WWuuuDRoag`^T zBzFcwjlB##8nBDnUm6b-nma(_^MHIbB>7ZAeT8Yxm(Zi%KO>d?cIENws&G}CSD&dj z!}XV1xOChHjC%My8IRyJ&Ponw>e5lPdNo1l&c}`#9VdgmxnJ-OU|i3@epd%lG$6O3iWrWH zY-Cd?0(>m(uXpv1`72FaURwL7-H=!FL7rl>qXM>K*!oiDT=8kD7wI}kFCM3;@Xw{H z!`DB+pJ`q#bS&r@Wap;VUe$dOF&i7eELn0CA>6KDg^Z2XtHzG)=0-ECfZ}Dzb#I=# z5LX9)LVfSS%1z?i?m~WiBhBH&5=z?$)C~>$d-m zM)H)vjoS43zXjItXXt9Ij;22S6GpjSo^{g^o=KAjJ-c1xArzeLR*M*YB}>Iw#@|!L zY^il|kBC%QTBN)h4R0FGOEh>6Yve67Lyj%-s4_Lli9WXcBN8z}D=n^X0YPlZYmgfx zbag8n@8@t`59d4@@ZgO+Fkj0 zigDV}^n})z6KBIZ*_E<{3NqTYN#@8;LqbWN1z^Nn!!?R@yq4up&$R~$J(|A*9ki1$ z8K^2(#l(@uirG??b`O($!Yf1Di#kg4PogQY*FDG2Hts4Hvm>F@qwC_97LRQrx|ReJ zEVv^rQ_dfa8thWQZMHz|vNXvWIOa}3(gPggMr%b?@ShQG$(`S*prNRcI!!A)>AH)E zVM`B2%zX2gpyj?Pf#k`hj8;1u%%U{3+2q`YWT+Wmr;nyPqvc%ZF?_3>+~`*8*=2IB z_-uI$ekR0|9(IGGRpygs?1sfs%ja|l#;$SPe4aX2CZXS5a2u+1E2T)kEcre72!+a$ zjJs<$B{3R!-#=Bzw0DcL*k)#1$}qi zBUl&PUO)Wp#cqw}Ydvev3kgY8!XB)agi)G%#B^zMketJ98zkwsl1eT?HmR@EV*K#Y z{3^JiUucke5~-^sL`))C$sseGk+{Y-2{*_7DYn|sgm<>KmAZ@@fA;AeJ^Z4I-xnCm zhZ@Kb*JLu_&%l{ziN!ctbH|-G4Xx5d+qJ>bAvjvi?txW{V>joA#}=3;Q4>rXWDeZUwZh8HZ=BU>nvvhkBmp4_-cXDj5TI4jU zsco8*|J2tFTbmQ|yWAJ1JbB%4xY@2WamIouQLFAfMq6Jf1sk5co_FhDl1$#6%9sel zhU7)7>z>M-s&RV{rZWtPK=nhiHR zW;^J#{1Id<e|k_{u;?y) zzP4|Ov6cW9ElepRK{mIp{NJbG-B$BSI~~t$n=n8~BlO4-P5AjGWP7_QYplAl-4+_L zd*~^vmO3w0{ znU**A{LAH5uTA52HEz9E{eR6}`Cn3b_qQ6W(aMdGa-m!jk}PuHAPU6PG_({FEg{s# zHZ-?Xtjrk^l-$kCHOCe+(H6_p7M4O8MQ0LAvmlqsFqOjH?`59n_52Or&kq+6dA;y@ z@8_KNa?ZI6YO&WIC`mshraTPS3vNodOKNz7@Q(u5*lSBl_z~i&CjVn^5U?mP$6lLX zk{%|O-3z}M)Rb|DbmJeyli$FH>{)qgz{^mNJA4m-mF}+P#i8XNz;)l-rQYn`19#7m zpBo~3^imG6>Hb*`Bx6t1ZtWii^0%BZ&goSD_2ilD+i{oRjGg-`f2&h5_SVHIQczLC-J5W zFm%1`0$8h_p%tj9-twjU<;3r20kHTp2FO;G23_GQK$K;u2?b>nAguiaZs2((1Ca4m zO+e^UH37NA4>f#bs0)J`3}rR+N8C_~iopN`@t;kA58y|;JO>~vAC#-l^0#jQ>R22H zY?O=R0L8gD4hS@@>RWR$c_L}(YXp#4jah+-SW3i$SHNBOZe9`J{!ZQXxYrM{B`bN< zb?Eabpd-bd0emxGMuUgu0@3RJ&}hP;@5@U=%U?$U%Xv6j9bnMQK#^6iAGsR%a1#TF zDrbN{=DE3=?L^bd9|G>4u8zL8pAQ%mYQw9b_PKu;Y7C@o0;YuhYyt*zDccr?cd86r zzv15i4FMQ!Kmh#N1Z>1Vrqg#OSC*^kfO2UaLci7pFPlBDX6C+F)%U5VF{8`p2S(>e z0C_Ucj5_mLjlmeQ%ayMH8s}}7I&ttD#|G)A8|M@R9=TPnP94krQoaN%)-}A)TIAKo z=lB6ZuCXrfWz&?D&+}AcUFszWlt@BME)FND1aaZEMy!Td7N!UJ-JEV35gL% zZ3UIcZCR5i*oUbDo8?kSuVBVO@EAFgHF<`eM)fh4%OO_6VrM}&vMie$%jQy_nouVo ze+Zl11Y^iR4n2wek&1xI=OLrQVzgkH4%JotLQmCI{YvlBRc)Z7^;8?_96gmWeL_#Q zmF}mng3;UcRXgZV1C<^9jDgCTK4GBRLq~&DczQWVMR{?sEVhT8>*7&IuO+*`cWd7$!nz!co*_F(IhyMr=IF2EeA_lO8~p) zYi^(+_YGJVX=;l#wdg}3;H~+%H8d`UbWB$@M?+#rdk%uv^W655EDnyC%9aJGrZH&!j#B`Hu=Qn^1Cw|K27)dCRiLS2_|JSUlgAePg`i`7L$L`fc%~y-K3K|J+lvs#U7_~UPS8Y>5=sHakB(o zn;mGM;|}|D39hb!b6Au6#B5pb-L}9GtYvbYUB*U@hZAeSc=K=MT#km(Ic48M_QK}R zH}5^Yw!dF;yjv1#Zu0pbH&IkKGE^*Y5&2rB#kp=ecRUDn+ZrkVb!&C2-g0cJY^A!(DlH2J*tv#v~tGZuIWjaYV0A-F@Ty#_3K^xNFZkul}0w z8@w%#uPzMf{MPG0D=NhmEVM5Za#O9Kg$wbJ{E?xZ%Lk?-wxkA%G6zZ*`dOd4BKOZ4 zJEBKtTMh=!I^?zci6@RMnL4yr54XHq2z6|q7M~CqK$`YY`_i%2cn2lOAQd#&K+I zbFwlRrMR2e89bfvXoPzjIOE`yglX8L5#(u_W$g6YN6E>-{myrd2LrQD8J!~sJKw%* z+#4uB4;Md-#su$X_*%-d{Z3R_S!l#H|+=GQ?Qf|(g90<&| z?7-*p2`h#@8{jA&;AzU;QN`7K(IjOyk~_ks&=FYYz>^Fi)1ITxl5Z0cC}JvawaL~(&W0#cBQQQB zpZapO$tH)f=7teMnD%)e;&eg-2A^in`Nim*v9zN4nenP^W{op~Skm#=zS9X0cQ4H~ zRQH3G#D^GsV~Ui1@>Dh@_zG3J+T=M{J|Dd<_?o#?7HXmJF2Oex$ophv+Z1O!To^kP z1+ubR#_eF$VKMO2C2Pe?SsOwjk%itxY+)unZtON!{FstN(Vp`?@%IY&dbF)r(u}UE z-rS@Wta>iyYtb(5jlt}VS@FVCc&{K`lZL^>=wVQd9s0mFQZ7t|o|4B-Hpx=0-v=!u z$>R0fM`wZs5%5$&i|0a{h6c))`wUqY%p)R4DyZx-A;Rpxt0P)=mGbvmf$hVa@7NLE z9l146c0GZ|8L-xrP9AeG-94&vDdU_`dYGA6Bf?|Z%FN6=xatF1O9;?v5!??5@Du*Z z7NXRU^($46YWgnYzYDRRd7zk5T`fHZbI{7nVo>tRoGup8Ztikng%njCbcw6Y9BiTp z?=5`%_fjMk!`NWGoSLoNG!;MxPaV<%7@G*dHMD4wBeUZ;(abYzr7a zt>QU7-d$$IXI`bxg_n-#-P2K9hf{060F2vD0P6N$17`V7015p!wOg`P?F=ag%ql-P z71sep^o$y-^Z`uVHFW|155QIScIeqCkiJc*jjxM;fGLz)sr+2Ds%Ud^hJKqiB+COYMUsq1M+S~aGPn2zT>0wryUk4xY z)!I>;UYNHR?_z1^`x9P!*}-pZR=@?(ufV$-j`*(5GDt76O3OZH7Fp_b$oChM&vxAy ztBZnL_+g9gXsyUn_95RDJFG4UKJOp?r5jV5S{Q)tcwIjGcbC)MTcvX(-+6=;W26@) zSJp{A{N?{fIu4Fg=qi7NB!7B1}p zSiB479L87YRGIN+>g>qB-(LCBcU@LePBbMFwZl#kC0qJ4(LZuPho3?ifDQ-jmA~Jv z;K~@*idLB^LLrp3)s^aQR-Kx?+&%KSg6;=V{VvYK$U}E4;PR#23R`)btpa#yr|_09 z*(nao+a4sEMGnXXt)~a(1@31Dbc8AN0dwJE^njx<<=jAkur(I-tDU0bTI~gad-6bs zFePPRROp^MFfVl5)A=iJU{9w3uN2b>1!8ZfHP3ior#O$jEqA}R> zAVxNy-cU!4e&XDajfwS%6h3>h?lx7{0vw{BuB)RSG|3wSelP7y@yVU5z815)fJ1Xv z+SlSwXErp*F?;r}d+1H+Hi7GG@S<#a@3T(iExWkS7D+twr(0j~S zMTYJ03Qt?Q`4t1l)z0+lD*>jBb_R|H&h!{0Z1Pz+gK3nTqwlzV+B?zd?_|&Xym$8x z4D8x*`_u9_PRWAnru>B#X#T<@BlxWC6|}YZk9YuPh9))?^)48XcAZ~BeVXu|Zpm+t z5>JFB5{dpmgR6G}7`SBO1NPv=MNCkKo6@kd_rrgXV(dk{JsI##`$YG`n?KJwVIkyc`A4#Hl?2Me z`Y82GpE6(J53q%l-3_2cAeHI%g@?nm;Zu~%9Ppt}xQ*iUjbi>ru_ib%2NzSxui%5l znub8i74s1nGl?TzkdQAUBe#0QAU$F*9;AE;xtIWsSa+m?06t-7_**`IGwr!Yj6_h8 zZbX~(h*^Or@g(F|1pRbmA^{&0h9?aWzzO*{Q(7gSG@fIaoR5Qw)1kCU{Obzb7E8jX z0Py8}+*VqcC&}2qhiu^w&dleVS#l$9AdFwL@S>Hu;Z?e~EWic%>6Vs+hC}+AJ~ZzB z{V|gL`w=L(_Cc>I$nD3F8iXgDS#>KnXJmZT@gAzjZPqhJu5D|G>M5P6NSwsP$P*dK zn98&3#8!}vL_ey?Xpz08f4%MS+kkr9 z@Z8@|!wbF=A3wx-O#+;dVMlBu*|8(`J~^o4!9#LV#{;MOj^QIA^@GDlLhHZLukTDR z%^B128q!U{DUEXc2R1R6YLt!=Rel?6uBOMY;6<0Gl2&uZIweGzB+)5EaY5;Yj3&?@ z9z#d8u;vm~;a-WSQX&b$w})hUm`fhv(a;pe=VdBFSN<>js08H+h-Ui#;t!&^z@(fEmB1CLfa7YB+cGB!>^v_3HdIsGHd60EsC?obP?dm)5FAIM zSo9?vYIj}A4l~YfT z*xr*O?l@Gh<$?+wgU%M3O*iH?)r}xr^RP%NslT5*ND53SJX|Ker1Z}Z)wf1_i+tgP zJtVC+-c=2|{o{yCv!A)JHiYIkOJpegj)!+n(*FL}mYGi1m@obcuY$B)ZM62;54t>p z{g`Y^i@2H#+qT$%eV!7;T=_=Fn{mK)w$(mw`IPf)yu@cV#XhxMJQO=U(Y;_)&>qsy ztOb26%x_PMi7)f72<}-J&#xM6r26$gs0B?Hc7@MAE$lk`{<+nJtaspbt@t#`{M#pk zq0tdv;E60C?mN6?Cf_7^%H9Ke{DdF5kBag1=@wo-*GX4H2DPl>6{Zwg1YYBb@`&mF zfxig17ZADnn^_k`8X9Zu_hT`K?gUXRz3YAhn#)rE@vghT{AU-}<P>0AY@Ze6t0?i5z z*KsNEz+L>zKZ(PK0xJZ!ZxZ1f@6?LENQm@})?7+#VBOp8cigBCg6cF_|AcYR*VR2? z7esQ8+^u7<3+UV@Hi1g}_#dq6SSr3f+KxExawKlr8h?RrQ<1TWNUP(<*iXGI^ndTvO zQdhH1R#K1D*-{ZeEy`<7%^LKg1m#L&EflfxHb=!pYQz=kuNI0NIm0<_I%9sUxi)+L zYja=ryrOvxXMR#jFpulbNct&-o5u+*aQ*;gJHGb<}=iRXEOgMh_)81JaMGDMR z7}?l?r|*Lo4gnsUIh+n*7gSTX<`_!L%_iY4!N=t1JwVhhUFS`m*H|H^Y_!A!MiEJooHw zK`Mb~M127PI-Mc~Y{Dxe`720(K)O3FoReO{J=O$L3V`k8CgE=*`5U5g6SW`G2M`V5 z-xWYr$l~M#z-$jf4T@F{0X@!cqT{mZ=ipOW0UU~&YzVJB!;;0IE` znPjl%<)&K{YrG_9jC&1*(*-Yvh`_K+L&Aa)z%?xEsm!vok7t!fyLPO60y$vKS3K^xww}j`UyiY-Cee2ku z1azajncu1}{7E_sZIR&V2gW_2I2HG0Xw&y4fKXrDGnq0jDANAk1$g3hKp)G2S}!P! z#~J)m{lO~k4o6ll<)XBvfNsizJGC-RG`tCn7}XriG}C01f(uqI!`imvmS}%0z?7WpU~g_J=p^oW zDtwMJ2=V@y+V70cT&6w}c#?k6bC;cun%9orZa{={LH#_j{x7Q!0i!-Bw$U@n9aNh&}vCYh{q2yKa z^N>D%GfEJ-1K_q}Nr2p%}pKc;`niaJZ?$e$SZjW+uV?Op2!>FYUP z6Ulw@In%z`<`Ln8c2I{$yYAvXnExG$vGM7+uOMr*zDcUrHi(%_g>U8D5L(ut@0mxA-<}}-pl5>=e zse(BQEVyfT3E*nsXP#OF`zwp4D&CBhU@s6`_YOj=_N z)9goT4QC005KsWnD2PD%HnDd8=gNI1!vobc4MY}yB_SCMXRS5^l+3b630w5}ztQwC z{RL>Pe$k~%u#+sDrZ`=bpajFU*O_sXXg3fJ8Q4m4|LgY0GZlzE8CXI{|3`G@xaiVl zPtbduNOswCyp*J`c^=5JDiLIu)vA0f<|wK2AlNRS_j<*!@>$_`OHuumOI$bz z-eYHwep$?uWrSBr8?F-VBt9UE5nfehc-2`tgUL4x*_LTJS~P&NYHtspYTseCY*PYn zZyK3snr%6~WKxn^J@tr{-ySh*gcl9D_bj;OcX{5J?PqrR&z>ykIx@S!kKiUdbc{Yo z{#`yzM!g$u3PsINy2FN;Qzr1Cs{j`+YXJ@2naSp>cIXea&X@|~ceh=ebkE|&JG8Y- zx@S+sShT&HbmvSYC9C9{b(vo=WFy&Ty}r!m(^%PN%98Se?*A>K?El3_m!b7zx=!iO*G#Iv*?ycawtnxiOaBLE@oXCa literal 0 HcmV?d00001 diff --git a/modules/test-machine/variables.tf b/modules/test-machine/variables.tf index f32d00e..6813331 100644 --- a/modules/test-machine/variables.tf +++ b/modules/test-machine/variables.tf @@ -56,7 +56,7 @@ variable "availability_zone" { variable "machine_type" { description = "Flavor of the machine" type = string - default = "g1.1" + default = "c2i.1" } variable "image_id" { From 20dd7ec31453935948cc649130ceb2aa6a517948 Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Wed, 13 May 2026 13:53:46 +0200 Subject: [PATCH 13/14] example(vpn): remove my mail --- examples/vpn-usecases/stackit-azure/020-variables.tf | 4 ++++ examples/vpn-usecases/stackit-azure/030-stackit-azure-vpn.tf | 2 +- examples/vpn-usecases/stackit-gcp/020-variables.tf | 4 ++++ examples/vpn-usecases/stackit-gcp/030-stackit-gcp-vpn.tf | 2 +- examples/vpn-usecases/stackit-stackit/020-variables.tf | 4 ++++ .../vpn-usecases/stackit-stackit/030-stackit-stackit-vpn.tf | 4 ++-- 6 files changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/vpn-usecases/stackit-azure/020-variables.tf b/examples/vpn-usecases/stackit-azure/020-variables.tf index d3bc60b..ae3c32e 100644 --- a/examples/vpn-usecases/stackit-azure/020-variables.tf +++ b/examples/vpn-usecases/stackit-azure/020-variables.tf @@ -28,3 +28,7 @@ variable "stackit_service_account_key_path" { variable "azure_subscription_id" { type = string } + +variable "stackit_admin_email" { + type = string +} diff --git a/examples/vpn-usecases/stackit-azure/030-stackit-azure-vpn.tf b/examples/vpn-usecases/stackit-azure/030-stackit-azure-vpn.tf index bad5cd7..2d3d7a2 100644 --- a/examples/vpn-usecases/stackit-azure/030-stackit-azure-vpn.tf +++ b/examples/vpn-usecases/stackit-azure/030-stackit-azure-vpn.tf @@ -20,7 +20,7 @@ module "vpn_sna_01" { machine_network_name = "vpn-sna-01" sna_name = "vpn-sna-01" machine_name = "vpn-sna-01" - stackit_admin_email = "mauritz.uphoff@digits.schwarz" + stackit_admin_email = var.stackit_admin_email stackit_org_id = var.stackit_org_id stackit_project_name = "vpn-sna-01" sna_network_range_prefix = [ diff --git a/examples/vpn-usecases/stackit-gcp/020-variables.tf b/examples/vpn-usecases/stackit-gcp/020-variables.tf index 0288fbb..474bdbc 100644 --- a/examples/vpn-usecases/stackit-gcp/020-variables.tf +++ b/examples/vpn-usecases/stackit-gcp/020-variables.tf @@ -34,3 +34,7 @@ variable "gcp_service_account_key_path" { variable "gcp_project" { type = string } + +variable "stackit_admin_email" { + type = string +} diff --git a/examples/vpn-usecases/stackit-gcp/030-stackit-gcp-vpn.tf b/examples/vpn-usecases/stackit-gcp/030-stackit-gcp-vpn.tf index 8f0c906..5f82603 100644 --- a/examples/vpn-usecases/stackit-gcp/030-stackit-gcp-vpn.tf +++ b/examples/vpn-usecases/stackit-gcp/030-stackit-gcp-vpn.tf @@ -20,7 +20,7 @@ module "vpn_sna_01" { machine_network_name = "vpn-sna-01" sna_name = "vpn-sna-01" machine_name = "vpn-sna-01" - stackit_admin_email = "mauritz.uphoff@digits.schwarz" + stackit_admin_email = var.stackit_admin_email stackit_org_id = var.stackit_org_id stackit_project_name = "vpn-sna-01" sna_network_range_prefix = [ diff --git a/examples/vpn-usecases/stackit-stackit/020-variables.tf b/examples/vpn-usecases/stackit-stackit/020-variables.tf index 2606c07..a0f733d 100644 --- a/examples/vpn-usecases/stackit-stackit/020-variables.tf +++ b/examples/vpn-usecases/stackit-stackit/020-variables.tf @@ -26,3 +26,7 @@ variable "stackit_region" { variable "stackit_service_account_key_path" { type = string } + +variable "stackit_admin_email" { + type = string +} diff --git a/examples/vpn-usecases/stackit-stackit/030-stackit-stackit-vpn.tf b/examples/vpn-usecases/stackit-stackit/030-stackit-stackit-vpn.tf index 234356c..42c60eb 100644 --- a/examples/vpn-usecases/stackit-stackit/030-stackit-stackit-vpn.tf +++ b/examples/vpn-usecases/stackit-stackit/030-stackit-stackit-vpn.tf @@ -19,7 +19,7 @@ module "vpn_sna_01" { machine_network_name = "vpn-sna-01" sna_name = "vpn-sna-01" machine_name = "vpn-sna-01" - stackit_admin_email = "mauritz.uphoff@digits.schwarz" + stackit_admin_email = var.stackit_admin_email stackit_org_id = var.stackit_org_id stackit_project_name = "vpn-sna-01" sna_network_range_prefix = [ @@ -34,7 +34,7 @@ module "vpn_sna_02" { machine_network_name = "vpn-sna-02" machine_name = "vpn-sna-02" sna_name = "vpn-sna-02" - stackit_admin_email = "mauritz.uphoff@digits.schwarz" + stackit_admin_email = var.stackit_admin_email stackit_org_id = var.stackit_org_id stackit_project_name = "vpn-sna-02" sna_network_range_prefix = [ From efab3f3f9810d070ef3561581759e2f590691f2e Mon Sep 17 00:00:00 2001 From: Mauritz Uphoff Date: Mon, 18 May 2026 16:40:56 +0200 Subject: [PATCH 14/14] example(stackit-landing-zone): create link to landing-zone repository --- examples/stackit-landing-zone/README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 examples/stackit-landing-zone/README.md diff --git a/examples/stackit-landing-zone/README.md b/examples/stackit-landing-zone/README.md new file mode 100644 index 0000000..5173e22 --- /dev/null +++ b/examples/stackit-landing-zone/README.md @@ -0,0 +1,4 @@ +# STACKIT Landing Zone + +For the full Terraform Landing Zone implementation, please visit: +[STACKIT Terraform Landing Zone Repository](https://github.com/stackitcloud/stackit-landing-zone)