Skip to content

feat(azure-kubernetes)!: rebuild on workspace building blocks only, add azure/aks-namespace - #383

Open
Jelledb wants to merge 6 commits into
mainfrom
feat/azure-kubernetes-workspace-bbs
Open

Jelledb wants to merge 6 commits into
mainfrom
feat/azure-kubernetes-workspace-bbs

Conversation

@Jelledb

@Jelledb Jelledb commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Rebuilds the azure-kubernetes reference architecture on workspace-level building blocks only. No meshStack project, tenant, platform or landing zone remains. A Kubernetes namespace is now a building block, not a tenant.

This needs a new workspace building block for namespaces, so the PR adds azure/aks-namespace and reworks aks/github-connector and aks/starterkit around it.

Breaking: three commits are feat!. Existing starterkit and connector deployments must be re-wired (see Migration).

Commits

Commit Change
feat(azure/aks-namespace) New module: backplane, building block, meshstack_integration.tf, e2e
feat(aks/github-connector)! Workspace-level; namespace comes from a parent block
feat(aks/starterkit)! Orders namespace blocks instead of projects and tenants
feat(azure/aks-namespace) (2nd) Creates the namespace's Entra groups and fills them from workspace members
feat(azure-kubernetes)! README, front-matter and diagram rewritten

azure/aks-namespace (new)

Backplane (follows azure-backplane.md, scorecard 100%):

  • User-assigned managed identity plus a federated credential from the BBD's workload_identity_federation. No secrets.
  • Custom role (managedClusters/read, listClusterUserCredential/action) at the cluster.
  • Built-in Azure Kubernetes Service RBAC Cluster Admin at the cluster. Namespace creation is a cluster-scoped write, so this is the narrowest built-in role that works.
  • Optional acr_id: grants AcrPull to the cluster's kubelet identity (lifecycle.enabled, not count).

Building block:

  • kubernetes_namespace_v1, resource_quota_v1, limit_range_v1, and one role_binding_v1 per Entra group for admin, edit and view.
  • Inputs: namespace name (DNS-label validated, the only user input), and static platform settings: resource quota, group name prefix, user lookup attribute, role mapping.
  • Outputs: namespace_name, cluster_name, cluster_resource_group_name, summary.

Cluster auth. provider.tf exchanges the runner's federated OIDC token for an Entra token (audience 6dae42f8-4368-4678-94ff-3960e28e3630) with the http provider, then hands it to the kubernetes provider. This is what kubelogin get-token --login workloadidentity does. I did it in HCL because the repo's pre-run convention wants tools from a Nix flake, and I couldn't generate a flake.lock here.

Entra groups and users (added after the first review pass)

The block now owns user-to-group assignment, not just role bindings:

  • Creates one security group per namespace role (admin, edit, view), named [prefix.]<workspace>.<namespace>.<role>.
  • Receives workspace members through a USER_PERMISSIONS input, resolves them in Entra in one azuread_users lookup (ignore_missing, matched on email or UPN), and adds each to the group their workspace role maps to. Unresolved members are reported in the unresolved_users output and the summary and never fail the run.
  • role_mapping (static input, default Owner/Manager to admin, Member to edit, Reader to view) maps workspace roles to namespace roles. A role missing from the map gets no access.
  • Only groups this block creates are managed: there are no inputs for binding pre-existing groups.
  • The resource quota is a static, platform-set input (resource_quota in meshstack_integration.tf), not something the ordering team picks.
  • The backplane gains Microsoft Graph User.Read.All and Group.ReadWrite.All app roles, which need admin consent.
  • The role binding for a created group is keyed by role alone, because the group's object ID is unknown until apply and can't be a for_each key.

I exercised the group and binding logic with a throwaway mocked tofu test (2 members resolved, 1 unresolved, 4 bindings; and the no-users case). I deleted it afterwards because repo policy only allows tests under e2e/.

