Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c7f6d9a
feat(ref-arch/stackit-kubernetes): add a summary to the cluster, Git,…
grubmeshi Nov 6, 2026
1a07877
docs(ref-arch/stackit-kubernetes): explain how the starter kit reache…
grubmeshi Nov 6, 2026
6cb4906
fix(ske/cluster): link the summary to the cluster's portal page
grubmeshi Nov 6, 2026
db1c493
feat(ref-arch/stackit-kubernetes): open the summary links in a new tab
grubmeshi Nov 6, 2026
60e62ef
feat(scorecard): check that a building block renders a summary with n…
grubmeshi Nov 6, 2026
557b9ff
fix(scorecard): give the summary checks emojis no other check uses
grubmeshi Nov 6, 2026
7073022
fix(ref-arch/stackit-kubernetes): write the summary links as Markdown…
grubmeshi Nov 6, 2026
a6acfe3
refactor(scorecard): drop the check that summary links open in a new tab
grubmeshi Nov 6, 2026
a4ad833
feat(stackit/git-runner): add a summary to the building block
grubmeshi Nov 6, 2026
12fcb28
feat(ref-arch/stackit-landingzone): put the whole Kubernetes platform…
grubmeshi Nov 6, 2026
bdd6919
feat(ref-arch/stackit-landingzone): explain the default landing zone …
grubmeshi Nov 6, 2026
b443a54
fix(stackit): link the portal pages of DNS zones, service accounts an…
grubmeshi Nov 6, 2026
7577801
fix(kubernetes/service-account): return the kubeconfig output as plai…
grubmeshi Nov 6, 2026
b981c5f
docs(kubernetes/service-account): say in the kubeconfig description t…
grubmeshi Nov 6, 2026
f0c8cb5
docs(kubernetes/service-account): move the kubeconfig warning to the …
grubmeshi Nov 6, 2026
8148636
docs(kubernetes): name STACKIT only as an example in the kubernetes m…
grubmeshi Nov 6, 2026
9c6febd
docs(kubernetes): rewrap the lines that named STACKIT
grubmeshi Nov 6, 2026
4fb2fa4
feat(ref-arch/stackit-kubernetes): name the building blocks and proje…
grubmeshi Nov 6, 2026
915d6e1
feat(ref-arch/stackit-landingzone): name the building block after the…
grubmeshi Nov 6, 2026
3181f26
feat(ref-arch/stackit-kubernetes)!: rename an adopted project to the …
grubmeshi Nov 6, 2026
a4fdc1b
test(ref-arch/stackit-kubernetes): name the e2e building block after …
grubmeshi Nov 6, 2026
0f266dd
docs(ref-arch/stackit-kubernetes): show the demo app inside the names…
grubmeshi Nov 6, 2026
1c6436e
docs(ref-arch/stackit-kubernetes): draw only building blocks and thei…
grubmeshi Nov 6, 2026
4511e37
docs(ref-arch/stackit-kubernetes): name the meshProject and meshTenan…
grubmeshi Nov 6, 2026
316cfa7
docs(ref-arch/stackit-kubernetes): drop the wildcard note from the pl…
grubmeshi Nov 6, 2026
ec14e56
fix(ske/cluster): bring back the Open Cluster button with the portal …
grubmeshi Nov 6, 2026
87f4e88
feat(stackit): name the resource buttons "Open …" and add the missing…
grubmeshi Nov 6, 2026
aa35ccb
feat(stackit): link Git, Container Registry, server and AI token to t…
grubmeshi Nov 6, 2026
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
6 changes: 6 additions & 0 deletions .agents/references/terraform-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ The comment sits directly above the `try`, or above the attribute that owns the
`try` is nested inside it. Prefer not needing it: a variable default, `optional()` or an explicit
`null` check says the same thing without hiding the next error too.

<!-- scorecard-checks: summary_output -->
## Summary Output

Every building block with an integration has a `summary` output, declared in the BBD with
`assignment_type = "SUMMARY"`, so meshPanel shows the result of a run.

