🎯 MỤC TIÊU BÀI HỌC
- ✅ Multi-tenancy models (soft vs hard isolation)
- ✅ Namespace-per-team/environment strategy
- ✅ Network Policies cho namespace isolation
- ✅ RBAC per tenant
- ✅ Tenant onboarding automation (Kyverno generate)
PHẦN 1: MULTI-TENANCY MODELS
Multi-Tenancy Models:
Model 1: Namespace per Environment
┌────────────────────────────────┐
│ Shared K8s Cluster │
│ ┌──────┐ ┌──────┐ ┌────────┐ │
│ │ dev │ │staging│ │ prod │ │
│ │ │ │ │ │ │ │
│ └──────┘ └──────┘ └────────┘ │
└────────────────────────────────┘
Model 2: Namespace per Team
┌────────────────────────────────┐
│ Shared K8s Cluster │
│ ┌────────┐ ┌────────┐ │
│ │team-a │ │team-b │ │
│ │-staging│ │-staging│ ... │
│ │-prod │ │-prod │ │
│ └────────┘ └────────┘ │
└────────────────────────────────┘
Model 3: Cluster per Team/Env (hard isolation)
┌────────┐ ┌────────┐ ┌──────────┐
│Dev │ │Staging │ │Production│
│Cluster │ │Cluster │ │Cluster │
└────────┘ └────────┘ └──────────┘
| Aspect | Namespace Isolation | Cluster Isolation |
|---|---|---|
| Cost | Low (shared infra) | High (separate clusters) |
| Security | Medium (soft boundary) | High (hard boundary) |
| Complexity | Low | High |
| Resource Sharing | Efficient | Wasteful |
| Best For | Same-org teams | Different customers/compliance |
PHẦN 2: NAMESPACE STRATEGY
# Namespace template with all isolation:
apiVersion: v1
kind: Namespace
metadata:
name: team-payments-prod
labels:
team: payments
environment: production
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
annotations:
scheduler.alpha.kubernetes.io/node-selector: "env=production"
# Auto-provision with Kyverno (on namespace create):
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: tenant-onboarding
spec:
rules:
# 1. Create ResourceQuota:
- name: generate-quota
match:
any:
- resources:
kinds: ["Namespace"]
selector:
matchExpressions:
- key: team
operator: Exists
generate:
synchronize: true
apiVersion: v1
kind: ResourceQuota
name: tenant-quota
namespace: "{{request.object.metadata.name}}"
data:
spec:
hard:
requests.cpu: "8"
requests.memory: 16Gi
limits.cpu: "16"
limits.memory: 32Gi
pods: "50"
services.loadbalancers: "2"
# 2. Create LimitRange:
- name: generate-limitrange
match:
any:
- resources:
kinds: ["Namespace"]
selector:
matchExpressions:
- key: team
operator: Exists
generate:
synchronize: true
apiVersion: v1
kind: LimitRange
name: tenant-limits
namespace: "{{request.object.metadata.name}}"
data:
spec:
limits:
- type: Container
default:
cpu: 200m
memory: 256Mi
defaultRequest:
cpu: 100m
memory: 128Mi
# 3. Create default NetworkPolicy:
- name: generate-netpol
match:
any:
- resources:
kinds: ["Namespace"]
selector:
matchExpressions:
- key: team
operator: Exists
generate:
synchronize: true
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
name: deny-all-default
namespace: "{{request.object.metadata.name}}"
data:
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
egress:
- to: []
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
PHẦN 3: NETWORK ISOLATION
# Allow intra-namespace traffic:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: team-payments-prod
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {}
---
# Allow ingress from gateway only:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-gateway
namespace: team-payments-prod
spec:
podSelector:
matchLabels:
app: payment-service
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
app: istio-gateway
ports:
- port: 8080
---
# Allow egress to database namespace:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-to-database
namespace: team-payments-prod
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
purpose: database
ports:
- port: 5432
- to: []
ports:
- port: 53
protocol: UDP
PHẦN 4: RBAC PER TENANT
# Team RBAC:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: team-developer
namespace: team-payments-prod
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["pods", "deployments", "services", "configmaps", "jobs"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: [""]
resources: ["pods/log", "pods/exec"]
verbs: ["get", "create"]
# No access to secrets, RBAC, or namespace-level resources
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: payments-team-binding
namespace: team-payments-prod
subjects:
- kind: Group
name: team-payments
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: team-developer
apiGroup: rbac.authorization.k8s.io
💡 KEY TAKEAWAYS
- Namespace-per-team: Balance isolation vs resource efficiency
- Automated onboarding: Kyverno generates Quota + LimitRange + NetworkPolicy
- Network isolation: Default deny-all, allow specific cross-namespace
- RBAC per tenant: Role per team, no cluster-admin
- PSS labels: Enforce restricted on all tenant namespaces
🎯 BÀI TẬP
Bài tập 1: Tenant Onboarding
- Create namespace with team label → verify auto-provisioned resources
- Verify NetworkPolicy blocks cross-namespace traffic
- Test RBAC: team member can deploy, but not access secrets
Bài tập 2: Cross-Namespace Communication
- Allow team-A service to call team-B API via NetworkPolicy
- Configure Istio AuthorizationPolicy for service-to-service auth
📚 BÀI TIẾP THEO
Trong Bài 44: Disaster Recovery & Backup Strategies, chúng ta sẽ bắt đầu Section 11 — DR & Chaos Engineering.