aks/github-connector

  • target_type is now WORKSPACE_LEVEL, with no supported_platforms and no TENANT_* permissions.
  • namespace is a BUILDING_BLOCK_OUTPUT of the namespace definition's namespace_name, replacing PLATFORM_TENANT_ID.
  • aks.namespace_definition_uuid is a new required input, and the namespace definition is added to dependency_refs.
  • Removed the empty main.tf and outputs.tf stubs (both only contained a TODO).
  • Unchanged: cluster auth still uses the config.tf admin-certificate stub from the backplane.

aks/starterkit

  • Removed meshstack_project, meshstack_project_user_binding, meshstack_tenant and all moved blocks.
  • Added meshstack_building_block.namespace per stage (for_each), and connectors now take [repo, namespace[stage]] as parents. Every child block keeps the run-status postcondition.
  • Removed inputs: platform_ref, landing_zone_refs, project_tags, creator.
  • building_block_definition_version_refs needs an extra aks-namespace key.
  • Permissions are down to BUILDINGBLOCK_*.
  • The summary output and BBD readme no longer mention projects or tenants.

Reference architecture

README, front-matter (azure/aks-namespace added to buildingBlocks), "How it works", deployment order and shared-responsibility table are rewritten. .dot edited and .svg re-rendered with tools/diagrams/render-diagrams.mjs.

Migration

For existing deployments:

  1. Deploy azure/aks-namespace (cluster must have Azure RBAC for Kubernetes enabled).
  2. Re-deploy aks/github-connector with aks.namespace_definition_uuid.
  3. Re-deploy aks/starterkit: drop the removed variables and add aks-namespace to building_block_definition_version_refs.
  4. Starterkit blocks already ordered still own projects and tenants. Applying the new version will plan their removal, so check the plan before letting it destroy anything.

Verification

  • ✅ tofu validate: namespace building block, its backplane, starterkit building block
  • ✅ Scorecard azure/aks-namespace: 100%
  • ✅ pre-commit terraform-docs, fmt and whitespace
  • ⚠️ ci/validate_modules.sh fails locally only because pngquant isn't installed
  • ⚠️ aks/github-connector and aks/starterkit still lack e2e and backplane scorecard items, as before this PR
  • ❌ Not run against a real cluster or meshStack. The e2e test for aks-namespace is written but unexecuted. Per the e2e skill, please dispatch a run and link it here before merge.

Please review closely

  1. Unverified: USER_PERMISSIONS at workspace level. azure/entra-id-groups uses it on a project-level definition. Neither the provider docs nor its source say what it delivers to a WORKSPACE_LEVEL definition. I assumed workspace members with their workspace roles. The role names in the default workspace_role_mapping (Workspace Owner/Manager/Member/Reader) are also from memory and need checking against a real instance. If the input arrives empty, namespaces get their groups but no members.

  2. Token in state. The http token exchange stores a bearer token, valid about an hour, in the run's state. Acceptable, or would you rather require kubelogin via a Nix flake?

  3. azure/aks doesn't enable Azure RBAC for Kubernetes (azure_rbac_enabled). The namespace block needs it. I documented it as a prerequisite and left azure/aks alone. Add a variable there in this PR or a follow-up?

  4. e2e fixture. The test needs fixtures.azure.aks (cluster_name, resource_group_name) in meshstack-smoke-test's test_context. That repo needs a matching change before the test can run.

  5. ACR pull is cluster-wide. The kubelet identity pulls images, so it can't be scoped per namespace.

  6. Diagram. I couldn't view the full rendered SVG (my preview was cropped), so please check the layout, especially the meshStack column.

  7. Website. I didn't build the website, so the new front-matter path azure/aks-namespace is unchecked.

  8. Connector auth. Moving the connector from the config.tf certificate stub to workload identity is out of scope here.

🤖 Generated with Claude Code

Jelledb and others added 4 commits October 12, 2026 12:07
…paces

Creates a namespace with ResourceQuota, LimitRange and Entra group role
bindings on an existing AKS cluster. The block authenticates through the
backplane UAMI by workload identity federation and holds no kubeconfig.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…namespace block

The connector no longer targets a meshStack tenant. It reads its namespace
from the namespace_name output of the Azure AKS Namespace building block it is
ordered under, so aks.namespace_definition_uuid is a new required input.
Drops the empty main.tf and outputs.tf stubs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ojects and tenants