## Output Content: Inline Heredoc Over a Template File

Write a markdown output's content — the `summary` output most of all — **inline with a `<<-EOT`
Expand Down
1 change: 1 addition & 0 deletions .agents/skills/module/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ conventions, see the reference files in `.agents/references/`.
```

3. **Implement `buildingblock/`** — `main.tf`, `variables.tf`, `outputs.tf`, `versions.tf`, `provider.tf`, `README.md` (with YAML front-matter), `logo.png` or `logo.svg`
- `outputs.tf` has a `summary` output (see [Summary Output](../../references/terraform-conventions.md#summary-output))

4. **Implement `backplane/`** (if needed) — read the provider-specific reference:
- AWS → `.agents/references/aws-backplane.md`
Expand Down
1 change: 1 addition & 0 deletions modules/kubernetes/ingress/buildingblock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ puts Helm's ownership label and annotations on the ClusterIssuer, so the release
| <a name="output_haproxy_lb_ip"></a> [haproxy\_lb\_ip](#output\_haproxy\_lb\_ip) | External IP of the HAProxy LoadBalancer service. Point application DNS A records here before TLS provisioning can complete. |
| <a name="output_haproxy_namespace"></a> [haproxy\_namespace](#output\_haproxy\_namespace) | Namespace of the HAProxy ingress controller and of the wildcard certificate secret. |
| <a name="output_ingress_class_name"></a> [ingress\_class\_name](#output\_ingress\_class\_name) | Name of the IngressClass an application puts on its Ingress to be served by this controller. |
| <a name="output_summary"></a> [summary](#output\_summary) | Markdown summary shown on the building block. |
| <a name="output_wildcard_certificate_domain"></a> [wildcard\_certificate\_domain](#output\_wildcard\_certificate\_domain) | Domain the wildcard certificate `*.<domain>` covers; null without `dns01`. |
| <a name="output_wildcard_certificate_secret_name"></a> [wildcard\_certificate\_secret\_name](#output\_wildcard\_certificate\_secret\_name) | Secret in `haproxy_namespace` holding the wildcard certificate; null without `dns01`. |
<!-- END_TF_DOCS -->
46 changes: 46 additions & 0 deletions modules/kubernetes/ingress/buildingblock/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,49 @@ output "wildcard_certificate_secret_name" {

depends_on = [module.issuer]
}

output "summary" {
description = "Markdown summary shown on the building block."
value = <<-EOT
# Kubernetes Ingress

| Property | Value |
|----------|-------|
| **Load Balancer IP** | `${data.kubernetes_service_v1.haproxy_controller.status[0].load_balancer[0].ingress[0].ip}` |
| **IngressClass** | `${var.ingress_class_name}` |
| **ClusterIssuer** | `${var.cluster_issuer_name}`, registered at `${var.acme_server}` |
| **Certificates** | ${local.dns01_enabled ? "wildcard `*.${local.dns01_certificate_domain}` in `${module.haproxy_namespace.name}/${var.wildcard_certificate_name}`, served by default" : "one per hostname, over HTTP-01"} |
| **HAProxy** | chart `${var.haproxy_version}`, ${var.haproxy_replica_count} replicas in `${module.haproxy_namespace.name}` |
| **cert-manager** | chart `${var.cert_manager_version}` in `${module.cert_manager_namespace.name}` |

Point the DNS records of your hostnames at the load balancer IP. An Ingress served by this
controller, with a certificate from Let's Encrypt:

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
cert-manager.io/cluster-issuer: ${var.cluster_issuer_name}
spec:
ingressClassName: ${var.ingress_class_name}
tls:
- hosts: [my-app.example.com]
secretName: my-app-tls
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
```
EOT

