Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 62 additions & 42 deletions modules/stackit/meshstack_integration.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand Down Expand Up @@ -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}"
]
}
}
Expand All @@ -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
Expand All @@ -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
}
Expand All @@ -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

Expand All @@ -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"
Expand Down Expand Up @@ -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."
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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"]
}
}

Expand Down
7 changes: 1 addition & 6 deletions modules/stackit/project/buildingblock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
|------|-------------|------|---------|:--------:|
| <a name="input_environment"></a> [environment](#input\_environment) | The environment type (production, staging, development). If not set, uses parent\_container\_id directly. | `string` | `null` | no |
| <a name="input_labels"></a> [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 |
| <a name="input_network_area_tag_name"></a> [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 |
| <a name="input_labels"></a> [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 |
| <a name="input_parent_container_id"></a> [parent\_container\_id](#input\_parent\_container\_id) | The parent container ID (organization or folder) where the project will be created. | `string` | n/a | yes |
| <a name="input_parent_container_ids"></a> [parent\_container\_ids](#input\_parent\_container\_ids) | Parent container IDs for different environments. If environment is set, the corresponding container ID will be used. | <pre>object({<br/> production = optional(string)<br/> staging = optional(string)<br/> development = optional(string)<br/> })</pre> | `{}` | no |
| <a name="input_platform_identifier"></a> [platform\_identifier](#input\_platform\_identifier) | meshStack platform identifier, used to look up this project's landing zone tags at runtime. | `string` | n/a | yes |
| <a name="input_project_name"></a> [project\_name](#input\_project\_name) | The name of the StackIt project to create. | `string` | n/a | yes |
| <a name="input_role_mapping"></a> [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 |
| <a name="input_service_account_email"></a> [service\_account\_email](#input\_service\_account\_email) | Email of the STACKIT service account for WIF-based authentication and project ownership. | `string` | n/a | yes |
| <a name="input_users"></a> [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`. | <pre>list(object({<br/> meshIdentifier = string<br/> username = string<br/> firstName = string<br/> lastName = string<br/> email = string<br/> euid = string<br/> roles = list(string)<br/> }))</pre> | n/a | yes |
| <a name="input_workspace_identifier"></a> [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

Expand Down
31 changes: 1 addition & 30 deletions modules/stackit/project/buildingblock/main.tf
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand Down
20 changes: 1 addition & 19 deletions modules/stackit/project/buildingblock/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand Down
8 changes: 5 additions & 3 deletions reference-architectures/stackit-landingzone/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.
Expand Down
Loading