Tenant Namespaces
MATIH provisions isolated Kubernetes namespaces for each tenant, providing resource isolation, network boundaries, and independent scaling. Tenant namespaces are created automatically during the tenant provisioning lifecycle (see Chapter 7).
Namespace Naming Convention
Tenant namespaces follow the pattern: tenant-{slug}
Examples:
tenant-acmefor Acme Corporationtenant-bigcorpfor BigCorp Inc.tenant-startup-xyzfor Startup XYZ
Provisioning Flow
When a new tenant is created through the Tenant Service API, the following Kubernetes resources are provisioned:
- Namespace with labels for identification and network policy matching
- ResourceQuota based on the tenant's subscription tier
- LimitRange with default container resource limits
- NetworkPolicy for tenant isolation
- ServiceAccount with minimal RBAC permissions
- Image pull secrets synced from the platform ACR
- ConfigMap with tenant-specific configuration
- Secrets synced via External Secrets Operator from the tenant's vault
Resource Quotas by Tier
| Tier | CPU Requests | Memory Requests | Pods | Storage |
|---|---|---|---|---|
| STARTER | 8 | 16Gi | 30 | 50Gi |
| STANDARD | 32 | 64Gi | 100 | 200Gi |
| ENTERPRISE | 80 | 160Gi | 300 | 500Gi |
| UNLIMITED | No limit | No limit | 500 | 2Ti |
Network Isolation
Each tenant namespace has a default-deny network policy with explicit allowances:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tenant-default-deny
namespace: tenant-acme
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tenant-allow-platform
namespace: tenant-acme
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
matih.io/namespace-type: platform
egress:
- to:
- namespaceSelector:
matchLabels:
matih.io/namespace-type: platform
ports:
- protocol: TCP
port: 8080
- protocol: TCP
port: 5432
- protocol: TCP
port: 6379
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53Tenants are fully isolated from each other -- no cross-tenant traffic is allowed.
Dedicated Ingress
Production tenants receive a dedicated NGINX Ingress Controller with a separate LoadBalancer IP:
# Deployed via infrastructure/helm/ingress-nginx/values-tenant.yaml
controller:
ingressClassResource:
name: "nginx-tenant-acme"
service:
type: LoadBalancerThe tenant's DNS zone is configured as a child of the platform zone:
matih.ai (Platform zone)
|
+-- acme.matih.ai (Tenant zone - NS delegation)
|
+-- api.acme.matih.ai (A record -> Tenant LB IP)
+-- app.acme.matih.ai (A record -> Tenant LB IP)Tenant Labels
Every resource in a tenant namespace carries billing and identification labels:
labels:
matih.io/tenant-id: "tenant-acme"
matih.io/tenant-tier: "ENTERPRISE"
matih.io/cost-center: "CC-DATA-PLANE"
matih.io/cost-type: "dynamic"
matih.io/environment: "production"