depends_on = [module.haproxy, module.issuer]
}
8 changes: 7 additions & 1 deletion modules/kubernetes/ingress/meshstack_integration.tf
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ variable "cluster_definition_ref" {
uuid = string
})
default = null
description = "Ref of the SKE cluster definition whose building blocks parent this definition's building blocks; null declares no dependency."
description = "Ref of the cluster definition (for example `ske/cluster`) whose building blocks parent this definition's building blocks; null declares no dependency."
}

variable "bbd_display_name" {
Expand Down Expand Up @@ -309,6 +309,12 @@ resource "meshstack_building_block_definition" "this" {
type = "STRING"
assignment_type = "NONE"
}

summary = {
display_name = "Summary"
type = "STRING"
assignment_type = "SUMMARY"
}
}

permissions = []
Expand Down
2 changes: 1 addition & 1 deletion modules/kubernetes/manifest/meshstack_integration.tf
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ resource "meshstack_building_block_definition" "this" {
symbol = "https://raw.githubusercontent.com/meshcloud/meshstack-hub/${var.hub.git_ref}/modules/kubernetes/manifest/buildingblock/logo.svg"
description = coalesce(var.bbd_description, "Deploys arbitrary Kubernetes manifests into a tenant namespace via a local Helm chart, with operator-supplied templates and user-provided values.")
target_type = "TENANT_LEVEL"
# TODO Correct would be to depend on the specific SKE cluster deployed (not just platform type),
# TODO Correct would be to depend on the specific cluster deployed (not just platform type),
# as the kubeconfig.yaml input only works for one specific cluster (representing the meshPlatform here)
supported_platforms = [{ name = "KUBERNETES" }]
run_transparency = true
Expand Down
8 changes: 4 additions & 4 deletions modules/kubernetes/meshstack_integration.tf
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ variable "cluster_definition_ref" {
uuid = string
})
default = null
description = "Ref of the SKE cluster definition whose building blocks parent this definition's building blocks; null declares no dependency."
description = "Ref of the cluster definition (for example `ske/cluster`) whose building blocks parent this definition's building blocks; null declares no dependency."
}

variable "bbd_display_name" {
Expand Down Expand Up @@ -425,9 +425,9 @@ resource "meshstack_building_block_definition" "this" {
## 🎯 When to use it

A platform team orders this once per cluster, as part of turning that cluster into a meshStack
platform — the **STACKIT Kubernetes Platform** reference architecture does it right after the
cluster exists and feeds the tokens into the platform it registers. It reaches the cluster
through the kubeconfig the ordering composition passes as an input.
platform. The **STACKIT Kubernetes Platform** reference architecture, for example, does it right
after the cluster exists and feeds the tokens into the platform it registers. It reaches the
cluster through the kubeconfig the ordering composition passes as an input.

## 📦 Resources created

Expand Down
6 changes: 3 additions & 3 deletions modules/kubernetes/platform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ is involved, so this runs on any conformant cluster.

It does **not** register a meshPlatform. Deciding that a cluster becomes a meshStack platform — its
identifier, location, landing zones and quota definitions — belongs to the composition that owns
the cluster, and the **STACKIT Kubernetes Platform** reference architecture does it in its own
`platform.tf` using the two tokens this block outputs. With `output_to_vault` set, it writes them to
the Vault KV v2 secret `<path_prefix>kubernetes/platform` under the keys `replicator-token` and
the cluster. The **STACKIT Kubernetes Platform** reference architecture, for example, does it in
its own `platform.tf` using the two tokens this block outputs. With `output_to_vault` set, it writes
them to the Vault KV v2 secret `<path_prefix>kubernetes/platform` under the keys `replicator-token` and
`metering-token` instead, and both outputs are empty.

## The kubeconfig is an input of the building block
Expand Down
7 changes: 4 additions & 3 deletions modules/kubernetes/platform/main.tf
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# The names below are cluster-global: `meshfed-service` and `meshfed-metering` are ClusterRoles, and
# two of these deployed to one cluster would collide. That is fine here — each platform ordered from
# the STACKIT Kubernetes Platform reference architecture gets a cluster of its own — and it is why
# the upstream module's `name_suffix` / `existing_clusterrole_name` machinery is not carried over.
# two of these deployed to one cluster would collide. That is fine while every cluster carries one
# meshStack platform (the STACKIT Kubernetes Platform reference architecture gives each its own),
# and it is why the upstream module's `name_suffix` / `existing_clusterrole_name` machinery is not
# carried over.
# Reintroduce it if a cluster ever has to carry more than one meshStack platform registration.
locals {
replicator_name = "meshfed-service"
Expand Down
3 changes: 2 additions & 1 deletion modules/kubernetes/platform/output_to_vault.tf
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ locals {

provider "vault" {
address = var.output_to_vault == null ? null : var.output_to_vault.address
# A Secrets Manager user may not create the child token the provider asks for by default.
# A Vault user without `auth/token/create`, such as a STACKIT Secrets Manager user, cannot create
# the child token the provider asks for by default.
skip_child_token = true

dynamic "auth_login_userpass" {
Expand Down
3 changes: 2 additions & 1 deletion modules/kubernetes/service-account/buildingblock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ No modules.
| Name | Description |
|------|-------------|
| <a name="output_instructions"></a> [instructions](#output\_instructions) | Instructions for using the kubeconfig |
| <a name="output_kubeconfig"></a> [kubeconfig](#output\_kubeconfig) | Kubeconfig file content for authenticating with the Kubernetes cluster. Empty when `output_to_vault` is set. |
| <a name="output_kubeconfig"></a> [kubeconfig](#output\_kubeconfig) | n/a |
| <a name="output_summary"></a> [summary](#output\_summary) | Markdown summary shown on the building block. |
| <a name="output_vault_secret"></a> [vault\_secret](#output\_vault\_secret) | `{path, secret_hash}` of the secret in Vault, where `secret_hash` changes with its content; `{}` without `output_to_vault`. |
<!-- END_TF_DOCS -->
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
locals {
write_to_vault = nonsensitive(var.output_to_vault != null)
vault_secret_path = local.write_to_vault ? "${nonsensitive(var.output_to_vault.path_prefix)}kubernetes/service-account" : null
vault_mount = local.write_to_vault ? nonsensitive(var.output_to_vault.mount) : null

vault_data_json = jsonencode({ kubeconfig = yamlencode(local.kubeconfig) })

Expand All @@ -10,7 +11,8 @@ locals {

provider "vault" {
address = var.output_to_vault == null ? null : var.output_to_vault.address
# A Secrets Manager user may not create the child token the provider asks for by default.
# A Vault user without `auth/token/create`, such as a STACKIT Secrets Manager user, cannot create
# the child token the provider asks for by default.
skip_child_token = true

dynamic "auth_login_userpass" {
Expand Down
21 changes: 18 additions & 3 deletions modules/kubernetes/service-account/buildingblock/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,8 @@ output "instructions" {
}

output "kubeconfig" {
description = "Kubeconfig file content for authenticating with the Kubernetes cluster. Empty when `output_to_vault` is set."
sensitive = true
value = local.write_to_vault ? "" : yamlencode(local.kubeconfig)
# "" because meshStack fails a run whose declared output is missing.
value = local.write_to_vault ? "" : nonsensitive(yamlencode(local.kubeconfig))
}

output "vault_secret" {
Expand All @@ -52,3 +51,19 @@ output "vault_secret" {
} : key => value if local.write_to_vault
}
}

output "summary" {
description = "Markdown summary shown on the building block."
value = <<-EOT
# Kubernetes Service Account: **${kubernetes_service_account.this.metadata[0].name}**

| Property | Value |
|----------|-------|
| **Service Account** | `${var.namespace}/${kubernetes_service_account.this.metadata[0].name}` |
| **Role** | `${var.cluster_role}`, ${var.bind_cluster_wide ? "in every namespace" : "in `${var.namespace}`"} |
| **Cluster** | `${var.cluster_name}` at `${local.kubeconfig_cluster.server}` |
| **Kubeconfig** | ${local.write_to_vault ? "key `kubeconfig` of the Vault secret `${local.vault_secret_path}` on mount `${local.vault_mount}`" : "the **Kubeconfig** output of this building block"} |

Save the kubeconfig to a file and use it with `kubectl --kubeconfig kubeconfig get pods`.
EOT
}
7 changes: 7 additions & 0 deletions modules/kubernetes/service-account/meshstack_integration.tf
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ resource "meshstack_building_block_definition" "this" {
assignment_type = "NONE"
}

# Carries the SA token in plain view, because BB outputs cannot be sensitive; output_to_vault leaves it "".
kubeconfig = {
display_name = "Kubeconfig"
type = "STRING"
Expand All @@ -279,6 +280,12 @@ resource "meshstack_building_block_definition" "this" {
type = "STRING"
assignment_type = "NONE"
}

summary = {
display_name = "Summary"
type = "STRING"
assignment_type = "SUMMARY"
}
}

permissions = []
Expand Down
3 changes: 2 additions & 1 deletion modules/ske/cluster/buildingblock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ place. `release_on_destroy` cannot change once the cluster is managed.
| Name | Description |
|------|-------------|
| <a name="output_cluster_name"></a> [cluster\_name](#output\_cluster\_name) | Name of the SKE cluster. |
| <a name="output_cluster_url"></a> [cluster\_url](#output\_cluster\_url) | Deep link to the STACKIT project the cluster lives in, in the STACKIT portal. |
| <a name="output_cluster_url"></a> [cluster\_url](#output\_cluster\_url) | Deep link to the cluster in the STACKIT portal. |
| <a name="output_kube_host"></a> [kube\_host](#output\_kube\_host) | Kubernetes API server URL of the cluster. |
| <a name="output_summary"></a> [summary](#output\_summary) | Markdown summary shown on the building block. |
| <a name="output_vault_secret"></a> [vault\_secret](#output\_vault\_secret) | `{path, secret_hash}` of the secret in Vault, where `secret_hash` changes with its content. |
<!-- END_TF_DOCS -->
2 changes: 2 additions & 0 deletions modules/ske/cluster/buildingblock/output_to_vault.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
locals {
vault_address = nonsensitive(var.output_to_vault.address)
vault_mount = nonsensitive(var.output_to_vault.mount)
vault_secret_path = "${nonsensitive(var.output_to_vault.path_prefix)}ske/cluster"

vault_data_json = jsonencode({ kubeconfig = local.admin_kubeconfig })
Expand Down
41 changes: 39 additions & 2 deletions modules/ske/cluster/buildingblock/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ output "cluster_name" {
value = module.cluster.cluster.name
}

locals {
cluster_url = "https://portal.stackit.cloud/kubernetes/clusters/details/${module.cluster.cluster.name}/overview?project=${var.stackit_project_id}"
}

output "cluster_url" {
description = "Deep link to the STACKIT project the cluster lives in, in the STACKIT portal."
value = "https://portal.stackit.cloud/projects/${var.stackit_project_id}/ske/clusters"
description = "Deep link to the cluster in the STACKIT portal."
value = local.cluster_url
}

output "kube_host" {
Expand All @@ -20,3 +24,36 @@ output "vault_secret" {
secret_hash = local.vault_secret_hash
}
}

output "summary" {
description = "Markdown summary shown on the building block."
value = <<-EOT
# SKE Cluster: **${module.cluster.cluster.name}**

| Property | Value |
|----------|-------|
| **Cluster** | [Open in STACKIT Portal](${local.cluster_url}) |
| **Kubernetes** | `${module.cluster.cluster.kubernetes_version_used}` |
| **API Server** | `${terraform_data.kube_host.output}` |
| **Node Pool** | `${var.node_pool.name}`: ${var.node_pool.minimum} to ${var.node_pool.maximum} × `${var.node_pool.machine_type}` in ${join(", ", var.node_pool.availability_zones)} |
| **Maintenance** | daily `${var.maintenance.start}` to `${var.maintenance.end}` |

## Platform admin kubeconfig

The service account `kube-system/${local.admin_name}` is bound to `cluster-admin`. Its kubeconfig is
the key `kubeconfig` of the Vault secret `${local.vault_secret_path}` on mount `${local.vault_mount}`.
The token belongs to generation `${var.admin_token_generation}`; the one of the month before stays valid.

```sh
export VAULT_ADDR=${local.vault_address}
export VAULT_TOKEN=$(stackit auth get-access-token)
vault kv get -mount=${local.vault_mount} -field=kubeconfig ${local.vault_secret_path} > kubeconfig
```

For your own access, STACKIT issues a kubeconfig that expires:

```sh
stackit ske kubeconfig create ${module.cluster.cluster.name} --project-id ${var.stackit_project_id}
```
EOT
}
6 changes: 6 additions & 0 deletions modules/ske/cluster/meshstack_integration.tf
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@ resource "meshstack_building_block_definition" "this" {
type = "STRING"
assignment_type = "RESOURCE_URL"
}

summary = {
display_name = "Summary"
type = "STRING"
assignment_type = "SUMMARY"
}
}

permissions = []
Expand Down
1 change: 1 addition & 0 deletions modules/ske/forgejo-connector/buildingblock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,5 @@ Secret of its own service account.
| Name | Description |
|------|-------------|
| <a name="output_app_link"></a> [app\_link](#output\_app\_link) | Public URL for this stage application. |
| <a name="output_summary"></a> [summary](#output\_summary) | Markdown summary shown on the building block. |
<!-- END_TF_DOCS -->
47 changes: 46 additions & 1 deletion modules/ske/forgejo-connector/buildingblock/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,49 @@
locals {
app_url = "https://${var.app_hostname}"
repository_url = "${trimsuffix(data.external.env.result["FORGEJO_HOST"], "/")}/${var.repository_owner}/${var.repository_name}"
actions_url = "${local.repository_url}/actions?workflow=pipeline.yaml"
}

output "app_link" {
description = "Public URL for this stage application."
value = "https://${var.app_hostname}"
value = local.app_url
}

output "actions_url" {
description = "Forgejo Actions page of the repository's `pipeline.yaml` workflow."
value = local.actions_url
}

output "summary" {
description = "Markdown summary shown on the building block."
value = <<-EOT
# Forgejo Connector: **${var.stage}**

The `${var.stage}` branch of [${var.repository_owner}/${var.repository_name}](${local.repository_url}) deploys
to the namespace `${var.namespace}`.

| Property | Value |
|----------|-------|
| **App** | [${local.app_url}](${local.app_url}) |
| **Pipeline** | [`pipeline.yaml` in Forgejo Actions](${local.actions_url}) |
| **Service Account** | `${kubernetes_service_account.forgejo_actions.metadata[0].name}`, `edit` on the namespace |

## Forgejo Actions secrets and variables

Set in the [repository settings](${local.repository_url}/settings/actions/secrets):

| Name | Kind | Holds |
|------|------|-------|
| `KUBECONFIG_${upper(var.stage)}` | secret | kubeconfig of the service account |
| `K8S_NAMESPACE_${upper(var.stage)}` | variable | `${var.namespace}` |
| `APP_HOSTNAME_${upper(var.stage)}` | variable | `${var.app_hostname}` |

## Kubernetes secrets in the namespace

| Secret | Filled from the Vault secret |
|--------|------------------------------|
| `${kubernetes_secret.image_pull.metadata[0].name}`, the image pull secret of `default` | `${var.registry_secret_path}` |${join("", [for name, path in var.additional_kubernetes_secrets : "\n| `${name}` | `${path}` |"])}

A changed Vault value reaches these secrets with the next increase of **Secrets Revision**.
EOT
}
Loading
Loading