MATIH Platform is in active MVP development. Documentation reflects current implementation status.
17. Kubernetes & Helm
Tenant Isolation

Tenant Isolation

Tenant isolation network policies ensure that workloads running in different tenant namespaces cannot communicate with each other. This is a critical security boundary in the MATIH multi-tenant architecture, preventing data leakage and unauthorized access between tenant environments.


Isolation Model

The MATIH platform supports two tenant isolation levels:

LevelNetwork IsolationCompute IsolationData Isolation
Namespace-isolatedNetworkPolicy per namespaceShared nodes, resource quotasSeparate databases/schemas
DedicatedNetworkPolicy + dedicated nodesDedicated node poolDedicated database instances

Default Deny Policy

Each tenant namespace starts with a default deny-all policy:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: tenant-acme
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress: []
  egress: []

This ensures that no traffic flows to or from the tenant namespace until explicit allow rules are created.

Tenant-to-Shared-Service Access

Tenant workloads can access shared platform services through explicit egress rules:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-shared-services
  namespace: tenant-acme
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    # DNS
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
 
    # API Gateway
    - to:
        - namespaceSelector:
            matchLabels:
              name: matih-system
          podSelector:
            matchLabels:
              app: api-gateway
      ports:
        - protocol: TCP
          port: 8080
 
    # AI Service
    - to:
        - namespaceSelector:
            matchLabels:
              name: matih-data-plane
          podSelector:
            matchLabels:
              app: ai-service
      ports:
        - protocol: TCP
          port: 8000

Cross-Tenant Denial

The critical isolation rule prevents any tenant from reaching another tenant namespace:

SourceDestinationAllowed
tenant-acmetenant-acmeYes (intra-namespace)
tenant-acmetenant-betaNo (blocked)
tenant-acmematih-systemLimited (API Gateway only)
tenant-acmematih-data-planeLimited (shared services only)
tenant-acmematih-monitoringNo
matih-data-planetenant-acmeLimited (ingress controller only)

Ingress to Tenant Services

Tenant-specific services receive traffic only through the dedicated tenant ingress controller:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-tenant-ingress
  namespace: tenant-acme
spec:
  podSelector:
    matchLabels:
      app: tenant-frontend
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: tenant-acme
          podSelector:
            matchLabels:
              app: ingress-nginx
      ports:
        - protocol: TCP
          port: 3000

Label Requirements

Tenant isolation depends on correct namespace labels:

LabelPurposeExample
nameNamespace name referencename: tenant-acme
matih.io/tenant-idTenant identifiermatih.io/tenant-id: acme
matih.io/namespace-typeNamespace categorymatih.io/namespace-type: tenant
matih.io/isolation-levelIsolation tiermatih.io/isolation-level: namespace

Provisioning Integration

Network policies are created automatically during tenant provisioning:

  1. Tenant Service creates the namespace with required labels
  2. Default deny policy is applied
  3. Shared service egress rules are created
  4. Tenant ingress policy is created
  5. Connectivity is validated

Verification

Tenant isolation can be verified using the validation script:

./scripts/tools/validate-tenant-ingress.sh --tenant acme

Troubleshooting

IssueSymptomResolution
Tenant cannot access AI serviceConnection timeoutVerify egress rule to matih-data-plane
Cross-tenant data leakUnauthorized namespace accessCheck default-deny policy exists
Missing namespace labelsPolicies not matchingVerify namespace labels with expected values
Ingress not workingTenant frontend unreachableCheck ingress controller pod labels