Skip to content
Merged
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
11 changes: 6 additions & 5 deletions .github/workflows/pre-commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ jobs:
grep -o -E -m 1 "https://.+?-linux-amd64.tar.gz")" > terraform-docs.tgz && \
tar -xzf terraform-docs.tgz terraform-docs && rm terraform-docs.tgz && chmod +x terraform-docs && \
sudo mv terraform-docs /usr/bin/

- name: Install tflint
run: |
# tflint
curl -L "$(curl -s https://api.github.com/repos/terraform-linters/tflint/releases/latest |
grep -o -E -m 1 "https://.+?_linux_amd64.zip")" > tflint.zip && \
unzip tflint.zip && rm tflint.zip && sudo mv tflint /usr/bin/
uses: terraform-linters/setup-tflint@v6
with:
tflint_version: latest
cache: 'true'

- name: Install shfmt
run: |
curl -L "$(curl -s https://api.github.com/repos/mvdan/sh/releases/latest |
Expand Down
15 changes: 5 additions & 10 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ default_stages:

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # frozen: v5.0.0
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
hooks:
- id: detect-private-key
- id: end-of-file-fixer
- id: trailing-whitespace
- id: mixed-line-ending
args: ['--fix', 'lf']
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: 55d0143972eec4905fdaea2f444f1e88218f9dce # frozen: v1.96.3
rev: d0e12caebb2ab0ee8bf98181c8bfe9702bca103d # frozen: v1.105.0
hooks:
- id: terraform_fmt
- id: terraform_tflint
Expand All @@ -40,7 +40,7 @@ repos:
args:
- --args=--config=.terraform-docs.yaml
- repo: https://github.com/adrienverge/yamllint
rev: 81e9f98ffd059efe8aa9c1b1a42e5cce61b640c6 # frozen: v1.35.1
rev: cba56bcde1fdd01c1deb3f945e69764c291a6530 # frozen: v1.38.0
hooks:
- id: yamllint
- repo: https://github.com/jumanjihouse/pre-commit-hooks
Expand All @@ -50,22 +50,17 @@ repos:
- id: shellcheck
- id: shfmt
- repo: https://github.com/hukkin/mdformat
rev: e20b1ac5acb8aba0b49d3a9109c6e6b58684ee83 # frozen: 0.7.21
rev: 2d496dbc18e31b83a1596685347ffe0b6041daf0 # frozen: 1.0.0
hooks:
- id: mdformat
# needed to support exclude in `.mdformat.toml`
# pre-commit runs on python 3.12 by default on MacOS and most linux distributions.
# Install python 3.13 if pre-commit fails.
language_version: "3.13"
# Optionally add plugins
additional_dependencies:
- mdformat-gfm
- mdformat-gfm-alerts
- mdformat-shfmt
- mdformat-toc
- mdformat-tables
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: a4288145006c83a91f59083ab813165ca05ad3f3 # frozen: v9.20.0
rev: 1f6454da22d006d5bb0d2e65c96c43c23c8a534f # frozen: v9.24.0
hooks:
- id: commitlint
stages: [commit-msg]
Expand Down
2 changes: 1 addition & 1 deletion .tflint.hcl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugin "google" {
enabled = true
version = "0.30.0"
version = "0.38.0"
source = "github.com/terraform-linters/tflint-ruleset-google"
}

Expand Down
2 changes: 1 addition & 1 deletion docs/TERRAFORM.md

Large diffs are not rendered by default.

16 changes: 13 additions & 3 deletions serviceaccounts-iam.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2025 METRO Digital GmbH
# Copyright 2026 METRO Digital GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -35,7 +35,7 @@ locals {
"roles/iam.workloadIdentityUser" = {
role = "roles/iam.workloadIdentityUser"
condition = null
members = compact(concat(
members = compact(flatten(concat(
[
for repo in config.github_action_repositories : format(
"principalSet://iam.googleapis.com/%s/attribute.repository/%s",
Expand All @@ -50,8 +50,18 @@ locals {
runtime_sa.namespace,
runtime_sa.service_account
)
],
[
for bb in config.meshstack_buildingblocks : [
for subject in bb.subjects :
format(
"principal://iam.googleapis.com/%s/subject/%s",
google_iam_workload_identity_pool.meshstack_buildingblocks[0].name,
subject
)
]
]
))
)))
}
}
}
Expand Down
26 changes: 25 additions & 1 deletion variables.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2025 METRO Digital GmbH
# Copyright 2026 METRO Digital GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -379,6 +379,12 @@ variable "service_accounts" {
in Cloud Native Runtime clusters to use this service account without the need for service account keys. A detailed
example can be found within the [FAQ].