The starter kit no longer creates meshStack projects, tenants or the creator's
project binding. It orders one Azure AKS Namespace building block per stage
and wires a GitHub Actions connector to each, all at workspace level.
platform_ref, landing_zone_refs, project_tags and the creator input are gone;
building_block_definition_version_refs now also needs an aks-namespace entry,
and namespace_group_object_ids controls who gets access.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ace building blocks only

Drops the meshStack project, tenant, platform and landing zone from the
architecture and its diagram. The starterkit now orders azure/aks-namespace
and aks/github-connector blocks directly in the workspace.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Scorecard Check

Scorecard run on commit d34d283d3f9852fb54faf84cfe002c7b9cd7ffd1 relative to origin/main

📊 meshstack-hub Module Scorecard

Generated: 2026-10-12 | Modules scanned: 3 | Categories: 7

📋 Per-Module Category Summary

Score per category per building block. n/a = category does not apply to this module.

Module Overall Core Structure Integration AWS Backplane Azure Backplane GCP Backplane STACKIT Backplane Testing
aks/github-connector 🟢 92% 🟢 100% 🟢 100% n/a n/a n/a n/a 🟡 50%
aks/starterkit 🟢 89% 🟢 100% 🟢 100% n/a n/a n/a n/a 🔴 25%
azure/aks-namespace 🟢 100% 🟢 100% 🟢 100% n/a 🟢 100% n/a n/a 🟢 100%

⚠️ 2 modules have failing checks — failing categories are expanded below.

Core Structure — ✅ all passing

Basic module file structure and documentation — applies to 3 modules

Module Score 📦 🔗 📋 📝 🖼️ 📌 🚦 🎯 🩹 🧼 ❄️ 🔒
aks/github-connector 🟢 100% ✅ ✅ ➖ ✅ ✅ ✅ ➖ ✅ ➖ ➖ ➖ ✅
aks/starterkit 🟢 100% ✅ ✅ ➖ ✅ ✅ ✅ ✅ ✅ ➖ ➖ ➖ ✅
azure/aks-namespace 🟢 100% ✅ ✅ ➖ ✅ ✅ ✅ ➖ ✅ ✅ ➖ ➖ ✅

Core Structure — Summary

Emoji Criterion Coverage Status
📦 buildingblock/ directory exists 3/3 🟢 100%
🔗 meshstack_integration.tf present 3/3 🟢 100%
📋 buildingblock/APP_TEAM_README.md present (no-integration fallback) n/a —
📝 buildingblock/README.md with YAML front-matter 3/3 🟢 100%
🖼️ buildingblock/logo.png included 3/3 🟢 100%
📌 buildingblock/versions.tf present 3/3 🟢 100%
🚦 Child meshstack_building_block asserts a SUCCEEDED run 1/1 🟢 100%
🎯 meshStack *_ref attributes use the resource's ref output 3/3 🟢 100%
🩹 Every try() carries a comment saying why 1/1 🟢 100%
🧼 Pre-run scripts install no tools on the runner n/a —
❄️ A module flake sits in nix/, is pinned, and Terraform calls it n/a —
🔒 Provider versions float within one major (>= X.Y.Z, < N.0.0) 3/3 🟢 100%
Integration — ✅ all passing

meshstack_integration.tf conventions — applies to 3 modules

Module Score 🏷️ 🏢 📤 🔌 📎 🔀 🌱 📋 🏷️ 🧱 🏪 📖 📝 📊 🚫 🔄 🪪
aks/github-connector 🟢 100% ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ➖ ➖
aks/starterkit 🟢 100% ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ➖ ➖
azure/aks-namespace 🟢 100% ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ➖ ✅

Integration — Summary

