---
id: w7/m1/t003
title: "Tenant NetworkPolicies: default-deny + Traefik / same-workspace / own-datastore / internet allows"
worker: worker7
status: done
estimate: 60m
depends_on: [w7/m1/t002]
---

## Objective

Ship the tenant-side policies per the t001 ADR: default-deny ingress on tenant pods except from Traefik and same-workspace pods; egress allowed to kube-dns, the public internet, and same-workspace services (incl. the workspace's own CNPG/Valkey) — everything else in the cluster denied.

## Context

- Mechanism + dialect fixed by t001 (label-scoped in shared ns vs namespace-per-workspace; k8s NetworkPolicy vs CiliumNetworkPolicy).
- Selectors ride t002's `app.bex.co/workspace` labels.
- Traefik terminates ingress (docs/ADR005-custom-domain.md); its namespace/pods need an ingress allow.
- "Internet yes, cluster no" egress: Cilium `toEntities: world`, or ipBlock `0.0.0.0/0` minus cluster/RFC1918 CIDRs with plain NetworkPolicy.
- Owner: per the ADR — either operator-reconciled per-workspace policy objects (mechanism, `lego/operator/`) or static manifests in `deploy/gitops/`.

## Steps

1. Implement the policy set the ADR chose (per-workspace or template) with the four allows: Traefik ingress, same-workspace ingress/egress, own-datastore egress, DNS + world egress.
2. Cover the wake activator path if `BEX_ACTIVATOR_SERVICE` is set (activator must still reach sleeping apps' services).
3. Deploy to the local mock cluster (`scripts/mock-cluster.sh`) and smoke: sample app still serves via its URL.

## Files

- `lego/operator/internal/controller/` (new policy builder + wiring) **or** `deploy/gitops/` manifests — per the t001 ADR
- `docs/ADR022-tenant-isolation.md` (record the final policy shape)

## Acceptance criteria

- [ ] Policy objects present for tenant workloads on a live cluster; `examples/whoami-app.yaml` still reaches Ready and serves via Traefik
- [ ] Cross-workspace pod→pod curl blocked; same-workspace private-service call succeeds (full matrix is t005)
- [ ] Sleep/wake (w1/m4) still works with policies in place

## Out of scope

- Platform-namespace lockdown (t004); the scripted full matrix (t005)