**`meshstack_buildingblocks` (optional):** You can list Meshstack Building Blocks here. For details on the format,
see the example below. A Workload Identity Pool and a Workload Identity Provider needed for Workload Identity Federation
will be created automatically. Each building block given gains permissions to authenticate as this service account
using Workload Identity Federation. This allows workloads running on Meshstacks SaaS platform to use this service
account without the need for service account keys.

**`github_action_repositories` (optional):** You can list GitHub repositories (format: `user/repo`) here.
A Workload Identity Pool and a Workload Identity Provider needed for Workload Identity Federation will be
created automatically. Each repository given gains permissions to authenticate as this service account using
Expand All @@ -402,6 +408,19 @@ variable "service_accounts" {
Example:
```
service_accounts = {
"meshstack-building-block" = {
description = "Used by the building block in the Cloud Foundation Panel (meshstack)"
display_name = "Building Block"
iam_policy = []
project_iam_policy_roles = []
meshstack_buildingblocks = [
{
issuer = "https://container.googleapis.com/v1/projects/some-project/locations/europe-west1/clusters/some-cluster"
audiences = ["gcp-workload-identity-provider:some-customer"]
subjects = ["system:serviceaccount:some-customer:workspace.example.buildingblockdefinition.29980db7-2a61-4f01-bf6b-18ea61606700"]
}
]
}
runtime-sa = {
display_name = "My Runtime Workload"
description = "Workload running in Cloud Native Runtime Cluster"
Expand Down Expand Up @@ -484,6 +503,11 @@ variable "service_accounts" {
namespace = string
service_account = string
})), [])
meshstack_buildingblocks = optional(list(object({
issuer = string
audiences = list(string)
subjects = list(string)
})), [])
tags = optional(list(string), [])
}))

Expand Down
72 changes: 72 additions & 0 deletions wif-meshstack-buildingblocks.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Copyright 2026 METRO Digital GmbH
#
# 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 {
meshstack_bb_pool_providers = { for k, v in flatten([
for sa, sacfg in var.service_accounts : [for bb in sacfg.meshstack_buildingblocks :
[for audience in bb.audiences :
{
(bb.issuer) = audience
}
]
] if can(length(sacfg.meshstack_buildingblocks) > 0)
]) : keys(v)[0] => values(v)[0]... }

meshstack_bb_pool_provider_subjects = { for k, v in flatten([
for sa, sacfg in var.service_accounts : [for bb in sacfg.meshstack_buildingblocks :
[for subject in bb.subjects :
{
(bb.issuer) = subject
}
]
] if can(length(sacfg.meshstack_buildingblocks) > 0)
]) : keys(v)[0] => values(v)[0]... }
}

resource "google_iam_workload_identity_pool" "meshstack_buildingblocks" {
count = local.meshstack_buildingblocks_enabled
project = var.project_id
workload_identity_pool_id = "meshstack-buildingblocks"
description = "Identity pool for meshStack building blocks"
}

resource "google_iam_workload_identity_pool_provider" "meshstack_buildingblocks" {
for_each = local.meshstack_bb_pool_providers
project = var.project_id

workload_identity_pool_id = google_iam_workload_identity_pool.meshstack_buildingblocks[0].workload_identity_pool_id
workload_identity_pool_provider_id = md5(each.key)
description = <<-EOD
OIDC identity provider for meshStack building blocks
GKE Cluster
Project ID: ${provider::google::project_from_id(each.key)}
Location: ${provider::google::location_from_id(each.key)}
Name: ${provider::google::name_from_id(each.key)}"
EOD

oidc {
issuer_uri = each.key
allowed_audiences = each.value
}

# Map the OIDC token's `sub` claim to google.subject
attribute_mapping = {
"google.subject" = "assertion.sub"
}

attribute_condition = join(" || ", [
for subject in local.meshstack_bb_pool_provider_subjects[each.key] :
"google.subject == '${subject}'"
])
}
8 changes: 6 additions & 2 deletions wif.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2025 METRO Digital GmbH
# Copyright 2026 METRO Digital GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -23,9 +23,13 @@ locals {
for sa, config in var.service_accounts : sa if length(config.runtime_service_accounts) > 0
])) > 0 ? 1 : 0

meshstack_buildingblocks_enabled = length(compact([
for sa, config in var.service_accounts : sa if length(config.meshstack_buildingblocks) > 0
])) > 0 ? 1 : 0

# We also need to enable some services to make the Workload Identity Federation setup possible
# if we have any usage of the service
wif_needed_services = (local.github_actions_enabled + local.runtime_service_accounts_enabled) > 0 ? toset([
wif_needed_services = (local.github_actions_enabled + local.runtime_service_accounts_enabled + local.meshstack_buildingblocks_enabled) > 0 ? toset([
"cloudresourcemanager.googleapis.com",
"iamcredentials.googleapis.com",
"sts.googleapis.com"
Expand Down
Loading