Emoji Criterion Coverage Status
🏷️ variable "hub" in integration 3/3 🟢 100%
🏢 variable "meshstack" in integration 3/3 🟢 100%
📤 building_block_definition output exposed 3/3 🟢 100%
🔌 meshcloud/meshstack in required_providers 3/3 🟢 100%
📎 backplane source uses var.hub.git_ref 3/3 🟢 100%
🔀 ref_name uses var.hub.git_ref 3/3 🟢 100%
🌱 BBD terraform_version >= 1.12.0 3/3 🟢 100%
📋 version_spec.draft uses var.hub.bbd_draft 3/3 🟢 100%
🏷️ BBD metadata.tags forwards var.meshstack.tags 3/3 🟢 100%
🧱 BBD input argument vars with optional() have explicit defaults 3/3 🟢 100%
🏪 BBD catalog properties are overridable 3/3 🟢 100%
📖 BBD readme field present 3/3 🟢 100%
📝 BBD readme starts with plain-text description (no heading) 3/3 🟢 100%
📊 BBD readme has shared responsibility table (✅/❌) 3/3 🟢 100%
🚫 No documentation_md output in backplane 3/3 🟢 100%
🔄 meshstack_platform has lifecycle ignore_changes = [availability] n/a —
🪪 Trusts the runner's identity, not the replicator's 1/1 🟢 100%
AWS Backplane — not applicable

AWS automation principal conventions (WIF or cross-account StackSet) — applies to 0 modules

No applicable modules.

Azure Backplane — ✅ all passing

Azure UAMI-based automation principal conventions — applies to 1 modules

Module Score 🪪 🚫 🚫 🔑 🔗 ⚡ 🧹 📤 📍
azure/aks-namespace 🟢 100% ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅

Azure Backplane — Summary

Emoji Criterion Coverage Status
🪪 Uses azurerm_user_assigned_identity 1/1 🟢 100%
🚫 No azuread_application resources 1/1 🟢 100%
🚫 No azuread_service_principal resources 1/1 🟢 100%
🔑 No azuread_application_password resources 1/1 🟢 100%
🔗 Uses azurerm_federated_identity_credential 1/1 🟢 100%
⚡ workload_identity_federation is non-nullable 1/1 🟢 100%
🧹 No create_service_principal_name toggle 1/1 🟢 100%
📤 Outputs identity (client_id, principal_id, tenant_id) 1/1 🟢 100%
📍 Integration has azure_location 1/1 🟢 100%
GCP Backplane — not applicable

GCP workload-identity-federation automation principal conventions — applies to 0 modules

No applicable modules.

STACKIT Backplane — not applicable

STACKIT WIF-based automation principal conventions — applies to 0 modules

No applicable modules.

Testing — some checks failing

End-to-end test coverage — applies to 3 modules

Module Score ⚙️ 🧪 🚫 ✅
aks/github-connector 🟡 50% ✅ ❌ ✅ ❌
aks/starterkit 🔴 25% ❌ ❌ ✅ ❌
azure/aks-namespace 🟢 100% ✅ ✅ ✅ ✅

Testing — Summary

Emoji Criterion Coverage Status
⚙️ backplane/ directory (optional tier) 2/3 🟡 67%
🧪 e2e/ test directory exists 1/3 🔴 33%
🚫 no .tftest.hcl outside e2e/ 3/3 🟢 100%
✅ e2e/ contains .tftest.hcl files 1/3 🔴 33%

📈 Overall Summary

Overall Average Score: 94%

Score Distribution

  • 🟢 High maturity (≥80%): 3 modules
  • 🟡 Medium maturity (50–79%): 0 modules
  • 🔴 Low maturity (<50%): 0 modules

@aws-amplify-eu-central-1

Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-383.d1o16zfeoh2slu.amplifyapp.com

Jelledb and others added 2 commits October 12, 2026 14:01
…ll them from workspace members

The block creates an admin, edit and view security group per namespace, looks
up the workspace members it receives through USER_PERMISSIONS, adds each to
the group their workspace role maps to, and binds the groups to the matching
cluster roles. Existing group IDs can still be bound alongside. The backplane
gains Graph User.Read.All and Group.ReadWrite.All.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…e the quota static

Drops the admin, edit and view group object ID inputs from the namespace block
and the starterkit's namespace_group_object_ids that fed them. The resource
quota becomes a static, platform-set input instead of a user input.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant