---
id: w7/m1/t001
title: "ADR docs/ADR022-tenant-isolation.md: threat model + namespace-tier mechanism choice"
worker: worker7
status: done
estimate: 45m
depends_on: []
---

## Objective

Fix the isolation design before any policy ships: write the ADR recording the threat model (tenant↔tenant lateral movement; tenant→platform services) and the namespace-tier mechanism choice — workspace-label-scoped policies inside a shared apps namespace vs namespace-per-workspace (a projector change) — plus the policy dialect (portable `networking.k8s.io/v1` NetworkPolicy vs `CiliumNetworkPolicy`).

## Context

- All tenant Apps project into one namespace: `BEX_CP_APPS_NAMESPACE`, default `default` (`lego/backend/cmd/api/main.go:137`). If the shared-namespace option wins, the ADR must also decide moving off `default` to a dedicated apps namespace so policies/PSS labels (w7/m2) don't hit unrelated workloads.
- The only NetworkPolicy in-tree is kubebuilder's scaffolded `lego/operator/config/network-policy/allow-metrics-traffic.yaml` — nothing governs tenant workloads.
- CNI is Cilium (w1/m7 t004: live cluster reports Cilium status), so either policy dialect enforces; Cilium's `toEntities: world` makes "internet yes, cluster no" egress cleaner.
- Same-workspace traffic must stay open: private services talk over internal Service DNS (docs/ADR006-bex-api.md service types); managed datastores are CNPG Clusters (docs/ADR009-postgresql-management.md) and Valkey StatefulSets (docs/ADR021-keyvalue-management.md).
- Hard constraint: `.pm/DO_NOT_DO.md` isolation ladder — namespace tier now, microVM parked in `.pm/FUTURE-MAYBE.md`, never vcluster.

## Steps

1. Enumerate what a tenant pod can reach today (other tenants' pods, CNPG/Valkey services, bex-api `:8091`, OpenBao `:8200`, Prometheus, zot) as the threat-model table.
2. Compare label-scoped-in-shared-ns vs namespace-per-workspace: projector churn, URL/metrics/logs blast radius, policy count and simplicity, quota story (w7/m2).
3. Decide mechanism + dialect, record consequences and rejected options; add the doc to CLAUDE.md's docs index.

## Files

- `docs/ADR022-tenant-isolation.md` (new)
- `CLAUDE.md` (docs index row)

## Acceptance criteria

- [ ] ADR states the chosen mechanism and dialect with the threat-model table and rejected alternatives
- [ ] DO_NOT_DO ladder position + microVM FUTURE-MAYBE deferral cross-referenced
- [ ] `npx prettier@3.4.2 --write "**/*.md"` clean

## Out of scope

- Implementing any policy or label (t002–t004)
