From ec1ccd5ad14342dce695e2edbfc70e3e07c587db Mon Sep 17 00:00:00 2001 From: Jo Schwandke Date: Tue, 4 Aug 2026 14:33:56 +0200 Subject: [PATCH 1/2] chore: dedicated networked-project setup that works without StackitNetworkArea tag on LZ level --- modules/stackit/meshstack_integration.tf | 104 +++++++++++------- .../stackit/project/buildingblock/README.md | 7 +- modules/stackit/project/buildingblock/main.tf | 31 +----- .../project/buildingblock/variables.tf | 20 +--- .../stackit-landingzone/README.md | 8 +- .../buildingblock/README.md | 4 +- .../buildingblock/SUMMARY.md.tftpl | 7 +- .../stackit-landingzone/buildingblock/main.tf | 41 ++----- .../buildingblock/outputs.tf | 18 ++- .../buildingblock/variables.tf | 3 +- .../meshstack_integration.tf | 13 ++- 11 files changed, 105 insertions(+), 151 deletions(-) diff --git a/modules/stackit/meshstack_integration.tf b/modules/stackit/meshstack_integration.tf index 614b4eed..3b2f2de8 100644 --- a/modules/stackit/meshstack_integration.tf +++ b/modules/stackit/meshstack_integration.tf @@ -45,13 +45,19 @@ variable "role_mapping" { variable "stackit_project_labels" { type = map(string) default = {} - description = "Additional labels applied to every STACKIT project created by this building block, merged with the `networkArea` label resolved at runtime from the landing zone's tags." + description = "Additional labels applied to every STACKIT project created by this building block." } -variable "stackit_network_area_tag_name" { +variable "stackit_networked_projects_enabled" { + type = bool + default = false + description = "Whether to create a second, `networked` STACKIT Project building block definition and landing zone whose projects are placed in `stackit_network_area_id`. Must be known at plan time (`stackit_network_area_id` itself may only resolve during apply)." +} + +variable "stackit_network_area_id" { type = string default = null - description = "Name of the meshStack landing zone tag whose value is used as the STACKIT project's `networkArea` label. Set to null (default) to skip network area assignment." + description = "STACKIT network area ID applied as the `networkArea` label to projects created through the `networked` landing zone. Only used when `stackit_networked_projects_enabled` is true." } variable "meshstack" { @@ -100,7 +106,8 @@ module "backplane" { workload_identity_federation = { issuer = data.meshstack_integrations.integrations.workload_identity_federation.replicator.issuer subjects = [ - "${trimsuffix(data.meshstack_integrations.integrations.workload_identity_federation.replicator.subject, ":replicator")}:workspace.${var.meshstack.owning_workspace_identifier}.buildingblockdefinition.${meshstack_building_block_definition.this.metadata.uuid}" + for bbd in meshstack_building_block_definition.this : + "${trimsuffix(data.meshstack_integrations.integrations.workload_identity_federation.replicator.subject, ":replicator")}:workspace.${var.meshstack.owning_workspace_identifier}.buildingblockdefinition.${bbd.metadata.uuid}" ] } } @@ -110,11 +117,40 @@ data "meshstack_integrations" "integrations" {} output "building_block_definition" { description = "BBD is consumed in building block compositions." value = { - uuid = meshstack_building_block_definition.this.metadata.uuid - version_ref = var.hub.bbd_draft ? meshstack_building_block_definition.this.version_latest : meshstack_building_block_definition.this.version_latest_release + uuid = meshstack_building_block_definition.this["default"].metadata.uuid + version_ref = var.hub.bbd_draft ? meshstack_building_block_definition.this["default"].version_latest : meshstack_building_block_definition.this["default"].version_latest_release } } +output "service_account_email" { + description = "Email of the backplane STACKIT service account that creates and manages tenant projects." + value = module.backplane.service_account_email +} + +# One STACKIT Project building block definition plus landing zone per project variant. The +# `networked` variant carries the `networkArea` label as a static building block input, so projects +# are placed in the network area without any landing zone tag lookup at run time. +locals { + project_variants = merge( + { + default = { + bbd_display_name = "STACKIT Project" + landingzone_display_name = "STACKIT Sandbox" + landingzone_description = "Creates a STACKIT project in the landing zone folder, with project roles mapped from meshStack project roles. The project is not attached to a network area, so it uses STACKIT's default flat networking." + network_area_id = null + } + }, + var.stackit_networked_projects_enabled ? { + networked = { + bbd_display_name = "STACKIT Networked Project" + landingzone_display_name = "STACKIT Networked" + landingzone_description = "Creates a STACKIT project placed in the shared hub network area, with project roles mapped from meshStack project roles. Order the STACKIT Network building block inside the project to get a routed subnet drawn from the hub's address plan." + network_area_id = var.stackit_network_area_id + } + } : {} + ) +} + resource "meshstack_platform" "stackit" { metadata = { name = var.meshstack.platform_identifier @@ -130,6 +166,8 @@ resource "meshstack_platform" "stackit" { description = "Create a STACKIT project with configurable role-based access control." endpoint = "https://portal.stackit.cloud" + documentation_url = "https://hub.meshcloud.io/reference-architectures/stackit-landingzone" + location_ref = { name = var.meshstack.location_name } @@ -148,16 +186,19 @@ resource "meshstack_platform" "stackit" { } } -resource "meshstack_landingzone" "stackit_default" { +resource "meshstack_landingzone" "this" { + for_each = local.project_variants + metadata = { - name = "${var.meshstack.platform_identifier}-default" + name = "${var.meshstack.platform_identifier}-${each.key}" owned_by_workspace = var.meshstack.owning_workspace_identifier tags = var.meshstack.tags.landingzone } spec = { - display_name = "STACKIT Default" - description = "Default landing zone for STACKIT projects." + display_name = each.value.landingzone_display_name + description = each.value.landingzone_description + info_link = "https://hub.meshcloud.io/reference-architectures/stackit-landingzone" automate_deletion_approval = true automate_deletion_replication = true @@ -170,19 +211,21 @@ resource "meshstack_landingzone" "stackit_default" { } mandatory_building_block_refs = [ - { uuid = meshstack_building_block_definition.this.metadata.uuid } + { uuid = meshstack_building_block_definition.this[each.key].metadata.uuid } ] } } resource "meshstack_building_block_definition" "this" { + for_each = local.project_variants + metadata = { owned_by_workspace = var.meshstack.owning_workspace_identifier tags = var.meshstack.tags.building_block } spec = { - display_name = "STACKIT Project" + display_name = each.value.bbd_display_name symbol = "https://raw.githubusercontent.com/meshcloud/meshstack-hub/${var.hub.git_ref}/modules/stackit/project/buildingblock/logo.png" description = "Creates a new STACKIT project and manages user access permissions with configurable role-based access control." support_url = "https://portal.stackit.cloud" @@ -211,7 +254,7 @@ resource "meshstack_building_block_definition" "this" { } } - inputs = merge({ + inputs = { parent_container_id = { display_name = "Parent Container ID" description = "Default parent container ID (organization or folder) where the project will be created." @@ -297,35 +340,15 @@ resource "meshstack_building_block_definition" "this" { labels = { display_name = "Labels" - description = "Additional labels applied to the STACKIT project, merged with the `networkArea` label resolved at runtime from the landing zone's tags." + description = "Labels applied to the STACKIT project, including the `networkArea` label for the networked variant." type = "CODE" assignment_type = "STATIC" - argument = jsonencode(jsonencode(var.stackit_project_labels)) + argument = jsonencode(jsonencode(merge( + var.stackit_project_labels, + each.value.network_area_id != null ? { networkArea = each.value.network_area_id } : {} + ))) } - - workspace_identifier = { - display_name = "Workspace Identifier" - description = "meshStack workspace identifier, used to look up this project's landing zone tags at runtime." - type = "STRING" - assignment_type = "WORKSPACE_IDENTIFIER" - } - - platform_identifier = { - display_name = "Platform Identifier" - description = "meshStack platform identifier, used to look up this project's landing zone tags at runtime." - type = "STRING" - assignment_type = "FULL_PLATFORM_IDENTIFIER" - } - - }, var.stackit_network_area_tag_name != null ? { - network_area_tag_name = { - display_name = "Network Area Tag Name" - description = "Name of the meshStack landing zone tag whose value is used as the STACKIT project's `networkArea` label." - type = "STRING" - assignment_type = "STATIC" - argument = jsonencode(var.stackit_network_area_tag_name) - } - } : {}) + } outputs = { project_url = { @@ -358,9 +381,6 @@ resource "meshstack_building_block_definition" "this" { assignment_type = "SUMMARY" } } - - # TENANT_LIST/LANDINGZONE_LIST: needed by meshstack_tenant/meshstack_landingzone data sources for network area tag lookup. - permissions = ["TENANT_LIST", "LANDINGZONE_LIST"] } } diff --git a/modules/stackit/project/buildingblock/README.md b/modules/stackit/project/buildingblock/README.md index 075786d8..632f6355 100644 --- a/modules/stackit/project/buildingblock/README.md +++ b/modules/stackit/project/buildingblock/README.md @@ -57,24 +57,19 @@ No modules. |------|------| | [stackit_authorization_project_role_assignment.role_assignments](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/authorization_project_role_assignment) | resource | | [stackit_resourcemanager_project.project](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/resourcemanager_project) | resource | -| [meshstack_landingzone.this](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/data-sources/landingzone) | data source | -| [meshstack_tenant.this](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/data-sources/tenant) | data source | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [environment](#input\_environment) | The environment type (production, staging, development). If not set, uses parent\_container\_id directly. | `string` | `null` | no | -| [labels](#input\_labels) | Additional labels to apply to the project, merged with the `networkArea` label resolved from the landing zone's tags. | `map(string)` | n/a | yes | -| [network\_area\_tag\_name](#input\_network\_area\_tag\_name) | Name of the meshStack landing zone tag whose value is used as the STACKIT project's `networkArea` label. Set to null (default) to skip network area assignment — projects remain usable without a network area. | `string` | `null` | no | +| [labels](#input\_labels) | Labels to apply to the project. Includes the `networkArea` label when the building block definition is wired to a network area. | `map(string)` | n/a | yes | | [parent\_container\_id](#input\_parent\_container\_id) | The parent container ID (organization or folder) where the project will be created. | `string` | n/a | yes | | [parent\_container\_ids](#input\_parent\_container\_ids) | Parent container IDs for different environments. If environment is set, the corresponding container ID will be used. |
object({
production = optional(string)
staging = optional(string)
development = optional(string)
})
| `{}` | no | -| [platform\_identifier](#input\_platform\_identifier) | meshStack platform identifier, used to look up this project's landing zone tags at runtime. | `string` | n/a | yes | | [project\_name](#input\_project\_name) | The name of the StackIt project to create. | `string` | n/a | yes | | [role\_mapping](#input\_role\_mapping) | Maps meshStack roles from `users[*].roles` to STACKIT project roles. Values can be built-in STACKIT roles or custom STACKIT role names. Unknown meshStack roles are ignored. | `map(list(string))` | n/a | yes | | [service\_account\_email](#input\_service\_account\_email) | Email of the STACKIT service account for WIF-based authentication and project ownership. | `string` | n/a | yes | | [users](#input\_users) | List of users from the authoritative system. Each user's `roles` are meshStack roles that are mapped to STACKIT project roles via `role_mapping`. |
list(object({
meshIdentifier = string
username = string
firstName = string
lastName = string
email = string
euid = string
roles = list(string)
}))
| n/a | yes | -| [workspace\_identifier](#input\_workspace\_identifier) | meshStack workspace identifier, used to look up this project's landing zone tags at runtime. | `string` | n/a | yes | ## Outputs diff --git a/modules/stackit/project/buildingblock/main.tf b/modules/stackit/project/buildingblock/main.tf index 8aea23d7..de99b36a 100644 --- a/modules/stackit/project/buildingblock/main.tf +++ b/modules/stackit/project/buildingblock/main.tf @@ -1,36 +1,7 @@ -# TODO: migrate to the meshstack_tenant_v4 data source once meshStack supports a tenant UUID -# as a building block input (currently under development). That will let us look up the -# tenant from a single identifier instead of the three separate identity inputs below -# (project_name/workspace_identifier/platform_identifier). -data "meshstack_tenant" "this" { - lifecycle { - enabled = var.network_area_tag_name != null - } - - metadata = { - owned_by_project = var.project_name - owned_by_workspace = var.workspace_identifier - platform_identifier = var.platform_identifier - } -} - -data "meshstack_landingzone" "this" { - lifecycle { - enabled = var.network_area_tag_name != null - } - - metadata = { - name = data.meshstack_tenant.this.spec.landing_zone_ref.name - } -} - locals { # Determine the parent container ID based on environment selected_parent_container_id = var.environment != null ? lookup(var.parent_container_ids, var.environment, var.parent_container_id) : var.parent_container_id - network_area_id = var.network_area_tag_name != null ? data.meshstack_landingzone.this.metadata.tags[var.network_area_tag_name][0] : null - project_labels = merge(var.labels, local.network_area_id != null ? { networkArea = local.network_area_id } : {}) - users_with_stackit_roles = [ for user in var.users : { email = user.email @@ -59,7 +30,7 @@ resource "stackit_resourcemanager_project" "project" { owner_email = var.service_account_email # Only set labels if there are actually labels to set - labels = length(local.project_labels) > 0 ? local.project_labels : null + labels = length(var.labels) > 0 ? var.labels : null } # User role assignments (experimental IAM feature) diff --git a/modules/stackit/project/buildingblock/variables.tf b/modules/stackit/project/buildingblock/variables.tf index 7d24c640..b6cab1ee 100644 --- a/modules/stackit/project/buildingblock/variables.tf +++ b/modules/stackit/project/buildingblock/variables.tf @@ -35,25 +35,7 @@ variable "service_account_email" { variable "labels" { type = map(string) nullable = false - description = "Additional labels to apply to the project, merged with the `networkArea` label resolved from the landing zone's tags." -} - -variable "workspace_identifier" { - type = string - nullable = false - description = "meshStack workspace identifier, used to look up this project's landing zone tags at runtime." -} - -variable "platform_identifier" { - type = string - nullable = false - description = "meshStack platform identifier, used to look up this project's landing zone tags at runtime." -} - -variable "network_area_tag_name" { - type = string - default = null - description = "Name of the meshStack landing zone tag whose value is used as the STACKIT project's `networkArea` label. Set to null (default) to skip network area assignment — projects remain usable without a network area." + description = "Labels to apply to the project. Includes the `networkArea` label when the building block definition is wired to a network area." } variable "users" { diff --git a/reference-architectures/stackit-landingzone/README.md b/reference-architectures/stackit-landingzone/README.md index 225160fa..73e647f9 100644 --- a/reference-architectures/stackit-landingzone/README.md +++ b/reference-architectures/stackit-landingzone/README.md @@ -80,8 +80,10 @@ When a **network** configuration is provided, it additionally: 5. Registers the [`stackit/network`](../../modules/stackit/network) building block definition (`TENANT_LEVEL`) so application teams can self-service order routed networks (spokes) inside their STACKIT projects, drawing from the hub's address plan. -6. Provisions an additional **networked landing zone**, tagged with the hub's network area ID, so - new STACKIT projects created against it are placed in the hub's network area. +6. Provisions an additional **networked project definition and landing zone**. The networked + `STACKIT Project` building block definition carries the hub's network area ID as a static + `networkArea` label, so new STACKIT projects created against that landing zone are placed in the + hub's network area. ## Getting Started @@ -96,7 +98,7 @@ When a **network** configuration is provided, it additionally: Order the **STACKIT Landing Zone** building block once per workspace. Without a network configuration it creates the platform and default landing zone. With a network configuration it -additionally creates the hub network area instance, the networked landing zone, and registers the +additionally creates the hub network area instance, the networked project definition and landing zone, and registers the spoke `stackit/network` building block in the same apply. Application teams can then request projects and — when networking is enabled — order `stackit/network` inside their own STACKIT projects once those projects exist. diff --git a/reference-architectures/stackit-landingzone/buildingblock/README.md b/reference-architectures/stackit-landingzone/buildingblock/README.md index e7fc4157..dee9862e 100644 --- a/reference-architectures/stackit-landingzone/buildingblock/README.md +++ b/reference-architectures/stackit-landingzone/buildingblock/README.md @@ -50,18 +50,16 @@ The user-facing readme is maintained inline in the `readme` field of the | Name | Type | |------|------| | [meshstack_building_block.network_area_hub](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block) | resource | -| [meshstack_landingzone.networked](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/landingzone) | resource | | [meshstack_location.this](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/location) | resource | | [stackit_resourcemanager_folder.this](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/resourcemanager_folder) | resource | | [stackit_resourcemanager_project.foundation](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/resourcemanager_project) | resource | -| [meshstack_landingzone.foundation_default](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/data-sources/landingzone) | data source | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [hub](#input\_hub) | `git_ref`: meshstack-hub reference used to source the nested foundation, network-area, and network integration modules. `const` so it can be interpolated into the module source at init time.
`bbd_draft`: Forwarded as-is to those nested integrations' own `hub.bbd_draft`, so their building block definition draft state tracks this building block's own release state. |
object({
git_ref = optional(string, "main")
bbd_draft = optional(bool, true)
})
|
{
"bbd_draft": true,
"git_ref": "main"
}
| no | -| [network](#input\_network) | Optional hub-and-spoke network topology. Leave unset (null) to deploy only the sandbox landing zone. When set, additionally provisions a shared hub network area with the given address plan (`hub_*` fields), registers the self-service spoke `STACKIT Network` building block (`tenant_network_*` prefix bounds), and creates a `networked` landing zone (tagged via `network_area_tag_name`) whose projects are placed in the hub network area. |
object({
network_area_tag_name = optional(string, "StackitNetworkArea")
hub_network_area_name = optional(string, "hub")
hub_network_ranges = optional(list(string), ["10.0.0.0/16"])
hub_transfer_network = optional(string, "10.1.255.0/24")
hub_min_prefix_length = optional(number, 24)
hub_max_prefix_length = optional(number, 28)
hub_default_prefix_length = optional(number, 28)
hub_default_nameservers = optional(list(string), [])
tenant_network_min_prefix_length = optional(number, 24)
tenant_network_max_prefix_length = optional(number, 28)
})
| `null` | no | +| [network](#input\_network) | Optional hub-and-spoke network topology. Leave unset (null) to deploy only the sandbox landing zone. When set, additionally provisions a shared hub network area with the given address plan (`hub_*` fields), registers the self-service spoke `STACKIT Network` building block (`tenant_network_*` prefix bounds), and adds a dedicated `networked` STACKIT Project building block definition and landing zone whose projects are placed in the hub network area. |
object({
hub_network_area_name = optional(string, "hub")
hub_network_ranges = optional(list(string), ["10.0.0.0/16"])
hub_transfer_network = optional(string, "10.1.255.0/24")
hub_min_prefix_length = optional(number, 24)
hub_max_prefix_length = optional(number, 28)
hub_default_prefix_length = optional(number, 28)
hub_default_nameservers = optional(list(string), [])
tenant_network_min_prefix_length = optional(number, 24)
tenant_network_max_prefix_length = optional(number, 28)
})
| `null` | no | | [platform\_identifier](#input\_platform\_identifier) | Identifier for the STACKIT sandbox platform created in meshStack (letters, digits and dashes only). | `string` | n/a | yes | | [role\_mapping](#input\_role\_mapping) | Default mapping from meshStack roles to STACKIT project roles for the nested STACKIT Project integration. Values can be built-in STACKIT roles or custom STACKIT role names. | `map(list(string))` | n/a | yes | | [stackit\_org](#input\_stackit\_org) | STACKIT organization UUID under which the landing-zone folder, foundation project and tenant projects are created. | `string` | n/a | yes | diff --git a/reference-architectures/stackit-landingzone/buildingblock/SUMMARY.md.tftpl b/reference-architectures/stackit-landingzone/buildingblock/SUMMARY.md.tftpl index a8d028ef..92c16729 100644 --- a/reference-architectures/stackit-landingzone/buildingblock/SUMMARY.md.tftpl +++ b/reference-architectures/stackit-landingzone/buildingblock/SUMMARY.md.tftpl @@ -4,11 +4,14 @@ | Property | Value | |----------|-------| +| **Organization** | [Open in STACKIT Portal](${organization_url}) (`${organization_id}`) | +| **Landing Zone Folder** | [Open in STACKIT Portal](${lz_folder_url}) (`${lz_folder_container_id}`) | | **Foundation Project** | [Open in STACKIT Portal](${foundation_project_url}) (`${foundation_project_id}`) | -| **Landing Zone Folder** | `${lz_folder_container_id}` | +| **Foundation Project Service Account** | [Open in STACKIT Portal](${service_account_url}) (`${service_account_email}`) | %{ if network_enabled ~} +| **Hub Network Area** | [Open in STACKIT Portal](${network_area_url}) (`${network_area_id}`) | +| **Hub Network Area Building Block** | @buildingblock[${network_area_hub_uuid}] | | **Networked Landing Zone** | `${networked_landingzone_name}` | -| **Hub Network Area** | @buildingblock[${network_area_hub_uuid}] | %{ endif ~} %{ if network_enabled ~} diff --git a/reference-architectures/stackit-landingzone/buildingblock/main.tf b/reference-architectures/stackit-landingzone/buildingblock/main.tf index 734156e5..2f141a07 100644 --- a/reference-architectures/stackit-landingzone/buildingblock/main.tf +++ b/reference-architectures/stackit-landingzone/buildingblock/main.tf @@ -1,6 +1,9 @@ locals { # Hub-and-spoke networking is deployed only when the operator supplies a `network` object. network_enabled = var.network != null + + # Only resolvable once the hub network area building block has completed. + network_area_id = local.network_enabled ? jsondecode(meshstack_building_block.network_area_hub[0].status.outputs["network_area_id"].value) : null } # ── Sandbox landing zone foundation (always deployed) ── @@ -42,7 +45,11 @@ module "stackit_integration" { stackit_service_account_name = substr(var.platform_identifier, 0, 20) role_mapping = var.role_mapping stackit_organization_onboarding_enabled = var.stackit_organization_onboarding_enabled - stackit_network_area_tag_name = local.network_enabled ? var.network.network_area_tag_name : null + + # The networked project definition places its projects in the hub network area via a static + # `networkArea` label, so no landing zone tag (and no tag definition) is involved. + stackit_networked_projects_enabled = local.network_enabled + stackit_network_area_id = local.network_area_id hub = var.hub @@ -117,35 +124,3 @@ resource "meshstack_building_block" "network_area_hub" { } } } - -# Looks up the default landing zone that `module.stackit_integration` already registered, without -# needing new outputs threaded through it. Used below only as an input into the independent -# `networked` landing zone — never fed back into the integration itself, which would create a cycle. -data "meshstack_landingzone" "foundation_default" { - count = local.network_enabled ? 1 : 0 - metadata = { name = "${var.platform_identifier}-default" } - depends_on = [module.stackit_integration] -} - -resource "meshstack_landingzone" "networked" { - count = local.network_enabled ? 1 : 0 - - metadata = { - name = "${var.platform_identifier}-networked" - owned_by_workspace = var.workspace - tags = merge(var.tags.landingzone, { - (var.network.network_area_tag_name) = [jsondecode(meshstack_building_block.network_area_hub[0].status.outputs["network_area_id"].value)] - }) - } - - spec = { - display_name = "STACKIT Networked" - description = "STACKIT landing zone whose projects are placed in the hub network area." - automate_deletion_approval = true - automate_deletion_replication = true - - platform_ref = data.meshstack_landingzone.foundation_default[0].spec.platform_ref - platform_properties = { custom = {} } - mandatory_building_block_refs = data.meshstack_landingzone.foundation_default[0].spec.mandatory_building_block_refs - } -} diff --git a/reference-architectures/stackit-landingzone/buildingblock/outputs.tf b/reference-architectures/stackit-landingzone/buildingblock/outputs.tf index db9506a6..88929d13 100644 --- a/reference-architectures/stackit-landingzone/buildingblock/outputs.tf +++ b/reference-architectures/stackit-landingzone/buildingblock/outputs.tf @@ -16,12 +16,20 @@ output "foundation_project_url" { output "summary" { description = "Summary of the meshStack resources created by this reference architecture." value = templatefile("${path.module}/SUMMARY.md.tftpl", { - platform_identifier = var.platform_identifier - foundation_project_id = stackit_resourcemanager_project.foundation.project_id - foundation_project_url = "https://portal.stackit.cloud/projects/${stackit_resourcemanager_project.foundation.project_id}" - lz_folder_container_id = stackit_resourcemanager_folder.this.container_id + platform_identifier = var.platform_identifier + organization_id = var.stackit_org + organization_url = "https://portal.stackit.cloud/dashboard?organization=${var.stackit_org}" + lz_folder_container_id = stackit_resourcemanager_folder.this.container_id + lz_folder_url = "https://portal.stackit.cloud/dashboard?organization=${var.stackit_org}&folder=${stackit_resourcemanager_folder.this.folder_id}" + foundation_project_id = stackit_resourcemanager_project.foundation.project_id + foundation_project_url = "https://portal.stackit.cloud/projects/${stackit_resourcemanager_project.foundation.project_id}" + service_account_email = module.stackit_integration.service_account_email + service_account_url = "https://portal.stackit.cloud/service-accounts/${module.stackit_integration.service_account_email}/overview?project=${stackit_resourcemanager_project.foundation.project_id}" + network_enabled = local.network_enabled - networked_landingzone_name = local.network_enabled ? meshstack_landingzone.networked[0].metadata.name : "" + networked_landingzone_name = local.network_enabled ? "${var.platform_identifier}-networked" : "" network_area_hub_uuid = local.network_enabled ? meshstack_building_block.network_area_hub[0].metadata.uuid : "" + network_area_id = local.network_enabled ? local.network_area_id : "" + network_area_url = local.network_enabled ? "https://portal.stackit.cloud/network-area/network-areas/${local.network_area_id}/overview?organization=${var.stackit_org}" : "" }) } diff --git a/reference-architectures/stackit-landingzone/buildingblock/variables.tf b/reference-architectures/stackit-landingzone/buildingblock/variables.tf index 35074ec9..3b23892f 100644 --- a/reference-architectures/stackit-landingzone/buildingblock/variables.tf +++ b/reference-architectures/stackit-landingzone/buildingblock/variables.tf @@ -68,7 +68,6 @@ variable "stackit_organization_onboarding_enabled" { variable "network" { type = object({ - network_area_tag_name = optional(string, "StackitNetworkArea") hub_network_area_name = optional(string, "hub") hub_network_ranges = optional(list(string), ["10.0.0.0/16"]) hub_transfer_network = optional(string, "10.1.255.0/24") @@ -80,7 +79,7 @@ variable "network" { tenant_network_max_prefix_length = optional(number, 28) }) default = null - description = "Optional hub-and-spoke network topology. Leave unset (null) to deploy only the sandbox landing zone. When set, additionally provisions a shared hub network area with the given address plan (`hub_*` fields), registers the self-service spoke `STACKIT Network` building block (`tenant_network_*` prefix bounds), and creates a `networked` landing zone (tagged via `network_area_tag_name`) whose projects are placed in the hub network area." + description = "Optional hub-and-spoke network topology. Leave unset (null) to deploy only the sandbox landing zone. When set, additionally provisions a shared hub network area with the given address plan (`hub_*` fields), registers the self-service spoke `STACKIT Network` building block (`tenant_network_*` prefix bounds), and adds a dedicated `networked` STACKIT Project building block definition and landing zone whose projects are placed in the hub network area." } variable "hub" { diff --git a/reference-architectures/stackit-landingzone/meshstack_integration.tf b/reference-architectures/stackit-landingzone/meshstack_integration.tf index c80eeef0..2bea9dfe 100644 --- a/reference-architectures/stackit-landingzone/meshstack_integration.tf +++ b/reference-architectures/stackit-landingzone/meshstack_integration.tf @@ -76,15 +76,15 @@ resource "meshstack_building_block_definition" "this" { **Example 2: Bootstrap with hub-and-spoke networking** A platform engineer provides a **network** configuration (CIDR plan, prefix bounds). In addition to the sandbox platform, the building block provisions the hub network area with the chosen - address plan, registers the **STACKIT Network** building block, and creates a `networked` landing - zone. Application teams can then self-service order routed spoke networks inside their projects. + address plan, registers the **STACKIT Network** building block, and adds a dedicated `networked` + STACKIT Project building block definition plus landing zone whose projects are placed in the hub + network area. Application teams can then self-service order routed spoke networks inside their projects. A **network** configuration looks like this (sensible example values shown — adapt them to your own address plan): ```json { - "network_area_tag_name": "StackitNetworkArea", "hub_network_area_name": "hub", "hub_network_ranges": ["10.0.0.0/16"], "hub_transfer_network": "10.1.255.0/24", @@ -106,9 +106,10 @@ resource "meshstack_building_block_definition" "this" { project-creation service account and other landing-zone core assets. - **STACKIT Project platform** – the `STACKIT Project` building block definition, platform and default landing zone, including the project-creation service account provisioned in the foundation project. - - **Hub network area + spoke network building block + networked landing zone** *(only when a - network configuration is provided)* – the shared hub address plan, the self-service - `STACKIT Network` building block, and a landing zone that places projects into the hub. + - **Hub network area + spoke network building block + networked project definition and landing + zone** *(only when a network configuration is provided)* – the shared hub address plan, the + self-service `STACKIT Network` building block, and a second `STACKIT Networked Project` + building block definition plus landing zone that places projects into the hub network area. ## 🔑 Authentication From d3393928ec32a55d741a388e044e33ce273b1aad Mon Sep 17 00:00:00 2001 From: Jo Schwandke Date: Fri, 7 Aug 2026 11:31:13 +0200 Subject: [PATCH 2/2] feat: add link to project to project summary --- modules/stackit/project/buildingblock/README.md | 2 +- .../stackit/project/buildingblock/SUMMARY.md.tftpl | 11 +++++++++++ modules/stackit/project/buildingblock/outputs.tf | 12 +++++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 modules/stackit/project/buildingblock/SUMMARY.md.tftpl diff --git a/modules/stackit/project/buildingblock/README.md b/modules/stackit/project/buildingblock/README.md index 632f6355..262c4f4b 100644 --- a/modules/stackit/project/buildingblock/README.md +++ b/modules/stackit/project/buildingblock/README.md @@ -79,5 +79,5 @@ No modules. | [project\_id](#output\_project\_id) | The UUID of the created StackIt project. | | [project\_name](#output\_project\_name) | The name of the created StackIt project. | | [project\_url](#output\_project\_url) | The deep link URL to access the project in the StackIt portal. | -| [summary](#output\_summary) | Summary of STACKIT organization membership onboarding for assigned project users. | +| [summary](#output\_summary) | Summary of the created project and STACKIT organization membership onboarding for assigned project users. | \ No newline at end of file diff --git a/modules/stackit/project/buildingblock/SUMMARY.md.tftpl b/modules/stackit/project/buildingblock/SUMMARY.md.tftpl new file mode 100644 index 00000000..ca939c5b --- /dev/null +++ b/modules/stackit/project/buildingblock/SUMMARY.md.tftpl @@ -0,0 +1,11 @@ +# Project: **${project_name}** + +## Details + +| Property | Value | +|----------|-------| +| **Project ID** | `${project_id}` | +| **Container ID** | `${container_id}` | +| **Portal** | [Open in STACKIT Portal](${project_url}) | + +${membership_summary} diff --git a/modules/stackit/project/buildingblock/outputs.tf b/modules/stackit/project/buildingblock/outputs.tf index 9bec4a92..213ba0c5 100644 --- a/modules/stackit/project/buildingblock/outputs.tf +++ b/modules/stackit/project/buildingblock/outputs.tf @@ -19,6 +19,12 @@ output "project_url" { } output "summary" { - value = fileexists("${path.module}/stackit_organization_membership_summary.md") ? file("${path.module}/stackit_organization_membership_summary.md") : "STACKIT organization membership summary was not generated." - description = "Summary of STACKIT organization membership onboarding for assigned project users." -} \ No newline at end of file + description = "Summary of the created project and STACKIT organization membership onboarding for assigned project users." + value = templatefile("${path.module}/SUMMARY.md.tftpl", { + project_name = stackit_resourcemanager_project.project.name + project_id = stackit_resourcemanager_project.project.project_id + container_id = stackit_resourcemanager_project.project.container_id + project_url = "https://portal.stackit.cloud/projects/${stackit_resourcemanager_project.project.project_id}" + membership_summary = fileexists("${path.module}/stackit_organization_membership_summary.md") ? file("${path.module}/stackit_organization_membership_summary.md") : "STACKIT organization membership summary was not generated." + }) +}